Skip to content

Instantly share code, notes, and snippets.

@asouza
Created December 8, 2019 12:59
Show Gist options
  • Save asouza/c4e0df99b1b614878671b900e32e0d2e to your computer and use it in GitHub Desktop.
Save asouza/c4e0df99b1b614878671b900e32e0d2e to your computer and use it in GitHub Desktop.
public class DataView<T> {
private T proxy;
private Trace trace;
private T original;
private Map<String, Object> complexValues = new HashMap<>();
private DataView(T instance) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(instance.getClass());
this.trace = new Trace(instance);
enhancer.setCallback(this.trace);
this.proxy = (T) enhancer.create();
this.original = instance;
}
public static <T> DataView<T> of(T instance) {
return new DataView<T>(instance);
}
public <ReturnType, MapperType> DataView<T> add(String key, Function<T, ReturnType> supplier,
Function<ReturnType, MapperType> mapper) {
MapperType finalObject = supplier.andThen(mapper).apply(original);
complexValues.put(key, finalObject);
return this;
}
public <ReturnType, MapperType> DataView<T> addCollection(String key, Function<T, Collection<ReturnType>> supplier,
Function<ReturnType, MapperType> mapper) {
Collection<ReturnType> collection = supplier.apply(original);
// using list to keep the original order
List<MapperType> resultList = collection.stream().map(mapper).collect(Collectors.toList());
complexValues.put(key, resultList);
return this;
}
public DataView<T> add(Function<T, Object> supplier) {
supplier.apply(proxy);
return this;
}
public DataView<T> add(String key, Function<T, Object> supplier) {
complexValues.put(key, supplier.apply(original));
return this;
}
public DataView<T> addDate(String key, Function<T, TemporalAccessor> supplier, String pattern) {
Function<TemporalAccessor, Object> formatter = (temporal) -> {
return DateTimeFormatter.ofPattern(pattern).format(temporal);
};
return this.addFormatted(key, supplier, formatter);
}
public DataView<T> addPercentual(String key, Function<T, Number> supplier) {
Function<Number, Object> formatter = (number) -> {
DecimalFormat df = new DecimalFormat("##.##%");
return df.format(number.doubleValue() / 100);
};
return this.addFormatted(key, supplier, formatter);
}
public <ReturnType> DataView<T> addFormatted(String key, Function<T, ReturnType> supplier,
Function<ReturnType, Object> formatter) {
ReturnType result = supplier.apply(original);
complexValues.put(key, formatter.apply(result));
return this;
}
public Map<String, Object> build() {
Map<String, Object> json = trace.getJson();
complexValues.entrySet().forEach(entry -> {
json.put(entry.getKey(), entry.getValue());
});
return json;
}
}
class Trace implements MethodInterceptor {
private Map<String, Object> json = new HashMap<>();
private Object instance;
public Trace(Object instance) {
this.instance = instance;
}
@Override
public Object intercept(Object proxy, Method currentMethod, Object[] args, MethodProxy proxyMethod)
throws Throwable {
String methodName = currentMethod.getName();
//FIXME tem que fazer o mecanismo o de defesa para o caso de invocação de nome de metodo que nao comeca com getter ou is
String propertyName = Introspector.decapitalize(methodName.substring(methodName.startsWith("is") ? 2 : 3));
Object methodResult = currentMethod.invoke(instance, args);
json.put(propertyName, methodResult);
return methodResult;
}
public Map<String, Object> getJson() {
return json;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment