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 boolean
true
if thisConverterRegistry
has been initialized. -
Constructor Summary
Constructors -
Method Summary
Modifier and TypeMethodDescriptionvoid
clear()
Removes all converters from this registry and set thisServiceRegistry
state 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, ornull
if 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
, ornull
if none.private static <S,
T> ObjectConverter <S, T> findEquals
(ObjectConverter<S, T> converter, ObjectConverter<S, ? extends T> existing) Ifexisting
or 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 void
Invoked when thisConverterRegistry
needs to be initialized.private static boolean
isExactlyFor
(ObjectConverter<?, ?> converter, Class<?> targetClass) Returnstrue
if 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 isInitializedtrue
if thisConverterRegistry
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 thisConverterRegistry
needs 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
ObjectConverter
instances from theMETA-INF/services
directories as below: -
clear
public void clear()Removes all converters from this registry and set thisServiceRegistry
state 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) Ifexisting
or one of its children is equal to the givenconverter
, returns it. Otherwise returnsnull
.- Type Parameters:
S
- theconverter
source class.T
- theconverter
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
, ornull
if none.
-
findEquals
Returns a converter equals to the givenconverter
, ornull
if none.- Type Parameters:
S
- theconverter
source class.T
- theconverter
target class.- Parameters:
converter
- the converter to replace by an existing converter, if possible.- Returns:
- a converter equals to
converter
, ornull
if 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 aAngle
class is defined, the static initializer of that class could register a converter fromAngle
toDouble
.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 producingDouble
can be used for clients that just ask for aNumber
.Which super-classes of the target class are registered
Consider a converter from classS
to classT
where the two classes are related in a hierarchy as below: Invoking this method will register the given converter for all the following cases:S
→T
S
→C4
S
→C2
orS
→C1
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 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
Returnstrue
if 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.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, orObject.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
Creates a new converter for the given source and target types, ornull
if 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
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, orObject.class
for any.- Returns:
- a newly generated converter from the specified source class to the target class,
or
null
if 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 areFallbackConverter
s which delegate their work to the leafs.
-