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.
com.araguacaima.commons.utils.parser.Beanspector Maven / Gradle / Ivy
package com.araguacaima.commons.utils.parser;
/*
Created by Alejandro on 20/11/2014.
*/
import com.araguacaima.commons.utils.EnumsUtils;
import com.araguacaima.commons.utils.ReflectionUtils;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.collections4.IterableUtils;
import org.apache.commons.collections4.Predicate;
import org.apache.commons.lang3.StringUtils;
import org.apache.cxf.jaxrs.utils.InjectionUtils;
import org.reflections.Reflections;
import javax.xml.datatype.DatatypeFactory;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.*;
import java.math.BigDecimal;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;
/**
* Bean introspection utility.
*/
class Beanspector {
private static final ReflectionUtils reflectionUtils = ReflectionUtils.getInstance();
private static final EnumsUtils enumsUtils = EnumsUtils.getInstance();
private final Map getters = new HashMap<>();
private final Map setters = new HashMap<>();
private final ClassLoader tclassloader;
private Class tclass;
private T tobj;
private String packageBase;
public Beanspector(final Class tclass, String packageBase) {
this(tclass, tclass.getClassLoader(), packageBase);
}
public Beanspector(final T tobj, String packageBase) {
this(tobj, tobj.getClass().getClassLoader(), packageBase);
}
public Beanspector(final T tobj, ClassLoader classLoader, String packageBase) {
if (tobj == null) {
throw new IllegalArgumentException("tobj is null");
}
this.tobj = tobj;
this.tclassloader = classLoader;
this.packageBase = packageBase;
init();
}
public Beanspector(Class tclass, ClassLoader classLoader, String packageBase) {
if (tclass == null) {
throw new IllegalArgumentException("tclass is null");
}
this.tclass = tclass;
this.tclassloader = classLoader;
this.packageBase = packageBase;
init();
}
private void init() {
fill(tclass, tobj, getters, setters);
}
private void fill(Class tclass, final Object tobj, final Map getters, final Map setters) {
if (tclass == null) {
if (tobj != null) {
tclass = tobj.getClass();
}
}
if (tclass != null) {
for (final Method m : tclass.getMethods()) {
if (isGetter(m)) {
getters.put(getterName(m), m);
} else if (isSetter(m)) {
setters.put(setterName(m), m);
}
}
// check type equality for getter-setter pairs
final Set pairs = new HashSet<>(getters.keySet());
pairs.retainAll(setters.keySet());
for (final String accessor : pairs) {
final Class> getterClass = getters.get(accessor).getReturnType();
final Class> setterClass = setters.get(accessor).getParameterTypes()[0];
if (!getterClass.equals(setterClass)) {
throw new IllegalArgumentException(String.format(
"Accessor '%s' type mismatch, getter type is %s while setter type is %s", accessor, getterClass.getName(),
setterClass.getName()));
}
}
} else {
throw new IllegalArgumentException("Class and Object can not both be null");
}
}
public T getBean() {
return tobj;
}
public Set getGettersNames() {
return Collections.unmodifiableSet(getters.keySet());
}
public Set getSettersNames() {
return Collections.unmodifiableSet(setters.keySet());
}
public Class> getAccessorType(final String getterOrSetterName) throws Exception {
final String[] tokens = getterOrSetterName.split("\\.");
if (tokens.length > 1) {
final String token = tokens[0];
Class clazz = reflectionUtils.extractGenerics(getAccessorType(token));
return getAccessorType(clazz, getterOrSetterName.replaceFirst(token + "\\.", StringUtils.EMPTY));
} else {
return getTopLevelAccesorType(getterOrSetterName, getters, setters);
}
}
private Class> getAccessorType(final Class clazz, final String getterOrSetterName) throws Exception {
final Map getters = new HashMap<>();
final Map setters = new HashMap<>();
fill(clazz, null, getters, setters);
final String[] tokens = getterOrSetterName.split("\\.");
if (tokens.length > 1) {
final String token = tokens[0];
Class> accessorType = getAccessorType(clazz, token);
if (reflectionUtils.isCollectionImplementation(accessorType)) {
return getAccessorType(reflectionUtils.extractGenerics(accessorType), getterOrSetterName.replaceFirst(token + "\\.", StringUtils.EMPTY));
} else {
return getAccessorType(accessorType, getterOrSetterName.replaceFirst(token + "\\.", StringUtils.EMPTY));
}
} else {
return getTopLevelAccesorType(getterOrSetterName, getters, setters);
}
}
private Class> getTopLevelAccesorType(final String getterOrSetterName, final Map getters,
final Map setters) throws IntrospectionException {
String[] splittedGetterOrSetterName = getterOrSetterName.split("<");
String property = splittedGetterOrSetterName[0];
if (splittedGetterOrSetterName.length > 1) {
String[] genericTokens = splittedGetterOrSetterName[1].split(">");
final String generic = genericTokens[0];
Class> clazz = getTopLevelAccesorType(property, getters, setters);
Reflections reflections = new Reflections(clazz.getPackage().getName(), tclassloader);
Set extends Class>> classes = reflections.getSubTypesOf(clazz);
return (Class) IterableUtils.find(classes, (Predicate) object -> ((Class) object).getSimpleName().equals(StringUtils.capitalize(generic)));
}
Method m = getters.get(property);
if (m == null) {
m = setters.get(property);
}
if (m == null) {
final String msg = String.format("Accessor '%s' not found, " + "known setters are: %s, known getters are: %s",
property, setters.keySet(), getters.keySet());
throw new IntrospectionException(msg);
}
Class> returnType = m.getReturnType();
if (reflectionUtils.isCollectionImplementation(returnType)) {
Type genericReturnType = m.getGenericReturnType();
try {
return (Class) (((ParameterizedType) genericReturnType).getActualTypeArguments()[0]);
} catch (Throwable ignored) {
assert genericReturnType instanceof Class;
return reflectionUtils.extractGenerics((Class) genericReturnType);
}
} else {
return returnType;
}
}
public Beanspector swap(final T newobject) {
if (newobject == null) {
throw new IllegalArgumentException("newobject is null");
}
tobj = newobject;
return this;
}
public Beanspector instantiate(boolean resetObject) throws Exception {
if (tobj == null) {
tobj = tclass.newInstance();
}
return this;
}
public void setValue(String setterName, Object value) throws Throwable {
Map fixedExpressionObject = instantiateNestedProperties(getBean(), setterName);
setterName = fixedExpressionObject.keySet().iterator().next();
Class type;
if (value == null) {
type = Object.class;
} else {
type = value.getClass();
}
if (reflectionUtils.isCollectionImplementation(type)) {
Object value1 = reflectionUtils.getValueFromCollectionImplementation(value);
PropertyUtils.setProperty(getBean(), setterName.split("\\.")[0], value1);
} else {
PropertyUtils.setProperty(getBean(), setterName, value);
}
}
public Object getValue(final String getterName) throws Throwable {
return getValue(getters.get(getterName));
}
public Object getValue(final Method getter) throws Throwable {
try {
return getter.invoke(tobj);
} catch (final InvocationTargetException e) {
throw e.getCause();
}
}
private boolean isGetter(final Method m) {
return m.getParameterTypes().length == 0 && (m.getName().startsWith("get") || m.getName().startsWith("is"));
}
private String getterName(final Method m) {
return StringUtils.uncapitalize(m.getName().startsWith("is") ? m.getName().substring(2) : m.getName().startsWith("get") ? m
.getName().substring(3) : m.getName());
}
private boolean isSetter(final Method m) {
return m.getReturnType().equals(void.class) && m.getParameterTypes().length == 1
&& (m.getName().startsWith("set") || m.getName().startsWith("is"));
}
private String setterName(final Method m) {
return StringUtils.uncapitalize(m.getName().replace("is", "").replace("set", ""));
}
private Map instantiateNestedProperties(final Object obj, String fieldName) {
Map newObject = new HashMap<>();
Object newInstance = new Object();
Object nestedObject;
try {
final String[] fieldNames = fieldName.split("\\.");
if (fieldNames.length > 1) {
String consumedProperty;
consumedProperty = fieldNames[0];
String property = consumedProperty.replaceAll("<.*?>", "");
String generic = null;
try {
generic = consumedProperty.substring(consumedProperty.indexOf("<") + 1, consumedProperty.indexOf(">"));
} catch (Throwable ignored) {
}
PropertyDescriptor propertyDescriptor = PropertyUtils.getPropertyDescriptor(obj, property);
Class> originalPropertyType = propertyDescriptor.getPropertyType();
Class> propertyType = getAccessorType(obj.getClass(), property);
String expression = property;
if (reflectionUtils.isCollectionImplementation(originalPropertyType)) {
boolean anInterface = propertyType.isInterface();
if (anInterface) {
Reflections reflections = new Reflections(packageBase, tclassloader);
Set extends Class>> classes = reflections.getSubTypesOf(propertyType);
final String finalGeneric = generic;
Class> propertyType_ = (Class) IterableUtils.find(classes, (Predicate) object -> ((Class) object).getSimpleName().equals(StringUtils.capitalize(finalGeneric)));
if (propertyType_ != null) {
propertyType = propertyType_;
newInstance = propertyType_.newInstance();
} else {
PropertyDescriptor[] propertyDescriptors = Introspector.getBeanInfo(propertyType).getPropertyDescriptors();
if (propertyDescriptors != null && propertyDescriptors.length > 0) {
List readMethods = new ArrayList<>();
List writeMethods = new ArrayList<>();
Map properties = new HashMap<>();
for (PropertyDescriptor pd : propertyDescriptors) {
String attributeName = pd.getName();
properties.put(attributeName, pd.getValue(attributeName));
readMethods.add(pd.getReadMethod());
writeMethods.add(pd.getWriteMethod());
}
InvocationHandler handler = new FiqlJsonSerializerInvocationHandler(readMethods, writeMethods, properties, propertyType);
newInstance = Proxy.newProxyInstance(propertyType.getClassLoader(),
new Class[]{propertyType},
handler);
} else {
InvocationHandler handler = new FiqlJsonSerializerInvocationHandler();
newInstance = Proxy.newProxyInstance(propertyType.getClassLoader(),
new Class[]{propertyType},
handler);
}
}
} else {
if (StringUtils.isNotBlank(generic) && !propertyType.getSimpleName().equals(StringUtils.capitalize(generic))) {
Reflections reflections = new Reflections(propertyType.getPackage().getName(), tclassloader);
Set extends Class>> classes = reflections.getSubTypesOf(propertyType);
final String finalGeneric = generic;
propertyType = (Class) IterableUtils.find(classes, (Predicate) object -> ((Class) object).getSimpleName().equals(StringUtils.capitalize(finalGeneric)));
}
newInstance = propertyType.newInstance();
}
Map objectMap = instantiateNestedProperties(newInstance,
fieldName.replaceFirst(consumedProperty + "\\.", StringUtils.EMPTY));
expression = objectMap.keySet().iterator().next();
newInstance = objectMap.values().iterator().next();
String newMethodName = fieldName.replaceFirst(consumedProperty + "\\.", StringUtils.EMPTY).split("\\.")[0];
if (propertyType.equals(newInstance.getClass())) {
newInstance = reflectionUtils.createAndInitializeCollection(originalPropertyType, newInstance);
} else {
newInstance = reflectionUtils.createAndInitializeTypedCollection(propertyType, newMethodName, newInstance);
}
expression = property + "[0]." + expression;
} else if (originalPropertyType.isInterface()) {
if (StringUtils.isNotBlank(generic)) {
Class> propertyType_ = reflectionUtils.extractGenerics(propertyType);
if (!propertyType_.getSimpleName().equals(StringUtils.capitalize(generic))) {
Reflections reflections = new Reflections(propertyType_.getPackage().getName(), tclassloader);
Set extends Class>> classes = reflections.getSubTypesOf(propertyType_);
final String finalGeneric = generic;
propertyType = (Class) IterableUtils.find(classes, (Predicate) object -> ((Class) object).getSimpleName().equals(StringUtils.capitalize(finalGeneric)));
Map objectMap = instantiateNestedProperties(propertyType.newInstance(),
fieldName.replaceFirst(consumedProperty + "\\.", StringUtils.EMPTY));
expression = property + "." + objectMap.keySet().iterator().next();
newInstance = objectMap.values().iterator().next();
}
} else if (reflectionUtils.isCollectionImplementation(propertyType)) {
Map objectMap = instantiateNestedProperties(propertyType.newInstance(),
fieldName.replaceFirst(consumedProperty + "\\.", StringUtils.EMPTY));
expression = objectMap.keySet().iterator().next();
nestedObject = objectMap.values().iterator().next();
newInstance = reflectionUtils.createAndInitializeTypedCollection(propertyType, nestedObject);
expression = expression + "[0]";
} else {
PropertyDescriptor[] propertyDescriptors = Introspector.getBeanInfo(propertyType).getPropertyDescriptors();
if (propertyDescriptors != null && propertyDescriptors.length > 0) {
List readMethods = new ArrayList<>();
List writeMethods = new ArrayList<>();
Map properties = new HashMap<>();
for (PropertyDescriptor pd : propertyDescriptors) {
String attributeName = pd.getName();
properties.put(attributeName, pd.getValue(attributeName));
readMethods.add(pd.getReadMethod());
writeMethods.add(pd.getWriteMethod());
}
InvocationHandler handler = new FiqlJsonSerializerInvocationHandler(readMethods, writeMethods, properties, propertyType);
newInstance = Proxy.newProxyInstance(propertyType.getClassLoader(),
new Class[]{propertyType},
handler);
} else {
InvocationHandler handler = new FiqlJsonSerializerInvocationHandler();
newInstance = Proxy.newProxyInstance(propertyType.getClassLoader(),
new Class[]{propertyType},
handler);
}
Map objectMap = instantiateNestedProperties(newInstance,
fieldName.replaceFirst(consumedProperty + "\\.", StringUtils.EMPTY));
expression = property + "." + objectMap.keySet().iterator().next();
}
} else {
newInstance = propertyType.newInstance();
try {
Map objectMap = instantiateNestedProperties(newInstance,
fieldName.replaceFirst(consumedProperty + "\\.", StringUtils.EMPTY));
String s = objectMap.keySet().iterator().next();
expression = expression + "." + s;
nestedObject = objectMap.values().iterator().next();
PropertyUtils.setProperty(newInstance, s.replaceAll("[0]", StringUtils.EMPTY),
nestedObject);
} catch (Throwable ignored) {
}
}
PropertyUtils.setProperty(obj, property, newInstance);
newObject.put(expression, newInstance);
} else {
Class> originalPropertyType = PropertyUtils.getPropertyDescriptor(obj, fieldName).getPropertyType();
Class> propertyType = getAccessorType(obj.getClass(), fieldName);
if (!reflectionUtils.isCollectionImplementation(originalPropertyType)) {
try {
newInstance = propertyType.newInstance();
} catch (InstantiationException ignored) {
try {
newInstance = instantiatePrimitive(propertyType);
} catch (IllegalArgumentException e) {
if (propertyType.isEnum() || Enumeration.class.isAssignableFrom(propertyType)) {
newInstance = enumsUtils.getAnyEnumElement(propertyType);
} else {
throw e;
}
}
}
PropertyUtils.setProperty(obj, fieldName, newInstance);
newObject.put(fieldName, obj);
} else {
newInstance = reflectionUtils.createAndInitializeTypedCollection(propertyType, null);
PropertyUtils.setProperty(obj, fieldName, newInstance);
newObject.put(fieldName + "[0]", obj);
}
}
} catch (final Exception e) {
throw new RuntimeException(e);
}
return newObject;
}
private Object instantiatePrimitive(Class valueType) throws Exception {
Object castedValue;
String value = StringUtils.EMPTY;
if (Date.class.isAssignableFrom(valueType)) {
value = "0000-00-00'T'00:00:00.000Z";
DateFormat df;
try {
df = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ");
// zone in XML is "+01:00" in Java is "+0100"; stripping
// semicolon
final int idx = value.lastIndexOf(':');
final String v = value.substring(0, idx) + value.substring(idx + 1);
castedValue = df.parse(v);
} catch (final ParseException e) {
// is that duration?
final Date now = new Date();
DatatypeFactory.newInstance().newDuration(value).addTo(now);
castedValue = now;
}
} else if (BigDecimal.class.isAssignableFrom(valueType)) {
value = "0";
castedValue = new BigDecimal(value);
} else if (valueType.isEnum() || Enumeration.class.isAssignableFrom(valueType)) {
String valueEnum = value;
castedValue = enumsUtils.getEnum(valueType, valueEnum);
} else {
try {
castedValue = InjectionUtils.convertStringToPrimitive(value, valueType);
} catch (Throwable ignored) {
castedValue = InjectionUtils.convertStringToPrimitive("0", valueType);
}
}
return castedValue;
}
}