All Downloads are FREE. Search and download functionalities are using the official Maven repository.
Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
framework.AbstractBuilder Maven / Gradle / Ivy
package framework;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.IntFunction;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import framework.Try.TriConsumer;
/**
* Value object builder base
*
* @param Value type
* @param Builder type
* @param Field names type
*/
public abstract class AbstractBuilder, NAMES extends Enum>> implements Supplier, TriConsumer, String, Object> {
/**
* Text in case of "Optional.empty" in "toString"
*/
public String empty = "(未設定)";
/**
* Key-value separator in "toString"
*/
public String pairSeparator = ": ";
/**
* Entry separator in "toString"
*/
public String entrySeparator = ", ";
/**
* Validator
*/
public Runnable validator = null;
/**
* Meta info
*/
final Meta meta;
/**
* Field values
*/
final Object[] values;
/**
* Converter
*/
final Function[] converters;
/**
* Caches
*/
private static final Map, Meta, Enum>>> caches = new ConcurrentHashMap<>();
/**
* Meta info
*
* @param Value type
* @param Names type
*/
private static class Meta> {
/**
* Target class
*/
private Class clazz;
/**
* Field names
*/
private U[] names;
/**
* Field reflections
*/
private Field[] fields;
/**
* constructor
*/
private Constructor constructor;
}
/**
* Constructor
*/
@SuppressWarnings("unchecked")
public AbstractBuilder() {
if(this instanceof PropertyBuilder) {
meta = null;
values = null;
converters = null;
return;
}
meta = (Meta) caches.computeIfAbsent(getClass(), key -> {
Type[] types = ((ParameterizedType) key.getGenericSuperclass()).getActualTypeArguments();
Meta m = new Meta<>();
m.clazz = (Class) types[0];
m.names = ((Class) types[2]).getEnumConstants();
m.fields = Stream.of(m.names).map(name -> Reflector.field(m.clazz, name.name()).orElseThrow(IllegalArgumentException::new)).toArray(Field[]::new);
m.constructor = (Constructor) Reflector.constructor(m.clazz, Stream.of(m.fields).map(Field::getType).toArray(Class[]::new))
.orElseThrow(IllegalArgumentException::new);
return (Meta, Enum>>) m;
});
values = new Object[meta.fields.length];
reset();
converters = new Function[values.length];
}
/**
* @param name Field name
* @param value Field value
* @return Self
*/
@SuppressWarnings("unchecked")
public BUILDER set(NAMES name, Object value) {
int i = name.ordinal();
values[i] = meta.fields[i].getType() == Optional.class && !(value instanceof Optional) ? Optional.ofNullable(value) : value;
return (BUILDER) this;
}
/**
* @param name Field name
* @param value Field value
* @param nameValues Name-value pairs
* @return Self
*/
@SuppressWarnings("unchecked")
public BUILDER set(NAMES name, Object value, Object... nameValues) {
set(name, value);
for (int i = 0; i + 1 < nameValues.length; i += 2) {
set((NAMES) nameValues[i], nameValues[i + 1]);
}
return (BUILDER) this;
}
@Override
public void accept(Class> type, String name, Object value) {
set(Stream.of(meta.names).filter(n -> n.name().equals(name)).findFirst().orElseThrow(IllegalArgumentException::new), value);
}
/**
* @param source Source
* @return Copied Builder
*/
@SuppressWarnings("unchecked")
public BUILDER set(VALUE source) {
for (NAMES i : meta.names) {
try {
set(i, meta.fields[i.ordinal()].get(source));
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new InternalError(e);
}
}
return (BUILDER) this;
}
/**
* @param setup Setup
* @return Self
*/
@SuppressWarnings("unchecked")
public BUILDER setup(Consumer setup) {
setup.accept((BUILDER) this);
return (BUILDER) this;
}
/**
* @param name Field name
* @return Field
*/
public Field getField(NAMES name) {
return meta.fields[name.ordinal()];
}
/**
* @param name Field name
* @return Field value
*/
public Object getValue(NAMES name) {
return values[name.ordinal()];
}
/**
* Reset values
*
* @return Self
*/
@SuppressWarnings("unchecked")
public BUILDER reset() {
System.arraycopy(Stream.of(meta.fields).map(field -> field.getType() == Optional.class ? Optional.empty() : null).toArray(Object[]::new), 0, values, 0,
values.length);
return (BUILDER) this;
}
/**
* @param name Field name
* @param converter Converter
* @return Self
*/
@SuppressWarnings("unchecked")
public BUILDER converter(NAMES name, Function converter) {
converters[name.ordinal()] = converter;
return (BUILDER) this;
}
/*
* (non-Javadoc)
*
* @see java.util.function.Supplier#get()
*/
@Override
public VALUE get() {
try {
if (validator != null) {
validator.run();
}
IntFunction convert = i -> converters[i] == null ? (values[i] == null && meta.fields[i].getType() == int.class ? 0 : values[i]) : converters[i].apply(values[i]);
return meta.constructor.newInstance(IntStream.range(0, values.length).mapToObj(convert).toArray());
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | SecurityException e) {
throw new RuntimeException(e);
}
}
/*
* (non-Javadoc)
*
* @see java.lang.Object#toString()
*/
@SuppressWarnings("unchecked")
@Override
public String toString() {
return IntStream.range(0, values.length).mapToObj(i -> {
Object v = values[i];
return meta.names[i] + pairSeparator + (v instanceof Optional ? ((Optional) v).orElse(empty) : v);
}).collect(Collectors.joining(entrySeparator));
}
/**
* Property builder
* @param Value type
*/
public static class PropertyBuilder extends AbstractBuilder, Enum>> {
/**
* instance
*/
T instance;
/**
* Constructor
* @param supplier instance supplier
*/
public PropertyBuilder(Supplier supplier) {
this.instance = supplier.get();
}
@Override
public T get() {
return instance;
}
@Override
public void accept(Class> type, String name, Object value) {
Reflector.setProperty(instance, type, name, value, true);
}
}
}