package org.simpleflatmapper.csv.impl.asm;
import org.simpleflatmapper.map.FieldMapperErrorHandler;
import org.simpleflatmapper.map.error.RethrowFieldMapperErrorHandler;
import org.simpleflatmapper.reflect.Instantiator;
import org.simpleflatmapper.reflect.asm.AsmFactory;
import org.simpleflatmapper.csv.CsvColumnKey;
import org.simpleflatmapper.csv.ParsingContextFactory;
import org.simpleflatmapper.csv.mapper.CellSetter;
import org.simpleflatmapper.csv.mapper.CsvMapperCellHandler;
import org.simpleflatmapper.csv.mapper.CsvMapperCellHandlerFactory;
import org.simpleflatmapper.csv.mapper.DelayedCellSetterFactory;
import org.simpleflatmapper.util.TypeHelper;
import java.lang.reflect.Type;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
public class CsvAsmFactory {
private final AsmFactory asmFactory;
private final ConcurrentMap<CsvMapperKey, Class<? extends CsvMapperCellHandlerFactory<?>>> csvMapperCache = new ConcurrentHashMap<CsvMapperKey, Class<? extends CsvMapperCellHandlerFactory<?>>>();
public CsvAsmFactory(AsmFactory asmFactory) {
this.asmFactory = asmFactory;
}
@SuppressWarnings("unchecked")
public <T> CsvMapperCellHandlerFactory<T> createCsvMapperCellHandler(Type target,
DelayedCellSetterFactory<T, ?>[] delayedCellSetterFactories,
CellSetter<T>[] setters,
Instantiator<CsvMapperCellHandler<T>, T> instantiator,
CsvColumnKey[] keys,
ParsingContextFactory parsingContextFactory,
FieldMapperErrorHandler<? super CsvColumnKey> fieldErrorHandler,
int maxMethodSize
) throws Exception {
CsvMapperKey key = new CsvMapperKey(keys, setters, delayedCellSetterFactories, instantiator, target, fieldErrorHandler, maxMethodSize);
Class<? extends CsvMapperCellHandlerFactory<?>> typeFactory = csvMapperCache.get(key);
if (typeFactory == null) {
final String className = generateClassNameCsvMapperCellHandler(target, delayedCellSetterFactories, setters);
final String factoryName = className + "Factory";
final byte[] bytes = CsvMapperCellHandlerBuilder.<T>createTargetSetterClass(className, delayedCellSetterFactories, setters, target, fieldErrorHandler == null || fieldErrorHandler instanceof RethrowFieldMapperErrorHandler, maxMethodSize);
final byte[] bytesFactory = CsvMapperCellHandlerBuilder.createTargetSetterFactory(factoryName, className, target);
asmFactory.createClass(className, bytes, target.getClass().getClassLoader());
typeFactory = (Class<? extends CsvMapperCellHandlerFactory<?>>) asmFactory.createClass(factoryName, bytesFactory, target.getClass().getClassLoader());
csvMapperCache.put(key, typeFactory);
}
return (CsvMapperCellHandlerFactory<T>) typeFactory
.getConstructor(Instantiator.class, CsvColumnKey[].class, ParsingContextFactory.class, FieldMapperErrorHandler.class)
.newInstance(instantiator, keys, parsingContextFactory, fieldErrorHandler);
}
private <T> String generateClassNameCsvMapperCellHandler(Type target, DelayedCellSetterFactory<T, ?>[] delayedCellSetterFactories, CellSetter<T>[] setters) {
StringBuilder sb = new StringBuilder();
sb.append( "org.simpleflatmapper.csv.generated.")
.append(asmFactory.getPackageName(target))
.append(".AsmCsvMapperCellHandlerTo").append(asmFactory.replaceArray(TypeHelper.toClass(target).getSimpleName()));
if (delayedCellSetterFactories.length > 0) {
sb.append("DS").append(Integer.toString(delayedCellSetterFactories.length));
}
if (setters.length > 0) {
sb.append("S").append(Integer.toString(setters.length));
}
sb.append("_I").append(Long.toHexString(asmFactory.getNextClassNumber()));
return sb.toString();
}
}