org.simpleflatmapper.map.context.MappingContextFactoryBuilder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of sfm-map Show documentation
Show all versions of sfm-map Show documentation
Java library to map flat record - ResultSet, csv - to java object with minimum configuration and low footprint.
package org.simpleflatmapper.map.context;
import org.simpleflatmapper.map.MappingContext;
import org.simpleflatmapper.map.context.impl.KeyDefinitionBuilder;
import org.simpleflatmapper.reflect.meta.ArrayElementPropertyMeta;
import org.simpleflatmapper.reflect.meta.MapElementPropertyMeta;
import org.simpleflatmapper.reflect.meta.PropertyMeta;
import org.simpleflatmapper.map.context.impl.BreakDetectorMappingContextFactory;
import org.simpleflatmapper.map.context.impl.NullChecker;
import org.simpleflatmapper.map.context.impl.ValuedMappingContextFactory;
import org.simpleflatmapper.reflect.setter.AppendCollectionSetter;
import org.simpleflatmapper.util.Predicate;
import org.simpleflatmapper.util.Supplier;
import java.util.ArrayList;
import java.util.List;
public class MappingContextFactoryBuilder {
private final Counter counter;
private final int currentIndex;
private final MappingContextFactoryBuilder parent;
private final List keys;
private final KeySourceGetter keySourceGetter;
private final List> children = new ArrayList>();
private final List> suppliers = new ArrayList>();
private final PropertyMeta, ?> owner;
public MappingContextFactoryBuilder(KeySourceGetter keySourceGetter) {
this(new Counter(), new ArrayList(), keySourceGetter, null, null);
}
protected MappingContextFactoryBuilder(Counter counter, List keys, KeySourceGetter keySourceGetter, MappingContextFactoryBuilder parent, PropertyMeta, ?> owner) {
this.counter = counter;
this.currentIndex = counter.value;
this.keys = keys;
this.keySourceGetter = keySourceGetter;
this.parent = parent;
this.counter.value++;
this.owner = owner;
}
public void addKey(K key) {
if (!keys.contains(key)) {
keys.add(key);
}
}
public void addSupplier(int index, Supplier> supplier) {
while(suppliers.size() <= index) {
suppliers.add(null);
}
suppliers.set(index, supplier);
}
public Predicate nullChecker() {
return new NullChecker(keys, keySourceGetter);
}
public MappingContextFactoryBuilder newBuilder(List subKeys, PropertyMeta, ?> owner) {
MappingContextFactoryBuilder subBuilder = new MappingContextFactoryBuilder(counter, subKeys, keySourceGetter, this, owner);
children.add(subBuilder);
return subBuilder;
}
@SuppressWarnings("unchecked")
public MappingContextFactory newFactory() {
if (parent != null) {
throw new IllegalStateException();
}
MappingContextFactory context;
if (suppliers.isEmpty()) {
context = MappingContext.EMPTY_FACTORY;
} else {
context = new ValuedMappingContextFactory(suppliers);
}
ArrayList> builders = new ArrayList>();
addAllBuilders(builders);
if (hasKeys(builders)) {
KeyDefinitionBuilder[] keyDefinitionsBuilder = new KeyDefinitionBuilder[builders.get(builders.size() - 1).currentIndex + 1];
for (int i = 0; i < builders.size(); i++) {
MappingContextFactoryBuilder builder = builders.get(i);
populateKey(keyDefinitionsBuilder, builders, builder);
}
KeyDefinition[] keyDefinitions = KeyDefinitionBuilder.toKeyDefinitions(keyDefinitionsBuilder);
KeyDefinition rootKeyDefinition = keyDefinitions[0];
context = new BreakDetectorMappingContextFactory(rootKeyDefinition, keyDefinitions, context);
}
return context;
}
private KeyDefinitionBuilder populateKey(KeyDefinitionBuilder[] keyDefinitions, ArrayList> builders, MappingContextFactoryBuilder builder) {
if (keyDefinitions[builder.currentIndex] != null) {
return keyDefinitions[builder.currentIndex];
}
int parentIndex = builder.getNonEmptyParentIndex();
KeyDefinitionBuilder parent = null;
if (parentIndex != -1) {
parent = keyDefinitions[parentIndex];
if (parent == null) {
// not yet define look for parent and create key
for(int i = 0; i < builders.size(); i++) {
MappingContextFactoryBuilder potentialParent = builders.get(i);
if (potentialParent.currentIndex == parentIndex) {
parent = populateKey(keyDefinitions, builders, potentialParent);
break;
}
}
if (parent == null) {
throw new IllegalArgumentException("Could not find parent for builder " + builder);
}
}
}
KeyDefinitionBuilder keyDefinition;
// empty key use parent key except for child of appendsetter
if (builder.effectiveKeys().isEmpty() && parent != null && ! builder.newObjectOnEachRow()) {
keyDefinition = parent.asChild(builder.currentIndex);
} else {
List keys = new ArrayList(builder.effectiveKeys());
// ignore root parent
if (parentIndex >0 && parent != null) {
appendParentKeys(parent, keys);
}
keyDefinition = new KeyDefinitionBuilder(keys, builder.keySourceGetter, builder.currentIndex);
}
keyDefinitions[builder.currentIndex] = keyDefinition;
return keyDefinition;
}
private void appendParentKeys(KeyDefinitionBuilder parent, List keys) {
// if keys is empty we generate a new row every time so leave empty
if (!keys.isEmpty()) {
for(K k : parent.getKeys()) {
if (!keys.contains(k)) {
keys.add(k);
}
}
}
}
private List effectiveKeys() {
if (!keys.isEmpty()) {
return keys;
}
List keys = new ArrayList();
for(MappingContextFactoryBuilder child : children) {
if (child.isEligibleAsSubstituteKey()) {
keys.addAll(child.effectiveKeys());
}
}
return keys;
}
private boolean newObjectOnEachRow() {
if (owner instanceof ArrayElementPropertyMeta) {
ArrayElementPropertyMeta elementPropertyMeta = (ArrayElementPropertyMeta) owner;
if (elementPropertyMeta.getSetter() instanceof AppendCollectionSetter) {
return true;
}
}
return false;
}
private static boolean hasKeys(ArrayList> builders) {
for(int i = 0; i < builders.size(); i++) {
if (!builders.get(i).hasNoKeys()) return true;
}
return false;
}
private int getRootDetector(List> builders) {
int rootDetector = -1;
// calculate rootDetector
for (int i = 0; i < builders.size(); i++) {
final MappingContextFactoryBuilder builder = builders.get(i);
if (!builder.effectiveKeys().isEmpty()) {
if (builder.currentIndex == 0 || (rootDetector == -1 && builder.isEligibleAsRootKey())) {
rootDetector = builder.currentIndex;
}
}
}
return rootDetector;
}
private boolean isEligibleAsRootKey() {
return isEligibleAsSubstituteKey()
&& (parent == null || parent.isEligibleAsRootKey());
}
private boolean isEligibleAsSubstituteKey() {
return !(owner instanceof ArrayElementPropertyMeta)
&& !(owner instanceof MapElementPropertyMeta);
}
// ignore empty parent useful to skip root keys
private int getNonEmptyParentIndex() {
return parent == null
? -1
: parent.effectiveKeys().isEmpty() ? parent.getNonEmptyParentIndex() : parent.currentIndex;
}
private void addAllBuilders(ArrayList> builders) {
builders.add(this);
for(MappingContextFactoryBuilder child : children) {
child.addAllBuilders(builders);
}
}
public boolean hasNoKeys() {
return effectiveKeys().isEmpty();
}
public boolean hasNoDependentKeys() {
if (!hasNoKeys()) {
return false;
}
for(MappingContextFactoryBuilder builder : children) {
if (!builder.hasNoDependentKeys()) {
return false;
}
}
return true;
}
public boolean isRoot() {
return parent == null;
}
public int currentIndex() {
return currentIndex;
}
private static class Counter {
int value;
}
@Override
public String toString() {
return "MappingContextFactoryBuilder{" +
"currentIndex=" + currentIndex +
", keys=" + keys +
", children=" + children +
'}';
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy