sirius.kernel.di.transformers.Transformers Maven / Gradle / Ivy
/*
* Made with all the love in the world
* by scireum in Remshalden, Germany
*
* Copyright by scireum GmbH
* http://www.scireum.de - [email protected]
*/
package sirius.kernel.di.transformers;
import sirius.kernel.commons.MultiMap;
import sirius.kernel.commons.Tuple;
import sirius.kernel.di.std.PriorityParts;
import sirius.kernel.di.std.Register;
import java.util.Collection;
import java.util.List;
/**
* Helper class to utilize available {@link Transformer} instances to perform conversions.
*
* This class is automatically utilized by {@link Composable} but kept public in case custom implementations need to
* access this functionality.
*/
@Register(classes = Transformers.class)
public class Transformers {
private MultiMap, Class>>, Transformer, ?>> factories;
@PriorityParts(Transformer.class)
private List> factoryList;
private Collection> getFactories(Class> sourceType, Class> targetType) {
if (factories == null) {
MultiMap, Class>>, Transformer, ?>> result = MultiMap.createOrdered();
for (Transformer, ?> factory : factoryList) {
result.put(Tuple.create(factory.getSourceClass(), factory.getTargetClass()), factory);
}
factories = result;
}
return factories.get(Tuple.create(sourceType, targetType));
}
/**
* Determines if the given object can be transformed into the given target type.
*
* @param source the object to transform
* @param target the target type
* @param the generic type of the target
* @return true if a conversion (adaption) is possible, false otherwise
*/
public boolean canMake(Object source, Class target) {
return make(source, target) != null;
}
/**
* Tries to transform the given object to match the given target type.
*
* The class is only transformed if it implements the {@link Transformable} interface.
*
* Transformations are done recursively until a matching transformation happens or the class tried
* to transform does not implement the {@link Transformable} interface.
*
* @param source the object to transform
* @param target the target type
* @param the generic type of the target
* @return a transformed object matching the given type or null to indicate that no conversion was possible
*/
@SuppressWarnings("unchecked")
public T make(Object source, Class target) {
Class> classToTransform = source.getClass();
while (Transformable.class.isAssignableFrom(classToTransform)) {
T result = makeWithClass(source, classToTransform, target);
if (result != null) {
return result;
}
classToTransform = classToTransform.getSuperclass();
}
return null;
}
@SuppressWarnings("unchecked")
private T makeWithClass(Object sourceObject, Class> sourceClass, Class target) {
for (Transformer, ?> adapterFactory : getFactories(sourceClass, target)) {
Transformer super Object, T> next = (Transformer super Object, T>) adapterFactory;
T result = next.make(sourceObject);
if (result != null) {
return result;
}
}
return null;
}
}