use of org.apache.sis.util.UnconvertibleObjectException in project sis by apache.
the class RangeFormat method parse.
/**
* Parses text from the given string to produce a range. This method use the full string.
* If there is some unparsed characters after the parsed range, then this method thrown an
* exception.
*
* @param source the text to parse.
* @return the parsed range (never {@code null}).
* @throws ParseException if the given string can not be fully parsed.
*/
public Range<?> parse(final String source) throws ParseException {
final ParsePosition pos = new ParsePosition(0);
UnconvertibleObjectException failure = null;
try {
final Range<?> range = tryParse(source, pos);
if (range != null) {
return range;
}
} catch (UnconvertibleObjectException e) {
failure = e;
}
throw new LocalizedParseException(locale, elementType, source, pos).initCause(failure);
}
use of org.apache.sis.util.UnconvertibleObjectException in project sis by apache.
the class PropertyAccessor method convert.
/**
* Converts values in the specified array to the given type.
* The array content is modified in-place. This method accepts an array instead than
* a single value because the values to convert may be the content of a collection.
*
* @param elements the array which contains element to convert.
* @param targetType the base type of target elements.
* @throws ClassCastException if an element can't be converted.
*/
@SuppressWarnings({ "unchecked", "rawtypes" })
private void convert(final Object[] elements, final Class<?> targetType) throws ClassCastException {
boolean hasNewConverter = false;
ObjectConverter<?, ?> converter = null;
for (int i = 0; i < elements.length; i++) {
final Object value = elements[i];
if (value != null) {
final Class<?> sourceType = value.getClass();
if (!targetType.isAssignableFrom(sourceType))
try {
if (converter == null) {
// Volatile field - read only if needed.
converter = lastConverter;
}
/*
* Require the exact same classes, not parent or subclass,
* otherwise the converter could be stricter than necessary.
*/
if (converter == null || converter.getSourceClass() != sourceType || converter.getTargetClass() != targetType) {
converter = ObjectConverters.find(sourceType, targetType);
hasNewConverter = true;
}
elements[i] = ((ObjectConverter) converter).apply(value);
} catch (UnconvertibleObjectException cause) {
throw (ClassCastException) new ClassCastException(Errors.format(Errors.Keys.IllegalClass_2, targetType, sourceType)).initCause(cause);
}
}
}
if (hasNewConverter) {
// Volatile field - store only if needed.
lastConverter = converter;
}
}
use of org.apache.sis.util.UnconvertibleObjectException in project sis by apache.
the class UnitDimensionTest method testRationalPower.
/**
* Tests a dimension with rational power. This tests use the specific detectivity, which dimension is T^2.5 / (M⋅L).
*/
@Test
@DependsOnMethod({ "testMultiply", "testDivide", "testPow", "testRoot" })
public void testRationalPower() {
final Dimension dim = specificDetectivity();
final Map<Dimension, Fraction> expected = new HashMap<>(4);
assertNull(expected.put(TIME, new Fraction(5, 2)));
assertNull(expected.put(MASS, new Fraction(-1, 1)));
assertNull(expected.put(LENGTH, new Fraction(-1, 1)));
assertMapEquals(expected, ((UnitDimension) dim).components);
try {
dim.getBaseDimensions().toString();
fail("Mapping from Fraction to Integer should not be allowed.");
} catch (UnconvertibleObjectException e) {
final String message = e.getMessage();
assertTrue(message, message.contains("Integer"));
}
// 'toString()' formatting tested in UnitFormatTest.testRationalPower().
}
use of org.apache.sis.util.UnconvertibleObjectException in project sis by apache.
the class StorageConnector method getStorageAs.
/**
* Returns the storage as a view of the given type if possible, or {@code null} otherwise.
* The default implementation accepts the following types:
*
* <ul>
* <li>{@link String}:
* <ul>
* <li>If the {@linkplain #getStorage() storage} object is an instance of the {@link java.nio.file.Path},
* {@link java.io.File}, {@link java.net.URL}, {@link java.net.URI} or {@link CharSequence} types,
* returns the string representation of their path.</li>
*
* <li>Otherwise this method returns {@code null}.</li>
* </ul>
* </li>
* <li>{@link java.nio.file.Path}, {@link java.net.URI}, {@link java.net.URL}, {@link java.io.File}:
* <ul>
* <li>If the {@linkplain #getStorage() storage} object is an instance of the {@link java.nio.file.Path},
* {@link java.io.File}, {@link java.net.URL}, {@link java.net.URI} or {@link CharSequence} types and
* that type can be converted to the requested type, returned the conversion result.</li>
*
* <li>Otherwise this method returns {@code null}.</li>
* </ul>
* </li>
* <li>{@link ByteBuffer}:
* <ul>
* <li>If the {@linkplain #getStorage() storage} object can be obtained as described in bullet 2 of the
* {@code DataInput} section below, then this method returns the associated byte buffer.</li>
*
* <li>Otherwise this method returns {@code null}.</li>
* </ul>
* </li>
* <li>{@link DataInput}:
* <ul>
* <li>If the {@linkplain #getStorage() storage} object is already an instance of {@code DataInput}
* (including the {@link ImageInputStream} and {@link javax.imageio.stream.ImageOutputStream} types),
* then it is returned unchanged.</li>
*
* <li>Otherwise if the input is an instance of {@link java.nio.file.Path}, {@link java.io.File},
* {@link java.net.URI}, {@link java.net.URL}, {@link CharSequence}, {@link InputStream} or
* {@link java.nio.channels.ReadableByteChannel}, then an {@link ImageInputStream} backed by a
* {@link ByteBuffer} is created when first needed and returned.</li>
*
* <li>Otherwise if {@link ImageIO#createImageInputStream(Object)} returns a non-null value,
* then this value is cached and returned.</li>
*
* <li>Otherwise this method returns {@code null}.</li>
* </ul>
* </li>
* <li>{@link ImageInputStream}:
* <ul>
* <li>If the above {@code DataInput} can be created and casted to {@code ImageInputStream}, returns it.</li>
*
* <li>Otherwise this method returns {@code null}.</li>
* </ul>
* </li>
* <li>{@link InputStream}:
* <ul>
* <li>If the {@linkplain #getStorage() storage} object is already an instance of {@link InputStream},
* then it is returned unchanged.</li>
*
* <li>Otherwise if the above {@code ImageInputStream} can be created,
* returns a wrapper around that stream.</li>
*
* <li>Otherwise this method returns {@code null}.</li>
* </ul>
* </li>
* <li>{@link Reader}:
* <ul>
* <li>If the {@linkplain #getStorage() storage} object is already an instance of {@link Reader},
* then it is returned unchanged.</li>
*
* <li>Otherwise if the above {@code InputStream} can be created, returns an {@link InputStreamReader}
* using the encoding specified by {@link OptionKey#ENCODING} if any, or using the system default
* encoding otherwise.</li>
*
* <li>Otherwise this method returns {@code null}.</li>
* </ul>
* </li>
* <li>{@link Connection}:
* <ul>
* <li>If the {@linkplain #getStorage() storage} object is already an instance of {@link Connection},
* then it is returned unchanged.</li>
*
* <li>Otherwise if the storage is an instance of {@link DataSource}, then a connection is obtained
* when first needed and returned.</li>
*
* <li>Otherwise this method returns {@code null}.</li>
* </ul>
* </li>
* <li>Any other types:
* <ul>
* <li>If the storage given at construction time is already an instance of the requested type,
* returns it <i>as-is</i>.</li>
*
* <li>Otherwise this method throws {@link IllegalArgumentException}.</li>
* </ul>
* </li>
* </ul>
*
* Multiple invocations of this method on the same {@code StorageConnector} instance will try
* to return the same instance on a <cite>best effort</cite> basis. Consequently, implementations of
* {@link DataStoreProvider#probeContent(StorageConnector)} methods shall not close the stream or
* database connection returned by this method. In addition, those {@code probeContent(StorageConnector)}
* methods are responsible for restoring the stream or byte buffer to its original position on return.
*
* @param <T> the compile-time type of the {@code type} argument.
* @param type the desired type as one of {@code ByteBuffer}, {@code DataInput}, {@code Connection}
* class or other type supported by {@code StorageConnector} subclasses.
* @return the storage as a view of the given type, or {@code null} if no view can be created for the given type.
* @throws IllegalArgumentException if the given {@code type} argument is not a supported type.
* @throws DataStoreException if an error occurred while opening a stream or database connection.
*
* @see #getStorage()
* @see #closeAllExcept(Object)
*/
public <T> T getStorageAs(final Class<T> type) throws IllegalArgumentException, DataStoreException {
ArgumentChecks.ensureNonNull("type", type);
/*
* Verify if the cache contains an instance created by a previous invocation of this method.
* Note that InputStream may need to be reseted if it has been used indirectly by other kind
* of stream (for example a java.io.Reader). Example:
*
* 1) The storage specified at construction time is a java.nio.file.Path.
* 2) getStorageAs(InputStream.class) opens an InputStream. Caller rewinds it after use.
* 3) getStorageAs(Reader.class) wraps the InputStream. Caller rewinds the Reader after use,
* but invoking BufferedReader.reset() has no effect on the underlying InputStream.
* 4) getStorageAs(InputStream.class) needs to rewind the InputStream itself since it was
* not done at step 3. However doing so invalidate the Reader, so we need to discard it.
*/
Coupled value = getView(type);
if (reset(value)) {
// null is a valid result.
return type.cast(value.view);
}
/*
* If the storage is already an instance of the requested type, returns the storage as-is.
* We check if the storage needs to be reseted in the same way than in getStorage() method.
* As a special case, we ensure that InputStream and Reader can be marked.
*/
if (type.isInstance(storage)) {
@SuppressWarnings("unchecked") T view = (T) storage;
reset();
byte cascade = 0;
if (type == InputStream.class) {
final InputStream in = (InputStream) view;
if (!in.markSupported()) {
view = type.cast(new BufferedInputStream(in));
cascade = (byte) (CLEAR_ON_RESET | CASCADE_ON_RESET);
}
} else if (type == Reader.class) {
final Reader in = (Reader) view;
if (!in.markSupported()) {
view = type.cast(new LineNumberReader(in));
cascade = (byte) (CLEAR_ON_RESET | CASCADE_ON_RESET);
}
}
addView(type, view, null, cascade);
return view;
}
/*
* If the type is not one of the types listed in OPENERS, we delegate to ObjectConverter.
* It may throw UnconvertibleObjectException (an IllegalArgumentException subtype) if the
* given type is unrecognized. So the IllegalArgumentException documented in method javadoc
* happen (indirectly) here.
*/
final Opener<?> method = OPENERS.get(type);
if (method == null) {
T view;
try {
view = ObjectConverters.convert(storage, type);
} catch (UnconvertibleObjectException e) {
if (!OPENERS.containsKey(type))
throw e;
Logging.recoverableException(Logging.getLogger(Modules.STORAGE), StorageConnector.class, "getStorageAs", e);
view = null;
}
addView(type, view);
return view;
}
/*
* No instance has been created previously for the requested type. Open the stream now.
* Some types will need to reset the InputStream or Channel, but the decision of doing
* so or not is left to openers. Result will be cached by the 'createFoo()' method.
* Note that it may cache 'null' value if no stream of the given type can be created.
*/
final Object view;
try {
view = method.open(this);
} catch (DataStoreException e) {
throw e;
} catch (Exception e) {
throw new DataStoreException(Errors.format(Errors.Keys.CanNotOpen_1, getStorageName()), e);
}
return type.cast(view);
}
use of org.apache.sis.util.UnconvertibleObjectException in project sis by apache.
the class MetadataSource method readColumn.
/**
* Invoked by {@link MetadataProxy} for fetching an attribute value from a table.
*
* @param info the interface type (together with cached information).
* This is mapped to the table name in the database.
* @param method the method invoked. This is mapped to the column name in the database.
* @param toSearch contains the identifier and preferred index of the record to search.
* @return the value of the requested attribute.
* @throws SQLException if the SQL query failed.
* @throws MetadataStoreException if a value was not found or can not be converted to the expected type.
*/
final Object readColumn(final LookupInfo info, final Method method, final Dispatcher toSearch) throws SQLException, MetadataStoreException {
/*
* If the identifier is prefixed with a table name as in "{CI_Organisation}identifier",
* the name between bracket is a subtype of the given 'type' argument.
*/
final Class<?> type = subType(info.getMetadataType(), toSearch.identifier);
final Class<?> returnType = Interim.getReturnType(method);
final boolean wantCollection = Collection.class.isAssignableFrom(returnType);
final Class<?> elementType = wantCollection ? Classes.boundOfParameterizedProperty(method) : returnType;
final boolean isMetadata = standard.isMetadata(elementType);
final String tableName = getTableName(type);
final String columnName = info.asNameMap(standard).get(method.getName());
final boolean isArray;
Object value;
synchronized (this) {
if (!getExistingColumns(tableName).contains(columnName)) {
value = null;
isArray = false;
} else {
/*
* Prepares the statement and executes the SQL query in this synchronized block.
* Note that the usage of 'result' must stay inside this synchronized block
* because we can not assume that JDBC connections are thread-safe.
*/
CachedStatement result = take(type, Byte.toUnsignedInt(toSearch.preferredIndex));
if (result == null) {
final SQLBuilder helper = helper();
final String query = helper.clear().append("SELECT * FROM ").appendIdentifier(schema, tableName).append(" WHERE ").append(ID_COLUMN).append("=?").toString();
result = new CachedStatement(type, connection().prepareStatement(query), listeners);
}
value = result.getValue(toSearch.identifier, columnName);
isArray = (value instanceof java.sql.Array);
if (isArray) {
final java.sql.Array array = (java.sql.Array) value;
value = array.getArray();
array.free();
}
toSearch.preferredIndex = (byte) recycle(result, Byte.toUnsignedInt(toSearch.preferredIndex));
}
}
/*
* If the value is an array and the return type is anything except an array of primitive type, ensure
* that the value is converted in an array of type Object[]. In this process, resolve foreigner keys.
*/
if (isArray && (wantCollection || !elementType.isPrimitive())) {
final Object[] values = new Object[Array.getLength(value)];
for (int i = 0; i < values.length; i++) {
Object element = Array.get(value, i);
if (element != null) {
if (isMetadata) {
element = lookup(elementType, element.toString());
} else
try {
element = info.convert(elementType, element);
} catch (UnconvertibleObjectException e) {
throw new MetadataStoreException(Errors.format(Errors.Keys.IllegalPropertyValueClass_3, columnName + '[' + i + ']', elementType, element.getClass()), e);
}
}
values[i] = element;
}
// Now a Java array.
value = values;
if (wantCollection) {
value = specialize(UnmodifiableArrayList.wrap(values), returnType, elementType);
}
}
/*
* Now converts the value to its final type. To be strict, we should convert null values into empty collections
* if the return type is a collection type. But we leave this task to the caller (which is the Dispatcher class)
* for making easier to detect when a value is absent, for allowing Dispatcher to manage its cache.
*/
if (value != null) {
if (isMetadata) {
value = lookup(elementType, value.toString());
} else
try {
value = info.convert(elementType, value);
} catch (UnconvertibleObjectException e) {
throw new MetadataStoreException(Errors.format(Errors.Keys.IllegalPropertyValueClass_3, columnName, elementType, value.getClass()), e);
}
if (wantCollection) {
if (Set.class.isAssignableFrom(returnType)) {
return Collections.singleton(value);
} else {
return Collections.singletonList(value);
}
}
}
return value;
}
Aggregations