org.sfm.map.MappingContextFactoryBuilder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of simpleFlatMapper Show documentation
Show all versions of simpleFlatMapper Show documentation
Java library to map flat record - ResultSet, csv - to java object with minimum configuration and low footprint.
package org.sfm.map;
import org.sfm.jdbc.impl.BreakDetector;
import org.sfm.reflect.Getter;
import org.sfm.reflect.meta.ListElementPropertyMeta;
import org.sfm.reflect.meta.PropertyMeta;
import org.sfm.utils.BooleanProvider;
import org.sfm.utils.ErrorHelper;
import org.sfm.utils.Predicate;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
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 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 Predicate nullChecker() {
return new NullChecker(keys, keySourceGetter);
}
public Getter, BooleanProvider> breakDetectorGetter() {
if (isEmpty()) {
if (parent != null) {
return parent.breakDetectorGetter();
} else {
return new RootGetterProvider();
}
} else {
return new BreakGetter(currentIndex);
}
}
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();
}
List> builders = getAllBuilders();
if (builders.isEmpty()) {
return new MappingContextFactoryImpl(new BreakDetector[0], null);
}
@SuppressWarnings("unchecked")
BreakDetector[] breakDetectors = new BreakDetector[builders.get(builders.size() -1).currentIndex + 1];
BreakDetector rootDetector = null;
for(int i = 0; i < builders.size(); i++) {
final MappingContextFactoryBuilder builder = builders.get(i);
BreakDetector parent = null;
int parentIndex = builder.getParentNonEmptyIndex();
if (parentIndex != -1) {
parent = breakDetectors[parentIndex];
}
final BreakDetector detector = builder.newBreakDetector(parent);
breakDetectors[builder.currentIndex] = detector;
if (builder.currentIndex == 0 || (rootDetector == null && builder.isRootEligible())) {
rootDetector = detector;
}
}
return new MappingContextFactoryImpl(breakDetectors, rootDetector);
}
private boolean isRootEligible() {
return !(owner instanceof ListElementPropertyMeta) && (parent == null || parent.isRootEligible());
}
private int getParentNonEmptyIndex() {
if (parent == null) {
return -1;
} else {
if (parent.isEmpty()) {
return parent.getParentNonEmptyIndex();
} else {
return parent.currentIndex;
}
}
}
private BreakDetector newBreakDetector(BreakDetector parent) {
return new BreakDetectorImpl(keys, keySourceGetter, parent);
}
private List> getAllBuilders() {
List> list = new ArrayList>();
if (!isEmpty()) {
list.add(this);
}
for(MappingContextFactoryBuilder child : children) {
list.addAll(child.getAllBuilders());
}
return list;
}
public boolean isEmpty() {
return keys.isEmpty();
}
public boolean hasNoDependentKeys() {
if (!isEmpty()) {
return false;
}
for(MappingContextFactoryBuilder builder : children) {
if (!builder.hasNoDependentKeys()) {
return false;
}
}
return true;
}
public boolean isRoot() {
return parent == null;
}
private static class Counter {
int value;
}
private static class BreakGetter implements Getter, BooleanProvider> {
private final int index;
private BreakGetter(int index) {
this.index = index;
}
@Override
public BooleanProvider get(MappingContext target) throws Exception {
return new MappingContextBooleanProvider(target, index);
}
}
private static class RootGetterProvider implements Getter, BooleanProvider> {
@Override
public BooleanProvider get(MappingContext target) throws Exception {
return new RootBooleanProvider(target);
}
}
private static class RootBooleanProvider implements BooleanProvider {
private final MappingContext target;
public RootBooleanProvider(MappingContext target) {
this.target = target;
}
@Override
public boolean getBoolean() {
return target == null || target.rootBroke();
}
}
private static class MappingContextBooleanProvider implements BooleanProvider {
private final MappingContext target;
private final int index;
public MappingContextBooleanProvider(MappingContext target, int index) {
this.target = target;
this.index = index;
}
@Override
public boolean getBoolean() {
return target == null || target.broke(index);
}
}
private static class NullChecker implements Predicate {
private final List keys;
private final KeySourceGetter keySourceGetter;
private NullChecker(List keys, KeySourceGetter keySourceGetter) {
this.keys = keys;
this.keySourceGetter = keySourceGetter;
}
@Override
public boolean test(S s) {
try {
if (keys.isEmpty()) return false;
for (int i = 0; i < keys.size(); i++) {
if (keySourceGetter.getValue(keys.get(i), s) != null) {
return false;
}
}
return true;
} catch(Exception e) {
ErrorHelper.rethrow(e);
throw new IllegalStateException();
}
}
}
public static interface KeySourceGetter {
public Object getValue(K key, S source) throws SQLException;
}
private static class MappingContextFactoryImpl implements MappingContextFactory {
private final BreakDetector[] breakDetectors;
private final BreakDetector rootDetector;
public MappingContextFactoryImpl(BreakDetector[] breakDetectors, BreakDetector rootDetector) {
this.breakDetectors = breakDetectors;
this.rootDetector = rootDetector;
}
@Override
public MappingContext newContext() {
return new MappingContext(breakDetectors, rootDetector);
}
}
private static class BreakDetectorImpl implements BreakDetector {
private final KeySourceGetter keySourceGetter;
private final List keys;
private final BreakDetector parent;
private Object[] lastValues;
private boolean isBroken = true;
public BreakDetectorImpl(List keys, KeySourceGetter keySourceGetter, BreakDetector parent) {
this.keys = keys;
this.keySourceGetter = keySourceGetter;
this.parent = parent;
}
@Override
public void handle(S source) throws MappingException {
if (keys.isEmpty()) {
return;
}
Object[] newValues = getValues(source);
isBroken = (parent != null && parent.isBroken())
|| lastValues == null
|| !Arrays.equals(lastValues, newValues);
lastValues = newValues;
}
private Object[] getValues(S source) {
try {
Object[] values = new Object[keys.size()];
for (int i = 0; i < values.length; i++) {
values[i] = keySourceGetter.getValue(keys.get(i), source);
}
return values;
} catch (Exception e) {
return ErrorHelper.rethrow(e);
}
}
@Override
public boolean isBroken() {
return isBroken;
}
@Override
public void markAsBroken() {
isBroken = true;
lastValues = null;
}
}
@Override
public String toString() {
return "MappingContextFactoryBuilder{" +
"currentIndex=" + currentIndex +
", keys=" + keys +
", children=" + children +
'}';
}
}