Class PropertyAccessor
- Direct Known Subclasses:
SpecialCases
PropertyAccessor
gives access
to all public properties of an instance of a metadata object. It uses reflection for this
purpose, a little bit like the Java Beans framework.
This accessor groups the properties in two categories:
- The standard properties defined by the GeoAPI (or other standard) interfaces.
Those properties are the only ones accessible by most methods in this class, except
equals(Object, Object, ComparisonMode)
andwalkWritable(MetadataVisitor, Object, Object)
. - Extra properties defined by the
IdentifiedObject
interface. Those properties invisible in the ISO 19115-1 model, but appears in ISO 19115-3 XML marshalling. So we do the same in the SIS implementation: invisible in map and tree view, but visible in XML marshalling.
Thread safety
The samePropertyAccessor
instance can be safely used by many threads without synchronization
on the part of the caller. Subclasses shall make sure that any overridden methods remain safe to call
from multiple threads, because the same PropertyAccessor
instances are typically used by many
ModifiableMetadata
instances.- Since:
- 0.3
- Version:
- 1.3
-
Field Summary
FieldsModifier and TypeFieldDescriptionprivate final int
Number ofgetters
methods that can be used, regardless of whether the methods are visible or hidden to the user.(package private) static final int
Enumeration constants for themode
argument in theset(int, Object, Object, int)
method.(package private) static final int
Enumeration constants for themode
argument in thecount(Object, ValueExistencePolicy, int)
method.(package private) static final int
Enumeration constants for themode
argument in thecount(Object, ValueExistencePolicy, int)
method.(package private) static final int
Enumeration constants for themode
argument in thecount(Object, ValueExistencePolicy, int)
method.private final Class<?>[]
The types of elements for the corresponding getter and setter methods.private static final Method
Additional getter to declare in every list of getter methods that do not already provide their owngetIdentifiers()
method.private final Method[]
The public getter methods.(package private) static final int
Enumeration constants for themode
argument in theset(int, Object, Object, int)
method.(package private) final Class
<?> The implementation class, ortype
if none.private org.opengis.metadata.ExtendedElementInformation[]
The property information, including the name and restrictions on valid values.private ObjectConverter
<?, ?> The last converter used.Index of getter or setter for a given name.private final String[]
The JavaBeans property names.(package private) static final int
Enumeration constants for themode
argument in theset(int, Object, Object, int)
method.(package private) static final int
Enumeration constants for themode
argument in theset(int, Object, Object, int)
method.private final Method[]
The corresponding setter methods, ornull
if none.private final int
Numbers of methods to show to the user.(package private) final Class
<?> The implemented metadata interface. -
Constructor Summary
ConstructorsConstructorDescriptionPropertyAccessor
(Class<?> type, Class<?> implementation, Class<?> standardImpl) Creates a new property accessor for the specified metadata implementation. -
Method Summary
Modifier and TypeMethodDescriptionprivate void
addMapping
(String name, Integer index) Adds the given (name, index) pair tomapping
, making sure we don't overwrite an existing entry with different value.private void
addMappingWithLowerCase
(String name, Integer index) Adds the given (name, index) pair and its lower-case variant.private void
Converts values in the specified array to the given type.private Boolean
convert
(Method getter, Object metadata, Object oldValue, Object[] newValues, Class<?> elementType, boolean append) Converts a value to the type required by a setter method.(package private) final int
count()
Returns the number of properties that can be read.(package private) final int
count
(Object metadata, ValueExistencePolicy valuePolicy, int mode) Counts the number of non-null or non-empty properties.boolean
equals
(Object metadata1, Object metadata2, ComparisonMode mode) Compares the two specified metadata objects.(package private) Object
Returns the value for the specified metadata, ornull
if none.private static Object
Gets a value from the specified metadata.private static Method[]
getGetters
(Class<?> type, Class<?> implementation, Class<?> standardImpl) Returns the getters.(package private) final int
Returns the index of the specified property, or -1 if none.(package private) final org.opengis.metadata.ExtendedElementInformation
information
(org.opengis.metadata.citation.Citation standard, int index) Returns the information for the property at the given index.(package private) final boolean
isCollectionOrMap
(int index) private boolean
isDeprecated
(int index) Returnstrue
if the property at the given index is deprecated, either in the interface that declare the method or in the implementation class.(package private) final boolean
isMap
(int index) Returnstrue
if the type at the given index isMap
.(package private) final boolean
Returnstrue
if theimplementation
class has at least one setter method.(package private) final boolean
isWritable
(int index) Returnstrue
if the property at the given index is writable.(package private) final String
name
(int index, KeyNamePolicy keyPolicy) Returns the name of the property at the given index, ornull
if none.(package private) CharSequence
Returns a remark or warning to format with the value at the given index, ornull
if none.(package private) Object
Sets a value for the specified metadata and returns the old value ifmode
isRETURN_PREVIOUS
.private static void
Sets a value for the specified metadata.toString()
Returns a string representation of this accessor for debugging purpose.(package private) Class
<?> type
(int index, TypeValuePolicy policy) Returns the type of the property at the given index.(package private) final void
walkReadable
(MetadataVisitor<?> visitor, Object metadata) InvokesMetadataVisitor.visit(Class, Object)
for all non-null properties in the given metadata.(package private) final void
walkWritable
(MetadataVisitor<?> visitor, Object source, Object target) InvokesMetadataVisitor.visit(Class, Object)
for all writable properties in the given metadata.
-
Field Details
-
COUNT_FIRST
static final int COUNT_FIRSTEnumeration constants for themode
argument in thecount(Object, ValueExistencePolicy, int)
method.- See Also:
-
COUNT_SHALLOW
static final int COUNT_SHALLOWEnumeration constants for themode
argument in thecount(Object, ValueExistencePolicy, int)
method.- See Also:
-
COUNT_DEEP
static final int COUNT_DEEPEnumeration constants for themode
argument in thecount(Object, ValueExistencePolicy, int)
method.- See Also:
-
RETURN_NULL
static final int RETURN_NULLEnumeration constants for themode
argument in theset(int, Object, Object, int)
method.- See Also:
-
RETURN_PREVIOUS
static final int RETURN_PREVIOUSEnumeration constants for themode
argument in theset(int, Object, Object, int)
method.- See Also:
-
APPEND
static final int APPENDEnumeration constants for themode
argument in theset(int, Object, Object, int)
method.- See Also:
-
IGNORE_READ_ONLY
static final int IGNORE_READ_ONLYEnumeration constants for themode
argument in theset(int, Object, Object, int)
method.- See Also:
-
EXTRA_GETTER
Additional getter to declare in every list of getter methods that do not already provide their owngetIdentifiers()
method. We handle this method specially because it is needed for XML marshalling in ISO 19115-3 compliant document, while not part of abstract ISO 19115-1 specification.- See Also:
-
type
The implemented metadata interface. -
implementation
The implementation class, ortype
if none. The following condition must hold:Design note: We could enforce the above-cited restriction with type parameter: if thetype
field is declared asClass<T>
, then thisimplementation
field would be declared asClass<? extends T>
. However, this is not useful for this internal class because the<T>
type is never known; we have the<?>
type everywhere except in tests, which result in compiler warnings atPropertyAccessor
construction. -
allCount
private final int allCountNumber ofgetters
methods that can be used, regardless of whether the methods are visible or hidden to the user. This is eithergetters.length
orgetters.length-1
, depending on whether theEXTRA_GETTER
method needs to be skipped or not. -
standardCount
private final int standardCountNumbers of methods to show to the user. This is always equal or lower thanallCount
. This count may be lower thanallCount
for two reasons:- The
EXTRA_GETTER
method is not part of the international standard. - The interface contains deprecated methods from an older international standard. Example: changes caused by the upgrade from ISO 19115:2003 to ISO 19115:2014.
- The
-
getters
The public getter methods. This array should not contain any null element. They are the methods defined in the interface, not the implementation class.This array shall not contains any
null
elements. -
setters
The corresponding setter methods, ornull
if none. This array must have the same length thangetters
. For everygetters[i]
element,setters[i]
is the corresponding setter ornull
if there is none. -
names
The JavaBeans property names. They are computed at construction time, interned then cached. Those names are often the same than field names (at least in SIS implementation), so it is reasonable to intern them in order to shareString
instances.This array shall not contains any
null
elements.- See Also:
-
elementTypes
The types of elements for the corresponding getter and setter methods. If a getter method returns a collection, then this is the type of elements in that collection. Otherwise this is the type of the returned value itself.Notes:
-
mapping
Index of getter or setter for a given name. Original names are duplicated with the same name converted to lower cases accordingLocale.ROOT
conventions, for case-insensitive searches. This map shall be considered as immutable after construction.The keys in this map are both inferred from the method names and fetched from the UML annotations. Consequently, the map may contain many entries for the same value if some method names are different than the UML identifiers.
- See Also:
-
lastConverter
The last converter used. This is remembered on the assumption that the same converter will often be reused for the same property. This optimization can reduce the cost of looking for a converter, and also reduce thread contention since it reduces the number of calls to the synchronizedObjectConverters.find(Class, Class)
method.- See Also:
-
informations
private transient org.opengis.metadata.ExtendedElementInformation[] informationsThe property information, including the name and restrictions on valid values. The array will be created when first needed. Anull
element means that the information at that index has not yet been computed.- See Also:
-
-
Constructor Details
-
PropertyAccessor
Creates a new property accessor for the specified metadata implementation.- Parameters:
type
- the interface implemented by the metadata class.implementation
- the class of metadata implementations, ortype
if none.standardImpl
- the implementation specified by theMetadataStandard
, ornull
if none. This is the same thanimplementation
unless a custom implementation is used.
-
-
Method Details
-
addMapping
Adds the given (name, index) pair tomapping
, making sure we don't overwrite an existing entry with different value. -
addMappingWithLowerCase
Adds the given (name, index) pair and its lower-case variant. -
getGetters
Returns the getters. The returned array should never be modified, since it may be shared among many instances ofPropertyAccessor
.- Parameters:
type
- the metadata interface.implementation
- the class of metadata implementations, ortype
if none.standardImpl
- the implementation specified by theMetadataStandard
, ornull
if none.- Returns:
- the getters declared in the given interface (never
null
).
-
count
final int count()Returns the number of properties that can be read. This is the properties to show in map or tree, not including hidden properties like deprecated methods orEXTRA_GETTER
method.- See Also:
-
indexOf
Returns the index of the specified property, or -1 if none. The search is case-insensitive.- Parameters:
name
- the name of the property to search.mandatory
- whether this method shall throw an exception or return-1
if the given name is not found.- Returns:
- the index of the given name, or -1 if none and
mandatory
isfalse
. - Throws:
IllegalArgumentException
- if the name is not found andmandatory
istrue
.
-
name
Returns the name of the property at the given index, ornull
if none.- Parameters:
index
- the index of the property for which to get the name.keyPolicy
- the kind of name to return.- Returns:
- the name of the given kind at the given index, or
null
if the index is out of bounds.
-
type
Returns the type of the property at the given index. The returned type is usually a GeoAPI interface (at least in the case of SIS implementation).If the given policy is
ELEMENT_TYPE
, then:- Primitive types like
double
orint
are converted to their wrapper types. - If the property is a collection, then returns the type of collection elements.
- Parameters:
index
- the index of the property.policy
- the kind of type to return.- Returns:
- the type of property values, or
null
if unknown.
- Primitive types like
-
isCollectionOrMap
final boolean isCollectionOrMap(int index) -
isMap
final boolean isMap(int index) Returnstrue
if the type at the given index isMap
. -
isDeprecated
private boolean isDeprecated(int index) Returnstrue
if the property at the given index is deprecated, either in the interface that declare the method or in the implementation class. A method may be deprecated in the implementation but not in the interface when the implementation has been updated for a new standard while the interface is still reflecting the old standard. -
information
final org.opengis.metadata.ExtendedElementInformation information(org.opengis.metadata.citation.Citation standard, int index) Returns the information for the property at the given index. The information are created when first needed.- Parameters:
standard
- the standard which define thetype
interface.index
- the index of the property for which to get the information.- Returns:
- the information for the property at the given index, or
null
if the index is out of bounds. - See Also:
-
remarks
Returns a remark or warning to format with the value at the given index, ornull
if none. This is provided when the value may look surprising, for example the longitude values in a geographic bounding box crossing the anti-meridian. -
isWritable
final boolean isWritable()Returnstrue
if theimplementation
class has at least one setter method. -
isWritable
final boolean isWritable(int index) Returnstrue
if the property at the given index is writable. -
get
Returns the value for the specified metadata, ornull
if none. If the given index is out of bounds, then this method returnsnull
, so it is safe to invoke this method even ifindexOf(String, boolean)
returned -1.- Parameters:
index
- the index of the property for which to get a value.metadata
- the metadata object to query.- Returns:
- the value, or
null
if none or if the given is out of bounds. - Throws:
BackingStoreException
- if the implementation threw a checked exception.
-
get
Gets a value from the specified metadata. We do not expect any checked exception to be thrown, since classes in theorg.opengis.metadata
packages do not declare any. However if a checked exception is throw anyway (maybe in user defined "standard"), it will be wrapped in aBackingStoreException
. Unchecked exceptions are propagated.- Parameters:
method
- the method to use for the query.metadata
- the metadata object to query.- Throws:
BackingStoreException
- if the implementation threw a checked exception.- See Also:
-
set
Object set(int index, Object metadata, Object value, int mode) throws UnmodifiableMetadataException, ClassCastException, BackingStoreException Sets a value for the specified metadata and returns the old value ifmode
isRETURN_PREVIOUS
. Themode
argument can be one of the following:- RETURN_NULL: Set the value and returns
null
. - RETURN_PREVIOUS: Set the value and returns the previous value. If the previous value was a collection or a map, then that value is copied in a new collection or map before the new value is set because the setter methods typically copy the new collection in their existing instance.
- APPEND: Set the value only if it does not overwrite an existing value, then returns
Boolean.TRUE
if the metadata changed as a result of this method call,Boolean.FALSE
if the metadata didn't changed ornull
if the value cannot be set because another value already exists. - IGNORE_READ_ONLY: Set the value and returns
null
on success. If the property is read-only, do not throw an exception; returns exception class instead.
The
APPEND
mode has an additional side effect: it sets theappend
argument totrue
in the call to theconvert(Method, Object, Object, Object[], Class, boolean)
method. See theconvert
javadoc for more information.If the given index is out of bounds, then this method does nothing and return
null
. We do that because theValueMap.remove(Object)
method may invoke this method with an index of -1 if theindexOf(String, boolean)
method didn't found the property name. However, the given value will be silently discarded, so index out-of-bounds shall be used only in the context ofremove
operations (this is not verified).- Parameters:
index
- the index of the property to set.metadata
- the metadata object on which to set the value.value
- the new value.mode
- whether this method should first fetches the old value, as one of the constants listed in this method javadoc.- Returns:
- the old value, or
null
ifmode
wasRETURN_NULL
orIGNORE_READ_ONLY
. - Throws:
UnmodifiableMetadataException
- if the property for the given key is read-only.ClassCastException
- if the given value is not of the expected type.BackingStoreException
- if the implementation threw a checked exception.
- RETURN_NULL: Set the value and returns
-
set
private static void set(Method setter, Object metadata, Object[] newValues) throws BackingStoreException Sets a value for the specified metadata. This method does not attempt any conversion of argument values. Conversion of type, if needed, must have been applied before to call this method.We do not expect any checked exception to be thrown, since classes in the
org.opengis.metadata
packages do not declare any. However if a checked exception is throw anyway, then it will be wrapped in aBackingStoreException
. Unchecked exceptions are propagated.- Parameters:
setter
- the method to use for setting the new value.metadata
- the metadata object to query.newValues
- the argument to give to the method to be invoked.- Throws:
BackingStoreException
- if the implementation threw a checked exception.- See Also:
-
convert
private Boolean convert(Method getter, Object metadata, Object oldValue, Object[] newValues, Class<?> elementType, boolean append) throws ClassCastException, BackingStoreException Converts a value to the type required by a setter method. The values are converted in-place in thenewValues
array. We use an array instead of a single argument and return value because an array will be needed anyway for invoking theconvert(Object[], Class)
andMethod.invoke(Object, Object[])
methods.The collection special case
If the metadata property is a collection, then there is a choice:- If
append
istrue
, then the new value (which may itself be a collection) is unconditionally added to the previous collection. - If
append
isfalse
and the new value is not a collection, then the new value is added to the existing collection. In other words, we behave as a multi-values map for the properties that allow multi-values. - Otherwise the new collection replaces the previous collection. All previous values are discarded.
- Parameters:
getter
- the method to use for fetching the previous value.metadata
- the metadata object to query and modify.oldValue
- the value returned byget(getter, metadata)
, ornull
if unknown. This parameter is only an optimization for avoiding to invoke the getter method twice if the value is already known.newValues
- the argument to convert. The content of this array will be modified in-place. Current implementation requires an array of length 1, however this restriction may be relaxed in a future SIS version if needed.elementType
- the target type (if singleton) or the type of elements in the collection.append
- iftrue
and the value is a collection, then that collection will be added to any previously existing collection instead of replacing it.- Returns:
- if the given value has been added to an existing collection, then whether that existing
collection has been modified as a result of this method call. Otherwise
null
. - Throws:
ClassCastException
- if the element of thearguments
array is not of the expected type.BackingStoreException
- if the implementation threw a checked exception.
- If
-
convert
Converts values in the specified array to the given type. The array content is modified in-place. This method accepts an array instead of a single value because the values to convert may be the content of a collection.- Parameters:
elements
- the array which contains element to convert.targetType
- the base type of target elements.- Throws:
ClassCastException
- if an element cannot be converted.
-
count
final int count(Object metadata, ValueExistencePolicy valuePolicy, int mode) throws BackingStoreException Counts the number of non-null or non-empty properties. Themode
argument can be one of the following:- COUNT_FIRST: stop at the first property found. This mode is used for testing if a metadata is empty or not, without the need to known the exact count.
- COUNT_SHALLOW: count all properties, counting collections as one property.
- COUNT_DEEP: count all properties, counting collections as the number of
properties returned by
Collection.size()
.
- Parameters:
valuePolicy
- the behavior of the count toward null or empty values.mode
- kinds of count, as described above.- Throws:
BackingStoreException
- if the implementation threw a checked exception.- See Also:
-
equals
public boolean equals(Object metadata1, Object metadata2, ComparisonMode mode) throws BackingStoreException Compares the two specified metadata objects. This method implements a shallow comparison, i.e. all metadata properties are compared using theirproperties.equals(…)
method without explicit calls to thisaccessor.equals(…)
method for children. However, the final result may still be a deep comparison.- Parameters:
metadata1
- the first metadata object to compare. This object determines the accessor.metadata2
- the second metadata object to compare.mode
- the strictness level of the comparison.- Throws:
BackingStoreException
- if the implementation threw a checked exception.- See Also:
-
walkReadable
InvokesMetadataVisitor.visit(Class, Object)
for all non-null properties in the given metadata. This method is not recursive, i.e. it does not traverse the children of the elements in the given metadata.- Parameters:
visitor
- the object on which to invokeMetadataVisitor.visit(Class, Object)
.metadata
- the metadata instance for which to visit the non-null properties.- Throws:
Exception
- if an error occurred while visiting a property.
-
walkWritable
InvokesMetadataVisitor.visit(Class, Object)
for all writable properties in the given metadata. This method is not recursive, i.e. it does not traverse the children of the elements in the given metadata.Constraint
In current implementation, ifsource
andtarget
are not the same, thentarget
is assumed empty. The intent is to skip easily null or empty properties.- Parameters:
visitor
- the object on which to invokeMetadataVisitor.visit(Class, Object)
.source
- the metadata from which to read properties. May be the same thantarget
.target
- the metadata instance where to write properties.- Throws:
Exception
- if an error occurred while visiting a property.
-
toString
Returns a string representation of this accessor for debugging purpose. Output example:
-