time | Calls | line |
|---|
| | 1 | function str = string(jobj)
|
| | 2 | %STRING Convert a Java object or array of objects to a MATLAB string
|
| | 3 | % STR = string(JOBJ) returns a string array STR the same size and dimensions as
|
| | 4 | % the Java array JOBJ, setting each STR member to the equivalent value of the
|
| | 5 | % JOBJ member's toString() method.
|
| | 6 | %
|
| | 7 | % If the JOBJ is not rectangular, the length of STR's dimensions will be
|
| | 8 | % equal to the maximum length of the corresponding dimension of JOBJ.
|
| | 9 | % Nonexistent and null elements in JOBJ result in <missing> elements in STR.
|
| | 10 | %
|
| | 11 | % Unlike the char function, this returns the value of toString() for objects
|
| | 12 | % of type java.lang.Number even if the class of JOBJ is java.lang.Object.
|
| | 13 |
|
| | 14 | % Copyright 2016-2019 The MathWorks, Inc.
|
| | 15 |
|
| | 16 | function str = jstring2string(jstr)
|
| | 17 | % Convert a Java string vector or scalar into a string vector. Input may be
|
| | 18 | % null, or may have null elements, which get converted to <missing>.
|
| | 19 | if isempty(jstr)
|
| | 20 | str = string(NaN);
|
| | 21 | else
|
| | 22 | % we don't have a builtin to directly convert a Java String scalar or
|
| | 23 | % vector to a string, but we can convert it to a cell array of chars.
|
| | 24 | cel = cell(jstr);
|
| | 25 | if ~iscellstr(cel)
|
| | 26 | % If it's not a cellstr, it's because it had [] cells where
|
| | 27 | % the input had nulls, so convert one cell at a time.
|
| | 28 | str(length(cel)) = string(NaN); % preallocate with <missing>
|
| | 29 | for i = 1 : length(cel)
|
| | 30 | ch = cel{i};
|
| | 31 | if ischar(ch)
|
| | 32 | % if not char, it must be [] which stays <missing>
|
| | 33 | str(i) = string(ch);
|
| | 34 | end
|
| | 35 | end
|
| | 36 | else
|
| | 37 | % convert the cellstr to a string all at once
|
| | 38 | str = string(cel);
|
| | 39 | end
|
| | 40 | end
|
| | 41 | end
|
| | 42 |
|
| | 43 | % Optimize the most common case: a scalar java.lang.String becomes a scalar string
|
< 0.001 | 1 | 44 | if isa(jobj, 'java.lang.String')
|
< 0.001 | 1 | 45 | str = jstring2string(jobj);
|
< 0.001 | 1 | 46 | return;
|
| | 47 | end
|
| | 48 |
|
| | 49 | % Next most common case: call toString on any scalar. Test using Java's isArray
|
| | 50 | % instead of MATLAB's isScalar, because isScalar returns true for 1-element
|
| | 51 | % Java array, and we need to treat that as an array, not a scalar. Anyway
|
| | 52 | % isScalar bombs if the object doesn't implement toDouble.
|
| | 53 | if ~jobj.getClass.isArray()
|
| | 54 | str = jstring2string(javaMethod('toString', jobj));
|
| | 55 | return;
|
| | 56 | end
|
| | 57 |
|
| | 58 | % So it must be a Java array. Get number of Java dimensions by counting ['s in
|
| | 59 | % class name.
|
| | 60 | className = char(jobj.getClass.getName());
|
| | 61 | nameStart = find(className ~= '[', 1);
|
| | 62 | ndims = nameStart - 1;
|
| | 63 | assert(ndims > 0);
|
| | 64 |
|
| | 65 | % dims(i) will eventually be the length of the i'th dimension, which is the maximum
|
| | 66 | % length of any of the vectors at the i'th dimension.
|
| | 67 | dims = zeros(1, ndims, 'int32');
|
| | 68 | % fill in the values of dims, to get size of the resulting array
|
| | 69 | getMaxDim(jobj, 1);
|
| | 70 |
|
| | 71 | % preallocate rectangular str array with the required number of dimensions and
|
| | 72 | % lengths and initialize it with <missing> in all elements
|
| | 73 | if ndims == 1 && dims > 0
|
| | 74 | % Special case of single dimension of nonzero size, insure we create column
|
| | 75 | % vector instead of square matrix
|
| | 76 | str(dims,1) = string(NaN);
|
| | 77 | else
|
| | 78 | str = repmat(string(NaN), dims);
|
| | 79 | end
|
| | 80 | if any(dims == 0)
|
| | 81 | return;
|
| | 82 | end
|
| | 83 |
|
| | 84 | basicClass = className(nameStart:end);
|
| | 85 | isString = basicClass == "Ljava.lang.String;";
|
| | 86 |
|
| | 87 | % copy all non-null elements of jobj into their proper positions in str
|
| | 88 | fill(jobj);
|
| | 89 |
|
| | 90 | function getMaxDim(jobj, dim)
|
| | 91 | % Fill in dims with the maximum number of elements at each dimension. For jobj, a
|
| | 92 | % possibly multidimensional jobj array, set dims(dim) to the max of it and the
|
| | 93 | % length of jobj, bump dim and recurse on each child of jobj.
|
| | 94 | assert(isempty(jobj) || jobj.getClass.isArray); % false if we recursed too far
|
| | 95 | % length of Java array refers to immediate children
|
| | 96 | dims(dim) = max([dims(dim) length(jobj)]);
|
| | 97 | if dim < length(dims)
|
| | 98 | % If not yet at the bottom level, recurse on each child, stopping at the
|
| | 99 | % last dimension, which points to the array elements
|
| | 100 | arrayfun(@(array) getMaxDim(array, dim+1), jobj);
|
| | 101 | end
|
| | 102 | end
|
| | 103 |
|
| | 104 | function fill(jobj, indices, dim)
|
| | 105 | % Insert the stringified value of each element of the multidimensional java array
|
| | 106 | % jobj into the same-indexed element of str. Original caller supplies just jobj.
|
| | 107 | % indices and dim arguments are for recursion as we go down the dimensions
|
| | 108 | if nargin == 1
|
| | 109 | % indices is cell array of indices into element of str that we are working
|
| | 110 | % on. Need to have it as a cell array so we can use its members as indices.
|
| | 111 | indices = num2cell(ones(1, ndims));
|
| | 112 | % dim is the dimension into indices that we are working on
|
| | 113 | dim = 1;
|
| | 114 | end
|
| | 115 | % Loop through each member of jobj. If the Java array element from which jobj
|
| | 116 | % was fetched was null, jobj is []. If it was an empty array, jobj is an empty
|
| | 117 | % Java array. In both cases we ignore it and all descendents beneath it will
|
| | 118 | % remain <missing>.
|
| | 119 | if isString && dim == length(dims)
|
| | 120 | % In the most common case, if the object was a Java String array, then
|
| | 121 | % we can call our string conversion function directly on each bottom-level
|
| | 122 | % string vector, instead of recursing to do one element at a time.
|
| | 123 | js = jstring2string(jobj); % result's length is equal to jobj length
|
| | 124 | str(indices{1:dim-1},1:numel(js)) = js; % unfilled elements correspond to nulls, which stay <missing>
|
| | 125 | else
|
| | 126 | for i = 1 : length(jobj)
|
| | 127 | % i is the dim'th index
|
| | 128 | indices{dim} = i;
|
| | 129 | if length(dims) > dim
|
| | 130 | % not at bottom level, so recurse, passing in the indices we are working
|
| | 131 | % on and the dimension (position in indices)
|
| | 132 | fill(jobj(i), indices, dim+1);
|
| | 133 | else
|
| | 134 | % We're at the bottom level, where jobj(i) is the Java array element to
|
| | 135 | % stringify and insert into str. Use callJava on Array.get() to fetch
|
| | 136 | % it, instead of indexing directly, to assure we get a Java Object,
|
| | 137 | % instead of having it automatically converted to a MATLAB type, which
|
| | 138 | % happens when jobj is of type Object. This is to be sure we get Java's
|
| | 139 | % toString() value out of it--converting to a MATLAB type could lose
|
| | 140 | % precision (e.g., Long is converted to double), and string() on a
|
| | 141 | % double or float returns a format different from toString().
|
| | 142 | element = matlab.internal.callJava('get', 'java.lang.reflect.Array', jobj, i-1);
|
| | 143 | if ~isempty(element)
|
| | 144 | % Look only at nonempty elements. An empty element means it was a
|
| | 145 | % Java null, which we leave as <missing>.
|
| | 146 | if ~isString
|
| | 147 | % Call toString if it isn't already String. Note that
|
| | 148 | % element might be an array, in the unlikely case that jobj
|
| | 149 | % is an Object array which has an array as an element. In
|
| | 150 | % this case toString will return something like
|
| | 151 | % "[Ljava.lang.Object;@72c4504"
|
| | 152 | element = javaMethod('toString', element);
|
| | 153 | end
|
| | 154 | str(indices{:}) = jstring2string(element);
|
| | 155 | else % empty else for code coverage
|
| | 156 | end
|
| | 157 | end
|
| | 158 | end
|
| | 159 | end
|
| | 160 | end
|
| | 161 | end
|
Other subfunctions in this file are not included in this listing.