[DEV] better introspection add node parsing, list mode and base for enums

This commit is contained in:
Edouard DUPIN 2021-06-29 00:02:19 +02:00
parent 7017468e46
commit cd25863ed9
14 changed files with 470 additions and 192 deletions

View File

@ -68,30 +68,33 @@ public class Exml {
Builder builder; Builder builder;
try { try {
builder = new BuilderIntrospection(classType, rootNodeName); builder = new BuilderIntrospection(classType, rootNodeName);
final ParseXml parser = new ParseXml(builder);
final ParsingProperty property = new ParsingProperty();
property.setDisplayError(true);
final IntrospectionObject introspectionObject = (IntrospectionObject) parser.parse(data, property);
final Object listRet = introspectionObject.getData();
if (listRet != null && listRet instanceof List) {
final List<T> rootList = (List<T>) listRet;
final T[] strarr = (T[]) Array.newInstance(classType, 0);
return rootList.toArray(strarr);
}
return null;
} catch (final ExmlBuilderException ex) {
throw ex;
} catch (final Exception e) { } catch (final Exception e) {
// TODO Auto-generated catch block // TODO Auto-generated catch block
e.printStackTrace(); e.printStackTrace();
return null; return null;
} }
final ParseXml parser = new ParseXml(builder);
final ParsingProperty property = new ParsingProperty();
property.setDisplayError(true);
final IntrospectionObject introspectionObject = (IntrospectionObject) parser.parse(data, property);
final Object listRet = introspectionObject.getData();
if (listRet != null && listRet instanceof List) {
final List<T> rootList = (List<T>) listRet;
final T[] strarr = (T[]) Array.newInstance(classType, 0);
return rootList.toArray(strarr);
}
return null;
} }
private static String readFile(final Path path, final Charset encoding) throws IOException private static String readFile(final Path path, final Charset encoding) throws IOException
{ {
byte[] encoded = Files.readAllBytes(path); byte[] encoded = Files.readAllBytes(path);
return new String(encoded, encoding); return new String(encoded, encoding);
} }
public static <T> T[] parse(final Path path, final Class<T> classType, final String rootNodeName) throws ExmlBuilderException, ExmlParserErrorMulti { public static <T> T[] parse(final Path path, final Class<T> classType, final String rootNodeName) throws ExmlBuilderException, ExmlParserErrorMulti {
String content = null; String content = null;
try { try {
@ -101,6 +104,16 @@ public class Exml {
} }
return Exml.parse(content, classType, rootNodeName); return Exml.parse(content, classType, rootNodeName);
} }
public static <T> T parseOne(final Path path, final Class<T> classType, final String rootNodeName) throws ExmlBuilderException, ExmlParserErrorMulti {
T[] elements = Exml.parse(path, classType, rootNodeName);
if (elements == null || elements.length == 0 ) {
throw new ExmlBuilderException("Error in parsing the file, no node find ...");
}
if (elements.length > 1 ) {
throw new ExmlBuilderException("Error in parsing the file, More than One node find ...");
}
return elements[0];
}
/** /**

View File

@ -9,27 +9,21 @@ import java.lang.annotation.Target;
* Marker annotation that can be used to define a group list of element: * Marker annotation that can be used to define a group list of element:
* {@code * {@code
* <GROUP> * <GROUP>
* <ELEMENT ... > ... </ELEMENT> * <NAME> ... </NAME>
* <ELEMENT ... > ... </ELEMENT> * <NAME> ... </NAME>
* <ELEMENT ... > ... </ELEMENT> * <NAME> ... </NAME>
* </GROUP> * </GROUP>
* } * }
* @apiNote To change the group name @see XmlName
*/ */
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER }) @Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@ExmlAnnotation @ExmlAnnotation
public @interface XmlModel { public @interface XmlList {
/** /**
* Group names node * Element names node
* @return The name of the group * @return The name of the elements
* @apiNote this is incompatible with XmlName
*/ */
String group(); String value();
/**
* Element names inside the group
* @return The name of the element in the group
* @apiNote this is incompatible with XmlName
*/
String element();
} }

View File

@ -17,7 +17,7 @@ public class BuilderIntrospection implements Builder {
public BuilderIntrospection(final Class<?> classType, final String rootNodeName) throws Exception { public BuilderIntrospection(final Class<?> classType, final String rootNodeName) throws Exception {
this.rootNodeName = rootNodeName; this.rootNodeName = rootNodeName;
this.rootClassType = classType; this.rootClassType = classType;
this.elements.put(classType, new IntrospectionData(classType)); this.elements.put(classType, new IntrospectionData(classType, null));
} }
IntrospectionData findOrCreate(final Class<?> classType) throws Exception { IntrospectionData findOrCreate(final Class<?> classType) throws Exception {
@ -44,38 +44,42 @@ public class BuilderIntrospection implements Builder {
public Object newElement(final Object parent, final String nodeName) throws ExmlBuilderException, Exception { public Object newElement(final Object parent, final String nodeName) throws ExmlBuilderException, Exception {
Log.warning("new element on NodeName=" + nodeName); Log.warning("new element on NodeName=" + nodeName);
final IntrospectionObject introspectionObject = (IntrospectionObject) parent; final IntrospectionObject introspectionObject = (IntrospectionObject) parent;
if (introspectionObject.getDataInterface() == null) { // special case of user request parsing of element with <XXX><value></value>...</XXX>
final Object previousData = introspectionObject.getData(); if (nodeName.equals(introspectionObject.getListNameModel())) {
if ((previousData == null) || !(previousData instanceof List)) { IntrospectionData inferData = introspectionObject.getDataInterface();
// throw an error... if (inferData.getClassType().isArray()) {
return null; inferData = findOrCreate(inferData.getClassType().getComponentType());
} else if (List.class.isAssignableFrom(inferData.getClassType())) {
inferData = findOrCreate(inferData.getSubClassType());
} }
final List<Object> rootList = (List<Object>) previousData; return new IntrospectionObject(inferData);
// detect root node... }
// TODO Pb if the root name appeared multiple time in the XML !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ==> need a urgent correction
// TODO here try to remove this condition (see): YYYYYYYYYYYYYYYYYYYYYYYYYYYY
if (introspectionObject.getDataInterface() == null) {
if (nodeName.contentEquals(this.rootNodeName)) { if (nodeName.contentEquals(this.rootNodeName)) {
Log.verbose("Create new class: " + this.rootClassType.getCanonicalName()); Log.verbose("Create new class: " + this.rootClassType.getCanonicalName());
final IntrospectionData inferData = findOrCreate(this.rootClassType); final IntrospectionData inferData = findOrCreate(this.rootClassType);
//final Object newElement = inferData.createObject(); return new IntrospectionObject(inferData);
//rootList.add(newElement);
return new IntrospectionObject(inferData);//, newElement);
} }
// need to add a throw on the node... // need to add a throw on the node...
return null; // ==> disable the parsing.. return null; // ==> disable the parsing.. (node is not parsed...)
} }
Class<?> typeClass = introspectionObject.getTypeOfSubNode(nodeName); Class<?> typeClass = introspectionObject.getTypeOfSubNode(nodeName);
String listTreeName = introspectionObject.getTreeNameOfSubNode(nodeName);
if (typeClass != null) { if (typeClass != null) {
// specific case for List ==> need to get the subType in introspection ...
if (!List.class.isAssignableFrom(typeClass)) { if (!List.class.isAssignableFrom(typeClass)) {
Log.verbose("Create new class: '" + typeClass.getCanonicalName() + "' for node '" + nodeName + "'"); Log.verbose("Create new class: '" + typeClass.getCanonicalName() + "' for node '" + nodeName + "'");
final IntrospectionData inferData = findOrCreate(typeClass); final IntrospectionData inferData = findOrCreate(typeClass);
// Create the data when object is ended created... // Create the data when object is ended created...
return new IntrospectionObject(inferData); return new IntrospectionObject(inferData, listTreeName);
} }
Class<?> subTypeClass = introspectionObject.getTypeOfSubNodeSubType(nodeName); Class<?> subTypeClass = introspectionObject.getTypeOfSubNodeSubType(nodeName);
Log.verbose("Create new 'SUB' class: '" + typeClass.getCanonicalName() + "' for node '" + nodeName + "'"); Log.verbose("Create new 'SUB' class: '" + typeClass.getCanonicalName() + "' for node '" + nodeName + "'");
final IntrospectionData inferData = findOrCreate(subTypeClass); final IntrospectionData inferData = findOrCreate(subTypeClass);
// Create the data when object is ended created... // Create the data when object is ended created...
return new IntrospectionObject(inferData); return new IntrospectionObject(inferData, listTreeName);
} }
return null; return null;
} }
@ -93,6 +97,11 @@ public class BuilderIntrospection implements Builder {
@Override @Override
public Object newRoot() throws ExmlBuilderException { public Object newRoot() throws ExmlBuilderException {
// TODO here try to set : YYYYYYYYYYYYYYYYYYYYYYYYYYYY
/*
final IntrospectionData inferData = findOrCreate(this.rootClassType);
return new IntrospectionObject(inferData, rootNodeName);
*/
return new IntrospectionObject(); return new IntrospectionObject();
} }
@ -107,18 +116,18 @@ public class BuilderIntrospection implements Builder {
} }
@Override @Override
public void endElement(Object element) throws ExmlBuilderException { public void endElement(final Object element) throws ExmlBuilderException {
final IntrospectionObject introspectionObject = (IntrospectionObject) element; final IntrospectionObject introspectionObject = (IntrospectionObject) element;
if (introspectionObject.getDataInterface() == null) { if (introspectionObject.getDataInterface() == null) {
// property on nothing ??? // property on nothing ???
return; return;
} }
introspectionObject.generateTheObject(); introspectionObject.generateTheObject();
} }
@Override @Override
public void newElementFinished(Object parent, String tmpname, Object element) { public void newElementFinished(final Object parent, final String tmpname, final Object element) {
final IntrospectionObject introspectionElementObject = (IntrospectionObject) element; final IntrospectionObject introspectionElementObject = (IntrospectionObject) element;
if (introspectionElementObject.getDataInterface() == null) { if (introspectionElementObject.getDataInterface() == null) {
// property on nothing ??? // property on nothing ???
@ -126,7 +135,15 @@ public class BuilderIntrospection implements Builder {
} }
final IntrospectionObject introspectionParentObject = (IntrospectionObject) parent; final IntrospectionObject introspectionParentObject = (IntrospectionObject) parent;
if (introspectionParentObject.getDataInterface() == null) { if (introspectionParentObject.getDataInterface() == null) {
// property on nothing ??? if (tmpname.equals(this.rootNodeName)) {
// this is the root node ...
Object tmpp = introspectionParentObject.getData();
if( tmpp instanceof List) {
@SuppressWarnings("unchecked")
List<Object> elementsOut = (List<Object>)tmpp;
elementsOut.add(introspectionElementObject.getData());
}
}
return; return;
} }
introspectionParentObject.addObject(tmpname, introspectionElementObject.getData()); introspectionParentObject.addObject(tmpname, introspectionElementObject.getData());

View File

@ -6,9 +6,6 @@ import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
@ -23,6 +20,7 @@ import org.atriasoft.exml.annotation.XmlCaseSensitive;
import org.atriasoft.exml.annotation.XmlDefaultCaseSensitive; import org.atriasoft.exml.annotation.XmlDefaultCaseSensitive;
import org.atriasoft.exml.annotation.XmlDefaultManaged; import org.atriasoft.exml.annotation.XmlDefaultManaged;
import org.atriasoft.exml.annotation.XmlDefaultOptional; import org.atriasoft.exml.annotation.XmlDefaultOptional;
import org.atriasoft.exml.annotation.XmlList;
import org.atriasoft.exml.annotation.XmlManaged; import org.atriasoft.exml.annotation.XmlManaged;
import org.atriasoft.exml.annotation.XmlName; import org.atriasoft.exml.annotation.XmlName;
import org.atriasoft.exml.annotation.XmlOptional; import org.atriasoft.exml.annotation.XmlOptional;
@ -40,120 +38,148 @@ public class IntrospectionData {
} }
private static final Map<Class<?>, Converter> VALUES_OF = new HashMap<>(); private static final Map<Class<?>, Converter> VALUES_OF = new HashMap<>();
static { static {
VALUES_OF.put(byte.class, new Converter() { IntrospectionData.VALUES_OF.put(byte.class, new Converter() {
public Object valueOf(String value) { @Override
public Object valueOf(final String value) {
return Byte.valueOf(value); return Byte.valueOf(value);
} }
}); });
VALUES_OF.put(Byte.class, new Converter() { IntrospectionData.VALUES_OF.put(Byte.class, new Converter() {
public Object valueOf(String value) { @Override
public Object valueOf(final String value) {
return Byte.valueOf(value); return Byte.valueOf(value);
} }
}); });
VALUES_OF.put(int.class, new Converter() { IntrospectionData.VALUES_OF.put(int.class, new Converter() {
public Object valueOf(String value) { @Override
public Object valueOf(final String value) {
return Integer.valueOf(value); return Integer.valueOf(value);
} }
}); });
VALUES_OF.put(Integer.class, new Converter() { IntrospectionData.VALUES_OF.put(Integer.class, new Converter() {
public Object valueOf(String value) { @Override
public Object valueOf(final String value) {
return Integer.valueOf(value); return Integer.valueOf(value);
} }
}); });
VALUES_OF.put(long.class, new Converter() { IntrospectionData.VALUES_OF.put(long.class, new Converter() {
public Object valueOf(String value) { @Override
public Object valueOf(final String value) {
return Long.valueOf(value); return Long.valueOf(value);
} }
}); });
VALUES_OF.put(Long.class, new Converter() { IntrospectionData.VALUES_OF.put(Long.class, new Converter() {
public Object valueOf(String value) { @Override
public Object valueOf(final String value) {
return Long.valueOf(value); return Long.valueOf(value);
} }
}); });
VALUES_OF.put(short.class, new Converter() { IntrospectionData.VALUES_OF.put(short.class, new Converter() {
public Object valueOf(String value) { @Override
public Object valueOf(final String value) {
return Short.valueOf(value); return Short.valueOf(value);
} }
}); });
VALUES_OF.put(Short.class, new Converter() { IntrospectionData.VALUES_OF.put(Short.class, new Converter() {
public Object valueOf(String value) { @Override
public Object valueOf(final String value) {
return Short.valueOf(value); return Short.valueOf(value);
} }
}); });
VALUES_OF.put(boolean.class, new Converter() { IntrospectionData.VALUES_OF.put(boolean.class, new Converter() {
public Object valueOf(String value) { @Override
public Object valueOf(final String value) {
return Boolean.valueOf(value); return Boolean.valueOf(value);
} }
}); });
VALUES_OF.put(Boolean.class, new Converter() { IntrospectionData.VALUES_OF.put(Boolean.class, new Converter() {
public Object valueOf(String value) { @Override
public Object valueOf(final String value) {
return Boolean.valueOf(value); return Boolean.valueOf(value);
} }
}); });
VALUES_OF.put(byte[].class, new Converter() { IntrospectionData.VALUES_OF.put(byte[].class, new Converter() {
public Object valueOf(String value) { @Override
public Object valueOf(final String value) {
return Tools.parseByteStringList(value); return Tools.parseByteStringList(value);
} }
}); });
VALUES_OF.put(Byte[].class, new Converter() { IntrospectionData.VALUES_OF.put(Byte[].class, new Converter() {
public Object valueOf(String value) { @Override
public Object valueOf(final String value) {
return Tools.parseByteClassStringList(value); return Tools.parseByteClassStringList(value);
} }
}); });
VALUES_OF.put(short[].class, new Converter() { IntrospectionData.VALUES_OF.put(short[].class, new Converter() {
public Object valueOf(String value) { @Override
public Object valueOf(final String value) {
return Tools.parseShortStringList(value); return Tools.parseShortStringList(value);
} }
}); });
VALUES_OF.put(Short[].class, new Converter() { IntrospectionData.VALUES_OF.put(Short[].class, new Converter() {
public Object valueOf(String value) { @Override
public Object valueOf(final String value) {
return Tools.parseShortClassStringList(value); return Tools.parseShortClassStringList(value);
} }
}); });
VALUES_OF.put(int[].class, new Converter() { IntrospectionData.VALUES_OF.put(int[].class, new Converter() {
public Object valueOf(String value) { @Override
public Object valueOf(final String value) {
return Tools.parseIntegerStringList(value); return Tools.parseIntegerStringList(value);
} }
}); });
VALUES_OF.put(Integer[].class, new Converter() { IntrospectionData.VALUES_OF.put(Integer[].class, new Converter() {
public Object valueOf(String value) { @Override
public Object valueOf(final String value) {
return Tools.parseIntegerClassStringList(value); return Tools.parseIntegerClassStringList(value);
} }
}); });
VALUES_OF.put(long[].class, new Converter() { IntrospectionData.VALUES_OF.put(long[].class, new Converter() {
public Object valueOf(String value) { @Override
public Object valueOf(final String value) {
return Tools.parseLongStringList(value); return Tools.parseLongStringList(value);
} }
}); });
VALUES_OF.put(Long[].class, new Converter() { IntrospectionData.VALUES_OF.put(Long[].class, new Converter() {
public Object valueOf(String value) { @Override
public Object valueOf(final String value) {
return Tools.parseLongClassStringList(value); return Tools.parseLongClassStringList(value);
} }
}); });
VALUES_OF.put(boolean[].class, new Converter() { IntrospectionData.VALUES_OF.put(boolean[].class, new Converter() {
public Object valueOf(String value) { @Override
public Object valueOf(final String value) {
return Tools.parseBooleanStringList(value); return Tools.parseBooleanStringList(value);
} }
}); });
VALUES_OF.put(Boolean[].class, new Converter() { IntrospectionData.VALUES_OF.put(Boolean[].class, new Converter() {
public Object valueOf(String value) { @Override
public Object valueOf(final String value) {
return Tools.parseBooleanClassStringList(value); return Tools.parseBooleanClassStringList(value);
} }
}); });
VALUES_OF.put(String.class, new Converter() { IntrospectionData.VALUES_OF.put(String.class, new Converter() {
public Object valueOf(String value) { @Override
public Object valueOf(final String value) {
return value; return value;
} }
}); });
} }
final Class<?> classType; private final Class<?> classType;
final Class<?> subClassType; private final Class<?> subClassType; // TODO deprecated
// TODO Optimize this with external object for basic types....
private final Method valueof; // used for the set Text if the object is an end point... private final Method valueof; // used for the set Text if the object is an end point...
private final List<IntrospectionProperty> methods = new ArrayList<>(); private final List<IntrospectionProperty> methods = new ArrayList<>();
private final List<IntrospectionProperty> properties = new ArrayList<>(); private final List<IntrospectionProperty> properties = new ArrayList<>();
public Class<?> getClassType() {
return this.classType;
}
public Class<?> getSubClassType() {
return this.subClassType;
}
public IntrospectionData(final Class<?> classType) throws Exception { public IntrospectionData(final Class<?> classType) throws Exception {
this(classType, null); this(classType, null);
} }
@ -176,9 +202,10 @@ public class IntrospectionData {
final Boolean isOptionnal = getIsOptional(elem, isDefaultOptional); final Boolean isOptionnal = getIsOptional(elem, isDefaultOptional);
final String[] names = getNames(elem, Tools.decapitalizeFirst(elem.getName())); final String[] names = getNames(elem, Tools.decapitalizeFirst(elem.getName()));
final Boolean caseSensitive = getIsCaseSensitive(elem, isDefaultCaseSensitive); final Boolean caseSensitive = getIsCaseSensitive(elem, isDefaultCaseSensitive);
final String listName = getListName(elem, null);
// TODO check if property does not already exist ... // TODO check if property does not already exist ...
if (isManaged) { if (isManaged) {
this.properties.add(new IntrospectionPropertyField(elem, names, caseSensitive, isOptionnal)); this.properties.add(new IntrospectionPropertyField(elem, names, listName, caseSensitive, isOptionnal));
} }
Log.verbose(" - " + elem.toGenericString()); Log.verbose(" - " + elem.toGenericString());
} }
@ -248,16 +275,25 @@ public class IntrospectionData {
// void setXxx(XXX elem); // void setXxx(XXX elem);
// [bB]oolean isXxx(); // [bB]oolean isXxx();
final List<Method> methodsGet = methods.stream().filter(o -> o.getName().startsWith("get")).collect(Collectors.toList()); List<Method> methodsGet;
final List<Method> methodsSet = methods.stream().filter(o -> o.getName().startsWith("set")).collect(Collectors.toList()); List<Method> methodsSet;
final List<Method> methodsIs = methods.stream().filter(o -> o.getName().startsWith("is")).collect(Collectors.toList()); 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());
} else {
methodsGet = new ArrayList<>();
methodsSet = new ArrayList<>();
methodsIs = new ArrayList<>();
}
final List<Method> valueOfString = methods.stream().filter(o -> o.getName().startsWith("valueOf")).collect(Collectors.toList()); final List<Method> valueOfString = methods.stream().filter(o -> o.getName().startsWith("valueOf")).collect(Collectors.toList());
if (valueOfString.size() == 1) { if (valueOfString.size() == 1) {
valueof = valueOfString.get(0); this.valueof = valueOfString.get(0);
} else { } else {
// some specific model: // some specific model:
valueof = null; this.valueof = null;
} }
// associate methods by pair. // associate methods by pair.
final List<OrderData> elements = new ArrayList<>(); final List<OrderData> elements = new ArrayList<>();
@ -350,18 +386,23 @@ public class IntrospectionData {
throw new Exception("Can net set oposite information on getter and setter"); 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[] names = namesSet != null ? namesSet : namesGet != null ? namesGet : new String[] { Tools.decapitalizeFirst(elem.name) };
this.methods.add(new IntrospectionPropertyMethod(elem.setter, elem.getter, names, isCaseSensitive, isOptional)); final String listNameSet = getListName(elem.setter, null);
final String listNameGet = getListName(elem.getter, null);
final String listName = listNameSet != null? listNameSet: listNameGet;
this.methods.add(new IntrospectionPropertyMethod(elem.setter, elem.getter, names, listName, isCaseSensitive, isOptional));
} else { } else {
Boolean isManaged = null; Boolean isManaged = null;
Boolean isOptionnal = null; Boolean isOptionnal = null;
String[] names = null; String[] names = null;
Boolean isCaseSensitive = null; Boolean isCaseSensitive = null;
String listName = null;
if (elem.setter != null) { if (elem.setter != null) {
Log.info(" setter: " + elem.setter.toGenericString()); Log.info(" setter: " + elem.setter.toGenericString());
isManaged = getIsManaged(elem.setter, isDefaultManaged); isManaged = getIsManaged(elem.setter, isDefaultManaged);
isOptionnal = getIsOptional(elem.setter, isDefaultOptional); isOptionnal = getIsOptional(elem.setter, isDefaultOptional);
names = getNames(elem.setter, Tools.decapitalizeFirst(elem.name)); names = getNames(elem.setter, Tools.decapitalizeFirst(elem.name));
isCaseSensitive = getIsCaseSensitive(elem.setter, isDefaultCaseSensitive); isCaseSensitive = getIsCaseSensitive(elem.setter, isDefaultCaseSensitive);
listName= getListName(elem.setter, null);
} else { } else {
Log.info(" setter: null"); Log.info(" setter: null");
} }
@ -371,20 +412,22 @@ public class IntrospectionData {
isOptionnal = getIsOptional(elem.getter, isDefaultOptional); isOptionnal = getIsOptional(elem.getter, isDefaultOptional);
names = getNames(elem.getter, Tools.decapitalizeFirst(elem.name)); names = getNames(elem.getter, Tools.decapitalizeFirst(elem.name));
isCaseSensitive = getIsCaseSensitive(elem.getter, isDefaultCaseSensitive); isCaseSensitive = getIsCaseSensitive(elem.getter, isDefaultCaseSensitive);
listName= getListName(elem.getter, null);
} else { } else {
Log.info(" getter: null"); Log.info(" getter: null");
} }
if (isManaged) { if (isManaged) {
this.methods.add(new IntrospectionPropertyMethod(elem.setter, elem.getter, names, isCaseSensitive, isOptionnal)); this.methods.add(new IntrospectionPropertyMethod(elem.setter, elem.getter, names, listName, isCaseSensitive, isOptionnal));
} }
} }
} }
} }
Object createObject(Map<String, Object> properties, Map<String, List<Object>> nodes) throws ExmlBuilderException { Object createObject(final Map<String, Object> properties, final Map<String, List<Object>> nodes) throws ExmlBuilderException {
Object tmp; Object tmp;
try { try {
// pb here, can not create a primitive object with the coreect elements... ==> must be generated with a siblist of elements
tmp = this.classType.getConstructor().newInstance(); tmp = this.classType.getConstructor().newInstance();
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) { } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) {
// TODO Auto-generated catch block // TODO Auto-generated catch block
@ -400,6 +443,17 @@ public class IntrospectionData {
return tmp; return tmp;
} }
protected List<String> getNodeAvaillable() {
List<String> out = new ArrayList<>();
for (final IntrospectionProperty prop : this.methods) {
out.add(prop.getNames()[0]);
}
for (final IntrospectionProperty prop : this.properties) {
out.add(prop.getNames()[0]);
}
return out;
}
protected IntrospectionProperty findMethodDescription(final String propertyName) throws ExmlBuilderException { protected IntrospectionProperty findMethodDescription(final String propertyName) throws ExmlBuilderException {
for (final IntrospectionProperty prop : this.methods) { for (final IntrospectionProperty prop : this.methods) {
if (prop.isCompatible(propertyName)) { if (prop.isCompatible(propertyName)) {
@ -574,8 +628,37 @@ public class IntrospectionData {
} }
return tmp; 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 hame 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 hame 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") @SuppressWarnings("unchecked")
private <T> T[] autoCast(Class<T> clazz, List<Object> data) { 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()]; T[] out = (T[]) java.lang.reflect.Array.newInstance(clazz, data.size());// T[data.size()];
for(int iii=0; iii<data.size(); iii++) { for(int iii=0; iii<data.size(); iii++) {
@ -585,7 +668,7 @@ public class IntrospectionData {
//return data.stream().map(clazz::cast).toArray(new T[data.size()]);//java.lang.reflect.Array.newInstance((propMethode.getSubType(), tmpp.size())); //return data.stream().map(clazz::cast).toArray(new T[data.size()]);//java.lang.reflect.Array.newInstance((propMethode.getSubType(), tmpp.size()));
} }
private void setValue(Object data, String name, Object value) throws ExmlBuilderException { private void setValue(final Object data, final String name, final Object value) throws ExmlBuilderException {
Log.error(" Set value ='" + name + "' propertyValue='" + value + "' " + value.getClass().getCanonicalName()); Log.error(" Set value ='" + name + "' propertyValue='" + value + "' " + value.getClass().getCanonicalName());
// by default use setter to set the property // by default use setter to set the property
final IntrospectionProperty propMethode = findMethodDescription(name); final IntrospectionProperty propMethode = findMethodDescription(name);
@ -593,7 +676,7 @@ public class IntrospectionData {
Log.verbose(" ==> find '" + Arrays.toString(propMethode.getNames()) + " type=" + propMethode.getType() + " sub-type=" + propMethode.getSubType() ); Log.verbose(" ==> find '" + Arrays.toString(propMethode.getNames()) + " type=" + propMethode.getType() + " sub-type=" + propMethode.getSubType() );
if (propMethode.getType().isAssignableFrom(value.getClass())) { if (propMethode.getType().isAssignableFrom(value.getClass())) {
propMethode.setExistingValue(data, value); propMethode.setExistingValue(data, value);
} else { } else if (value instanceof List){
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
List<Object> tmpp = (List<Object>)value; List<Object> tmpp = (List<Object>)value;
if (propMethode.getType().isArray()) { if (propMethode.getType().isArray()) {
@ -617,25 +700,82 @@ public class IntrospectionData {
Log.verbose(" methode type: " + propMethode.getType().getCanonicalName()); Log.verbose(" methode type: " + propMethode.getType().getCanonicalName());
propMethode.setExistingValue(data, autoCast(propMethode.getType().componentType(), tmpp)); propMethode.setExistingValue(data, autoCast(propMethode.getType().componentType(), tmpp));
} }
} else if (tmpp.size() == 1) {
propMethode.setExistingValue(data, tmpp.get(0));
} else { } else {
if (tmpp.size() == 1) { // impossible case ...
propMethode.setExistingValue(data, tmpp.get(0));
} else {
// impossible case ...
}
} }
//Log.verbose(" ==> TODO...."); } else if (propMethode.getType() == byte.class) {
byte dataPrimitive = (Byte)value;
propMethode.setExistingValue(data, dataPrimitive);
} else if (propMethode.getType() == short.class) {
short dataPrimitive = (Short)value;
propMethode.setExistingValue(data, dataPrimitive);
} else if (propMethode.getType() == int.class) {
int dataPrimitive = (Integer)value;
propMethode.setExistingValue(data, dataPrimitive);
} else if (propMethode.getType() == long.class) {
long dataPrimitive = (Long)value;
propMethode.setExistingValue(data, dataPrimitive);
} else if (propMethode.getType() == boolean.class) {
boolean dataPrimitive = (Boolean)value;
propMethode.setExistingValue(data, dataPrimitive);
} else {
} }
return; return;
} }
// try with direct field // try with direct field
final IntrospectionProperty propField = findPropertyDescription(name); final IntrospectionProperty propField = findPropertyDescription(name);
if (propField != null && propField.canSetValue()) { if (propField != null && propField.canSetValue()) {
Log.verbose(" ==> find '" + Arrays.toString(propField.getNames()) + " type=" + propMethode.getType() + " sub-type=" + propMethode.getSubType() ); Log.verbose(" ==> find '" + Arrays.toString(propField.getNames()) + " type=" + propField.getType() + " sub-type=" + propField.getSubType() );
if (propField.getType().isAssignableFrom(value.getClass())) { if (propField.getType().isAssignableFrom(value.getClass())) {
propField.setExistingValue(data, value); propField.setExistingValue(data, value);
// Some specific case for primitives values
} else if (propField.getType() == byte.class) {
byte dataPrimitive = (Byte)value;
propField.setExistingValue(data, dataPrimitive);
} else if (propField.getType() == short.class) {
short dataPrimitive = (Short)value;
propField.setExistingValue(data, dataPrimitive);
} else if (propField.getType() == int.class) {
int dataPrimitive = (Integer)value;
propField.setExistingValue(data, dataPrimitive);
} else if (propField.getType() == long.class) {
long dataPrimitive = (Long)value;
propField.setExistingValue(data, dataPrimitive);
} else if (propField.getType() == boolean.class) {
boolean dataPrimitive = (Boolean)value;
propField.setExistingValue(data, dataPrimitive);
} else { } else {
Log.verbose(" ==> TODO...."); @SuppressWarnings("unchecked")
List<Object> tmpp = (List<Object>)value;
if (propField.getType().isArray()) {
if (propField.getType().componentType() == byte.class) {
byte[] datas = ArraysTools.listByteToPrimitive(tmpp);
propField.setExistingValue(data, datas);
} else if (propField.getType().componentType() == short.class) {
short[] datas = ArraysTools.listShortToPrimitive(tmpp);
propField.setExistingValue(data, datas);
} else if (propField.getType().componentType() == int.class) {
int[] datas = ArraysTools.listIntegerToPrimitive(tmpp);
propField.setExistingValue(data, datas);
} else if (propField.getType().componentType() == long.class) {
long[] datas = ArraysTools.listLongToPrimitive(tmpp);
propField.setExistingValue(data, datas);
} else if (propField.getType().componentType() == boolean.class) {
boolean[] datas = ArraysTools.listBooleanToPrimitive(tmpp);
propField.setExistingValue(data, datas);
} else {
Log.verbose(" datas type: " + autoCast(propMethode.getType().componentType(), tmpp).getClass().getCanonicalName());
Log.verbose(" methode type: " + propMethode.getType().getCanonicalName());
propField.setExistingValue(data, autoCast(propMethode.getType().componentType(), tmpp));
}
} else if (tmpp.size() == 1) {
propField.setExistingValue(data, tmpp.get(0));
} else {
// impossible case ...
}
} }
return; return;
} }
@ -680,9 +820,10 @@ public class IntrospectionData {
Log.error(" ==> find '" + propField.getNames()); Log.error(" ==> find '" + propField.getNames());
return propMethode.getType(); return propMethode.getType();
} }
throw new ExmlBuilderException("can not find the field '" + nodeName + "'");
throw new ExmlBuilderException("can not find the field '" + nodeName + "' availlable: " + getNodeAvaillable());
} }
public Class<?> getTypeOfSubNodeList(Object data, String nodeName) throws ExmlBuilderException { public Class<?> getTypeOfSubNodeList(final Object data, final String nodeName) throws ExmlBuilderException {
Log.error(" nodeType='" + nodeName + "'"); Log.error(" nodeType='" + nodeName + "'");
// by default use setter to set the property // by default use setter to set the property
final IntrospectionProperty propMethode = findMethodDescription(nodeName); final IntrospectionProperty propMethode = findMethodDescription(nodeName);
@ -696,8 +837,25 @@ public class IntrospectionData {
Log.error(" ==> find '" + propField.getNames()); Log.error(" ==> find '" + propField.getNames());
return propMethode.getSubType(); return propMethode.getSubType();
} }
throw new ExmlBuilderException("can not find the field '" + nodeName + "' availlable: " + getNodeAvaillable());
}
public String getTreeNameOfSubNode(final Object data, final String nodeName) throws ExmlBuilderException {
Log.error(" nodeType='" + nodeName + "'");
// by default use setter to set the property
final IntrospectionProperty propMethode = findMethodDescription(nodeName);
if (propMethode != null && propMethode.canSetValue()) {
Log.error(" ==> find '" + propMethode.getNames());
return propMethode.getListName();
}
// try with direct field
final IntrospectionProperty propField = findPropertyDescription(nodeName);
if (propField != null && propField.canSetValue()) {
Log.error(" ==> find '" + propField.getNames());
return propMethode.getListName();
}
throw new ExmlBuilderException("can not find the field '" + nodeName + "'"); throw new ExmlBuilderException("can not find the field '" + nodeName + "'");
} }
public Object getValueFromText(final String text) throws ExmlBuilderException { public Object getValueFromText(final String text) throws ExmlBuilderException {
// Note if the type is an Array<>() or a List<>() ==> we parse element by element ... then we need to keep the undertype... // Note if the type is an Array<>() or a List<>() ==> we parse element by element ... then we need to keep the undertype...
@ -709,8 +867,8 @@ public class IntrospectionData {
classTypeLocal = this.classType.getComponentType(); classTypeLocal = this.classType.getComponentType();
} else if (List.class == this.classType || Collection.class.isAssignableFrom(this.classType)) { } else if (List.class == this.classType || Collection.class.isAssignableFrom(this.classType)) {
// a generic list .... // a generic list ....
if (subClassType != null) { if (this.subClassType != null) {
classTypeLocal = subClassType; classTypeLocal = this.subClassType;
} }
//Type[] tmpp = this.classType.getGenericInterfaces(); //Type[] tmpp = this.classType.getGenericInterfaces();
//Class<?>[] tmpp = this.classType.getNestMembers(); //Class<?>[] tmpp = this.classType.getNestMembers();
@ -732,23 +890,24 @@ public class IntrospectionData {
Log.warning("======>>>>>>> subElement input type : " + classTypeLocal.getCanonicalName()); Log.warning("======>>>>>>> subElement input type : " + classTypeLocal.getCanonicalName());
if (this.valueof == null) { if (this.valueof == null) {
Converter con = VALUES_OF.get(classTypeLocal); Converter con = IntrospectionData.VALUES_OF.get(classTypeLocal);
if (con == null) { if (con == null) {
throw new ExmlBuilderException("function 'valueOf' for '" + classTypeLocal.getCanonicalName() + "' is not defined and not registered for specific type"); throw new ExmlBuilderException("function 'valueOf' for '" + classTypeLocal.getCanonicalName() + "' is not defined and not registered for specific type");
} else {
return con.valueOf(text);
} }
return con.valueOf(text);
} }
try { try {
return this.valueof.invoke(null, text); return this.valueof.invoke(null, text);
} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
// TODO Auto-generated catch block if (Enum.class.isAssignableFrom(this.classType)) {
throw new ExmlBuilderException("Error in call 'valueOf(String ...)' for enum '" + classTypeLocal.getCanonicalName() + "' ==> '" + text + "' ... availlable list: " + Arrays.asList(this.classType.getEnumConstants()));
}
e.printStackTrace(); e.printStackTrace();
throw new ExmlBuilderException("Error in call 'valueOf(String ...)' for '" + classTypeLocal.getCanonicalName() + "' " + e.getMessage()); throw new ExmlBuilderException("Error in call 'valueOf(String ...)' for '" + classTypeLocal.getCanonicalName() + "' " + e.getMessage());
} }
} }
public Object getValue(String propertyName, String propertyValue) throws ExmlBuilderException { public Object getValue(final String propertyName, final String propertyValue) throws ExmlBuilderException {
Log.error(" propertyName='" + propertyName + "' propertyValue='" + propertyValue + "' "); Log.error(" propertyName='" + propertyName + "' propertyValue='" + propertyValue + "' ");
// by default use setter to set the property // by default use setter to set the property
final IntrospectionProperty propMethode = findMethodDescription(propertyName); final IntrospectionProperty propMethode = findMethodDescription(propertyName);

View File

@ -11,6 +11,7 @@ import org.atriasoft.exml.internal.Log;
public class IntrospectionObject { public class IntrospectionObject {
private final IntrospectionData dataInterface; private final IntrospectionData dataInterface;
private Object data = null; private Object data = null;
private final String listNameModel;
private final Map<String, Object> properties = new HashMap<>(); private final Map<String, Object> properties = new HashMap<>();
private final Map<String, List<Object>> nodes = new HashMap<>(); private final Map<String, List<Object>> nodes = new HashMap<>();
@ -20,18 +21,23 @@ public class IntrospectionObject {
public IntrospectionObject() { public IntrospectionObject() {
this.dataInterface = null; this.dataInterface = null;
this.data = new ArrayList<>(); this.data = new ArrayList<>();
this.listNameModel = null;
} }
public IntrospectionObject(final IntrospectionData dataInterface, final Object data) { public IntrospectionObject(final IntrospectionData dataInterface, final String listNameModel) {
this.dataInterface = dataInterface; this.dataInterface = dataInterface;
this.data = data; this.listNameModel = listNameModel;
} }
public IntrospectionObject(final IntrospectionData dataInterface) { public IntrospectionObject(final IntrospectionData dataInterface) {
this.dataInterface = dataInterface; this.dataInterface = dataInterface;
this.data = null; this.listNameModel = null;
} }
public String getListNameModel() {
return this.listNameModel;
}
public Object getData() { public Object getData() {
return this.data; return this.data;
} }
@ -41,14 +47,12 @@ public class IntrospectionObject {
} }
public void setProperty(final String propertyName, final String propertyValue) throws Exception { public void setProperty(final String propertyName, final String propertyValue) throws Exception {
this.dataInterface.setProperty(this.data, propertyName, propertyValue); // Old way ... this.dataInterface.setProperty(this.data, propertyName, propertyValue);
Object value = this.dataInterface.getValue(propertyName, propertyValue); Object value = this.dataInterface.getValue(propertyName, propertyValue);
Object property = properties.get(propertyName); if (this.properties.containsKey(propertyName)) {
if (property == null) {
properties.put(propertyName, value);
} else {
throw new ExmlBuilderException("Property have multiple values ==> impossible case; A Node must contain only 1 attibutes"); throw new ExmlBuilderException("Property have multiple values ==> impossible case; A Node must contain only 1 attibutes");
} }
this.properties.put(propertyName, value);
} }
/** /**
@ -59,9 +63,12 @@ public class IntrospectionObject {
public Class<?> getTypeOfSubNode(final String nodeName) throws ExmlBuilderException { public Class<?> getTypeOfSubNode(final String nodeName) throws ExmlBuilderException {
return this.dataInterface.getTypeOfSubNode(this.data, nodeName); return this.dataInterface.getTypeOfSubNode(this.data, nodeName);
} }
public Class<?> getTypeOfSubNodeSubType(String nodeName) throws ExmlBuilderException { public Class<?> getTypeOfSubNodeSubType(final String nodeName) throws ExmlBuilderException {
return this.dataInterface.getTypeOfSubNodeList(this.data, nodeName); return this.dataInterface.getTypeOfSubNodeList(this.data, nodeName);
} }
public String getTreeNameOfSubNode(final String nodeName) throws ExmlBuilderException {
return this.dataInterface.getTreeNameOfSubNode(this.data, nodeName);
}
public void setText(final String text) throws ExmlBuilderException { public void setText(final String text) throws ExmlBuilderException {
if (this.data != null) { if (this.data != null) {
@ -70,26 +77,55 @@ public class IntrospectionObject {
this.data = this.dataInterface.getValueFromText(text); this.data = this.dataInterface.getValueFromText(text);
} }
public void addObject(String nodeName, Object value) { @SuppressWarnings("unchecked")
List<Object> node = nodes.get(nodeName); public void addObject(final String nodeName, final Object value) {
List<Object> node = this.nodes.get(nodeName);
if (node == null) { if (node == null) {
node = new ArrayList<>(); if (value instanceof List) {
node.add(value); node = (List<Object>) value;
nodes.put(nodeName, node); } else {
node = new ArrayList<>();
node.add(value);
}
this.nodes.put(nodeName, node);
} else if (value instanceof List) {
List<Object> nodeIn = (List<Object>) value;
node.addAll(nodeIn);
} else { } else {
node.add(value); node.add(value);
} }
} }
public void generateTheObject() throws ExmlBuilderException { public void generateTheObject() throws ExmlBuilderException {
if (data != null) { if (this.data != null) {
// nothing to do ... ==> element already created // nothing to do ... ==> element already created
return; return;
} }
Log.info("Create the element for the Specific node ... type = " + dataInterface.classType.getCanonicalName()); if (this.listNameModel == null) {
Log.info(" Properties : " + this.properties.keySet()); Log.info("Create the element for the Specific node ... type = " + this.dataInterface.getClassType().getCanonicalName());
Log.info(" Nodes : " + this.nodes.keySet()); Log.info(" Properties : " + this.properties.keySet());
this.data = dataInterface.createObject(this.properties, this.nodes); Log.info(" Nodes : " + this.nodes.keySet());
this.data = this.dataInterface.createObject(this.properties, this.nodes);
} else {
if (this.properties.size() != 0) {
throw new ExmlBuilderException("SubNode in tree can not have propoerties !!!!");
}
if (this.nodes.size() == 0) {
this.data = new ArrayList<Object>();
return;
}
if (this.nodes.size() > 1) {
throw new ExmlBuilderException("SubNode in tree can not have more than 1 subNodes !!!!");
}
// check name of node
List<Object> values = this.nodes.get(this.listNameModel);
if (values == null) {
throw new ExmlBuilderException("SubNode in tree name is wrong !!!! must be '" + this.listNameModel + "'");
}
// create real object ...
this.data = values;
}
} }
} }

View File

@ -5,14 +5,22 @@ import org.atriasoft.exml.exception.ExmlBuilderException;
public abstract class IntrospectionProperty { public abstract class IntrospectionProperty {
protected final Boolean caseSensitive; protected final Boolean caseSensitive;
protected final Boolean isOptionnal; protected final Boolean isOptionnal;
// name that can take the Node
protected final String[] names; protected final String[] names;
// if organized in sublist (!= null) then the subNode have this value
protected final String listName;
public String getListName() {
return this.listName;
}
protected final Class<?> type; protected final Class<?> type;
protected final Class<?> subType; protected final Class<?> subType;
public IntrospectionProperty(final Class<?>[] type, final String[] names, final Boolean caseSensitive, final Boolean isOptionnal) { public IntrospectionProperty(final Class<?>[] type, final String[] names, final String listName, final Boolean caseSensitive, final Boolean isOptionnal) {
this.type = type[0]; this.type = type[0];
this.subType = type[1]; this.subType = type[1];
this.names = names; this.names = names;
this.listName = listName;
this.caseSensitive = caseSensitive; this.caseSensitive = caseSensitive;
this.isOptionnal = isOptionnal; this.isOptionnal = isOptionnal;
} }

View File

@ -1,15 +1,12 @@
package org.atriasoft.exml.builder; package org.atriasoft.exml.builder;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType; import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.List;
import org.atriasoft.exml.exception.ExmlBuilderException; import org.atriasoft.exml.exception.ExmlBuilderException;
import org.atriasoft.exml.internal.Log;
import org.atriasoft.exml.parser.Tools; import org.atriasoft.exml.parser.Tools;
public class IntrospectionPropertyField extends IntrospectionProperty { public class IntrospectionPropertyField extends IntrospectionProperty {
private final Field fieldDescription; private final Field fieldDescription;
@ -32,8 +29,8 @@ public class IntrospectionPropertyField extends IntrospectionProperty {
return new Class<?>[] {type, subType}; return new Class<?>[] {type, subType};
} }
public IntrospectionPropertyField(final Field fieldDescription, final String[] names, final Boolean caseSensitive, final Boolean isOptionnal) { public IntrospectionPropertyField(final Field fieldDescription, final String[] names, final String listName, final Boolean caseSensitive, final Boolean isOptionnal) {
super(getTypeField(fieldDescription), names, caseSensitive, isOptionnal); super(IntrospectionPropertyField.getTypeField(fieldDescription), names, listName, caseSensitive, isOptionnal);
this.fieldDescription = fieldDescription; this.fieldDescription = fieldDescription;
} }
@ -57,19 +54,19 @@ public class IntrospectionPropertyField extends IntrospectionProperty {
public void setValue(final Object object, final String value) throws ExmlBuilderException { public void setValue(final Object object, final String value) throws ExmlBuilderException {
try { try {
if (this.type == byte.class) { if (this.type == byte.class) {
final byte data = Byte.valueOf(value); final byte data = Byte.parseByte(value);
this.fieldDescription.setByte(object, data); this.fieldDescription.setByte(object, data);
} else if (this.type == short.class) { } else if (this.type == short.class) {
final short data = Short.valueOf(value); final short data = Short.parseShort(value);
this.fieldDescription.setShort(object, data); this.fieldDescription.setShort(object, data);
} else if (this.type == int.class) { } else if (this.type == int.class) {
final int data = Integer.valueOf(value); final int data = Integer.parseInt(value);
this.fieldDescription.setInt(object, data); this.fieldDescription.setInt(object, data);
} else if (this.type == long.class) { } else if (this.type == long.class) {
final long data = Long.valueOf(value); final long data = Long.parseLong(value);
this.fieldDescription.setLong(object, data); this.fieldDescription.setLong(object, data);
} else if (this.type == boolean.class) { } else if (this.type == boolean.class) {
final boolean data = Boolean.valueOf(value); final boolean data = Boolean.parseBoolean(value);
this.fieldDescription.setBoolean(object, data); this.fieldDescription.setBoolean(object, data);
} else if (this.type == String.class) { } else if (this.type == String.class) {
this.fieldDescription.set(object, value); this.fieldDescription.set(object, value);
@ -119,13 +116,15 @@ public class IntrospectionPropertyField extends IntrospectionProperty {
} }
@Override @Override
protected Object createValue(String value) throws ExmlBuilderException { protected Object createValue(final String value) throws ExmlBuilderException {
try { try {
if (this.type == byte.class) { if (this.type == byte.class) {
return Byte.valueOf(value); return Byte.valueOf(value);
} else if (this.type == short.class) { }
if (this.type == short.class) {
return Short.valueOf(value); return Short.valueOf(value);
} else if (this.type == int.class) { }
if (this.type == int.class) {
return Integer.valueOf(value); return Integer.valueOf(value);
} else if (this.type == long.class) { } else if (this.type == long.class) {
return Long.valueOf(value); return Long.valueOf(value);
@ -174,7 +173,7 @@ public class IntrospectionPropertyField extends IntrospectionProperty {
} }
@Override @Override
public void setExistingValue(Object object, Object value) throws ExmlBuilderException { public void setExistingValue(final Object object, final Object value) throws ExmlBuilderException {
try { try {
this.fieldDescription.set(object, value); this.fieldDescription.set(object, value);
} catch (IllegalArgumentException | IllegalAccessException e) { } catch (IllegalArgumentException | IllegalAccessException e) {

View File

@ -4,13 +4,12 @@ import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType; import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type; import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.List; import java.util.List;
import org.atriasoft.exml.exception.ExmlBuilderException; import org.atriasoft.exml.exception.ExmlBuilderException;
import org.atriasoft.exml.internal.Log; import org.atriasoft.exml.internal.Log;
import org.atriasoft.exml.parser.Tools; import org.atriasoft.exml.parser.Tools;
public class IntrospectionPropertyMethod extends IntrospectionProperty { public class IntrospectionPropertyMethod extends IntrospectionProperty {
private static Class<?>[] getTypefunction(final Method setter, final Method getter) throws Exception { private static Class<?>[] getTypefunction(final Method setter, final Method getter) throws Exception {
Class<?> type = null; Class<?> type = null;
@ -21,21 +20,23 @@ public class IntrospectionPropertyMethod extends IntrospectionProperty {
} }
if (getter != null) { if (getter != null) {
type = getter.getReturnType(); type = getter.getReturnType();
Type empppe = getter.getGenericReturnType(); if (Enum.class.isAssignableFrom(type)) {
if (empppe instanceof ParameterizedType plopppppp) { Log.verbose("Find an enum ...");
Type[] realType = plopppppp.getActualTypeArguments(); } else {
if (realType.length > 0) { Type empppe = getter.getGenericReturnType();
subType = Class.forName(realType[0].getTypeName()); if (empppe instanceof ParameterizedType plopppppp) {
Type[] realType = plopppppp.getActualTypeArguments();
if (realType.length > 0) {
subType = Class.forName(realType[0].getTypeName());
}
} }
} }
} }
if (setter != null) { if (setter != null) {
if (type != null && setter.getParameters()[0].getType() != type) { if (type != null && setter.getParameters()[0].getType() != type) {
throw new Exception("The type of the setter ands the type return by the getter are not the same ..."); throw new Exception("The type of the setter ands the type return by the getter are not the same ...");
} else {
type = setter.getParameters()[0].getType();
} }
// specific for the list: type = setter.getParameters()[0].getType();
if (List.class.isAssignableFrom(type)) { if (List.class.isAssignableFrom(type)) {
Class<?> internalModelClass = null; Class<?> internalModelClass = null;
Type[] empppe = setter.getGenericParameterTypes(); Type[] empppe = setter.getGenericParameterTypes();
@ -61,8 +62,8 @@ public class IntrospectionPropertyMethod extends IntrospectionProperty {
protected Method getter; protected Method getter;
public IntrospectionPropertyMethod(final Method setter, final Method getter, final String[] names, final Boolean isCaseSensitive, final Boolean isOptional) throws Exception { public IntrospectionPropertyMethod(final Method setter, final Method getter, final String[] names, final String listName, final Boolean isCaseSensitive, final Boolean isOptional) throws Exception {
super(getTypefunction(setter, getter), names, isCaseSensitive, isOptional); super(IntrospectionPropertyMethod.getTypefunction(setter, getter), names, listName, isCaseSensitive, isOptional);
this.setter = setter; this.setter = setter;
this.getter = getter; this.getter = getter;
} }
@ -93,19 +94,19 @@ public class IntrospectionPropertyMethod extends IntrospectionProperty {
} }
try { try {
if (this.type == byte.class) { if (this.type == byte.class) {
final byte data = Byte.valueOf(value); final byte data = Byte.parseByte(value);
this.setter.invoke(object, data); this.setter.invoke(object, data);
} else if (this.type == short.class) { } else if (this.type == short.class) {
final short data = Short.valueOf(value); final short data = Short.parseShort(value);
this.setter.invoke(object, data); this.setter.invoke(object, data);
} else if (this.type == int.class) { } else if (this.type == int.class) {
final int data = Integer.valueOf(value); final int data = Integer.parseInt(value);
this.setter.invoke(object, data); this.setter.invoke(object, data);
} else if (this.type == long.class) { } else if (this.type == long.class) {
final long data = Long.valueOf(value); final long data = Long.parseLong(value);
this.setter.invoke(object, data); this.setter.invoke(object, data);
} else if (this.type == boolean.class) { } else if (this.type == boolean.class) {
final boolean data = Boolean.valueOf(value); final boolean data = Boolean.parseBoolean(value);
this.setter.invoke(object, data); this.setter.invoke(object, data);
} else if (this.type == String.class) { } else if (this.type == String.class) {
this.setter.invoke(object, value); this.setter.invoke(object, value);
@ -159,19 +160,24 @@ public class IntrospectionPropertyMethod extends IntrospectionProperty {
} }
@Override @Override
protected Object createValue(String value) throws ExmlBuilderException { protected Object createValue(final String value) throws ExmlBuilderException {
try { try {
if (this.type == byte.class) { if (this.type == byte.class) {
return Byte.valueOf(value); return Byte.valueOf(value);
} else if (this.type == short.class) { }
if (this.type == short.class) {
return Short.valueOf(value); return Short.valueOf(value);
} else if (this.type == int.class) { }
if (this.type == int.class) {
return Integer.valueOf(value); return Integer.valueOf(value);
} else if (this.type == long.class) { }
if (this.type == long.class) {
return Long.valueOf(value); return Long.valueOf(value);
} else if (this.type == boolean.class) { }
if (this.type == boolean.class) {
return Boolean.valueOf(value); return Boolean.valueOf(value);
} else if (this.type == String.class) { }
if (this.type == String.class) {
return value; return value;
} else if (this.type == Byte.class) { } else if (this.type == Byte.class) {
return Byte.valueOf(value); return Byte.valueOf(value);
@ -214,7 +220,7 @@ public class IntrospectionPropertyMethod extends IntrospectionProperty {
} }
@Override @Override
public void setExistingValue(Object object, Object value) throws ExmlBuilderException { public void setExistingValue(final Object object, final Object value) throws ExmlBuilderException {
if (this.setter == null) { if (this.setter == null) {
throw new ExmlBuilderException("no setter availlable"); throw new ExmlBuilderException("no setter availlable");
} }

View File

@ -242,6 +242,8 @@ public class ParseXml {
// TODO : Can have white spaces .... // TODO : Can have white spaces ....
if (data.charAt(iii + 1) == '>') { if (data.charAt(iii + 1) == '>') {
pos.value = iii + 1; pos.value = iii + 1;
// end of parsing element in auto end close &lt;/&gt;
this.builder.endElement(parent);
return true; return true;
} }
// error // error

View File

@ -6,7 +6,6 @@
package test.atriasoft.exml; package test.atriasoft.exml;
import java.util.Arrays; import java.util.Arrays;
import java.util.List;
import org.atriasoft.exml.Exml; import org.atriasoft.exml.Exml;
import org.atriasoft.exml.exception.ExmlBuilderException; import org.atriasoft.exml.exception.ExmlBuilderException;
@ -16,10 +15,12 @@ import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test; import org.junit.jupiter.api.Test;
import test.atriasoft.exml.introspection.ClassMethodEnum;
import test.atriasoft.exml.introspection.ClassPublicMemberOnly; import test.atriasoft.exml.introspection.ClassPublicMemberOnly;
import test.atriasoft.exml.introspection.ClassPublicMethodOnly; import test.atriasoft.exml.introspection.ClassPublicMethodOnly;
import test.atriasoft.exml.introspection.ClassPublicMethodeNode; import test.atriasoft.exml.introspection.ClassPublicMethodeNode;
import test.atriasoft.exml.introspection.ClassPublicMethodeStructured; import test.atriasoft.exml.introspection.ClassPublicMethodeStructured;
import test.atriasoft.exml.introspection.SimpleEnum;
public class ExmlTestIntrospection { public class ExmlTestIntrospection {
@BeforeAll @BeforeAll
@ -329,11 +330,11 @@ public class ExmlTestIntrospection {
+ " <value>2</value>\n" + " <value>2</value>\n"
+ " </memberArrayByte>\n" + " </memberArrayByte>\n"
+ " <memberListByte>\n" + " <memberListByte>\n"
+ " <elem>12</elem>\n" + " <elem>-12</elem>\n"
+ " <elem>15</elem>\n" + " <elem>-15</elem>\n"
+ " <elem>123</elem>\n" + " <elem>-123</elem>\n"
+ " <elem>100</elem>\n" + " <elem>-100</elem>\n"
+ " <elem>2</elem>\n" + " <elem>-2</elem>\n"
+ " </memberListByte>\n" + " </memberListByte>\n"
+ "</elem>\n"; + "</elem>\n";
//@formatter:on //@formatter:on
@ -346,5 +347,27 @@ public class ExmlTestIntrospection {
Assertions.assertEquals((byte) 15, elem.getMemberArrayByte()[1]); Assertions.assertEquals((byte) 15, elem.getMemberArrayByte()[1]);
Assertions.assertEquals((byte) 123, elem.getMemberArrayByte()[2]); Assertions.assertEquals((byte) 123, elem.getMemberArrayByte()[2]);
Assertions.assertEquals((byte) 100, elem.getMemberArrayByte()[3]); Assertions.assertEquals((byte) 100, elem.getMemberArrayByte()[3]);
Assertions.assertEquals((byte) 2, elem.getMemberArrayByte()[4]);
Assertions.assertEquals(5, elem.getMemberListByte().size());
Assertions.assertEquals((byte) -12, elem.getMemberListByte().get(0));
Assertions.assertEquals((byte) -15, elem.getMemberListByte().get(1));
Assertions.assertEquals((byte) -123, elem.getMemberListByte().get(2));
Assertions.assertEquals((byte) -100, elem.getMemberListByte().get(3));
Assertions.assertEquals((byte) -2, elem.getMemberListByte().get(4));
}
@Test
public void test5() {
//@formatter:off
final String dataToParse = "<elem>\n"
+ " <data>PLIF</data>\n"
+ "</elem>\n";
//@formatter:on
final ClassMethodEnum[] root = Assertions.assertDoesNotThrow(() -> Exml.parse(dataToParse, ClassMethodEnum.class, "elem"));
Assertions.assertEquals(1, root.length);
final ClassMethodEnum elem = root[0];
Assertions.assertEquals(SimpleEnum.PLIF, elem.getData());
} }
} }

View File

@ -0,0 +1,14 @@
package test.atriasoft.exml.introspection;
public class ClassMethodEnum {
private SimpleEnum data;
public SimpleEnum getData() {
return this.data;
}
public void setData(final SimpleEnum data) {
this.data = data;
}
}

View File

@ -1,7 +1,6 @@
package test.atriasoft.exml.introspection; package test.atriasoft.exml.introspection;
import org.atriasoft.exml.annotation.XmlDefaultAttibute; import org.atriasoft.exml.annotation.XmlDefaultAttibute;
import org.atriasoft.exml.annotation.XmlName;
@XmlDefaultAttibute @XmlDefaultAttibute
public class ClassPublicMemberOnly { public class ClassPublicMemberOnly {
@ -17,7 +16,7 @@ public class ClassPublicMemberOnly {
public Short[] memberArrayShortClass; public Short[] memberArrayShortClass;
public boolean memberBoolean; public boolean memberBoolean;
public Boolean memberBooleanClass; public Boolean memberBooleanClass;
@XmlName(value = "jhkjhhkj") //this work !!! @XmlName(value = "jhkjhhkj")
public byte memberByte; public byte memberByte;
public Byte memberByteClass; public Byte memberByteClass;
public int memberInteger; public int memberInteger;

View File

@ -3,21 +3,22 @@ package test.atriasoft.exml.introspection;
import java.util.List; import java.util.List;
import org.atriasoft.exml.annotation.XmlDefaultManaged; import org.atriasoft.exml.annotation.XmlDefaultManaged;
import org.atriasoft.exml.annotation.XmlModel; import org.atriasoft.exml.annotation.XmlList;
@XmlDefaultManaged(value = false) @XmlDefaultManaged(value = false)
public class ClassPublicMethodeStructured { public class ClassPublicMethodeStructured {
@XmlModel(group="memberArrayByte", element="value") // note: when private the decorator must be set on getter or setter, liker this you can use the internal name you want...
private byte[] memberArrayByte; private byte[] memberArrayByte;
@XmlModel(group="listByte", element="elem")
private List<Byte> memberListByte; private List<Byte> memberListByte;
@XmlList(value="value")
public byte[] getMemberArrayByte() { public byte[] getMemberArrayByte() {
return this.memberArrayByte; return this.memberArrayByte;
} }
public void setMemberArrayByte(final byte[] memberArrayByte) { public void setMemberArrayByte(final byte[] memberArrayByte) {
this.memberArrayByte = memberArrayByte; this.memberArrayByte = memberArrayByte;
} }
@XmlList(value="elem")
public List<Byte> getMemberListByte() { public List<Byte> getMemberListByte() {
return this.memberListByte; return this.memberListByte;
} }

View File

@ -0,0 +1,7 @@
package test.atriasoft.exml.introspection;
public enum SimpleEnum {
PLIF,
PLAF,
PROUT;
}