Class ConverterRegistry
- Direct Known Subclasses:
SystemRegistry
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 Summary
FieldsModifier and TypeFieldDescriptionprivate final Map<ClassPair<?,?>, ObjectConverter<?, ?>> The map of converters of any kind.private booleantrueif thisConverterRegistryhas been initialized. -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionvoidclear()Removes all converters from this registry and set thisServiceRegistrystate to uninitialized.protected <S,T> ObjectConverter<S, T> createConverter(Class<S> sourceClass, Class<T> targetClass) Creates a new converter for the given source and target types, ornullif none.<S,T> ObjectConverter<? super S, ? extends T> Returns a converter suitable for the given source and target classes.(package private) final <S,T> ObjectConverter<S, T> findEquals(SystemConverter<S, T> converter) Returns a converter equals to the givenconverter, ornullif none.private static <S,T> ObjectConverter<S, T> findEquals(ObjectConverter<S, T> converter, ObjectConverter<S, ? extends T> existing) Ifexistingor one of its children is equal to the givenconverter, returns it.<S,T> ObjectConverter<S, T> Returns a converter for exactly the given source and target classes.private <S,T> ObjectConverter<? super S, ? extends T> Gets the value from the converters map for the given key.protected voidInvoked when thisConverterRegistryneeds to be initialized.private static booleanisExactlyFor(ObjectConverter<?, ?> converter, Class<?> targetClass) Returnstrueif the given converter has exactly the given target class.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.private <S,T> void register(ClassPair<S, T> key, ObjectConverter<S, ? extends T> converter) Registers the given converter under the given key.<S,T> void register(ObjectConverter<S, T> converter) Registers a new converter.toString()Returns a string representation of registered converters for debugging purpose.
-
Field Details
-
converters
The map of converters of any kind. For any key of typeClassPair<S,T>, the value shall be of typeObjectConverter<? super S, ? extends T>. To ensure this constraint, values should be read and written using only the type-safeget(ClassPair)andput(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 bysynchronized(converters)statements. We triedReadWriteLock, 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 isInitializedtrueif thisConverterRegistryhas 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 thisConverterRegistryneeds to be initialized. This method is automatically invoked the first time thatregister(ObjectConverter)orfind(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
ObjectConverterinstances from theMETA-INF/servicesdirectories as below: -
clear
public void clear()Removes all converters from this registry and set thisServiceRegistrystate to uninitialized. Theinitialize()method will be invoked again when first needed. -
get
Gets the value from the converters map for the given key. -
put
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) Ifexistingor one of its children is equal to the givenconverter, returns it. Otherwise returnsnull.- Type Parameters:
S- theconvertersource class.T- theconvertertarget class.- Parameters:
converter- the converter to replace by an existing converter, if possible.existing- existing converter to test.- Returns:
- a converter equals to
converter, ornullif none.
-
findEquals
Returns a converter equals to the givenconverter, ornullif none.- Type Parameters:
S- theconvertersource class.T- theconvertertarget class.- Parameters:
converter- the converter to replace by an existing converter, if possible.- Returns:
- a converter equals to
converter, ornullif none.
-
register
Registers a new converter. This method should be invoked only once for a given converter, for example in class static initializer. For example if aAngleclass is defined, the static initializer of that class could register a converter fromAngletoDouble.This method registers the converter for the target class, some parents of the target class (see below) and every interfaces except
Cloneablewhich are implemented by the target class and not by the source class. For example, a converter producingDoublecan be used for clients that just ask for aNumber.Which super-classes of the target class are registered
Consider a converter from classSto classTwhere the two classes are related in a hierarchy as below: Invoking this method will register the given converter for all the following cases:S→TS→C4
S→C2orS→C1converter 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 thefind(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
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.
- If one converter is defined exactly for the
-
isExactlyFor
Returnstrueif the given converter has exactly the given target class. If the given converter is aFallbackConverter, 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 invokesfind(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, orObject.classfor 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, orObject.classfor 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
Creates a new converter for the given source and target types, ornullif none. This method is invoked byfind(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
nullin 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, orObject.classfor any.- Returns:
- a newly generated converter from the specified source class to the target class,
or
nullif none.
-
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 areFallbackConverters which delegate their work to the leafs.
-