Class Classes

java.lang.Object
org.apache.sis.util.Static
org.apache.sis.util.Classes

public final class Classes extends Static
Static methods working on Class objects. This class defines helper methods for working with reflection. Some functionalities are:
Since:
0.3
Version:
1.3
  • Field Details

    • EMPTY_ARRAY

      private static final Class<Object>[] EMPTY_ARRAY
      An empty array of classes.
    • EXCLUDES

      private static final String[] EXCLUDES
      Methods to be rejected by isPossibleGetter(Method). They are mostly methods inherited from Object. Only no-argument methods having a non-void return value need to be declared in this list.

      Note that testing type.getDeclaringClass().equals(Object.class) is not sufficient because those methods may be overridden in subclasses.

  • Constructor Details

    • Classes

      private Classes()
      Do not allow instantiation of this class.
  • Method Details

    • changeArrayDimension

      public static Class<?> changeArrayDimension(Class<?> element, int change)
      Changes the array dimension by the given amount. The given class can be a primitive type, a Java object, or an array of the above. If the given change is positive, then the array dimension will be increased by that amount. For example, a change of +1 dimension will change an int class into int[], and a String[] class into String[][]. A change of +2 dimensions is like applying two times a change of +1 dimension.

      The change of dimension can also be negative. For example, a change of -1 dimension will change a String[] class into a String. More specifically:

      • If the given element is null, then this method returns null.
      • Otherwise if the given change is 0, then the given element is returned unchanged.
      • Otherwise if the given change is negative, then Class.getComponentType() is invoked abs(change) times. The result is a null value if abs(change) is greater than the array dimension.
      • Otherwise if element is Void.TYPE, then this method returns Void.TYPE since arrays of void do not exist.
      • Otherwise this method returns a class that represents an array of the given class augmented by the given amount of dimensions.
      Parameters:
      element - the type of elements in the array.
      change - the change of dimension, as a negative or positive number.
      Returns:
      the type of an array of the given element type augmented by the given number of dimensions (which may be negative), or null.
    • boundOfParameterizedProperty

      public static Class<?> boundOfParameterizedProperty(Field field)
      Returns the upper bounds of the parameterized type of the given property. If the property does not have a parameterized type, returns null. If the property has more than one parameterized type, then the parameter examined by this method depends on the property type:
      • If Map, then this method returns the type of keys in map entries.
      • For all other types, this method expects exactly one parameterized type for avoiding ambiguity. If this is not the case, null is returned.
      This method is used for fetching the type of elements in a collection. This information cannot be obtained from a Class instance because of the way parameterized types are implemented in Java (by erasure).

      Examples

      When invoking this method for a field of the following types:
      • Map<String,Number>: returns String.class, the type of keys.
      • Set<Number>: returns Number.class.
      • Set<? extends Number>: returns Number.class as well, because that collection cannot contain instances of super-classes. Number is the upper bound.
      • Set<? super Number>: returns Object.class, because that collection is allowed to contain such elements.
      • Set: returns null because that collection is declared with raw type.
      • Long: returns null because that type is not parameterized.
      Parameters:
      field - the field for which to obtain the parameterized type.
      Returns:
      the upper bound of parameterized type, or null if the given field is not of a parameterized type.
    • boundOfParameterizedProperty

      public static Class<?> boundOfParameterizedProperty(Method method)
      If the given method is a getter or a setter for a parameterized property, returns the upper bounds of the parameterized type. Otherwise returns null. This method provides the same semantic than boundOfParameterizedProperty(Field), but works on a getter or setter method rather than a field. See boundOfParameterizedProperty(Field) javadoc for details.

      This method is used for fetching the type of elements in a collection. This information cannot be obtained from a Class instance because of the way parameterized types are implemented in Java (by erasure).

      Parameters:
      method - the getter or setter method for which to obtain the parameterized type.
      Returns:
      the upper bound of parameterized type, or null if the given method is not a getter or setter for a property of a parameterized type.
    • boundOfParameterizedDeclaration

      public static Class<?> boundOfParameterizedDeclaration(GenericDeclaration typeOrMethod)
      Returns a single bound declared in a parameterized class or a parameterized method. The typeOrMethod argument is usually a Class for a collection type. If the given argument is a non-parameterized class, then this method searches for the first parameterized super-class (see example below). If no parameterized declaration is found, then this method returns null. If the declaration has more than one parameterized type, then this method applies the same heuristic rule as boundOfParameterizedProperty(Field) (see the javadoc of that method for details).

      Examples

      When invoking this method with the following Class argument values:
      • List.class: returns Object.class because List is declared as List<E> (implicitly <E extends Object>).
      • Map.class: returns Object.class because Map is declared as Map<K,V> and, as an heuristic rule, we return the key type of map entry.
      • PrinterStateReasons.class: returns PrinterStateReason.class because PrinterStateReasons is not parameterized but extends HashMap<PrinterStateReason,Severity>.
      • Long.class: returns null because that type is not parameterized.
      This method is used as a fallback when boundOfParameterizedProperty(…) cannot be used.
      Parameters:
      typeOrMethod - the Class or Method from which to get the bounds of its parameter.
      Returns:
      the upper bound of parameterized class or method, or null if this method cannot identify a single parameterized type to return.
      Since:
      1.3
      See Also:
    • getActualTypeArgument

      private static Class<?> getActualTypeArgument(Object typeOrMethod)
      Returns the type argument of the given type or the first parameterized parent type. For example if the given type is List<String>, then this method returns String.class. This method expects a fixed amount of parameterized types (currently 2 if the given type is Map and 1 for all other types), otherwise it returns null.
      See Also:
    • chooseSingleType

      private static int chooseSingleType(Object rawType, int count)
      Chooses (using heuristic rules) a single element in an array of type arguments. The given raw type should be a Class instance when possible, usually a collection type. The given count shall be the number of parameters, for example 2 in Map<String,Integer>.
      Parameters:
      rawType - the parameterized class, as a Class instance if possible.
      count - length of the array of type parameters in which to select a single type.
      Returns:
      index of the parameter to select in an array of length count, or -1 if none.
    • getClass

      @Workaround(library="JDK", version="1.7") public static <T> Class<? extends T> getClass(T object)
      Returns the class of the specified object, or null if object is null. This method is also useful for fetching the class of an object known only by its bound type. As of Java 6, the usual pattern: doesn't seem to work if Number is replaced by a parameterized type T.
      Type Parameters:
      T - the type of the given object.
      Parameters:
      object - the object for which to get the class, or null.
      Returns:
      the class of the given object, or null if the given object was null.
    • getClasses

      private static <T> Set<Class<? extends T>> getClasses(Iterable<? extends T> objects)
      Returns the classes of all objects in the given collection. If the given collection contains some null elements, then the returned set will contain a null element as well. The returned set is modifiable and can be freely updated by the caller.

      Note that interfaces are not included in the returned set.

      Type Parameters:
      T - the base type of elements in the given collection.
      Parameters:
      objects - the collection of objects.
      Returns:
      the set of classes of all objects in the given collection.
    • getStandardType

      public static <T> Class<? super T> getStandardType(Class<T> type)
      Returns the first type or super-type (including interface) considered "standard" in Apache SIS sense. This method applies the following heuristic rules, in that order:
      • If the given type implements at least one interface having the UML annotation, then the first annotated interface is returned.
      • Otherwise the first public class or parent class is returned.
      Those heuristic rules may be adjusted in any future Apache SIS version.
      Type Parameters:
      T - the compile-time type argument.
      Parameters:
      type - the type for which to get the standard interface or class. May be null.
      Returns:
      a standard interface implemented by type, or otherwise the most specific public class. Is null if the given type argument was null.
      Since:
      1.0
    • getAllInterfaces

      public static <T> Class<? super T>[] getAllInterfaces(Class<T> type)
      Returns every interfaces implemented, directly or indirectly, by the given class or interface. This is similar to Class.getInterfaces() except that this method searches recursively in the super-interfaces. For example if the given type is ArrayList, then the returned set will contain List (which is implemented directly) together with its parent interfaces Collection and Iterable.

      Elements ordering

      All interfaces implemented directly by the given type are first and in the order they are declared in the implements or extends clause. Parent interfaces are next.
      Type Parameters:
      T - the compile-time type of the Class argument.
      Parameters:
      type - the class or interface for which to get all implemented interfaces.
      Returns:
      all implemented interfaces (not including the given type if it was an interface), or an empty array if none.
      See Also:
    • getInterfaceSet

      private static Set<Class<?>> getInterfaceSet(Class<?> type)
      Implementation of getAllInterfaces(Class) returning a Set. The public API exposes the method returning an array instead of a set for the following reasons:
      • Consistency with other methods (getLeafInterfaces(Class, Class), Class.getInterfaces()).
      • Because arrays in Java are covariant, while the Set are not. Consequently, callers can cast Class<? super T>[] to Class<?>[] while they cannot cast Set<Class<? super T>> to Set<Class<?>>.
      See getInterfaceSet(Class, Set) javadoc for a note about elements order.
      Parameters:
      type - the class or interface for which to get all implemented interfaces.
      Returns:
      all implemented interfaces (not including the given type if it was an interface), or null if none. Callers can freely modify the returned set.
    • getInterfaceSet

      private static Set<Class<?>> getInterfaceSet(Class<?> type, Set<Class<?>> addTo)
      Adds to the given set every interfaces implemented by the given class or interface. This method invokes itself recursively for adding parent interfaces. The given type is not added to the set.

      Elements ordering

      All interfaces directly implemented by the given type are added first. Then parent interfaces are added recursively. The goal is to increase the chances to have the most specific types first. Example: suppose a class implementing two interfaces: A extends C and B extends C. If the parents of A were added immediately after A, we would get {A, C, B} order. But if instead we add all directly implemented interfaces before to add parents, then we get {A, B, C} order, which is better.
      Parameters:
      type - the type for which to add the interfaces in the given set.
      addTo - the set where to add interfaces, or null if not yet created.
      Returns:
      the given set (may be null), or a new set if the given set was null and at least one interface has been found.
    • getLeafInterfaces

      public static <T> Class<? extends T>[] getLeafInterfaces(Class<?> type, Class<T> baseInterface)
      Returns the interfaces implemented by the given class and assignable to the given base interface, or an empty array if none. If more than one interface extends the given base, then the most specialized interfaces are returned. For example if the given class implements both the Set and Collection interfaces, then the returned array contains only the Set interface.

      Example

      getLeafInterfaces(ArrayList.class, Collection.class) returns an array of length 1 containing List.class.
      Type Parameters:
      T - the type of the baseInterface class argument.
      Parameters:
      type - a class for which the implemented interfaces are desired, or null.
      baseInterface - the base type of the interfaces to search.
      Returns:
      the leaf interfaces matching the given criterion, or an empty array if none.
    • findSpecializedClass

      public static Class<?> findSpecializedClass(Iterable<?> objects)
      Returns the most specific class implemented by the objects in the given collection. If there is more than one specialized class, returns their most specific common super class.

      This method searches for classes only, not interfaces.

      Parameters:
      objects - a collection of objects. May contains duplicated values and null values.
      Returns:
      the most specialized class, or null if the given collection does not contain at least one non-null element.
    • common

      private static Class<?> common(Set<Class<?>> types)
      Returns the most specific class which is a common parent of all the specified classes. This method is not public in order to make sure that it contains only classes, not interfaces, since our implementation is not designed for multi-inheritances.
      Parameters:
      types - the collection where to search for a common parent.
      Returns:
      the common parent, or null if the given collection is empty.
    • findCommonClass

      public static Class<?> findCommonClass(Iterable<?> objects)
      Returns the most specific class which is assignable from the type of all given objects. If no element in the given collection has a type assignable from the type of all other elements, then this method searches for a common super class.

      This method searches for classes only, not interfaces.

      Parameters:
      objects - a collection of objects. May contains duplicated values and null values.
      Returns:
      the most specific class common to all supplied objects, or null if the given collection does not contain at least one non-null element.
    • findCommonClass

      public static Class<?> findCommonClass(Class<?> c1, Class<?> c2)
      Returns the most specific class which is assignable from the given classes or a parent of those classes. This method returns either c1, c2 or a common parent of c1 and c2.

      This method considers classes only, not the interfaces.

      Parameters:
      c1 - the first class, or null.
      c2 - the second class, or null.
      Returns:
      the most specific class common to the supplied classes, or null if both c1 and c2 are null.
    • findCommonInterfaces

      public static Set<Class<?>> findCommonInterfaces(Class<?> c1, Class<?> c2)
      Returns the interfaces which are implemented by the two given classes. The returned set does not include the parent interfaces. For example if the two given objects implement the Collection interface, then the returned set will contain the Collection type but not the Iterable type, since it is implied by the collection type.
      Parameters:
      c1 - the first class.
      c2 - the second class.
      Returns:
      the interfaces common to both classes, or an empty set if none. Callers can freely modify the returned set.
    • implementSameInterfaces

      public static boolean implementSameInterfaces(Class<?> object1, Class<?> object2, Class<?> baseInterface)
      Returns true if the two specified objects implements exactly the same set of interfaces. Only interfaces assignable to baseInterface are compared. Declaration order does not matter.
      Example: in ISO 19111, different interfaces exist for different coordinate system (CS) geometries (CartesianCS, PolarCS, etc.). One can check if two implementations have the same geometry with the following code:
      Parameters:
      object1 - the first object to check for interfaces.
      object2 - the second object to check for interfaces.
      baseInterface - the parent of all interfaces to check.
      Returns:
      true if both objects implement the same set of interfaces, considering only sub-interfaces of baseInterface.
    • getShortName

      public static String getShortName(Class<?> classe)
      Returns the name of the given class without package name, but including the names of enclosing classes if any. This method is similar to the Class.getSimpleName() method, except that if the given class is an inner class, then the returned value is prefixed with the outer class name. Another difference is that if the given class is local or anonymous, then this method returns the name of the parent class.

      The following table compares the various kind of names for some examples:

      Class name comparisons
      Class getName() getSimpleName() getCanonicalName() getShortName()
      String "java.lang.String" "String" "java.lang.String" "String"
      double[] "[D" "double[]" "double[]" "double[]"
      Point2D.Double "java.awt.geom.Point2D$Double" "Double" "java.awt.geom.Point2D.Double" "Point2D.Double"
      Anonymous Comparable "com.mycompany.myclass$1" "" null "Object"
      Parameters:
      classe - the object class (may be null).
      Returns:
      the simple name with outer class name (if any) of the first non-anonymous class in the hierarchy, or "<*>" if the given class is null.
      See Also:
    • getShortClassName

      public static String getShortClassName(Object object)
      Returns the class name of the given object without package name, but including the enclosing class names if any. Invoking this method is equivalent to invoking getShortName(object.getClass()) except for null value. See getShortName(Class) for more information on the class name returned by this method.
      Parameters:
      object - the object (may be null).
      Returns:
      the simple class name with outer class name (if any) of the first non-anonymous class in the hierarchy, or "<*>" if the given object is null.
      See Also:
    • isAssignableToAny

      public static boolean isAssignableToAny(Class<?> type, Class<?>... allowedTypes)
      Returns true if the given type is assignable to one of the given allowed types. More specifically, if at least one allowedTypes[i] element exists for which allowedTypes[i].isAssignableFrom(type) returns true, then this method returns true.

      Special cases:

      • If type is null, then this method returns false.
      • If allowedTypes is null, then this method returns true. This is to be interpreted as "no restriction on the allowed types".
      • Any null element in the allowedTypes array are silently ignored.
      Parameters:
      type - the type to be tested, or null.
      allowedTypes - the allowed types.
      Returns:
      true if the given type is assignable to one of the allowed types.
    • isPossibleGetter

      public static boolean isPossibleGetter(Method method)
      Returns true if the given method may possibly be the getter method for a property. This method implements the algorithm used by SIS in order to identify getter methods in metadata interfaces. We do not rely on naming convention (method names starting with "get" or "is" prefixes) because not every methods follow such convention (e.g. ConformanceResult.pass()).

      The current implementation returns true if the given method meets all the following conditions. Note that a true value is not a guaranteed that the given method is really a getter. The caller is encouraged to perform additional checks if possible.

      • The method does no expect any argument.
      • The method returns a value (anything except void).
      • The method name is not clone, getClass, hashCode, toString or toWKT.
      • The method is not synthetic.

      Those conditions may be updated in any future SIS version.

      Parameters:
      method - the method to inspect.
      Returns:
      true if the given method may possibly be a non-deprecated getter method.