Class ConverterRegistry

java.lang.Object
org.apache.sis.internal.converter.ConverterRegistry
Direct Known Subclasses:
SystemRegistry

public class ConverterRegistry extends Object
A collection of ObjectConverter instances. A converter from the given source type to the given target type can be obtained by a call to find(Class, Class). If no converter exists for the given source and target types, then this registry searches for a suitable converter accepting a parent class of the given source type, or returning a sub-class of the given target type.

New instances of ConverterRegistry are initially empty. Custom converters must be explicitly registered. However, a system-wide registry initialized with default converters is provided by the SystemRegistry.INSTANCE constant.

Note about conversions from interfaces

ConverterRegistry is primarily designed for handling converters from classes to other classes. Handling of interfaces are not prohibited (and actually sometimes supported), but their behavior may be more ambiguous than in the case of classes because of multi-inheritance in interface hierarchy.

Thread safety

This base class is thread-safe. Subclasses shall make sure that any overridden methods remain safe to call from multiple threads.
Since:
0.3
Version:
0.8
  • Field Details

    • converters

      private final Map<ClassPair<?,?>,ObjectConverter<?,?>> converters
      The map of converters of any kind. For any key of type ClassPair<S,T>, the value shall be of type ObjectConverter<? super S, ? extends T>. To ensure this constraint, values should be read and written using only the type-safe get(ClassPair) and put(ClassPair, ObjectConverter) methods.

      In the special case where the value is actually SystemConverter<S,T>, then the key and the value may be the same instance (in order to save object allocations).

      Synchronization note

      Synchronization if performed by synchronized(converters) statements. We tried ReadWriteLock, but this is not very convenient because read operations may be followed by write operations at any time if the requested converter is not in the cache. Furthermore, profiling has not identified this class as a noticeable contention point.
    • isInitialized

      private boolean isInitialized
      true if this ConverterRegistry has been initialized.
      See Also:
  • Constructor Details

    • ConverterRegistry

      public ConverterRegistry()
      Creates an initially empty set of object converters.
  • Method Details

    • initialize

      protected void initialize()
      Invoked when this ConverterRegistry needs to be initialized. This method is automatically invoked the first time that register(ObjectConverter) or find(Class, Class) is invoked.

      The default implementation does nothing. Subclasses can override this method in order to register a default set of converters. For example, a subclass could fetch the ObjectConverter instances from the META-INF/services directories as below:

    • clear

      public void clear()
      Removes all converters from this registry and set this ServiceRegistry state to uninitialized. The initialize() method will be invoked again when first needed.
    • get

      private <S, T> ObjectConverter<? super S,? extends T> get(ClassPair<S,T> key)
      Gets the value from the converters map for the given key.
    • put

      private <S, T> void put(ClassPair<S,T> key, ObjectConverter<? super S,? extends T> converter)
      Puts the given value in the converters map for the given key.
    • findEquals

      private static <S, T> ObjectConverter<S,T> findEquals(ObjectConverter<S,T> converter, ObjectConverter<S,? extends T> existing)
      If existing or one of its children is equal to the given converter, returns it. Otherwise returns null.
      Type Parameters:
      S - the converter source class.
      T - the converter target class.
      Parameters:
      converter - the converter to replace by an existing converter, if possible.
      existing - existing converter to test.
      Returns:
      a converter equals to converter, or null if none.
    • findEquals

      final <S, T> ObjectConverter<S,T> findEquals(SystemConverter<S,T> converter)
      Returns a converter equals to the given converter, or null if none.
      Type Parameters:
      S - the converter source class.
      T - the converter target class.
      Parameters:
      converter - the converter to replace by an existing converter, if possible.
      Returns:
      a converter equals to converter, or null if none.
    • register

      public <S, T> void register(ObjectConverter<S,T> converter)
      Registers a new converter. This method should be invoked only once for a given converter, for example in class static initializer. For example if a Angle class is defined, the static initializer of that class could register a converter from Angle to Double.

      This method registers the converter for the target class, some parents of the target class (see below) and every interfaces except Cloneable which are implemented by the target class and not by the source class. For example, a converter producing Double can be used for clients that just ask for a Number.

      Which super-classes of the target class are registered

      Consider a converter from class S to class T where the two classes are related in a hierarchy as below: Invoking this method will register the given converter for all the following cases:
      • ST
      • SC4
      No SC2 or SC1 converter will be registered, because an identity converter would be sufficient for those cases.

      Which sub-classes of the source class are registered

      Sub-classes of the source class will be registered on a case-by-case basis when the find(Class, Class) is invoked, because we cannot know the set of all sub-classes in advance (and would not necessarily want to register all of them anyway).
      Type Parameters:
      S - the class of source value.
      T - the class of target (converted) values.
      Parameters:
      converter - the converter to register.
    • register

      private <S, T> void register(ClassPair<S,T> key, ObjectConverter<S,? extends T> converter)
      Registers the given converter under the given key. If a previous converter is already registered for the given key, then there is a choice:
      • If one converter is defined exactly for the <S,T> classes while the other converter is not, then the most accurate converter will have precedence.
      • Otherwise the new converter is registered in addition of the old one in a chain of fallbacks.
      Parameters:
      key - the key under which to register the converter.
      converter - the converter to register.
    • isExactlyFor

      private static boolean isExactlyFor(ObjectConverter<?,?> converter, Class<?> targetClass)
      Returns true if the given converter has exactly the given target class. If the given converter is a FallbackConverter, then all children shall have the same target type too.
    • findExact

      public <S, T> ObjectConverter<S,T> findExact(Class<S> sourceClass, Class<T> targetClass) throws UnconvertibleObjectException
      Returns a converter for exactly the given source and target classes. The default implementation invokes find(Class, Class), then ensures that the converter source and target classes are the same ones than the classes given in argument to this method.
      Type Parameters:
      S - the source class.
      T - the target class.
      Parameters:
      sourceClass - the source class.
      targetClass - the target class, or Object.class for any.
      Returns:
      the converter from the specified source class to the target class.
      Throws:
      UnconvertibleObjectException - if no converter is found for the given classes.
    • find

      public <S, T> ObjectConverter<? super S,? extends T> find(Class<S> sourceClass, Class<T> targetClass) throws UnconvertibleObjectException
      Returns a converter suitable for the given source and target classes. This method may return a converter accepting more generic sources or converting to more specific targets.
      Type Parameters:
      S - the source class.
      T - the target class.
      Parameters:
      sourceClass - the source class.
      targetClass - the target class, or Object.class for any.
      Returns:
      the converter from the specified source class to the target class.
      Throws:
      UnconvertibleObjectException - if no converter is found for the given classes.
    • createConverter

      protected <S, T> ObjectConverter<S,T> createConverter(Class<S> sourceClass, Class<T> targetClass)
      Creates a new converter for the given source and target types, or null if none. This method is invoked by find(source, target) when no registered converter were found for the given types.

      The default implementation checks for the trivial case where an identity converter would fit, and returns null in all other cases. Subclasses can override this method in order to generate some converters dynamically.

      Type Parameters:
      S - the source class.
      T - the target class.
      Parameters:
      sourceClass - the source class.
      targetClass - the target class, or Object.class for any.
      Returns:
      a newly generated converter from the specified source class to the target class, or null if none.
    • toString

      public String toString()
      Returns a string representation of registered converters for debugging purpose. The converters are show in a tree where all real converters are leafs. Parents of those leafs are FallbackConverters which delegate their work to the leafs.
      Overrides:
      toString in class Object
      Returns:
      a string representation of registered converters.