org.jtransfo.JTransfoImpl Maven / Gradle / Ivy
/*
* This file is part of jTransfo, a library for converting to and from transfer objects.
* Copyright (c) PROGS bvba, Belgium
*
* The program is available in open source according to the Apache License, Version 2.0.
* For full licensing details, see LICENSE.txt in the project root.
*/
package org.jtransfo;
import org.jtransfo.internal.ConvertInterceptorChainPiece;
import org.jtransfo.internal.ConverterHelper;
import org.jtransfo.internal.LockableList;
import org.jtransfo.internal.NewInstanceObjectFinder;
import org.jtransfo.internal.ToHelper;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
/**
* jTransfo main access point standard implementation.
*/
public class JTransfoImpl implements JTransfo, ConvertSourceTarget {
private static final String[] DEFAULT_TAGS_WHEN_NO_TAGS = {JTransfo.DEFAULT_TAG_WHEN_NO_TAGS};
private ToHelper toHelper = new ToHelper();
private ConverterHelper converterHelper = new ConverterHelper();
private Map converters = new ConcurrentHashMap();
private List modifyableObjectFinders = new ArrayList();
private LockableList objectFinders = new LockableList();
private List modifyableTypeConverters = new ArrayList();
private List modifyableConvertInterceptors = new ArrayList();
private ConvertSourceTarget convertInterceptorChain;
/**
* Constructor.
*/
public JTransfoImpl() {
modifyableObjectFinders.add(new NewInstanceObjectFinder());
updateObjectFinders();
modifyableTypeConverters.add(new NoConversionTypeConverter());
modifyableTypeConverters.add(new ToDomainTypeConverter(this));
updateTypeConverters();
updateConvertInterceptors();
// CHECKSTYLE EMPTY_BLOCK: OFF
try {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
Class> plugin = cl.loadClass("org.jtransfo.JTransfoJrebelPlugin");
Method setInstance = plugin.getMethod("setInstance", JTransfoImpl.class);
Method preInit = plugin.getMethod("preinit");
if (null != setInstance && null != preInit) {
Object instance = plugin.newInstance();
setInstance.invoke(instance, this);
preInit.invoke(instance);
}
System.out.println("jRebel reload support for jTransfo loaded.");
} catch (Throwable ex) {
// JRebel not found - will not reload directory service automatically.
}
// CHECKSTYLE EMPTY_BLOCK: ON
}
/**
* Get the set of type converters which are used by this jTransfo instance.
*
* You are explicitly allowed to change this list, but beware to do this from one thread only.
*
* Changes in the list are not used until you call {@link #updateTypeConverters()}.
*
* @return current list of type converters.
*/
public List getTypeConverters() {
return modifyableTypeConverters;
}
/**
* Update the list of type converters which is used based on the internal list (see {@link #getTypeConverters()}.
*/
public void updateTypeConverters() {
updateTypeConverters(null);
}
/**
* Update the list of type converters which is used.
*
* When null is passed, this updates the changes to the internal list (see {@link #getTypeConverters()}.
* Alternatively, you can pass the new list explicitly.
*
* @param newConverters new list of type converters
*/
public void updateTypeConverters(List newConverters) {
if (null != newConverters) {
modifyableTypeConverters.clear();
modifyableTypeConverters.addAll(newConverters);
}
for (TypeConverter tc : modifyableTypeConverters) {
if (tc instanceof NeedsJTransfo) {
((NeedsJTransfo) tc).setJTransfo(this);
}
}
converterHelper.setTypeConvertersInOrder(modifyableTypeConverters);
}
/**
* Get the list of {@link ObjectFinder}s to allow customization.
*
* The elements are tried in reverse order (from end to start of list).
*
* You are explicitly allowed to change this list, but beware to do this from one thread only.
*
* Changes in the list are not used until you call {@link #updateObjectFinders()}.
*
* @return list of object finders
*/
public List getObjectFinders() {
return modifyableObjectFinders;
}
/**
* Update the list of object finders which is used based on the internal list (see {@link #getObjectFinders()}.
*/
public void updateObjectFinders() {
updateObjectFinders(null);
}
/**
* Update the list of object finders which is used.
*
* When null is passed, this updates the changes to the internal list (see {@link #getObjectFinders()}.
* Alternatively, you can pass the new list explicitly.
*
* @param newObjectFinders new list of type converters
*/
public void updateObjectFinders(List newObjectFinders) {
if (null != newObjectFinders) {
modifyableObjectFinders.clear();
modifyableObjectFinders.addAll(newObjectFinders);
}
LockableList newList = new LockableList();
newList.addAll(modifyableObjectFinders);
newList.lock();
objectFinders = newList;
}
/**
* Get the list of {@link ConvertInterceptor}s to allow customization.
*
* The elements are tried in reverse order (from end to start of list).
*
* You are explicitly allowed to change this list, but beware to do this from one thread only.
*
* Changes in the list are not used until you call {@link #updateObjectFinders()}.
*
* @return list of object finders
*/
public List getConvertInterceptors() {
return modifyableConvertInterceptors;
}
/**
* Update the list of convert interceptors which is used based on the internal list
* (see {@link #getConvertInterceptors()}.
*/
public void updateConvertInterceptors() {
updateConvertInterceptors(null);
}
/**
* Update the list of convert interceptors which is used.
*
* When null is passed, this updates the changes to the internal list (see {@link #getConvertInterceptors()}.
* Alternatively, you can pass the new list explicitly.
*
* @param newConvertInterceptors new list of convert interceptors
*/
public void updateConvertInterceptors(List newConvertInterceptors) {
if (null != newConvertInterceptors) {
modifyableConvertInterceptors.clear();
modifyableConvertInterceptors.addAll(newConvertInterceptors);
}
ConvertSourceTarget chainPart = this; // actual conversion at the end of the list
for (int i = modifyableConvertInterceptors.size() - 1; i >= 0; i--) {
chainPart = new ConvertInterceptorChainPiece(modifyableConvertInterceptors.get(i), chainPart);
}
convertInterceptorChain = chainPart;
}
@Override
public T convert(Object source, T target, String... tags) {
if (null == source || null == target) {
throw new JTransfoException("Source and target are required to be not-null.");
}
boolean targetIsTo = false;
if (!toHelper.isTo(source)) {
targetIsTo = true;
if (!toHelper.isTo(target)) {
throw new JTransfoException(String.format("Neither source nor target are annotated with DomainClass " +
"on classes %s and %s.", source.getClass().getName(), target.getClass().getName()));
}
}
if (0 == tags.length) {
tags = DEFAULT_TAGS_WHEN_NO_TAGS;
}
return convertInterceptorChain.convert(source, target, targetIsTo, tags);
}
@Override
public T convert(Object source, T target, boolean targetIsTo, String... tags) {
List converters = targetIsTo ? getToToConverters(target.getClass()) :
getToDomainConverters(source.getClass());
for (Converter converter : converters) {
converter.convert(source, target, tags);
}
return target;
}
@Override
public Object convert(Object source) {
if (null == source) {
return null;
}
Class> domainClass = getDomainClass(source.getClass());
return convertTo(source, domainClass);
}
@Override
public T convertTo(Object source, Class targetClass, String... tags) {
Class realTarget = targetClass;
if (null == source) {
return null;
}
if (isToClass(targetClass)) {
realTarget = (Class) getToSubType(targetClass, source);
}
return (T) convert(source, findTarget(source, realTarget), tags);
}
@Override
public List convertList(List> source, Class targetClass, String... tags) {
if (null == source) {
return null;
}
List result = new ArrayList();
for (Object object : source) {
result.add(convertTo(object, targetClass, tags));
}
return result;
}
@Override
public T findTarget(Object source, Class targetClass) {
if (null == source) {
return null;
}
int i = objectFinders.size() - 1;
T target = null;
while (null == target && i >= 0) {
target = objectFinders.get(i--).getObject(targetClass, source);
}
if (null == target) {
throw new JTransfoException("Cannot create instance of target class " + targetClass.getName() +
" for source object " + source + ".");
}
return target;
}
@Override
public Class> getDomainClass(Class> toClass) {
return toHelper.getDomainClass(toClass);
}
@Override
public boolean isToClass(Class> toClass) {
return toHelper.isToClass(toClass);
}
@Override
public Class> getToSubType(Class> toType, Object domainObject) {
return toHelper.getToSubType(toType, domainObject);
}
/**
* Clear cache with converters. Needed when classes are reloaded by something like jRebel or spring reloaded.
*/
public void clearCaches() {
converters.clear();
}
private List getToToConverters(Class toClass) {
return getToConverter(toClass).getToTo();
}
private List getToDomainConverters(Class toClass) {
return getToConverter(toClass).getToDomain();
}
private ToConverter getToConverter(Class toClass) {
ToConverter toConverter = converters.get(toClass);
if (null == toConverter) {
Class> domainClass = getDomainClass(toClass);
toConverter = converterHelper.getToConverter(toClass, domainClass);
converters.put(toClass, toConverter);
}
return toConverter;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy