[DEV] set it work for imutable and basic records
This commit is contained in:
parent
c8ff65615f
commit
3ad74f0fb1
@ -9,7 +9,7 @@ import java.lang.annotation.Target;
|
||||
* Marker annotation that can be used to define an other name of the attribute or the Element name.
|
||||
*
|
||||
*/
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER })
|
||||
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.PARAMETER })
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@ExmlAnnotation
|
||||
public @interface XmlName {
|
||||
|
@ -1,14 +1,16 @@
|
||||
package org.atriasoft.exml.builder;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.Parameter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
@ -16,21 +18,16 @@ import java.util.stream.Collectors;
|
||||
|
||||
import org.atriasoft.eStringSerialize.StringSerializer;
|
||||
import org.atriasoft.etk.util.ArraysTools;
|
||||
import org.atriasoft.exml.annotation.XmlAttribute;
|
||||
import org.atriasoft.exml.annotation.XmlCaseSensitive;
|
||||
import org.atriasoft.exml.annotation.XmlDefaultAttibute;
|
||||
import org.atriasoft.exml.annotation.XmlDefaultCaseSensitive;
|
||||
import org.atriasoft.exml.annotation.XmlDefaultManaged;
|
||||
import org.atriasoft.exml.annotation.XmlDefaultOptional;
|
||||
import org.atriasoft.exml.annotation.XmlList;
|
||||
import org.atriasoft.exml.annotation.XmlManaged;
|
||||
import org.atriasoft.exml.annotation.XmlName;
|
||||
import org.atriasoft.exml.annotation.XmlOptional;
|
||||
import org.atriasoft.exml.exception.ExmlBuilderException;
|
||||
import org.atriasoft.exml.internal.Log;
|
||||
import org.atriasoft.exml.parser.Tools;
|
||||
import org.atriasoft.exml.reflect.ReflectTools;
|
||||
|
||||
|
||||
record ConstructorModel(String[] values,
|
||||
Constructor<?> constructor) {
|
||||
}
|
||||
|
||||
public class IntrospectionModelComplex extends IntrospectionModel {
|
||||
|
||||
// TODO Optimize this with external object for basic types....
|
||||
@ -38,6 +35,7 @@ public class IntrospectionModelComplex extends IntrospectionModel {
|
||||
private final Method tostring; // used for the set Text if the object is an end point...
|
||||
private final boolean isSubClass; // if true, the constructor must be called with a null first object.
|
||||
private final Constructor<?> constructorEmpty;
|
||||
private final List<ConstructorModel> constructors = new ArrayList<>();
|
||||
private final List<IntrospectionProperty> nodes = new ArrayList<>();
|
||||
|
||||
private final List<IntrospectionProperty> attributes = new ArrayList<>();
|
||||
@ -62,11 +60,18 @@ public class IntrospectionModelComplex extends IntrospectionModel {
|
||||
} else {
|
||||
this.isSubClass = false;
|
||||
}
|
||||
final boolean isRecord = Record.class.isAssignableFrom(classType);
|
||||
if (isRecord) {
|
||||
Log.error("Detect record !!! ");
|
||||
}
|
||||
if (classType.isPrimitive()) {
|
||||
Log.critical("Detect primitive ==> impossible case !!! ");
|
||||
}
|
||||
|
||||
final Boolean isDefaultAttribute = getIsDefaultAttribute(classType, IntrospectionModel.DEFAULT_ATTRIBUTE);
|
||||
final Boolean isDefaultManaged = getIsDefaultManaged(classType, IntrospectionModel.DEFAULT_MANAGED);
|
||||
final Boolean isDefaultOptional = getIsDefaultOptional(classType, IntrospectionModel.DEFAULT_OPTIONAL);
|
||||
final Boolean isDefaultCaseSensitive = getIsDefaultCaseSensitive(classType, IntrospectionModel.DEFAULT_CASE_SENSITIVE);
|
||||
final Boolean isDefaultAttribute = ReflectTools.getIsDefaultAttribute(classType, IntrospectionModel.DEFAULT_ATTRIBUTE);
|
||||
final Boolean isDefaultManaged = ReflectTools.getIsDefaultManaged(classType, IntrospectionModel.DEFAULT_MANAGED);
|
||||
final Boolean isDefaultOptional = ReflectTools.getIsDefaultOptional(classType, IntrospectionModel.DEFAULT_OPTIONAL);
|
||||
final Boolean isDefaultCaseSensitive = ReflectTools.getIsDefaultCaseSensitive(classType, IntrospectionModel.DEFAULT_CASE_SENSITIVE);
|
||||
Log.verbose("Introspect class: '" + classType.getCanonicalName() + "'");
|
||||
final Constructor<?>[] constructors = this.classType.getConstructors();
|
||||
Log.verbose(" Constructors: (" + constructors.length + ")");
|
||||
@ -81,16 +86,113 @@ public class IntrospectionModelComplex extends IntrospectionModel {
|
||||
emptyConstructorTmp = elem;
|
||||
Log.verbose(" >>> " + elem.toGenericString());
|
||||
} else {
|
||||
Log.verbose(" - " + elem.toGenericString());
|
||||
String[] names = ReflectTools.getNames(elem, null);
|
||||
if (names == null) {
|
||||
// Search in the parameters ...
|
||||
List<String> restoredElementNames = new ArrayList<>();
|
||||
Parameter[] params = elem.getParameters();
|
||||
for (int iii=1; iii<params.length; iii++) {
|
||||
Parameter paramElem = params[iii];
|
||||
String[] namesParam = ReflectTools.getNames(elem, paramElem, null);
|
||||
if (namesParam == null) {
|
||||
break;
|
||||
}
|
||||
if (namesParam.length != 1) {
|
||||
throw new ExmlBuilderException("the @XmlName in constructor parameter must not exceed 1 element");
|
||||
}
|
||||
restoredElementNames.add(namesParam[0]);
|
||||
}
|
||||
if (restoredElementNames.size() == 0) {
|
||||
Log.verbose(" - " + elem.toGenericString());
|
||||
Log.verbose(" ==> unmanaged");
|
||||
} else if (restoredElementNames.size() != params.length-1) {
|
||||
throw new ExmlBuilderException("the @XmlName in constructor parameter must set for every one");
|
||||
} else {
|
||||
this.constructors.add(new ConstructorModel(restoredElementNames.toArray(new String[restoredElementNames.size()]), elem));
|
||||
}
|
||||
} else {
|
||||
if (elem.getParameterCount() != names.length+1) {
|
||||
throw new ExmlBuilderException("Wrong number of parameter in constructor with ne number declared in the @XmlName");
|
||||
}
|
||||
this.constructors.add(new ConstructorModel(names, elem));
|
||||
}
|
||||
}
|
||||
} else if (elem.getParameterCount() == 0) {
|
||||
emptyConstructorTmp = elem;
|
||||
Log.verbose(" >>> " + elem.toGenericString());
|
||||
} else {
|
||||
Log.verbose(" - " + elem.toGenericString());
|
||||
String[] names = ReflectTools.getNames(elem, null);
|
||||
if (names == null) {
|
||||
// Search in the parameters ...
|
||||
List<String> restoredElementNames = new ArrayList<>();
|
||||
Parameter[] params = elem.getParameters();
|
||||
for (int iii=0; iii<params.length; iii++) {
|
||||
Parameter paramElem = params[iii];
|
||||
String[] namesParam = ReflectTools.getNames(elem, paramElem, null);
|
||||
if (namesParam == null) {
|
||||
break;
|
||||
}
|
||||
if (namesParam.length != 1) {
|
||||
throw new ExmlBuilderException("the @XmlName in constructor parameter must not exceed 1 element");
|
||||
}
|
||||
restoredElementNames.add(namesParam[0]);
|
||||
}
|
||||
if (restoredElementNames.size() == 0) {
|
||||
Log.verbose(" - " + elem.toGenericString());
|
||||
Log.verbose(" ==> unmanaged");
|
||||
} else if (restoredElementNames.size() != params.length) {
|
||||
throw new ExmlBuilderException("the @XmlName in constructor parameter must set for every one");
|
||||
} else {
|
||||
this.constructors.add(new ConstructorModel(restoredElementNames.toArray(new String[restoredElementNames.size()]), elem));
|
||||
}
|
||||
} else {
|
||||
if (elem.getParameterCount() != names.length) {
|
||||
throw new ExmlBuilderException("Wrong number of parameter in constructor with ne number declared in the @XmlName");
|
||||
}
|
||||
this.constructors.add(new ConstructorModel(names, elem));
|
||||
}
|
||||
}
|
||||
}
|
||||
this.constructorEmpty = emptyConstructorTmp;
|
||||
|
||||
// Order the constructor from the bigger number of element to the lowest...
|
||||
Collections.sort(this.constructors, new Comparator<ConstructorModel>() {
|
||||
@Override
|
||||
public
|
||||
int compare(final ConstructorModel a, final ConstructorModel b) {
|
||||
return a.values().length - b.values().length;
|
||||
}
|
||||
});
|
||||
for (ConstructorModel elem : this.constructors) {
|
||||
Log.verbose(" * " + elem.constructor().toGenericString());
|
||||
StringBuilder tmpPrint = new StringBuilder(" ==> (");
|
||||
if (this.isSubClass) {
|
||||
tmpPrint.append("null, ");
|
||||
}
|
||||
for (int iii=0; iii<elem.values().length; iii++) {
|
||||
if (iii != 0) {
|
||||
tmpPrint.append(", ");
|
||||
}
|
||||
tmpPrint.append(elem.values()[iii]);
|
||||
}
|
||||
tmpPrint.append(")");
|
||||
Log.verbose(tmpPrint.toString());
|
||||
}
|
||||
final List<String> recordAllPossibleValues = new ArrayList<>();
|
||||
final List<String> recordAllPossibleValuesFiltered = new ArrayList<>();
|
||||
if (isRecord) {
|
||||
for (ConstructorModel elem : this.constructors) {
|
||||
for (int iii=0; iii<elem.values().length; iii++) {
|
||||
String tmpp = elem.values()[iii];
|
||||
if (!recordAllPossibleValues.contains(tmpp)) {
|
||||
recordAllPossibleValues.add(tmpp);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
final Field[] fields = this.classType.getFields();
|
||||
Log.verbose(" Fields: (" + fields.length + ")");
|
||||
for (final Field elem : fields) {
|
||||
@ -102,12 +204,12 @@ public class IntrospectionModelComplex extends IntrospectionModel {
|
||||
if (!Modifier.isPublic(elem.getModifiers())) {
|
||||
continue;
|
||||
}
|
||||
final Boolean isAttribute = getIsAttribute(elem, isDefaultAttribute);
|
||||
final Boolean isManaged = getIsManaged(elem, isDefaultManaged);
|
||||
final Boolean isOptionnal = getIsOptional(elem, isDefaultOptional);
|
||||
final String[] names = getNames(elem, Tools.decapitalizeFirst(elem.getName()));
|
||||
final Boolean caseSensitive = getIsCaseSensitive(elem, isDefaultCaseSensitive);
|
||||
final String listName = getListName(elem, null);
|
||||
final Boolean isAttribute = ReflectTools.getIsAttribute(elem, isDefaultAttribute);
|
||||
final Boolean isManaged = ReflectTools.getIsManaged(elem, isDefaultManaged);
|
||||
final Boolean isOptionnal = ReflectTools.getIsOptional(elem, isDefaultOptional);
|
||||
final String[] names = ReflectTools.getNames(elem, Tools.decapitalizeFirst(elem.getName()));
|
||||
final Boolean caseSensitive = ReflectTools.getIsCaseSensitive(elem, isDefaultCaseSensitive);
|
||||
final String listName = ReflectTools.getListName(elem, null);
|
||||
// TODO check if property does not already exist ...
|
||||
if (isManaged) {
|
||||
if (isAttribute) {
|
||||
@ -118,7 +220,7 @@ public class IntrospectionModelComplex extends IntrospectionModel {
|
||||
}
|
||||
Log.verbose(" - " + elem.toGenericString());
|
||||
}
|
||||
final Method[] methodsTmp = this.classType.getMethods();
|
||||
final Method[] methodsTmp = this.classType.getMethods();
|
||||
// filter getX setX isX
|
||||
final List<Method> methods = List.of(methodsTmp).stream().filter(o -> {
|
||||
if (o.getName().contentEquals("getClass")) {
|
||||
@ -140,46 +242,52 @@ public class IntrospectionModelComplex extends IntrospectionModel {
|
||||
}
|
||||
return true;
|
||||
}
|
||||
if (o.getName().startsWith("get")) {
|
||||
if (o.getParameterCount() != 0 || o.getReturnType() == void.class || o.getReturnType() == Boolean.class || o.getReturnType() == boolean.class) {
|
||||
return false;
|
||||
}
|
||||
// check name format
|
||||
if (o.getName().length() == 3) {
|
||||
return false;
|
||||
}
|
||||
if (o.getName().charAt(3) >= 'A' && o.getName().charAt(3) <= 'Z') {
|
||||
if (isRecord) {
|
||||
if (recordAllPossibleValues.contains(o.getName())) {
|
||||
// This list is the real list of record members
|
||||
recordAllPossibleValuesFiltered.add(o.getName());
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (o.getName().startsWith("set")) {
|
||||
if (o.getReturnType() != void.class || o.getParameterCount() != 1) {
|
||||
} else {
|
||||
if (o.getName().startsWith("get")) {
|
||||
if (o.getParameterCount() != 0 || o.getReturnType() == void.class || o.getReturnType() == Boolean.class || o.getReturnType() == boolean.class) {
|
||||
return false;
|
||||
}
|
||||
// check name format
|
||||
if (o.getName().length() == 3) {
|
||||
return false;
|
||||
}
|
||||
if (o.getName().charAt(3) >= 'A' && o.getName().charAt(3) <= 'Z') {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// check name format
|
||||
if (o.getName().length() == 3) {
|
||||
if (o.getName().startsWith("set")) {
|
||||
if (o.getReturnType() != void.class || o.getParameterCount() != 1) {
|
||||
return false;
|
||||
}
|
||||
// check name format
|
||||
if (o.getName().length() == 3) {
|
||||
return false;
|
||||
}
|
||||
if (o.getName().charAt(3) >= 'A' && o.getName().charAt(3) <= 'Z') {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
if (o.getName().charAt(3) >= 'A' && o.getName().charAt(3) <= 'Z') {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
if (o.getName().startsWith("is")) {
|
||||
if ((o.getReturnType() != Boolean.class && o.getReturnType() != boolean.class) || o.getParameterCount() != 0) {
|
||||
if (o.getName().startsWith("is")) {
|
||||
if ((o.getReturnType() != Boolean.class && o.getReturnType() != boolean.class) || o.getParameterCount() != 0) {
|
||||
return false;
|
||||
}
|
||||
// check name format
|
||||
if (o.getName().length() == 2) {
|
||||
return false;
|
||||
}
|
||||
if (o.getName().charAt(2) >= 'A' && o.getName().charAt(2) <= 'Z') {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
// check name format
|
||||
if (o.getName().length() == 2) {
|
||||
return false;
|
||||
}
|
||||
if (o.getName().charAt(2) >= 'A' && o.getName().charAt(2) <= 'Z') {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}).collect(Collectors.toList());
|
||||
@ -198,9 +306,15 @@ public class IntrospectionModelComplex extends IntrospectionModel {
|
||||
List<Method> methodsSet;
|
||||
List<Method> methodsIs;
|
||||
if (!Enum.class.isAssignableFrom(classType)) {
|
||||
methodsGet = methods.stream().filter(o -> o.getName().startsWith("get")).collect(Collectors.toList());
|
||||
methodsSet = methods.stream().filter(o -> o.getName().startsWith("set")).collect(Collectors.toList());
|
||||
methodsIs = methods.stream().filter(o -> o.getName().startsWith("is")).collect(Collectors.toList());
|
||||
if (isRecord) {
|
||||
methodsGet = methods.stream().filter(o -> recordAllPossibleValues.contains(o.getName())).collect(Collectors.toList());
|
||||
methodsSet = new ArrayList<>();
|
||||
methodsIs = new ArrayList<>();
|
||||
} else {
|
||||
methodsGet = methods.stream().filter(o -> o.getName().startsWith("get")).collect(Collectors.toList());
|
||||
methodsSet = methods.stream().filter(o -> o.getName().startsWith("set")).collect(Collectors.toList());
|
||||
methodsIs = methods.stream().filter(o -> o.getName().startsWith("is")).collect(Collectors.toList());
|
||||
}
|
||||
} else {
|
||||
methodsGet = new ArrayList<>();
|
||||
methodsSet = new ArrayList<>();
|
||||
@ -225,58 +339,40 @@ public class IntrospectionModelComplex extends IntrospectionModel {
|
||||
// associate methods by pair.
|
||||
final List<OrderData> elements = new ArrayList<>();
|
||||
for (final Method method : methodsGet) {
|
||||
final String name = method.getName().substring(3);
|
||||
final String name = isRecord?method.getName():method.getName().substring(3);
|
||||
final OrderData tmp = new OrderData(name);
|
||||
tmp.getter = method;
|
||||
elements.add(tmp);
|
||||
}
|
||||
for (final Method method : methodsIs) {
|
||||
final String name = method.getName().substring(2);
|
||||
for (final OrderData elem : elements) {
|
||||
if (elem.name.contentEquals(name)) {
|
||||
Log.error("Can not have a setXXX and isXXX with the same name ... " + method.getName());
|
||||
throw new Exception("lmkjlkjlk");
|
||||
}
|
||||
}
|
||||
final OrderData tmp = new OrderData(name);
|
||||
tmp.getter = method;
|
||||
elements.add(tmp);
|
||||
}
|
||||
for (final Method method : methodsSet) {
|
||||
final String name = method.getName().substring(3);
|
||||
OrderData tmp = null;
|
||||
for (final OrderData elem : elements) {
|
||||
if (elem.name.contentEquals(name)) {
|
||||
tmp = elem;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/*
|
||||
Class<?> internalModelClass = null;
|
||||
Class<?>[] tmppp = method.getParameterTypes();
|
||||
if (tmppp.length > 0 && (List.class.isAssignableFrom(tmppp[0]))) {
|
||||
Log.warning(" * " + method.getName());
|
||||
Type[] empppe = method.getGenericParameterTypes();
|
||||
if (empppe.length > 0) {
|
||||
if (empppe[0] instanceof ParameterizedType plopppppp) {
|
||||
Type[] realType = plopppppp.getActualTypeArguments();
|
||||
if (realType.length > 0) {
|
||||
Log.warning(" -->> " + realType[0]);
|
||||
internalModelClass = Class.forName(realType[0].getTypeName());
|
||||
}
|
||||
if (!isRecord) {
|
||||
for (final Method method : methodsIs) {
|
||||
final String name = method.getName().substring(2);
|
||||
for (final OrderData elem : elements) {
|
||||
if (elem.name.contentEquals(name)) {
|
||||
Log.error("Can not have a setXXX and isXXX with the same name ... " + method.getName());
|
||||
throw new Exception("lmkjlkjlk");
|
||||
}
|
||||
}
|
||||
for (int iii=0; iii<tmppp.length; iii++) {
|
||||
Log.warning(" -- " + tmppp[iii].getCanonicalName());
|
||||
}
|
||||
}
|
||||
*/
|
||||
if (tmp == null) {
|
||||
tmp = new OrderData(name);
|
||||
tmp.setter = method;
|
||||
final OrderData tmp = new OrderData(name);
|
||||
tmp.getter = method;
|
||||
elements.add(tmp);
|
||||
} else {
|
||||
tmp.setter = method;
|
||||
}
|
||||
for (final Method method : methodsSet) {
|
||||
final String name = method.getName().substring(3);
|
||||
OrderData tmp = null;
|
||||
for (final OrderData elem : elements) {
|
||||
if (elem.name.contentEquals(name)) {
|
||||
tmp = elem;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (tmp == null) {
|
||||
tmp = new OrderData(name);
|
||||
tmp.setter = method;
|
||||
elements.add(tmp);
|
||||
} else {
|
||||
tmp.setter = method;
|
||||
}
|
||||
}
|
||||
}
|
||||
// Add it in the engine
|
||||
@ -284,44 +380,47 @@ public class IntrospectionModelComplex extends IntrospectionModel {
|
||||
Log.info("find methode : '" + elem.name + "' :");
|
||||
if (elem.setter != null && elem.getter != null) {
|
||||
Log.info(" setter: " + elem.setter.toGenericString());
|
||||
if (recordAllPossibleValuesFiltered.contains(elem.name)) {
|
||||
Log.info(" and by constructor");
|
||||
}
|
||||
Log.info(" getter: " + elem.getter.toGenericString());
|
||||
final Boolean isAttributeSet = getIsAttribute(elem.setter, null);
|
||||
final Boolean isAttributeGet = getIsAttribute(elem.getter, null);
|
||||
final Boolean isAttributeSet = ReflectTools.getIsAttribute(elem.setter, null);
|
||||
final Boolean isAttributeGet = ReflectTools.getIsAttribute(elem.getter, null);
|
||||
if (isAttributeSet != null && isAttributeGet != null && isAttributeSet != isAttributeGet) {
|
||||
throw new Exception("Can net set oposite information on getter and setter");
|
||||
}
|
||||
final Boolean isAttribute = isAttributeSet != null ? isAttributeSet : isAttributeGet != null ? isAttributeGet : isDefaultAttribute;
|
||||
|
||||
final Boolean isManagedSet = getIsManaged(elem.setter, null);
|
||||
final Boolean isManagedGet = getIsManaged(elem.getter, null);
|
||||
final Boolean isManagedSet = ReflectTools.getIsManaged(elem.setter, null);
|
||||
final Boolean isManagedGet = ReflectTools.getIsManaged(elem.getter, null);
|
||||
if (isManagedSet != null && isManagedGet != null && isManagedSet != isManagedGet) {
|
||||
throw new Exception("Can net set oposite information on getter and setter");
|
||||
}
|
||||
final Boolean isManaged = isManagedSet != null ? isManagedSet : isManagedGet != null ? isManagedGet : isDefaultManaged;
|
||||
|
||||
final Boolean isOptionnalSet = getIsOptional(elem.setter, null);
|
||||
final Boolean isOptionnalGet = getIsOptional(elem.getter, null);
|
||||
final Boolean isOptionnalSet = ReflectTools.getIsOptional(elem.setter, null);
|
||||
final Boolean isOptionnalGet = ReflectTools.getIsOptional(elem.getter, null);
|
||||
if (isOptionnalSet != null && isOptionnalGet != null && isOptionnalSet != isOptionnalGet) {
|
||||
throw new Exception("Can net set oposite information on getter and setter");
|
||||
}
|
||||
final Boolean isOptional = isOptionnalSet != null ? isOptionnalSet : isOptionnalGet != null ? isOptionnalGet : isDefaultOptional;
|
||||
|
||||
final Boolean caseSensitiveSet = getIsCaseSensitive(elem.setter, null);
|
||||
final Boolean caseSensitiveGet = getIsCaseSensitive(elem.getter, null);
|
||||
final Boolean caseSensitiveSet = ReflectTools.getIsCaseSensitive(elem.setter, null);
|
||||
final Boolean caseSensitiveGet = ReflectTools.getIsCaseSensitive(elem.getter, null);
|
||||
if (caseSensitiveSet != null && caseSensitiveGet != null && caseSensitiveSet != caseSensitiveGet) {
|
||||
throw new Exception("Can net set oposite information on getter and setter");
|
||||
}
|
||||
|
||||
final Boolean isCaseSensitive = caseSensitiveSet != null ? caseSensitiveSet : caseSensitiveGet != null ? caseSensitiveGet : isDefaultCaseSensitive;
|
||||
|
||||
final String[] namesSet = getNames(elem.setter, null);
|
||||
final String[] namesGet = getNames(elem.getter, null);
|
||||
final String[] namesSet = ReflectTools.getNames(elem.setter, null);
|
||||
final String[] namesGet = ReflectTools.getNames(elem.getter, null);
|
||||
if (namesSet != null && namesGet != null && namesSet.equals(namesGet)) {
|
||||
throw new Exception("Can net set oposite information on getter and setter");
|
||||
}
|
||||
final String[] names = namesSet != null ? namesSet : namesGet != null ? namesGet : new String[] { Tools.decapitalizeFirst(elem.name) };
|
||||
final String listNameSet = getListName(elem.setter, null);
|
||||
final String listNameGet = getListName(elem.getter, null);
|
||||
final String listNameSet = ReflectTools.getListName(elem.setter, null);
|
||||
final String listNameGet = ReflectTools.getListName(elem.getter, null);
|
||||
final String listName = listNameSet != null? listNameSet: listNameGet;
|
||||
if (isAttribute) {
|
||||
this.attributes.add(new IntrospectionPropertyMethod(elem.setter, elem.getter, names, listName, isCaseSensitive, isOptional));
|
||||
@ -337,31 +436,35 @@ public class IntrospectionModelComplex extends IntrospectionModel {
|
||||
Boolean isAttribute = isDefaultAttribute;
|
||||
if (elem.setter != null) {
|
||||
Log.info(" setter: " + elem.setter.toGenericString());
|
||||
isAttribute = getIsAttribute(elem.setter, isDefaultAttribute);
|
||||
isManaged = getIsManaged(elem.setter, isDefaultManaged);
|
||||
isOptionnal = getIsOptional(elem.setter, isDefaultOptional);
|
||||
names = getNames(elem.setter, Tools.decapitalizeFirst(elem.name));
|
||||
isCaseSensitive = getIsCaseSensitive(elem.setter, isDefaultCaseSensitive);
|
||||
listName= getListName(elem.setter, null);
|
||||
isAttribute = ReflectTools.getIsAttribute(elem.setter, isDefaultAttribute);
|
||||
isManaged = ReflectTools.getIsManaged(elem.setter, isDefaultManaged);
|
||||
isOptionnal = ReflectTools.getIsOptional(elem.setter, isDefaultOptional);
|
||||
names = ReflectTools.getNames(elem.setter, Tools.decapitalizeFirst(elem.name));
|
||||
isCaseSensitive = ReflectTools.getIsCaseSensitive(elem.setter, isDefaultCaseSensitive);
|
||||
listName= ReflectTools.getListName(elem.setter, null);
|
||||
} else {
|
||||
Log.info(" setter: null");
|
||||
}
|
||||
if (elem.getter != null) {
|
||||
Log.info(" getter: " + elem.getter.toGenericString());
|
||||
isAttribute = getIsAttribute(elem.getter, isDefaultAttribute);
|
||||
isManaged = getIsManaged(elem.getter, isDefaultManaged);
|
||||
isOptionnal = getIsOptional(elem.getter, isDefaultOptional);
|
||||
names = getNames(elem.getter, Tools.decapitalizeFirst(elem.name));
|
||||
isCaseSensitive = getIsCaseSensitive(elem.getter, isDefaultCaseSensitive);
|
||||
listName= getListName(elem.getter, null);
|
||||
isAttribute = ReflectTools.getIsAttribute(elem.getter, isDefaultAttribute);
|
||||
isManaged = ReflectTools.getIsManaged(elem.getter, isDefaultManaged);
|
||||
isOptionnal = ReflectTools.getIsOptional(elem.getter, isDefaultOptional);
|
||||
names = ReflectTools.getNames(elem.getter, Tools.decapitalizeFirst(elem.name));
|
||||
isCaseSensitive = ReflectTools.getIsCaseSensitive(elem.getter, isDefaultCaseSensitive);
|
||||
listName= ReflectTools.getListName(elem.getter, null);
|
||||
} else {
|
||||
Log.info(" getter: null");
|
||||
}
|
||||
if (isManaged) {
|
||||
if (isAttribute) {
|
||||
this.attributes.add(new IntrospectionPropertyMethod(elem.setter, elem.getter, names, listName, isCaseSensitive, isOptionnal));
|
||||
IntrospectionPropertyMethod tmpp = new IntrospectionPropertyMethod(elem.setter, elem.getter, names, listName, isCaseSensitive, isOptionnal);
|
||||
tmpp.setCanBeSetByConstructor(recordAllPossibleValuesFiltered.contains(elem.name));
|
||||
this.attributes.add(tmpp);
|
||||
} else {
|
||||
this.nodes.add(new IntrospectionPropertyMethod(elem.setter, elem.getter, names, listName, isCaseSensitive, isOptionnal));
|
||||
IntrospectionPropertyMethod tmpp = new IntrospectionPropertyMethod(elem.setter, elem.getter, names, listName, isCaseSensitive, isOptionnal);
|
||||
tmpp.setCanBeSetByConstructor(recordAllPossibleValuesFiltered.contains(elem.name));
|
||||
this.nodes.add(tmpp);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -374,22 +477,83 @@ public class IntrospectionModelComplex extends IntrospectionModel {
|
||||
|
||||
@Override
|
||||
public Object createObject(final Map<String, Object> properties, final Map<String, List<Object>> nodes) throws ExmlBuilderException {
|
||||
Object tmp;
|
||||
if (this.constructorEmpty == null) {
|
||||
throw new ExmlBuilderException("No constructor accessible for class: " + this.classType.getCanonicalName());
|
||||
}
|
||||
try {
|
||||
if (this.isSubClass) {
|
||||
Object tmp2 = null;
|
||||
tmp = this.constructorEmpty.newInstance(tmp2);
|
||||
} else {
|
||||
tmp = this.constructorEmpty.newInstance();
|
||||
Object tmp = null;
|
||||
// STEP 1: try to create the object with provided parameter (if a constructor exist....)
|
||||
if (!this.constructors.isEmpty()) {
|
||||
// try to find the constructor that fit with parameters ...
|
||||
for (ConstructorModel elem : this.constructors) {
|
||||
int offset = this.isSubClass?1:0;
|
||||
Object[] inputs = new Object[elem.values().length+offset];
|
||||
inputs[0] = null;
|
||||
for (int iii=0; iii<elem.values().length; iii++) {
|
||||
Object valueToInject = properties.get(elem.values()[iii]);
|
||||
if (valueToInject == null) {
|
||||
List<Object> tmppp = nodes.get(elem.values()[iii]);
|
||||
if (tmppp != null && tmppp.size() >=1) {
|
||||
valueToInject = tmppp.get(0);
|
||||
}
|
||||
}
|
||||
if (valueToInject == null) {
|
||||
inputs = null;
|
||||
break;
|
||||
}
|
||||
inputs[iii+offset] = valueToInject;
|
||||
}
|
||||
if (inputs != null) {
|
||||
// here we find our constructor...
|
||||
try {
|
||||
switch(inputs.length) {
|
||||
case 0: tmp = elem.constructor().newInstance(); break;
|
||||
case 1: tmp = elem.constructor().newInstance(inputs[0]); break;
|
||||
case 2: tmp = elem.constructor().newInstance(inputs[0],inputs[1]); break;
|
||||
case 3: tmp = elem.constructor().newInstance(inputs[0],inputs[1],inputs[2]); break;
|
||||
case 4: tmp = elem.constructor().newInstance(inputs[0],inputs[1],inputs[2],inputs[3]); break;
|
||||
case 5: tmp = elem.constructor().newInstance(inputs[0],inputs[1],inputs[2],inputs[3],inputs[4]); break;
|
||||
case 6: tmp = elem.constructor().newInstance(inputs[0],inputs[1],inputs[2],inputs[3],inputs[4],inputs[5]); break;
|
||||
case 7: tmp = elem.constructor().newInstance(inputs[0],inputs[1],inputs[2],inputs[3],inputs[4],inputs[5],inputs[6]); break;
|
||||
case 8: tmp = elem.constructor().newInstance(inputs[0],inputs[1],inputs[2],inputs[3],inputs[4],inputs[5],inputs[6],inputs[7]); break;
|
||||
case 9: tmp = elem.constructor().newInstance(inputs[0],inputs[1],inputs[2],inputs[3],inputs[4],inputs[5],inputs[6],inputs[7],inputs[8]); break;
|
||||
case 10: tmp = elem.constructor().newInstance(inputs[0],inputs[1],inputs[2],inputs[3],inputs[4],inputs[5],inputs[6],inputs[7],inputs[8],inputs[9]); break;
|
||||
case 11: tmp = elem.constructor().newInstance(inputs[0],inputs[1],inputs[2],inputs[3],inputs[4],inputs[5],inputs[6],inputs[7],inputs[8],inputs[9],inputs[10]); break;
|
||||
case 12: tmp = elem.constructor().newInstance(inputs[0],inputs[1],inputs[2],inputs[3],inputs[4],inputs[5],inputs[6],inputs[7],inputs[8],inputs[9],inputs[10],inputs[11]); break;
|
||||
case 13: tmp = elem.constructor().newInstance(inputs[0],inputs[1],inputs[2],inputs[3],inputs[4],inputs[5],inputs[6],inputs[7],inputs[8],inputs[9],inputs[10],inputs[11],inputs[12]); break;
|
||||
default:
|
||||
throw new ExmlBuilderException("to much parameter in the constructor... " + inputs.length);
|
||||
}
|
||||
//tmp = elem.constructor().newInstance(inputs);
|
||||
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
throw new ExmlBuilderException("Error when creating the Object ..." + this.classType.getCanonicalName());
|
||||
}
|
||||
// Remove all previously added parameters
|
||||
for (int iii=0; iii<elem.values().length; iii++) {
|
||||
properties.remove(elem.values()[iii]);
|
||||
nodes.remove(elem.values()[iii]);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | SecurityException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
// STEP 2: If we do not create the object ==> try with empty constructor...
|
||||
if (tmp == null) {
|
||||
if (this.constructorEmpty == null) {
|
||||
throw new ExmlBuilderException("No constructor accessible for class: " + this.classType.getCanonicalName());
|
||||
}
|
||||
try {
|
||||
if (this.isSubClass) {
|
||||
Object tmp2 = null;
|
||||
tmp = this.constructorEmpty.newInstance(tmp2);
|
||||
} else {
|
||||
tmp = this.constructorEmpty.newInstance();
|
||||
}
|
||||
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | SecurityException e) {
|
||||
// TODO Auto-generated catch block
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
// STEP 3: set the rest if the parameters...
|
||||
for (Entry<String, Object> elem : properties.entrySet()) {
|
||||
setValue(tmp, elem.getKey(), elem.getValue());
|
||||
}
|
||||
@ -429,224 +593,6 @@ public class IntrospectionModelComplex extends IntrospectionModel {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected Boolean getIsCaseSensitive(final Field element, final Boolean defaultValue) throws ExmlBuilderException {
|
||||
final Annotation[] annotation = element.getDeclaredAnnotationsByType(XmlCaseSensitive.class);
|
||||
if (annotation.length == 0) {
|
||||
return defaultValue;
|
||||
}
|
||||
if (annotation.length > 1) {
|
||||
throw new ExmlBuilderException("Must not have more that ");
|
||||
}
|
||||
return ((XmlCaseSensitive) annotation[0]).value();
|
||||
}
|
||||
|
||||
protected Boolean getIsCaseSensitive(final Method element, final Boolean defaultValue) throws ExmlBuilderException {
|
||||
final Annotation[] annotation = element.getDeclaredAnnotationsByType(XmlCaseSensitive.class);
|
||||
if (annotation.length == 0) {
|
||||
return defaultValue;
|
||||
}
|
||||
if (annotation.length > 1) {
|
||||
throw new ExmlBuilderException("Must not have more that ");
|
||||
}
|
||||
return ((XmlCaseSensitive) annotation[0]).value();
|
||||
}
|
||||
|
||||
private Boolean getIsDefaultCaseSensitive(final Class<?> classType, final Boolean defaultValue) throws ExmlBuilderException {
|
||||
final Annotation[] annotation = classType.getDeclaredAnnotationsByType(XmlDefaultCaseSensitive.class);
|
||||
if (annotation.length == 0) {
|
||||
return defaultValue;
|
||||
}
|
||||
if (annotation.length > 1) {
|
||||
throw new ExmlBuilderException("Must not have more that ");
|
||||
}
|
||||
return ((XmlDefaultCaseSensitive) annotation[0]).value();
|
||||
}
|
||||
|
||||
private Boolean getIsDefaultAttribute(final Class<?> classType, final Boolean defaultValue) throws ExmlBuilderException {
|
||||
final Annotation[] annotation = classType.getDeclaredAnnotationsByType(XmlDefaultAttibute.class);
|
||||
if (annotation.length == 0) {
|
||||
return defaultValue;
|
||||
}
|
||||
if (annotation.length > 1) {
|
||||
throw new ExmlBuilderException("Must not have more that ");
|
||||
}
|
||||
return ((XmlDefaultAttibute) annotation[0]).value();
|
||||
}
|
||||
|
||||
private Boolean getIsDefaultManaged(final Class<?> classType, final Boolean defaultValue) throws ExmlBuilderException {
|
||||
final Annotation[] annotation = classType.getDeclaredAnnotationsByType(XmlDefaultManaged.class);
|
||||
if (annotation.length == 0) {
|
||||
return defaultValue;
|
||||
}
|
||||
if (annotation.length > 1) {
|
||||
throw new ExmlBuilderException("Must not have more that ");
|
||||
}
|
||||
return ((XmlDefaultManaged) annotation[0]).value();
|
||||
}
|
||||
|
||||
private Boolean getIsDefaultOptional(final Class<?> classType, final Boolean defaultValue) throws ExmlBuilderException {
|
||||
final Annotation[] annotation = classType.getDeclaredAnnotationsByType(XmlDefaultOptional.class);
|
||||
if (annotation.length == 0) {
|
||||
return defaultValue;
|
||||
}
|
||||
if (annotation.length > 1) {
|
||||
throw new ExmlBuilderException("Must not have more that ");
|
||||
}
|
||||
return ((XmlDefaultOptional) annotation[0]).value();
|
||||
}
|
||||
|
||||
protected Boolean getIsAttribute(final Field element, final Boolean parentValue) throws ExmlBuilderException {
|
||||
final Annotation[] annotation = element.getDeclaredAnnotationsByType(XmlAttribute.class);
|
||||
if (annotation.length == 0) {
|
||||
return parentValue;
|
||||
}
|
||||
if (annotation.length > 1) {
|
||||
throw new ExmlBuilderException("Must not have more that ");
|
||||
}
|
||||
return ((XmlAttribute) annotation[0]).value();
|
||||
}
|
||||
|
||||
protected Boolean getIsAttribute(final Method element, final Boolean parentValue) throws ExmlBuilderException {
|
||||
final Annotation[] annotation = element.getDeclaredAnnotationsByType(XmlAttribute.class);
|
||||
if (annotation.length == 0) {
|
||||
return parentValue;
|
||||
}
|
||||
if (annotation.length > 1) {
|
||||
throw new ExmlBuilderException("Must not have more that ");
|
||||
}
|
||||
return ((XmlAttribute) annotation[0]).value();
|
||||
}
|
||||
|
||||
protected Boolean getIsManaged(final Field element, final Boolean parentValue) throws ExmlBuilderException {
|
||||
final Annotation[] annotation = element.getDeclaredAnnotationsByType(XmlManaged.class);
|
||||
if (annotation.length == 0) {
|
||||
return parentValue;
|
||||
}
|
||||
if (annotation.length > 1) {
|
||||
throw new ExmlBuilderException("Must not have more that ");
|
||||
}
|
||||
return ((XmlManaged) annotation[0]).value();
|
||||
}
|
||||
|
||||
protected Boolean getIsManaged(final Method element, final Boolean parentValue) throws ExmlBuilderException {
|
||||
final Annotation[] annotation = element.getDeclaredAnnotationsByType(XmlManaged.class);
|
||||
if (annotation.length == 0) {
|
||||
return parentValue;
|
||||
}
|
||||
if (annotation.length > 1) {
|
||||
throw new ExmlBuilderException("Must not have more that ");
|
||||
}
|
||||
return ((XmlManaged) annotation[0]).value();
|
||||
}
|
||||
|
||||
protected Boolean getIsOptional(final Field element, final Boolean parentValue) throws Exception {
|
||||
final Annotation[] annotation = element.getDeclaredAnnotationsByType(XmlOptional.class);
|
||||
if (annotation.length == 0) {
|
||||
return parentValue;
|
||||
}
|
||||
if (annotation.length > 1) {
|
||||
throw new Exception("Must not have more that ");
|
||||
}
|
||||
return ((XmlOptional) annotation[0]).value();
|
||||
}
|
||||
|
||||
protected Boolean getIsOptional(final Method element, final Boolean parentValue) throws Exception {
|
||||
final Annotation[] annotation = element.getDeclaredAnnotationsByType(XmlOptional.class);
|
||||
if (annotation.length == 0) {
|
||||
return parentValue;
|
||||
}
|
||||
if (annotation.length > 1) {
|
||||
throw new Exception("Must not have more that ");
|
||||
}
|
||||
return ((XmlOptional) annotation[0]).value();
|
||||
}
|
||||
|
||||
protected String[] getNames(final Field element, final String defaultValue) throws Exception {
|
||||
final Annotation[] annotation = element.getDeclaredAnnotationsByType(XmlName.class);
|
||||
if (annotation.length == 0) {
|
||||
if (defaultValue == null) {
|
||||
return null;
|
||||
}
|
||||
return new String[] { defaultValue };
|
||||
}
|
||||
if (annotation.length > 1) {
|
||||
throw new Exception("Must not have more that ");
|
||||
}
|
||||
final String[] tmp = ((XmlName) annotation[0]).value();
|
||||
if (tmp == null) {
|
||||
throw new Exception("Set null value in decorator @XmlName is not availlable on: " + element.toGenericString());
|
||||
}
|
||||
if (tmp.length == 0) {
|
||||
throw new Exception("Set empty list value in decorator @XmlName is not availlable on: " + element.toGenericString());
|
||||
}
|
||||
for (final String elem : tmp) {
|
||||
if (elem == null) {
|
||||
throw new Exception("Set null String in list of value in decorator @XmlName is not availlable on: " + element.toGenericString());
|
||||
}
|
||||
if (elem.isEmpty()) {
|
||||
throw new Exception("Set empty String in list of value in decorator @XmlName is not availlable on: " + element.toGenericString());
|
||||
}
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
protected String[] getNames(final Method element, final String defaultValue) throws Exception {
|
||||
final Annotation[] annotation = element.getDeclaredAnnotationsByType(XmlName.class);
|
||||
if (annotation.length == 0) {
|
||||
if (defaultValue == null) {
|
||||
return null;
|
||||
}
|
||||
return new String[] { defaultValue };
|
||||
}
|
||||
if (annotation.length > 1) {
|
||||
throw new Exception("Must not have more that ");
|
||||
}
|
||||
final String[] tmp = ((XmlName) annotation[0]).value();
|
||||
if (tmp == null) {
|
||||
throw new Exception("Set null value in decorator @XmlName is not availlable on: " + element.toGenericString());
|
||||
}
|
||||
if (tmp.length == 0) {
|
||||
throw new Exception("Set empty list value in decorator @XmlName is not availlable on: " + element.toGenericString());
|
||||
}
|
||||
for (final String elem : tmp) {
|
||||
if (elem == null) {
|
||||
throw new Exception("Set null String in list of value in decorator @XmlName is not availlable on: " + element.toGenericString());
|
||||
}
|
||||
if (elem.isEmpty()) {
|
||||
throw new Exception("Set empty String in list of value in decorator @XmlName is not availlable on: " + element.toGenericString());
|
||||
}
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
protected String getListName(final Field element, final String defaultValue) throws Exception {
|
||||
final Annotation[] annotation = element.getDeclaredAnnotationsByType(XmlList.class);
|
||||
if (annotation.length == 0) {
|
||||
return defaultValue;
|
||||
}
|
||||
if (annotation.length > 1) {
|
||||
throw new Exception("Must not have more that ");
|
||||
}
|
||||
final String tmp = ((XmlList) annotation[0]).value();
|
||||
if (tmp == null) {
|
||||
throw new Exception("Set null value in decorator @XmlList is not availlable on: " + element.toGenericString());
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
protected String getListName(final Method element, final String defaultValue) throws Exception {
|
||||
final Annotation[] annotation = element.getDeclaredAnnotationsByType(XmlList.class);
|
||||
if (annotation.length == 0) {
|
||||
return defaultValue;
|
||||
}
|
||||
if (annotation.length > 1) {
|
||||
throw new Exception("Must not have more that ");
|
||||
}
|
||||
final String tmp = ((XmlList) annotation[0]).value();
|
||||
if (tmp == null) {
|
||||
throw new Exception("Set null value in decorator @XmlList is not availlable on: " + element.toGenericString());
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T[] autoCast(final Class<T> clazz, final List<Object> data) {
|
||||
T[] out = (T[]) java.lang.reflect.Array.newInstance(clazz, data.size());// T[data.size()];
|
||||
|
@ -17,7 +17,15 @@ public abstract class IntrospectionProperty {
|
||||
public String getListName() {
|
||||
return this.listName;
|
||||
}
|
||||
protected boolean canBeSetByConstructor = false;
|
||||
|
||||
public boolean isCanBeSetByConstructor() {
|
||||
return this.canBeSetByConstructor;
|
||||
}
|
||||
|
||||
public void setCanBeSetByConstructor(final boolean canBeSetByConstructor) {
|
||||
this.canBeSetByConstructor = canBeSetByConstructor;
|
||||
}
|
||||
protected final Class<?> type;
|
||||
protected final Class<?> subType;
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
package org.atriasoft.exml.builder;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
@ -8,6 +9,7 @@ import org.atriasoft.exml.exception.ExmlBuilderException;
|
||||
|
||||
public class IntrospectionPropertyField extends IntrospectionProperty {
|
||||
private final Field fieldDescription;
|
||||
private final boolean finalValue;
|
||||
|
||||
|
||||
private static Class<?>[] getTypeField(final Field fieldDescription) {
|
||||
@ -31,6 +33,7 @@ public class IntrospectionPropertyField extends IntrospectionProperty {
|
||||
public IntrospectionPropertyField(final Field fieldDescription, final String[] names, final String listName, final Boolean caseSensitive, final Boolean isOptionnal) {
|
||||
super(IntrospectionPropertyField.getTypeField(fieldDescription), names, listName, caseSensitive, isOptionnal);
|
||||
this.fieldDescription = fieldDescription;
|
||||
this.finalValue = Modifier.isFinal(fieldDescription.getModifiers());
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -40,7 +43,7 @@ public class IntrospectionPropertyField extends IntrospectionProperty {
|
||||
|
||||
@Override
|
||||
public boolean canSetValue() {
|
||||
return true;
|
||||
return this.canBeSetByConstructor || !this.finalValue;
|
||||
}
|
||||
@Override
|
||||
public Object getValue(final Object object) throws ExmlBuilderException {
|
||||
|
@ -74,7 +74,7 @@ public class IntrospectionPropertyMethod extends IntrospectionProperty {
|
||||
|
||||
@Override
|
||||
public boolean canSetValue() {
|
||||
return this.setter != null;
|
||||
return this.canBeSetByConstructor || this.setter != null;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
299
src/org/atriasoft/exml/reflect/ReflectTools.java
Normal file
299
src/org/atriasoft/exml/reflect/ReflectTools.java
Normal file
@ -0,0 +1,299 @@
|
||||
package org.atriasoft.exml.reflect;
|
||||
|
||||
import java.lang.annotation.Annotation;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Parameter;
|
||||
|
||||
import org.atriasoft.exml.annotation.XmlAttribute;
|
||||
import org.atriasoft.exml.annotation.XmlCaseSensitive;
|
||||
import org.atriasoft.exml.annotation.XmlDefaultAttibute;
|
||||
import org.atriasoft.exml.annotation.XmlDefaultCaseSensitive;
|
||||
import org.atriasoft.exml.annotation.XmlDefaultManaged;
|
||||
import org.atriasoft.exml.annotation.XmlDefaultOptional;
|
||||
import org.atriasoft.exml.annotation.XmlList;
|
||||
import org.atriasoft.exml.annotation.XmlManaged;
|
||||
import org.atriasoft.exml.annotation.XmlName;
|
||||
import org.atriasoft.exml.annotation.XmlOptional;
|
||||
import org.atriasoft.exml.exception.ExmlBuilderException;
|
||||
|
||||
public class ReflectTools {
|
||||
private ReflectTools() {}
|
||||
|
||||
public static Boolean getIsCaseSensitive(final Field element, final Boolean defaultValue) throws ExmlBuilderException {
|
||||
final Annotation[] annotation = element.getDeclaredAnnotationsByType(XmlCaseSensitive.class);
|
||||
if (annotation.length == 0) {
|
||||
return defaultValue;
|
||||
}
|
||||
if (annotation.length > 1) {
|
||||
throw new ExmlBuilderException("Must not have more that ");
|
||||
}
|
||||
return ((XmlCaseSensitive) annotation[0]).value();
|
||||
}
|
||||
|
||||
public static Boolean getIsCaseSensitive(final Method element, final Boolean defaultValue) throws ExmlBuilderException {
|
||||
final Annotation[] annotation = element.getDeclaredAnnotationsByType(XmlCaseSensitive.class);
|
||||
if (annotation.length == 0) {
|
||||
return defaultValue;
|
||||
}
|
||||
if (annotation.length > 1) {
|
||||
throw new ExmlBuilderException("Must not have more that ");
|
||||
}
|
||||
return ((XmlCaseSensitive) annotation[0]).value();
|
||||
}
|
||||
|
||||
public static Boolean getIsDefaultCaseSensitive(final Class<?> classType, final Boolean defaultValue) throws ExmlBuilderException {
|
||||
final Annotation[] annotation = classType.getDeclaredAnnotationsByType(XmlDefaultCaseSensitive.class);
|
||||
if (annotation.length == 0) {
|
||||
return defaultValue;
|
||||
}
|
||||
if (annotation.length > 1) {
|
||||
throw new ExmlBuilderException("Must not have more that ");
|
||||
}
|
||||
return ((XmlDefaultCaseSensitive) annotation[0]).value();
|
||||
}
|
||||
|
||||
public static Boolean getIsDefaultAttribute(final Class<?> classType, final Boolean defaultValue) throws ExmlBuilderException {
|
||||
final Annotation[] annotation = classType.getDeclaredAnnotationsByType(XmlDefaultAttibute.class);
|
||||
if (annotation.length == 0) {
|
||||
return defaultValue;
|
||||
}
|
||||
if (annotation.length > 1) {
|
||||
throw new ExmlBuilderException("Must not have more that ");
|
||||
}
|
||||
return ((XmlDefaultAttibute) annotation[0]).value();
|
||||
}
|
||||
|
||||
public static Boolean getIsDefaultManaged(final Class<?> classType, final Boolean defaultValue) throws ExmlBuilderException {
|
||||
final Annotation[] annotation = classType.getDeclaredAnnotationsByType(XmlDefaultManaged.class);
|
||||
if (annotation.length == 0) {
|
||||
return defaultValue;
|
||||
}
|
||||
if (annotation.length > 1) {
|
||||
throw new ExmlBuilderException("Must not have more that ");
|
||||
}
|
||||
return ((XmlDefaultManaged) annotation[0]).value();
|
||||
}
|
||||
|
||||
public static Boolean getIsDefaultOptional(final Class<?> classType, final Boolean defaultValue) throws ExmlBuilderException {
|
||||
final Annotation[] annotation = classType.getDeclaredAnnotationsByType(XmlDefaultOptional.class);
|
||||
if (annotation.length == 0) {
|
||||
return defaultValue;
|
||||
}
|
||||
if (annotation.length > 1) {
|
||||
throw new ExmlBuilderException("Must not have more that ");
|
||||
}
|
||||
return ((XmlDefaultOptional) annotation[0]).value();
|
||||
}
|
||||
|
||||
public static Boolean getIsAttribute(final Field element, final Boolean parentValue) throws ExmlBuilderException {
|
||||
final Annotation[] annotation = element.getDeclaredAnnotationsByType(XmlAttribute.class);
|
||||
if (annotation.length == 0) {
|
||||
return parentValue;
|
||||
}
|
||||
if (annotation.length > 1) {
|
||||
throw new ExmlBuilderException("Must not have more that ");
|
||||
}
|
||||
return ((XmlAttribute) annotation[0]).value();
|
||||
}
|
||||
|
||||
public static Boolean getIsAttribute(final Method element, final Boolean parentValue) throws ExmlBuilderException {
|
||||
final Annotation[] annotation = element.getDeclaredAnnotationsByType(XmlAttribute.class);
|
||||
if (annotation.length == 0) {
|
||||
return parentValue;
|
||||
}
|
||||
if (annotation.length > 1) {
|
||||
throw new ExmlBuilderException("Must not have more that ");
|
||||
}
|
||||
return ((XmlAttribute) annotation[0]).value();
|
||||
}
|
||||
|
||||
public static Boolean getIsManaged(final Field element, final Boolean parentValue) throws ExmlBuilderException {
|
||||
final Annotation[] annotation = element.getDeclaredAnnotationsByType(XmlManaged.class);
|
||||
if (annotation.length == 0) {
|
||||
return parentValue;
|
||||
}
|
||||
if (annotation.length > 1) {
|
||||
throw new ExmlBuilderException("Must not have more that ");
|
||||
}
|
||||
return ((XmlManaged) annotation[0]).value();
|
||||
}
|
||||
|
||||
public static Boolean getIsManaged(final Method element, final Boolean parentValue) throws ExmlBuilderException {
|
||||
final Annotation[] annotation = element.getDeclaredAnnotationsByType(XmlManaged.class);
|
||||
if (annotation.length == 0) {
|
||||
return parentValue;
|
||||
}
|
||||
if (annotation.length > 1) {
|
||||
throw new ExmlBuilderException("Must not have more that ");
|
||||
}
|
||||
return ((XmlManaged) annotation[0]).value();
|
||||
}
|
||||
|
||||
public static Boolean getIsOptional(final Field element, final Boolean parentValue) throws Exception {
|
||||
final Annotation[] annotation = element.getDeclaredAnnotationsByType(XmlOptional.class);
|
||||
if (annotation.length == 0) {
|
||||
return parentValue;
|
||||
}
|
||||
if (annotation.length > 1) {
|
||||
throw new Exception("Must not have more that ");
|
||||
}
|
||||
return ((XmlOptional) annotation[0]).value();
|
||||
}
|
||||
|
||||
public static Boolean getIsOptional(final Method element, final Boolean parentValue) throws Exception {
|
||||
final Annotation[] annotation = element.getDeclaredAnnotationsByType(XmlOptional.class);
|
||||
if (annotation.length == 0) {
|
||||
return parentValue;
|
||||
}
|
||||
if (annotation.length > 1) {
|
||||
throw new Exception("Must not have more that ");
|
||||
}
|
||||
return ((XmlOptional) annotation[0]).value();
|
||||
}
|
||||
|
||||
public static String[] getNames(final Field element, final String defaultValue) throws Exception {
|
||||
final Annotation[] annotation = element.getDeclaredAnnotationsByType(XmlName.class);
|
||||
if (annotation.length == 0) {
|
||||
if (defaultValue == null) {
|
||||
return null;
|
||||
}
|
||||
return new String[] { defaultValue };
|
||||
}
|
||||
if (annotation.length > 1) {
|
||||
throw new Exception("Must not have more that ");
|
||||
}
|
||||
final String[] tmp = ((XmlName) annotation[0]).value();
|
||||
if (tmp == null) {
|
||||
throw new Exception("Set null value in decorator @XmlName is not availlable on: " + element.toGenericString());
|
||||
}
|
||||
if (tmp.length == 0) {
|
||||
throw new Exception("Set empty list value in decorator @XmlName is not availlable on: " + element.toGenericString());
|
||||
}
|
||||
for (final String elem : tmp) {
|
||||
if (elem == null) {
|
||||
throw new Exception("Set null String in list of value in decorator @XmlName is not availlable on: " + element.toGenericString());
|
||||
}
|
||||
if (elem.isEmpty()) {
|
||||
throw new Exception("Set empty String in list of value in decorator @XmlName is not availlable on: " + element.toGenericString());
|
||||
}
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
public static String[] getNames(final Method element, final String defaultValue) throws Exception {
|
||||
final Annotation[] annotation = element.getDeclaredAnnotationsByType(XmlName.class);
|
||||
if (annotation.length == 0) {
|
||||
if (defaultValue == null) {
|
||||
return null;
|
||||
}
|
||||
return new String[] { defaultValue };
|
||||
}
|
||||
if (annotation.length > 1) {
|
||||
throw new Exception("Must not have more that ");
|
||||
}
|
||||
final String[] tmp = ((XmlName) annotation[0]).value();
|
||||
if (tmp == null) {
|
||||
throw new Exception("Set null value in decorator @XmlName is not availlable on: " + element.toGenericString());
|
||||
}
|
||||
if (tmp.length == 0) {
|
||||
throw new Exception("Set empty list value in decorator @XmlName is not availlable on: " + element.toGenericString());
|
||||
}
|
||||
for (final String elem : tmp) {
|
||||
if (elem == null) {
|
||||
throw new Exception("Set null String in list of value in decorator @XmlName is not availlable on: " + element.toGenericString());
|
||||
}
|
||||
if (elem.isEmpty()) {
|
||||
throw new Exception("Set empty String in list of value in decorator @XmlName is not availlable on: " + element.toGenericString());
|
||||
}
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
public static String[] getNames(final Constructor<?> element, final String defaultValue) throws Exception {
|
||||
final Annotation[] annotation = element.getDeclaredAnnotationsByType(XmlName.class);
|
||||
if (annotation.length == 0) {
|
||||
if (defaultValue == null) {
|
||||
return null;
|
||||
}
|
||||
return new String[] { defaultValue };
|
||||
}
|
||||
if (annotation.length > 1) {
|
||||
throw new Exception("Must not have more that ");
|
||||
}
|
||||
final String[] tmp = ((XmlName) annotation[0]).value();
|
||||
if (tmp == null) {
|
||||
throw new Exception("Set null value in decorator @XmlName is not availlable on: " + element.toGenericString());
|
||||
}
|
||||
if (tmp.length == 0) {
|
||||
throw new Exception("Set empty list value in decorator @XmlName is not availlable on: " + element.toGenericString());
|
||||
}
|
||||
for (final String elem : tmp) {
|
||||
if (elem == null) {
|
||||
throw new Exception("Set null String in list of value in decorator @XmlName is not availlable on: " + element.toGenericString());
|
||||
}
|
||||
if (elem.isEmpty()) {
|
||||
throw new Exception("Set empty String in list of value in decorator @XmlName is not availlable on: " + element.toGenericString());
|
||||
}
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
public static String[] getNames(final Constructor<?> constructor, final Parameter element, final String defaultValue) throws Exception {
|
||||
final Annotation[] annotation = element.getDeclaredAnnotationsByType(XmlName.class);
|
||||
if (annotation.length == 0) {
|
||||
if (defaultValue == null) {
|
||||
return null;
|
||||
}
|
||||
return new String[] { defaultValue };
|
||||
}
|
||||
if (annotation.length > 1) {
|
||||
throw new Exception("Must not have more that ");
|
||||
}
|
||||
final String[] tmp = ((XmlName) annotation[0]).value();
|
||||
if (tmp == null) {
|
||||
throw new Exception("Set null value in decorator @XmlName is not availlable on: " + constructor.toGenericString());
|
||||
}
|
||||
if (tmp.length == 0) {
|
||||
throw new Exception("Set empty list value in decorator @XmlName is not availlable on: " + constructor.toGenericString());
|
||||
}
|
||||
for (final String elem : tmp) {
|
||||
if (elem == null) {
|
||||
throw new Exception("Set null String in list of value in decorator @XmlName is not availlable on: " + constructor.toGenericString());
|
||||
}
|
||||
if (elem.isEmpty()) {
|
||||
throw new Exception("Set empty String in list of value in decorator @XmlName is not availlable on: " + constructor.toGenericString());
|
||||
}
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
||||
public static String getListName(final Field element, final String defaultValue) throws Exception {
|
||||
final Annotation[] annotation = element.getDeclaredAnnotationsByType(XmlList.class);
|
||||
if (annotation.length == 0) {
|
||||
return defaultValue;
|
||||
}
|
||||
if (annotation.length > 1) {
|
||||
throw new Exception("Must not have more that ");
|
||||
}
|
||||
final String tmp = ((XmlList) annotation[0]).value();
|
||||
if (tmp == null) {
|
||||
throw new Exception("Set null value in decorator @XmlList is not availlable on: " + element.toGenericString());
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
public static String getListName(final Method element, final String defaultValue) throws Exception {
|
||||
final Annotation[] annotation = element.getDeclaredAnnotationsByType(XmlList.class);
|
||||
if (annotation.length == 0) {
|
||||
return defaultValue;
|
||||
}
|
||||
if (annotation.length > 1) {
|
||||
throw new Exception("Must not have more that ");
|
||||
}
|
||||
final String tmp = ((XmlList) annotation[0]).value();
|
||||
if (tmp == null) {
|
||||
throw new Exception("Set null value in decorator @XmlList is not availlable on: " + element.toGenericString());
|
||||
}
|
||||
return tmp;
|
||||
}
|
||||
}
|
@ -340,7 +340,7 @@ public class ExmlTestIntrospection {
|
||||
//@formatter:on
|
||||
final ClassPublicMethodeStructured[] root = Assertions.assertDoesNotThrow(() -> Exml.parse(dataToParse, ClassPublicMethodeStructured.class, "elem"));
|
||||
Assertions.assertEquals(1, root.length);
|
||||
|
||||
|
||||
final ClassPublicMethodeStructured elem = root[0];
|
||||
Assertions.assertEquals(5, elem.getMemberArrayByte().length);
|
||||
Assertions.assertEquals((byte) 12, elem.getMemberArrayByte()[0]);
|
||||
|
@ -7,6 +7,7 @@ package test.atriasoft.exml;
|
||||
|
||||
import org.atriasoft.exml.Exml;
|
||||
import org.atriasoft.exml.annotation.XmlAttribute;
|
||||
import org.atriasoft.exml.annotation.XmlName;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
@ -45,5 +46,55 @@ public class ExmlTestIntrospectionObjectConstructor {
|
||||
Assertions.assertEquals(18523.0f, root.valueB);
|
||||
}
|
||||
|
||||
public class TestConstructorSpecificParameter {
|
||||
@XmlAttribute
|
||||
public Integer valueA;
|
||||
public double valueB;
|
||||
public TestConstructorSpecificParameter(@XmlName("valueA") final Integer valueA, @XmlName("valueB") final double valueB) {
|
||||
this.valueA = valueA;
|
||||
this.valueB = valueB;
|
||||
}
|
||||
}
|
||||
@Test
|
||||
public void testModelConstructorSpecificParameter() {
|
||||
TestConstructorSpecificParameter elem = new TestConstructorSpecificParameter(66, 18523.0);
|
||||
StringBuilder builder = new StringBuilder();
|
||||
Assertions.assertDoesNotThrow(() -> Exml.generate(elem, ExmlTestIntrospectionObject.NODE_NAME, builder));
|
||||
String dataTest = builder.toString();
|
||||
Log.warning("data generated: " + builder.toString());
|
||||
Assertions.assertEquals("<elem valueA=\"66\">\n"
|
||||
+ " <valueB>18523.0</valueB>\n"
|
||||
+ "</elem>", dataTest);
|
||||
|
||||
final TestConstructorSpecificParameter root = Assertions.assertDoesNotThrow(() -> Exml.parseOne(dataTest, TestConstructorSpecificParameter.class, ExmlTestIntrospectionObject.NODE_NAME));
|
||||
Assertions.assertEquals(66, root.valueA);
|
||||
Assertions.assertEquals(18523.0f, root.valueB);
|
||||
}
|
||||
|
||||
public class TestConstructorSpecific {
|
||||
@XmlAttribute
|
||||
public Integer valueA;
|
||||
public double valueB;
|
||||
@XmlName({"valueA", "valueB"})
|
||||
public TestConstructorSpecific(final Integer valueA, final double valueB) {
|
||||
this.valueA = valueA;
|
||||
this.valueB = valueB;
|
||||
}
|
||||
}
|
||||
@Test
|
||||
public void testModelConstructorSpecific() {
|
||||
TestConstructorSpecific elem = new TestConstructorSpecific(66, 18523.0);
|
||||
StringBuilder builder = new StringBuilder();
|
||||
Assertions.assertDoesNotThrow(() -> Exml.generate(elem, ExmlTestIntrospectionObject.NODE_NAME, builder));
|
||||
String dataTest = builder.toString();
|
||||
Log.warning("data generated: " + builder.toString());
|
||||
Assertions.assertEquals("<elem valueA=\"66\">\n"
|
||||
+ " <valueB>18523.0</valueB>\n"
|
||||
+ "</elem>", dataTest);
|
||||
|
||||
final TestConstructorSpecific root = Assertions.assertDoesNotThrow(() -> Exml.parseOne(dataTest, TestConstructorSpecific.class, ExmlTestIntrospectionObject.NODE_NAME));
|
||||
Assertions.assertEquals(66, root.valueA);
|
||||
Assertions.assertEquals(18523.0f, root.valueB);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -6,6 +6,7 @@
|
||||
package test.atriasoft.exml;
|
||||
|
||||
import org.atriasoft.exml.Exml;
|
||||
import org.atriasoft.exml.annotation.XmlName;
|
||||
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
@ -18,12 +19,8 @@ public class ExmlTestIntrospectionRecord {
|
||||
Log.warning("================================================================");
|
||||
}
|
||||
public record TestRecord(
|
||||
Integer valueA,
|
||||
double valueB) {
|
||||
public TestRecord(final Integer valueA, final double valueB) {
|
||||
this.valueA = valueA;
|
||||
this.valueB = valueB;
|
||||
}
|
||||
@XmlName("valueA") Integer valueA,
|
||||
@XmlName("valueB") double valueB) {
|
||||
}
|
||||
@Test
|
||||
public void testModelRecord() {
|
||||
@ -32,7 +29,8 @@ public class ExmlTestIntrospectionRecord {
|
||||
Assertions.assertDoesNotThrow(() -> Exml.generate(elem, ExmlTestIntrospectionObject.NODE_NAME, builder));
|
||||
String dataTest = builder.toString();
|
||||
Log.warning("data generated: " + builder.toString());
|
||||
Assertions.assertEquals("<elem valueA=\"66\">\n"
|
||||
Assertions.assertEquals("<elem>\n"
|
||||
+ " <valueA>66</valueA>\n"
|
||||
+ " <valueB>18523.0</valueB>\n"
|
||||
+ "</elem>", dataTest);
|
||||
|
||||
@ -40,6 +38,7 @@ public class ExmlTestIntrospectionRecord {
|
||||
Assertions.assertEquals(66, root.valueA);
|
||||
Assertions.assertEquals(18523.0f, root.valueB);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user