[DEV] contiue rework

This commit is contained in:
Edouard DUPIN 2021-03-16 00:30:49 +01:00
parent 240b71805e
commit f81392846a
23 changed files with 754 additions and 84 deletions

View File

@ -58,7 +58,14 @@ public class Exml {
} }
public static <TYPE> TYPE[] parse(final String data, final Class<TYPE> classType, final String rootNodeName) throws ExmlBuilderException, ExmlParserErrorMulti { public static <TYPE> TYPE[] parse(final String data, final Class<TYPE> classType, final String rootNodeName) throws ExmlBuilderException, ExmlParserErrorMulti {
final Builder builder = new BuilderIntrospection(classType, rootNodeName); Builder builder;
try {
builder = new BuilderIntrospection(classType, rootNodeName);
} catch (final Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
return null;
}
final ParseXml parser = new ParseXml(builder); final ParseXml parser = new ParseXml(builder);
final ParsingProperty property = new ParsingProperty(); final ParsingProperty property = new ParsingProperty();
property.setDisplayError(true); property.setDisplayError(true);

View File

@ -0,0 +1,21 @@
package org.atriasoft.exml.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Marker annotation that to set the element is case sensitive or not.
*
*/
@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER })
@Retention(RetentionPolicy.RUNTIME)
@ExmlAnnotation
public @interface XmlCaseSensitive {
/**
* Set if the element is is case sensitive.
* @return true if case sensitive
*/
boolean value() default true;
}

View File

@ -0,0 +1,20 @@
package org.atriasoft.exml.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Marker annotation that permit to set the default parsing as attributes.
*/
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@ExmlAnnotation
public @interface XmlDefaultAttibute {
/**
* Set this to false to select the attribute as default.
* @return true select default attribute, false select default element.
*/
boolean value() default true;
}

View File

@ -0,0 +1,20 @@
package org.atriasoft.exml.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Marker annotation that permit to select if the parsing is case sensitive or not.
*/
@Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME)
@ExmlAnnotation
public @interface XmlDefaultCaseSensitive {
/**
* Set this at true to set all the element are case sensitive.
* @return true if the element are by default case_sensitive.
*/
boolean value() default true;
}

View File

@ -9,8 +9,13 @@ import java.lang.annotation.Target;
* Marker annotation that set the element are not managed by default. Need to add @XmlManaged to be enable. * Marker annotation that set the element are not managed by default. Need to add @XmlManaged to be enable.
* *
*/ */
@Target({ ElementType.MODULE }) @Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@ExmlAnnotation @ExmlAnnotation
public @interface XmlDefaultNotManaged { public @interface XmlDefaultManaged {
/**
* Set this at false to remove all the field and the function from Xml introspection
* @return true if the element are by default managed.
*/
boolean value() default true;
} }

View File

@ -9,8 +9,13 @@ import java.lang.annotation.Target;
* Marker annotation that set the element not found are ignored. * Marker annotation that set the element not found are ignored.
* *
*/ */
@Target({ ElementType.MODULE }) @Target({ ElementType.TYPE })
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@ExmlAnnotation @ExmlAnnotation
public @interface XmlDefaultOptional { public @interface XmlDefaultOptional {
/**
* Set this at true to set all the element optional.
* @return true if the element are by default optional.
*/
boolean value() default false;
} }

View File

@ -13,4 +13,9 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@ExmlAnnotation @ExmlAnnotation
public @interface XmlManaged { public @interface XmlManaged {
/**
* Set this at false to remove this function or this field form the XML parsing system
* @return true if the element is managed.
*/
boolean value() default true;
} }

View File

@ -13,16 +13,11 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@ExmlAnnotation @ExmlAnnotation
public @interface XmlName { public @interface XmlName {
/**
* Set if the element has a specific case sensitivity (if the full parsing is case insensitive, this change nothing)
* @return true if the element is case insensitive.
*/
boolean caseSensitive() default true;
/** /**
* Names of the property of the Element name * Names of the property of the Element name
* @note The first name if the default generated in serialization. * @note The first name if the default generated in serialization.
* @return The list the the possible names * @return The list the the possible names
*/ */
String[] names(); String[] value();
} }

View File

@ -13,4 +13,9 @@ import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@ExmlAnnotation @ExmlAnnotation
public @interface XmlOptional { public @interface XmlOptional {
/**
* Set if the element is optional or not. If optional, the parser does not throw error if the element is not declared.
* @return thru if optional
*/
boolean value() default true;
} }

View File

@ -6,11 +6,15 @@ import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target; import java.lang.annotation.Target;
/** /**
* Marker annotation that Permit to ignore the function or the attribute. * Marker annotation that set the Xml element seen as a property.
*
*/ */
@Target({ ElementType.FIELD, ElementType.METHOD }) @Target({ ElementType.FIELD, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME) @Retention(RetentionPolicy.RUNTIME)
@ExmlAnnotation @ExmlAnnotation
public @interface XmlNotManaged { public @interface XmlProperty {
/**
* Set at true to set the element managed as a property of the Xml node
* @return property management.
*/
boolean value() default true;
} }

View File

@ -33,7 +33,7 @@ public interface Builder {
* @return the object representing the Element. * @return the object representing the Element.
* @throws ExmlBuilderException Error with this node or element. * @throws ExmlBuilderException Error with this node or element.
*/ */
Object newElement(Object parent, String nodeName) throws ExmlBuilderException; Object newElement(Object parent, String nodeName) throws ExmlBuilderException, Exception;
/** /**
* Add a property on the Element. * Add a property on the Element.
@ -42,7 +42,7 @@ public interface Builder {
* @param propertyValue Value of the property * @param propertyValue Value of the property
* @throws ExmlBuilderException Error with this node or element. * @throws ExmlBuilderException Error with this node or element.
*/ */
void newProperty(Object element, String propertyName, String propertyValue) throws ExmlBuilderException; void newProperty(Object element, String propertyName, String propertyValue) throws ExmlBuilderException, Exception;
/** /**
* Create or get the root element of the document * Create or get the root element of the document

View File

@ -14,13 +14,13 @@ public class BuilderIntrospection implements Builder {
final Class<?> rootClassType; final Class<?> rootClassType;
final String rootNodeName; final String rootNodeName;
public BuilderIntrospection(final Class<?> classType, final String rootNodeName) { 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));
} }
IntrospectionData findOrCreate(final Class<?> classType) { IntrospectionData findOrCreate(final Class<?> classType) throws Exception {
IntrospectionData out = this.elements.get(classType); IntrospectionData out = this.elements.get(classType);
if (out != null) { if (out != null) {
return out; return out;
@ -43,7 +43,7 @@ public class BuilderIntrospection implements Builder {
} }
@Override @Override
public Object newElement(final Object parent, final String nodeName) throws ExmlBuilderException { public Object newElement(final Object parent, final String nodeName) throws ExmlBuilderException, Exception {
final IntrospectionObject introspectionObject = (IntrospectionObject) parent; final IntrospectionObject introspectionObject = (IntrospectionObject) parent;
if (introspectionObject.getDataInterface() == null) { if (introspectionObject.getDataInterface() == null) {
final Object previousData = introspectionObject.getData(); final Object previousData = introspectionObject.getData();
@ -72,7 +72,7 @@ public class BuilderIntrospection implements Builder {
} }
@Override @Override
public void newProperty(final Object element, final String propertyName, final String propertyValue) throws ExmlBuilderException { public void newProperty(final Object element, final String propertyName, final String propertyValue) throws ExmlBuilderException, Exception {
final IntrospectionObject introspectionObject = (IntrospectionObject) element; final IntrospectionObject introspectionObject = (IntrospectionObject) element;
if (introspectionObject.getDataInterface() == null) { if (introspectionObject.getDataInterface() == null) {
// property on nothing ??? // property on nothing ???

View File

@ -1,5 +1,6 @@
package org.atriasoft.exml.builder; package org.atriasoft.exml.builder;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Field; import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
@ -8,34 +9,110 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.atriasoft.exml.annotation.XmlCaseSensitive;
import org.atriasoft.exml.annotation.XmlDefaultCaseSensitive;
import org.atriasoft.exml.annotation.XmlDefaultManaged;
import org.atriasoft.exml.annotation.XmlDefaultOptional;
import org.atriasoft.exml.annotation.XmlManaged;
import org.atriasoft.exml.annotation.XmlName;
import org.atriasoft.exml.annotation.XmlOptional;
import org.atriasoft.exml.internal.Log; import org.atriasoft.exml.internal.Log;
import org.atriasoft.exml.parser.Tools;
public class IntrospectionData { public class IntrospectionData {
private static final Boolean DEFAULT_MANAGED = true;
private static final Boolean DEFAULT_OPTIONAL = false;
private static final Boolean DEFAULT_CASE_SENSITIVE = true;
final Class<?> classType; final Class<?> classType;
private final List<IntrospectionProperty> properties = new ArrayList<>(); private final List<IntrospectionProperty> properties = new ArrayList<>();
public IntrospectionData(final Class<?> classType) { private final List<IntrospectionProperty> methods = new ArrayList<>();
public IntrospectionData(final Class<?> classType) throws Exception {
this.classType = classType; this.classType = classType;
Log.info("Introspect class: '" + classType.getCanonicalName() + "'"); final Boolean isDefaultManaged = getIsDefaultManaged(classType, DEFAULT_MANAGED);
final Boolean isDefaultOptional = getIsDefaultOptional(classType, DEFAULT_OPTIONAL);
final Boolean isDefaultCaseSensitive = getIsDefaultCaseSensitive(classType, DEFAULT_CASE_SENSITIVE);
Log.verbose("Introspect class: '" + classType.getCanonicalName() + "'");
final Constructor<?>[] constructors = this.classType.getConstructors(); final Constructor<?>[] constructors = this.classType.getConstructors();
Log.info(" Constructors: (" + constructors.length + ")"); Log.verbose(" Constructors: (" + constructors.length + ")");
for (final Constructor<?> elem : constructors) { for (final Constructor<?> elem : constructors) {
Log.info(" - " + elem.toGenericString()); Log.verbose(" - " + elem.toGenericString());
} }
final Field[] fields = this.classType.getFields(); final Field[] fields = this.classType.getFields();
Log.info(" Fields: (" + fields.length + ")"); Log.verbose(" Fields: (" + fields.length + ")");
for (final Field elem : fields) { for (final Field elem : fields) {
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);
// TODO: check if property does not already exist ... // TODO: check if property does not already exist ...
this.properties.add(new IntrospectionPropertyField(elem)); if (isManaged == true) {
Log.info(" - " + elem.toGenericString()); this.properties.add(new IntrospectionPropertyField(elem, names, caseSensitive, isOptionnal));
}
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 -> { final List<Method> methods = List.of(methodsTmp).stream().filter(o -> {
return (o.getName().startsWith("get") || o.getName().startsWith("set") || o.getName().startsWith("is")) && !o.getName().contentEquals("getClass"); if (o.getName().contentEquals("getClass") == true) {
return false;
}
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;
}
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().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;
}
return false;
}).collect(Collectors.toList()); }).collect(Collectors.toList());
// separate the methods...
Log.verbose(" Methods: (" + methods.size() + ")");
for (final Method elem : methods) {
Log.verbose(" - " + elem.toGenericString());
}
// Separate the methods and filer as:
// XXX GetXxx(); & XXX != boolean
// void setXxx(XXX elem);
// [bB]oolean isXxx();
final List<Method> methodsGet = methods.stream().filter(o -> { final List<Method> methodsGet = methods.stream().filter(o -> {
return o.getName().startsWith("get"); return o.getName().startsWith("get");
}).collect(Collectors.toList()); }).collect(Collectors.toList());
@ -47,12 +124,106 @@ public class IntrospectionData {
}).collect(Collectors.toList()); }).collect(Collectors.toList());
// associate methods by pair. // associate methods by pair.
// nameProperty, getter, setter final List<OrderData> elements = new ArrayList<>();
for (final Method method : methodsGet) {
Log.info(" Methods: (" + methods.size() + ")"); final String name = method.getName().substring(3);
for (final Method elem : methods) { final OrderData tmp = new OrderData(name);
Log.info(" - " + elem.toGenericString()); 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;
}
}
if (tmp == null) {
tmp = new OrderData(name);
tmp.setter = method;
elements.add(tmp);
} else {
tmp.setter = method;
}
}
// Add it in the engine
for (final OrderData elem : elements) {
Log.info("find methode : '" + elem.name + "' :");
if (elem.setter != null && elem.getter != null) {
Log.info(" setter: " + elem.setter.toGenericString());
Log.info(" getter: " + elem.getter.toGenericString());
final Boolean isManagedSet = getIsManaged(elem.setter, null);
final Boolean isManagedGet = 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);
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);
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);
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) };
this.methods.add(new IntrospectionPropertyMethod(elem.setter, elem.getter, names, isCaseSensitive, isOptional));
} else {
Boolean isManaged = null;
Boolean isOptionnal = null;
String[] names = null;
Boolean isCaseSensitive = null;
if (elem.setter != null) {
Log.info(" setter: " + elem.setter.toGenericString());
isManaged = getIsManaged(elem.setter, isDefaultManaged);
isOptionnal = getIsOptional(elem.setter, isDefaultOptional);
names = getNames(elem.setter, Tools.decapitalizeFirst(elem.name));
isCaseSensitive = getIsCaseSensitive(elem.setter, isDefaultCaseSensitive);
} else {
Log.info(" setter: null");
}
if (elem.getter != null) {
Log.info(" getter: " + elem.getter.toGenericString());
isManaged = getIsManaged(elem.getter, isDefaultManaged);
isOptionnal = getIsOptional(elem.getter, isDefaultOptional);
names = getNames(elem.getter, Tools.decapitalizeFirst(elem.name));
isCaseSensitive = getIsCaseSensitive(elem.getter, isDefaultCaseSensitive);
} else {
Log.info(" getter: null");
}
if (isManaged == true) {
this.methods.add(new IntrospectionPropertyMethod(elem.setter, elem.getter, names, isCaseSensitive, isOptionnal));
}
}
}
} }
Object createObject() { Object createObject() {
@ -65,25 +236,210 @@ public class IntrospectionData {
} }
} }
protected IntrospectionProperty findMethodDescription(final String propertyName) throws Exception {
for (final IntrospectionProperty prop : this.methods) {
if (prop.isCompatible(propertyName) == true) {
return prop;
}
}
return null;
}
protected IntrospectionProperty findPropertyDescription(final String propertyName) throws Exception { protected IntrospectionProperty findPropertyDescription(final String propertyName) throws Exception {
for (final IntrospectionProperty prop : this.properties) { for (final IntrospectionProperty prop : this.properties) {
if (prop.isCompatible(propertyName) == true) { if (prop.isCompatible(propertyName) == true) {
return prop; return prop;
} }
} }
Log.error("lkjlkjlkjlkj"); return null;
throw new Exception("lkjlkjlk");
} }
public void setProperty(final Object data, final String propertyName, final String propertyValue) { protected Boolean getIsCaseSensitive(final Field element, final Boolean defaultValue) throws Exception {
try { final Annotation[] annotation = element.getDeclaredAnnotationsByType(XmlCaseSensitive.class);
final IntrospectionProperty prop = findPropertyDescription(propertyName); if (annotation.length == 0) {
prop.setValue(data, propertyValue); return defaultValue;
} catch (final Exception e) {
Log.error("can not find the field '" + propertyName + "' " + e.getMessage());
e.printStackTrace();
} }
if (annotation.length > 1) {
throw new Exception("Must not hame more that ");
}
return ((XmlCaseSensitive) annotation[0]).value();
}
protected Boolean getIsCaseSensitive(final Method element, final Boolean defaultValue) throws Exception {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(XmlCaseSensitive.class);
if (annotation.length == 0) {
return defaultValue;
}
if (annotation.length > 1) {
throw new Exception("Must not hame more that ");
}
return ((XmlCaseSensitive) annotation[0]).value();
}
private Boolean getIsDefaultCaseSensitive(final Class<?> classType, final Boolean defaultValue) throws Exception {
final Annotation[] annotation = classType.getDeclaredAnnotationsByType(XmlDefaultCaseSensitive.class);
if (annotation.length == 0) {
return defaultValue;
}
if (annotation.length > 1) {
throw new Exception("Must not hame more that ");
}
return ((XmlDefaultCaseSensitive) annotation[0]).value();
}
private Boolean getIsDefaultManaged(final Class<?> classType, final Boolean defaultValue) throws Exception {
final Annotation[] annotation = classType.getDeclaredAnnotationsByType(XmlDefaultManaged.class);
if (annotation.length == 0) {
return defaultValue;
}
if (annotation.length > 1) {
throw new Exception("Must not hame more that ");
}
return ((XmlDefaultManaged) annotation[0]).value();
}
private Boolean getIsDefaultOptional(final Class<?> classType, final Boolean defaultValue) throws Exception {
final Annotation[] annotation = classType.getDeclaredAnnotationsByType(XmlDefaultOptional.class);
if (annotation.length == 0) {
return defaultValue;
}
if (annotation.length > 1) {
throw new Exception("Must not hame more that ");
}
return ((XmlDefaultOptional) annotation[0]).value();
}
protected Boolean getIsManaged(final Field element, final Boolean parentValue) throws Exception {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(XmlManaged.class);
if (annotation.length == 0) {
return parentValue;
}
if (annotation.length > 1) {
throw new Exception("Must not hame more that ");
}
return ((XmlManaged) annotation[0]).value();
}
protected Boolean getIsManaged(final Method element, final Boolean parentValue) throws Exception {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(XmlManaged.class);
if (annotation.length == 0) {
return parentValue;
}
if (annotation.length > 1) {
throw new Exception("Must not hame 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 hame 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 hame 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;
} else {
return new String[] { defaultValue };
}
}
if (annotation.length > 1) {
throw new Exception("Must not hame 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() == true) {
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;
} else {
return new String[] { defaultValue };
}
}
if (annotation.length > 1) {
throw new Exception("Must not hame 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() == true) {
throw new Exception("Set empty String in list of value in decorator @XmlName is not availlable on: " + element.toGenericString());
}
}
return tmp;
}
public void setProperty(final Object data, final String propertyName, final String propertyValue) throws Exception {
//Log.error(" propertyName='" + propertyName + "' propertyValue='" + propertyValue + "' ");
// by default use setter to set the property
final IntrospectionProperty propMethode = findMethodDescription(propertyName);
if (propMethode != null && propMethode.cansetValue() == true) {
//Log.error(" ==> find '" + propMethode.getNames());
propMethode.setValue(data, propertyValue);
return;
}
// try with direct field
final IntrospectionProperty propField = findPropertyDescription(propertyName);
if (propField != null && propField.cansetValue() == true) {
//Log.error(" ==> find '" + propField.getNames());
propField.setValue(data, propertyValue);
return;
}
throw new Exception("can not find the field '" + propertyName + "'");
} }
} }
class OrderData {
public final String name;
public Method setter = null;
public Method getter = null;
public OrderData(final String name) {
this.name = name;
}
}

View File

@ -27,7 +27,7 @@ public class IntrospectionObject {
return this.dataInterface; return this.dataInterface;
} }
public void setProperty(final String propertyName, final String propertyValue) { public void setProperty(final String propertyName, final String propertyValue) throws Exception {
this.dataInterface.setProperty(this.data, propertyName, propertyValue); this.dataInterface.setProperty(this.data, propertyName, propertyValue);
} }

View File

@ -1,18 +1,23 @@
package org.atriasoft.exml.builder; package org.atriasoft.exml.builder;
import java.util.ArrayList;
import java.util.List;
public abstract class IntrospectionProperty { public abstract class IntrospectionProperty {
protected List<String> names = new ArrayList<>();
protected boolean caseSensitive = true;
protected final Class<?> type; protected final Class<?> type;
protected final String[] names;
protected final Boolean caseSensitive;
protected final Boolean isOptionnal;
public IntrospectionProperty(final Class<?> type) { public IntrospectionProperty(final Class<?> type, final String[] names, final Boolean caseSensitive, final Boolean isOptionnal) {
this.type = type; this.type = type;
this.names = names;
this.caseSensitive = caseSensitive;
this.isOptionnal = isOptionnal;
} }
public List<String> getNames() { public abstract boolean canGetValue();
public abstract boolean cansetValue();
public String[] getNames() {
return this.names; return this.names;
} }
@ -20,14 +25,14 @@ public abstract class IntrospectionProperty {
return this.type; return this.type;
} }
public abstract String getValue(Object object); public abstract String getValue(Object object) throws Exception;
public boolean isCaseSensitive() { public boolean isCaseSensitive() {
return this.caseSensitive; return this.caseSensitive;
} }
public boolean isCompatible(String name) { public boolean isCompatible(String name) {
if (this.caseSensitive == false) { if (this.caseSensitive == true) {
for (final String elem : this.names) { for (final String elem : this.names) {
if (elem.contentEquals(name) == true) { if (elem.contentEquals(name) == true) {
return true; return true;
@ -44,13 +49,5 @@ public abstract class IntrospectionProperty {
return false; return false;
} }
public void setCaseSensitive(final boolean caseSensitive) { public abstract void setValue(Object object, String value) throws Exception;
this.caseSensitive = caseSensitive;
}
public void setNames(final List<String> names) {
this.names = names;
}
public abstract void setValue(Object object, String value);
} }

View File

@ -8,10 +8,19 @@ import org.atriasoft.exml.parser.Tools;
public class IntrospectionPropertyField extends IntrospectionProperty { public class IntrospectionPropertyField extends IntrospectionProperty {
private final Field fieldDescription; private final Field fieldDescription;
public IntrospectionPropertyField(final Field fieldDescription) { public IntrospectionPropertyField(final Field fieldDescription, final String[] names, final Boolean caseSensitive, final Boolean isOptionnal) {
super(fieldDescription.getType()); super(fieldDescription.getType(), names, caseSensitive, isOptionnal);
this.fieldDescription = fieldDescription; this.fieldDescription = fieldDescription;
this.names.add(this.fieldDescription.getName()); }
@Override
public boolean canGetValue() {
return true;
}
@Override
public boolean cansetValue() {
return true;
} }
@Override @Override

View File

@ -0,0 +1,124 @@
package org.atriasoft.exml.builder;
import java.lang.reflect.Method;
import org.atriasoft.exml.internal.Log;
import org.atriasoft.exml.parser.Tools;
public class IntrospectionPropertyMethod extends IntrospectionProperty {
private static Class<?> getTypefunction(final Method setter, final Method getter) throws Exception {
Class<?> type = null;
if (setter == null && getter == null) {
// impossible case...
throw new Exception("kjhkhjkj");
}
if (getter != null) {
type = getter.getReturnType();
}
if (setter != null) {
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 ...");
} else {
type = setter.getParameters()[0].getType();
}
}
return type;
}
protected Method setter;
protected Method getter;
public IntrospectionPropertyMethod(final Method setter, final Method getter, final String[] names, final Boolean isCaseSensitive, final Boolean isOptional) throws Exception {
super(getTypefunction(setter, getter), names, isCaseSensitive, isOptional);
this.setter = setter;
this.getter = getter;
}
@Override
public boolean canGetValue() {
return this.getter != null;
}
@Override
public boolean cansetValue() {
return this.setter != null;
}
@Override
public String getValue(final Object object) throws Exception {
if (this.getter == null) {
throw new Exception("no getter availlable");
}
// TODO Auto-generated method stub
return null;
}
@Override
public void setValue(final Object object, final String value) throws Exception {
if (this.setter == null) {
throw new Exception("no setter availlable");
}
try {
if (this.type == byte.class) {
final byte data = Byte.valueOf(value);
this.setter.invoke(object, data);
} else if (this.type == short.class) {
final short data = Short.valueOf(value);
this.setter.invoke(object, data);
} else if (this.type == int.class) {
final int data = Integer.valueOf(value);
this.setter.invoke(object, data);
} else if (this.type == long.class) {
final long data = Long.valueOf(value);
this.setter.invoke(object, data);
} else if (this.type == boolean.class) {
final boolean data = Boolean.valueOf(value);
this.setter.invoke(object, data);
} else if (this.type == String.class) {
this.setter.invoke(object, value);
} else if (this.type == Byte.class) {
final Byte data = Byte.valueOf(value);
this.setter.invoke(object, data);
} else if (this.type == Short.class) {
final Short data = Short.valueOf(value);
this.setter.invoke(object, data);
} else if (this.type == Integer.class) {
final Integer data = Integer.valueOf(value);
this.setter.invoke(object, data);
} else if (this.type == Long.class) {
final Long data = Long.valueOf(value);
this.setter.invoke(object, data);
} else if (this.type == Boolean.class) {
final Boolean data = Boolean.valueOf(value);
this.setter.invoke(object, data);
} else if (this.type == byte[].class) {
this.setter.invoke(object, Tools.parseByteStringList(value));
} else if (this.type == Byte[].class) {
this.setter.invoke(object, (Object) Tools.parseByteClassStringList(value));
} else if (this.type == short[].class) {
this.setter.invoke(object, Tools.parseShortStringList(value));
} else if (this.type == Short[].class) {
this.setter.invoke(object, (Object) Tools.parseShortClassStringList(value));
} else if (this.type == int[].class) {
this.setter.invoke(object, Tools.parseIntegerStringList(value));
} else if (this.type == Integer[].class) {
this.setter.invoke(object, (Object) Tools.parseIntegerClassStringList(value));
} else if (this.type == long[].class) {
this.setter.invoke(object, Tools.parseLongStringList(value));
} else if (this.type == Long[].class) {
this.setter.invoke(object, (Object) Tools.parseLongClassStringList(value));
} else if (this.type == boolean[].class) {
this.setter.invoke(object, Tools.parseBooleanStringList(value));
} else if (this.type == Boolean[].class) {
this.setter.invoke(object, (Object) Tools.parseBooleanClassStringList(value));
} else {
Log.error("Can not parse the specific element ... need to introspect and find the 'xxx valueOf(String data);'");
}
} catch (IllegalArgumentException | IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}

View File

@ -82,7 +82,12 @@ public class ParseXml {
//EXML_PARSE_ATTRIBUTE(pos << " attribute : " << name << "=\"" << value << "\""); //EXML_PARSE_ATTRIBUTE(pos << " attribute : " << name << "=\"" << value << "\"");
_pos.value = lastAttributePos - 1; _pos.value = lastAttributePos - 1;
this.builder.newProperty(parent, name, value); try {
this.builder.newProperty(parent, name, value);
} catch (final Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return true; return true;
} }
int lastAttributePos = lastElementName + white + 3; int lastAttributePos = lastElementName + white + 3;
@ -100,7 +105,12 @@ public class ParseXml {
//EXML_PARSE_ATTRIBUTE(pos << " attribute : " << name << "=\"" << value << "\""); //EXML_PARSE_ATTRIBUTE(pos << " attribute : " << name << "=\"" << value << "\"");
_pos.value = lastAttributePos; _pos.value = lastAttributePos;
this.builder.newProperty(parent, name, value); try {
this.builder.newProperty(parent, name, value);
} catch (final Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
return true; return true;
} }
@ -495,7 +505,13 @@ public class ParseXml {
Log.debug("find node named : '" + tmpname + "'"); Log.debug("find node named : '" + tmpname + "'");
// find text: // find text:
final Object element = this.builder.newElement(parent, tmpname); Object element = null;
try {
element = this.builder.newElement(parent, tmpname);
} catch (final Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
_pos.value = endPosName + 1; _pos.value = endPosName + 1;
_filePos.add(tmpPos); _filePos.add(tmpPos);
Log.verbose("start parse : 'element' named='" + tmpname + "'"); Log.verbose("start parse : 'element' named='" + tmpname + "'");

View File

@ -1,7 +1,5 @@
package org.atriasoft.exml.parser; package org.atriasoft.exml.parser;
import org.atriasoft.exml.internal.Log;
public class Tools { public class Tools {
/** /**
* add indentation of the string input. * add indentation of the string input.
@ -79,19 +77,29 @@ public class Tools {
return out; return out;
} }
// based on this: https://stackoverflow.com/questions/4052840/most-efficient-way-to-make-the-first-character-of-a-string-lower-case
public static String decapitalizeFirst(final String string) {
if (string == null || string.length() == 0) {
return string;
}
final char c[] = string.toCharArray();
c[0] = Character.toLowerCase(c[0]);
return new String(c);
}
/** /**
* Display the cuurent element that is curently parse. * Display the cuurent element that is curently parse.
* @param[in] _val Char that is parsed. * @param[in] _val Char that is parsed.
* @param[in] _filePos Position of the char in the file. * @param[in] _filePos Position of the char in the file.
*/ */
public static void drawElementParsed(final Character _val, final FilePos _filePos) { public static void drawElementParsed(final Character _val, final FilePos _filePos) {
if (_val == '\n') { // if (_val == '\n') {
Log.debug(_filePos + " parse '\\n'"); // Log.debug(_filePos + " parse '\\n'");
} else if (_val == '\t') { // } else if (_val == '\t') {
Log.debug(_filePos + " parse '\\t'"); // Log.debug(_filePos + " parse '\\t'");
} else { // } else {
Log.debug(_filePos + " parse '" + _val + "'"); // Log.debug(_filePos + " parse '" + _val + "'");
} // }
} }
public static String extractLine(final String data, final int _pos) { public static String extractLine(final String data, final int _pos) {

View File

@ -122,10 +122,72 @@ public class ExmlTestIntrospection {
+ " memberIntegerClass = \"4654654\" \n" + " memberIntegerClass = \"4654654\" \n"
+ " memberLongClass = \"545645645454\"\n" + " memberLongClass = \"545645645454\"\n"
+ " memberBooleanClass = \"true\" \n" + " memberBooleanClass = \"true\" \n"
+ " memberStringClass = \"sdfgsdkjfglksqjéé\"\n/>\n"; + " memberStringClass = \"sdfgsdkjfglksqjéé\"\n"
+ " memberArrayByte=\"12, 15,123, 100, 2\"\n"
+ " memberArrayByteClass=\"\t\t\r\n 12,1, 100,122\"\n"
+ " memberArrayShort=\"1245,1894, -100,-12542\"\n"
+ " memberArrayShortClass=\"-1245,-1894, 0,2542,15615\"\n"
+ " memberArrayInteger=\"123456,-654987\"\n"
+ " memberArrayIntegerClass=\"1567845,45621354,-5646544\"\n"
+ " memberArrayLong=\"1651324654,65421351685,-5\"\n"
+ " memberArrayLongClass=\"6746541351,546546546,564654654,654654654654,-45546\"\n"
+ " memberArrayBoolean=\"true, true, false\"\n"
+ " memberArrayBooleanClass=\"false, false, true, true\"\n"
+ "/>\n";
//@formatter:on //@formatter:on
final ClassPublicMethodOnly[] root = Assertions.assertDoesNotThrow(() -> Exml.parse(dataToParse, ClassPublicMethodOnly.class, "elem")); final ClassPublicMethodOnly[] root = Assertions.assertDoesNotThrow(() -> Exml.parse(dataToParse, ClassPublicMethodOnly.class, "elem"));
Assertions.assertEquals(1, root.length); Assertions.assertEquals(1, root.length);
final ClassPublicMethodOnly elem = root[0];
Assertions.assertEquals((byte) 12, elem.getMemberByte());
Assertions.assertEquals((short) 1223, elem.getMemberShort());
Assertions.assertEquals(4541542, elem.getMemberInteger());
Assertions.assertEquals(4564654654L, elem.getMemberLong());
Assertions.assertEquals(true, elem.isMemberBoolean());
Assertions.assertEquals((byte) 55, elem.getMemberByteClass());
Assertions.assertEquals((short) 1523, elem.getMemberShortClass());
Assertions.assertEquals(4654654, elem.getMemberIntegerClass());
Assertions.assertEquals(545645645454L, elem.getMemberLongClass());
Assertions.assertEquals(true, elem.isMemberBooleanClass());
Assertions.assertEquals("sdfgsdkjfglksqjéé", elem.getMemberStringClass());
Assertions.assertEquals(5, elem.getMemberArrayByte().length);
Assertions.assertEquals((byte) 12, elem.getMemberArrayByte()[0]);
Assertions.assertEquals((byte) 15, elem.getMemberArrayByte()[1]);
Assertions.assertEquals((byte) 123, elem.getMemberArrayByte()[2]);
Assertions.assertEquals((byte) 100, elem.getMemberArrayByte()[3]);
Assertions.assertEquals(2, elem.getMemberArrayByte()[4]);
Assertions.assertEquals(4, elem.getMemberArrayByteClass().length);
Assertions.assertEquals((byte) 12, elem.getMemberArrayByteClass()[0]);
Assertions.assertEquals((byte) 1, elem.getMemberArrayByteClass()[1]);
Assertions.assertEquals((byte) 100, elem.getMemberArrayByteClass()[2]);
Assertions.assertEquals((byte) 122, elem.getMemberArrayByteClass()[3]);
Assertions.assertEquals(4, elem.getMemberArrayShort().length);
Assertions.assertEquals((short) 1245, elem.getMemberArrayShort()[0]);
Assertions.assertEquals((short) 1894, elem.getMemberArrayShort()[1]);
Assertions.assertEquals((short) -100, elem.getMemberArrayShort()[2]);
Assertions.assertEquals((short) -12542, elem.getMemberArrayShort()[3]);
Assertions.assertEquals(5, elem.getMemberArrayShortClass().length);
Assertions.assertEquals((short) -1245, elem.getMemberArrayShortClass()[0]);
Assertions.assertEquals((short) -1894, elem.getMemberArrayShortClass()[1]);
Assertions.assertEquals((short) 0, elem.getMemberArrayShortClass()[2]);
Assertions.assertEquals((short) 2542, elem.getMemberArrayShortClass()[3]);
Assertions.assertEquals((short) 15615, elem.getMemberArrayShortClass()[4]);
Assertions.assertEquals(2, elem.getMemberArrayInteger().length);
//Assertions.assertArrayEquals(Arrays.asList(123456, -654987).toArray(), elem.getMemberArrayInteger());
Assertions.assertEquals(3, elem.getMemberArrayIntegerClass().length);
Assertions.assertArrayEquals(Arrays.asList(1567845, 45621354, -5646544).toArray(), elem.getMemberArrayIntegerClass());
Assertions.assertEquals(3, elem.getMemberArrayLong().length);
//Assertions.assertArrayEquals(Arrays.asList(1651324654L, 65421351685L, -5L).toArray(), elem.getMemberArrayLong());
Assertions.assertEquals(5, elem.getMemberArrayLongClass().length);
Assertions.assertArrayEquals(Arrays.asList(6746541351L, 546546546L, 564654654L, 654654654654L, -45546L).toArray(), elem.getMemberArrayLongClass());
Assertions.assertEquals(3, elem.getMemberArrayBoolean().length);
//Assertions.assertArrayEquals(Arrays.asList(true, true, false).toArray(), elem.getMemberArrayBoolean());
Assertions.assertEquals(4, elem.getMemberArrayBooleanClass().length);
Assertions.assertArrayEquals(Arrays.asList(false, false, true, true).toArray(), elem.getMemberArrayBooleanClass());
} }
} }

View File

@ -0,0 +1,8 @@
package test.atriasoft.exml.introspection;
import org.atriasoft.exml.annotation.XmlDefaultManaged;
@XmlDefaultManaged(value = false)
public class ClassInversion {
}

View File

@ -1,6 +1,9 @@
package test.atriasoft.exml.introspection; package test.atriasoft.exml.introspection;
import org.atriasoft.exml.annotation.XmlName;
public class ClassPublicMemberOnly { public class ClassPublicMemberOnly {
@XmlName(value = { "jhkjhhkj" })
public byte memberByte; public byte memberByte;
public short memberShort; public short memberShort;
public int memberInteger; public int memberInteger;

View File

@ -63,10 +63,6 @@ public class ClassPublicMethodOnly {
return this.memberArrayShortClass; return this.memberArrayShortClass;
} }
public Boolean getMemberBooleanClass() {
return this.memberBooleanClass;
}
public byte getMemberByte() { public byte getMemberByte() {
return this.memberByte; return this.memberByte;
} }
@ -107,6 +103,10 @@ public class ClassPublicMethodOnly {
return this.memberBoolean; return this.memberBoolean;
} }
public Boolean isMemberBooleanClass() {
return this.memberBooleanClass;
}
public void setMemberArrayBoolean(final boolean[] memberArrayBoolean) { public void setMemberArrayBoolean(final boolean[] memberArrayBoolean) {
this.memberArrayBoolean = memberArrayBoolean; this.memberArrayBoolean = memberArrayBoolean;
} }