use of org.apache.sis.metadata.PropertyComparator in project sis by apache.
the class PropertyAccessor method getGetters.
/**
* Returns the getters. The returned array should never be modified,
* since it may be shared among many instances of {@code PropertyAccessor}.
*
* @param type the metadata interface.
* @param implementation the class of metadata implementations, or {@code type} if none.
* @param standardImpl the implementation specified by the {@link MetadataStandard}, or {@code null} if none.
* @return the getters declared in the given interface (never {@code null}).
*/
private static Method[] getGetters(final Class<?> type, final Class<?> implementation, final Class<?> standardImpl) {
/*
* Indices map is used for choosing what to do in case of name collision.
*/
Method[] getters = (MetadataStandard.IMPLEMENTATION_CAN_ALTER_API ? implementation : type).getMethods();
final Map<String, Integer> indices = new HashMap<>(hashMapCapacity(getters.length));
boolean hasExtraGetter = false;
int count = 0;
for (Method candidate : getters) {
if (Classes.isPossibleGetter(candidate)) {
final String name = candidate.getName();
if (name.startsWith(SET)) {
// Paranoiac check.
continue;
}
/*
* The candidate method should be declared in the interface. If not, then we require it to have
* a @UML annotation. The later case happen when the Apache SIS implementation contains methods
* for a new international standard not yet reflected in the GeoAPI interfaces.
*/
if (MetadataStandard.IMPLEMENTATION_CAN_ALTER_API) {
if (type == implementation) {
if (!type.isInterface() && !candidate.isAnnotationPresent(UML.class)) {
// @UML considered optional only for interfaces.
continue;
}
} else
try {
candidate = type.getMethod(name, (Class[]) null);
} catch (NoSuchMethodException e) {
if (!candidate.isAnnotationPresent(UML.class)) {
// Not a method from an interface, and no @UML in implementation.
continue;
}
}
}
/*
* At this point, we are ready to accept the method. Before doing so, check if the method override
* an other method defined in a parent class with a covariant return type. The JVM considers such
* cases as two different methods, while from a Java developer point of view this is the same method.
*/
final Integer pi = indices.put(name, count);
if (pi != null) {
final Class<?> pt = getters[pi].getReturnType();
final Class<?> ct = candidate.getReturnType();
if (ct.isAssignableFrom(pt)) {
// Previous type was more accurate.
continue;
}
if (pt.isAssignableFrom(ct)) {
getters[pi] = candidate;
continue;
}
throw new ClassCastException(Errors.format(Errors.Keys.IllegalArgumentClass_3, Classes.getShortName(type) + '.' + name, ct, pt));
}
getters[count++] = candidate;
if (!hasExtraGetter) {
hasExtraGetter = name.equals(EXTRA_GETTER.getName());
}
}
}
/*
* Sort the standard methods before to add the extra methods (if any) in order to
* keep the extra methods last. The code checking for the extra methods require
* them to be last.
*/
Arrays.sort(getters, 0, count, new PropertyComparator(implementation, standardImpl));
if (!hasExtraGetter) {
if (getters.length == count) {
getters = Arrays.copyOf(getters, count + 1);
}
getters[count++] = EXTRA_GETTER;
}
getters = ArraysExt.resize(getters, count);
return getters;
}
Aggregations