diff --git a/src/org/atriasoft/exml/builder/IntrospectionModelComplex.java b/src/org/atriasoft/exml/builder/IntrospectionModelComplex.java index 6055d6f..fba72b5 100644 --- a/src/org/atriasoft/exml/builder/IntrospectionModelComplex.java +++ b/src/org/atriasoft/exml/builder/IntrospectionModelComplex.java @@ -10,7 +10,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Collections; -import java.util.Comparator; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -23,78 +22,20 @@ import org.atriasoft.exml.internal.Log; import org.atriasoft.exml.parser.Tools; import org.atriasoft.exml.reflect.ReflectTools; - -record ConstructorModel(String[] values, +record ConstructorModel( + String[] values, Boolean[] isAttributes, - Constructor constructor) { -} + Constructor constructor) {} public class IntrospectionModelComplex extends IntrospectionModel { - + // 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 tostring; // used for the set Text if the object is an end point... - private final boolean isSubClass; // if true, the constructor must be called with a null first object. + private final boolean isSubClass; // if true, the constructor must be called with a null first object. private final Constructor constructorEmpty; private final List constructors = new ArrayList<>(); private final List elements = new ArrayList<>(); - - @Override - public String getBeanName(final String nodeName) { - for (IntrospectionProperty elem : this.elements) { - if (elem.isCompatible(nodeName)) { - return elem.getBeanName(); - } - } - return null; - } - @Override - public List getNodes() { - List out = new ArrayList<>(); - for (IntrospectionProperty elem : this.elements) { - if (!elem.isAttribute()) { - out.add(elem); - } - } - return out; - } - @Override - public List getAttributes() { - List out = new ArrayList<>(); - for (IntrospectionProperty elem : this.elements) { - if (elem.isAttribute()) { - out.add(elem); - } - } - return out; - } - protected IntrospectionProperty findElement(final String beanName) { - for (IntrospectionProperty elem : this.elements) { - if (elem.getBeanName().equals(beanName)) { - return elem; - } - } - return null; - } - - - -// private boolean checkIfOneIsNull(Boolean[] values, int offset) { -// for (int iii=offset; iii classType) throws ExmlBuilderException { super(classType); @@ -141,48 +82,49 @@ public class IntrospectionModelComplex extends IntrospectionModel { String[] namesBeans = ReflectTools.getNames(elem, null); if (namesBeans == null) { namesBeans = new String[elem.getParameterCount() - offsetSubClass]; - } else if (elem.getParameterCount() != namesBeans.length+offsetSubClass) { + } else if (elem.getParameterCount() != namesBeans.length + offsetSubClass) { throw new ExmlBuilderException("Wrong number of parameter in constructor with ne number declared in the @XmlName (for bean name)"); } - Boolean[] isAttributes = new Boolean[elem.getParameterCount()-offsetSubClass]; - Boolean[] isCaseSensitives = new Boolean[elem.getParameterCount()-offsetSubClass]; - Boolean[] isOptionals = new Boolean[elem.getParameterCount()-offsetSubClass]; - Boolean[] isManageds = new Boolean[elem.getParameterCount()-offsetSubClass]; - - Class[][] clazz = new Class[elem.getParameterCount()-offsetSubClass][]; - String[][] names = new String[elem.getParameterCount()-offsetSubClass][]; + Boolean[] isAttributes = new Boolean[elem.getParameterCount() - offsetSubClass]; + Boolean[] isCaseSensitives = new Boolean[elem.getParameterCount() - offsetSubClass]; + Boolean[] isOptionals = new Boolean[elem.getParameterCount() - offsetSubClass]; + Boolean[] isManageds = new Boolean[elem.getParameterCount() - offsetSubClass]; + + Class[][] clazz = new Class[elem.getParameterCount() - offsetSubClass][]; + String[][] names = new String[elem.getParameterCount() - offsetSubClass][]; Parameter[] params = elem.getParameters(); - for (int iii=offsetSubClass; iii[] types = ReflectTools.getTypeParameterfunction(elem, iii); - clazz[iii-offsetSubClass] = types; - names[iii-offsetSubClass] = namesParam; - if (namesParam != null && namesParam.length != 0 ) { + clazz[iii - offsetSubClass] = types; + names[iii - offsetSubClass] = namesParam; + if (namesParam != null && namesParam.length != 0) { // TODO maybe do something id name is already set ??? - namesBeans[iii-offsetSubClass] = namesParam[0]; + namesBeans[iii - offsetSubClass] = namesParam[0]; } } - if (checkIfOneIsNull(namesBeans,0)) { + if (checkIfOneIsNull(namesBeans, 0)) { Log.verbose(" - " + elem.toGenericString()); Log.verbose(" ==> unmanaged (missing names description: " + Arrays.toString(namesBeans) + ")"); } else { // check default attributes in the global list ... (do it at the end to be sure the constructor is VALID ... - for (int iii=0; iii curentType = prop.getType(); Class curentSubType = prop.getSubType(); if (curentType != clazz[iii][0] && curentSubType != clazz[iii][1]) { - throw new ExmlBuilderException("Set 'return type' with a different value previous=" + curentType.getCanonicalName() + " / " + curentSubType.getCanonicalName() + " ==> new=" + clazz[iii][0] + " / " + clazz[iii][1] + " in " + elem.toGenericString()); + throw new ExmlBuilderException("Set 'return type' with a different value previous=" + curentType.getCanonicalName() + " / " + curentSubType.getCanonicalName() + + " ==> new=" + clazz[iii][0] + " / " + clazz[iii][1] + " in " + elem.toGenericString()); } String[] names1 = names[iii]; if (names1 != null) { @@ -208,7 +150,8 @@ public class IntrospectionModelComplex extends IntrospectionModel { if (isCaseSensitive != null) { Boolean curentValue = prop.isCaseSensitive(); if (curentValue != null && curentValue != isCaseSensitive) { - throw new ExmlBuilderException("Set 'caseSensitive' with a different value previous=" + curentValue + " ==> new=" + isCaseSensitive + " in " + elem.toGenericString()); + throw new ExmlBuilderException( + "Set 'caseSensitive' with a different value previous=" + curentValue + " ==> new=" + isCaseSensitive + " in " + elem.toGenericString()); } prop.setCaseSensitive(isCaseSensitive); } @@ -237,20 +180,14 @@ public class IntrospectionModelComplex extends IntrospectionModel { this.constructorEmpty = emptyConstructorTmp; // Order the constructor from the bigger number of element to the lowest... - Collections.sort(this.constructors, new Comparator() { - @Override - public - int compare(final ConstructorModel a, final ConstructorModel b) { - return a.values().length - b.values().length; - } - }); + Collections.sort(this.constructors, (a, b) -> a.values().length - b.values().length); for (ConstructorModel elem : this.constructors) { Log.verbose(" * " + elem.constructor().toGenericString()); StringBuilder tmpPrint = new StringBuilder(" ==> ("); if (this.isSubClass) { tmpPrint.append("null, "); } - for (int iii=0; iii recordAllPossibleValuesFiltered = new ArrayList<>(); if (isRecord) { for (ConstructorModel elem : this.constructors) { - for (int iii=0; iii curentType = prop.getType(); Class curentSubType = prop.getSubType(); if (curentType != types[0] && curentSubType != types[1]) { - throw new ExmlBuilderException("Set 'return type' with a different value previous=" + curentType.getCanonicalName() + " / " + curentSubType.getCanonicalName() + " ==> new=" + types[0] + " / " + types[1] + " in " + elem.toGenericString()); + throw new ExmlBuilderException("Set 'return type' with a different value previous=" + curentType.getCanonicalName() + " / " + curentSubType.getCanonicalName() + " ==> new=" + + types[0] + " / " + types[1] + " in " + elem.toGenericString()); } String[] names1 = names; if (names1 != null) { @@ -309,7 +247,7 @@ public class IntrospectionModelComplex extends IntrospectionModel { prop.setNames(names1); } } - + final String listName = ReflectTools.getListName(elem, null); if (listName != null) { prop.setListName(listName); @@ -331,8 +269,8 @@ public class IntrospectionModelComplex extends IntrospectionModel { prop.setCaseSensitive(isCaseSensitive); } // generate getter and setter with field. - - IntrospectionPropertyField modifier = new IntrospectionPropertyField(elem); + + IntrospectionPropertyField modifier = new IntrospectionPropertyField(elem); // if the field is final ==> we can not set the value... if (Modifier.isFinal(elem.getModifiers())) { prop.setGetter(modifier); @@ -342,7 +280,7 @@ public class IntrospectionModelComplex extends IntrospectionModel { } Log.verbose(" - " + elem.toGenericString()); } - final Method[] methodsTmp = this.classType.getMethods(); + final Method[] methodsTmp = this.classType.getMethods(); // filter getX setX isX final List methods = List.of(methodsTmp).stream().filter(o -> { if (o.getName().contentEquals("getClass")) { @@ -418,9 +356,8 @@ public class IntrospectionModelComplex extends IntrospectionModel { Log.verbose(" - " + elem.toGenericString()); } - // Separate the methods and filer as: - // - XXX GetXxx(); & XXX != boolean + // - XXX GetXxx(); & XXX != boolean // - void setXxx(XXX elem); // - [bB]oolean isXxx(); // for records: @@ -462,7 +399,7 @@ public class IntrospectionModelComplex extends IntrospectionModel { } // associate methods by pair. for (final Method method : methodsGet) { - final String name = Tools.decapitalizeFirst(isRecord?method.getName():method.getName().substring(3)); + final String name = Tools.decapitalizeFirst(isRecord ? method.getName() : method.getName().substring(3)); IntrospectionProperty prop = updateForMethod(name, method, ReflectTools.getTypeReturnFunction(method)); // generate getter and setter with field. IntrospectionPropertyMethodGetter modifier = new IntrospectionPropertyMethodGetter(method); @@ -516,45 +453,49 @@ public class IntrospectionModelComplex extends IntrospectionModel { // set default name in the list: for (IntrospectionProperty prop : this.elements) { if (prop.getNames() == null) { - prop.setNames(new String[] {prop.getBeanName()}); + prop.setNames(new String[] { prop.getBeanName() }); } } - } catch (Exception ex) { ex.printStackTrace(); throw new ExmlBuilderException("Error in creating introspection data ... " + ex.getMessage()); } - + // Sort the parameters to generate all time the same XML.. - Collections.sort(this.elements, new Comparator() { - @Override - public - int compare(final IntrospectionProperty a, final IntrospectionProperty b) { - return a.getNames()[0].compareTo(b.getNames()[0]); - } - }); - + Collections.sort(this.elements, (a, b) -> a.getNames()[0].compareTo(b.getNames()[0])); + for (IntrospectionProperty prop : this.elements) { - Log.warning("Property/node : " + prop.getBeanName()); - Log.warning(" names: " + Arrays.toString(prop.getNames())); - Log.warning(" list: " + prop.getListName()); - Log.warning(" managed: " + prop.isManaged()); - Log.warning(" attribute: " + prop.isAttribute()); - Log.warning(" case-sensitive: " + prop.isCaseSensitive()); - Log.warning(" optionnal: " + prop.isOptionnal()); - Log.warning(" constructor: " + prop.isCanBeSetByConstructor()); - Log.warning(" get/set: " + prop.canGetValue() + " / " + prop.canSetValue()); - Log.warning(" type: " + prop.getType().getCanonicalName()); + Log.debug("Property/node : " + prop.getBeanName()); + Log.debug(" names: " + Arrays.toString(prop.getNames())); + Log.debug(" list: " + prop.getListName()); + Log.debug(" managed: " + prop.isManaged()); + Log.debug(" attribute: " + prop.isAttribute()); + Log.debug(" case-sensitive: " + prop.isCaseSensitive()); + Log.debug(" optionnal: " + prop.isOptionnal()); + Log.debug(" constructor: " + prop.isCanBeSetByConstructor()); + Log.debug(" get/set: " + prop.canGetValue() + " / " + prop.canSetValue()); + Log.debug(" type: " + prop.getType().getCanonicalName()); if (prop.getSubType() != null) { - Log.warning(" sub-type: " + prop.getSubType().getCanonicalName()); + Log.debug(" sub-type: " + prop.getSubType().getCanonicalName()); } else { - Log.warning(" sub-type: null"); + Log.debug(" sub-type: null"); } - + } } + @SuppressWarnings("unchecked") + private T[] autoCast(final Class clazz, final List data) { + T[] out = (T[]) java.lang.reflect.Array.newInstance(clazz, data.size());// T[data.size()]; + + for (int iii = 0; iii < data.size(); iii++) { + out[iii] = (T) data.get(iii); + } + return out; + //return data.stream().map(clazz::cast).toArray(new T[data.size()]);//java.lang.reflect.Array.newInstance((propMethode.getSubType(), tmpp.size())); + } + private boolean checkIdenticalArray(final String[] valA, final String[] valB) { if (valA == valB) { return true; @@ -562,7 +503,7 @@ public class IntrospectionModelComplex extends IntrospectionModel { if (valA.length != valB.length) { return false; } - for (int iii=0; iii properties, final Map> nodes) throws ExmlBuilderException { + Object tmp = null; + // STEP 1: try to create the object with provided parameter (if a constructor exist....) + if (!this.constructors.isEmpty()) { + Object[] inputs = null; + ConstructorModel betterModel = null; + int lastEmpty = Integer.MAX_VALUE; + // try to find the constructor that fit with parameters ... + for (ConstructorModel elem : this.constructors) { + int offset = this.isSubClass ? 1 : 0; + Object[] inputsTmp = new Object[elem.values().length + offset]; + inputsTmp[0] = null; + int empty = 0; + for (int iii = 0; iii < elem.values().length; iii++) { + Object valueToInject = properties.get(elem.values()[iii]); + if (valueToInject == null) { + List tmppp = nodes.get(elem.values()[iii]); + if (tmppp != null) { + if (List.class == findBeanNodeDescription(elem.values()[iii]).getType()) { + valueToInject = tmppp; + } else if (tmppp.size() >= 1) { + valueToInject = tmppp.get(0); + } + } + } + if (valueToInject == null) { + empty++; + inputsTmp[iii + offset] = null; + continue; + } + inputsTmp[iii + offset] = valueToInject; + } + if (lastEmpty > empty) { + inputs = inputsTmp; + betterModel = elem; + lastEmpty = empty; + } + } + if (betterModel != null) { + if (isDefaultNullValue() || lastEmpty == 0) { + ConstructorModel elem = betterModel; + if (inputs != null) { + // here we find our constructor... + try { + tmp = switch (inputs.length) { + case 0 -> elem.constructor().newInstance(); + case 1 -> elem.constructor().newInstance(inputs[0]); + case 2 -> elem.constructor().newInstance(inputs[0], inputs[1]); + case 3 -> elem.constructor().newInstance(inputs[0], inputs[1], inputs[2]); + case 4 -> elem.constructor().newInstance(inputs[0], inputs[1], inputs[2], inputs[3]); + case 5 -> elem.constructor().newInstance(inputs[0], inputs[1], inputs[2], inputs[3], inputs[4]); + case 6 -> elem.constructor().newInstance(inputs[0], inputs[1], inputs[2], inputs[3], inputs[4], inputs[5]); + case 7 -> elem.constructor().newInstance(inputs[0], inputs[1], inputs[2], inputs[3], inputs[4], inputs[5], inputs[6]); + case 8 -> elem.constructor().newInstance(inputs[0], inputs[1], inputs[2], inputs[3], inputs[4], inputs[5], inputs[6], inputs[7]); + case 9 -> elem.constructor().newInstance(inputs[0], inputs[1], inputs[2], inputs[3], inputs[4], inputs[5], inputs[6], inputs[7], inputs[8]); + case 10 -> elem.constructor().newInstance(inputs[0], inputs[1], inputs[2], inputs[3], inputs[4], inputs[5], inputs[6], inputs[7], inputs[8], inputs[9]); + case 11 -> elem.constructor().newInstance(inputs[0], inputs[1], inputs[2], inputs[3], inputs[4], inputs[5], inputs[6], inputs[7], inputs[8], inputs[9], inputs[10]); + case 12 -> elem.constructor().newInstance(inputs[0], inputs[1], inputs[2], inputs[3], inputs[4], inputs[5], inputs[6], inputs[7], inputs[8], inputs[9], inputs[10], + inputs[11]); + case 13 -> elem.constructor().newInstance(inputs[0], inputs[1], inputs[2], inputs[3], inputs[4], inputs[5], inputs[6], inputs[7], inputs[8], inputs[9], inputs[10], + inputs[11], inputs[12]); + case 14 -> elem.constructor().newInstance(inputs[0], inputs[1], inputs[2], inputs[3], inputs[4], inputs[5], inputs[6], inputs[7], inputs[8], inputs[9], inputs[10], + inputs[11], inputs[12], inputs[13]); + case 15 -> elem.constructor().newInstance(inputs[0], inputs[1], inputs[2], inputs[3], inputs[4], inputs[5], inputs[6], inputs[7], inputs[8], inputs[9], inputs[10], + inputs[11], inputs[12], inputs[13], inputs[14]); + case 16 -> elem.constructor().newInstance(inputs[0], inputs[1], inputs[2], inputs[3], inputs[4], inputs[5], inputs[6], inputs[7], inputs[8], inputs[9], inputs[10], + inputs[11], inputs[12], inputs[13], inputs[14], inputs[15]); + case 17 -> elem.constructor().newInstance(inputs[0], inputs[1], inputs[2], inputs[3], inputs[4], inputs[5], inputs[6], inputs[7], inputs[8], inputs[9], inputs[10], + inputs[11], inputs[12], inputs[13], inputs[14], inputs[15], inputs[16]); + case 18 -> elem.constructor().newInstance(inputs[0], inputs[1], inputs[2], inputs[3], inputs[4], inputs[5], inputs[6], inputs[7], inputs[8], inputs[9], inputs[10], + inputs[11], inputs[12], inputs[13], inputs[14], inputs[15], inputs[16], inputs[17]); + case 19 -> elem.constructor().newInstance(inputs[0], inputs[1], inputs[2], inputs[3], inputs[4], inputs[5], inputs[6], inputs[7], inputs[8], inputs[9], inputs[10], + inputs[11], inputs[12], inputs[13], inputs[14], inputs[15], inputs[16], inputs[17], inputs[18]); + case 20 -> elem.constructor().newInstance(inputs[0], inputs[1], inputs[2], inputs[3], inputs[4], inputs[5], inputs[6], inputs[7], inputs[8], inputs[9], inputs[10], + inputs[11], inputs[12], inputs[13], inputs[14], inputs[15], inputs[16], inputs[17], inputs[18], inputs[19]); + case 21 -> elem.constructor().newInstance(inputs[0], inputs[1], inputs[2], inputs[3], inputs[4], inputs[5], inputs[6], inputs[7], inputs[8], inputs[9], inputs[10], + inputs[11], inputs[12], inputs[13], inputs[14], inputs[15], inputs[16], inputs[17], inputs[18], inputs[19], inputs[20]); + default -> throw new ExmlBuilderException("to much parameter in the constructor... " + inputs.length); + }; + } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + throw new ExmlBuilderException("Error when creating the Object ..." + this.classType.getCanonicalName()); + } + // Remove all previously added parameters + for (int iii = 0; iii < elem.values().length; iii++) { + properties.remove(elem.values()[iii]); + nodes.remove(elem.values()[iii]); + } + } + } + } + } + // STEP 2: If we do not create the object ==> try with empty constructor... + if (tmp == null) { + if (this.constructorEmpty == null) { + throw new ExmlBuilderException("No constructor accessible for class: " + this.classType.getCanonicalName()); + } + try { + if (this.isSubClass) { + Object tmp2 = null; + tmp = this.constructorEmpty.newInstance(tmp2); + } else { + tmp = this.constructorEmpty.newInstance(); + } + } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | SecurityException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + return null; + } + } + // STEP 3: set the rest if the parameters... + for (Entry elem : properties.entrySet()) { + setValue(tmp, elem.getKey(), elem.getValue()); + } + for (Entry> elem : nodes.entrySet()) { + setValue(tmp, elem.getKey(), elem.getValue()); + } + return tmp; + } + + protected IntrospectionProperty findBeanNodeDescription(final String propertyBeanName) throws ExmlBuilderException { + for (final IntrospectionProperty prop : this.elements) { + if (prop.isAttribute()) { + continue; + } + if (prop.getBeanName().equals(propertyBeanName)) { + return prop; + } + } + return null; + } + + protected IntrospectionProperty findBeanPropertyDescription(final String propertyBeanName) throws ExmlBuilderException { + for (final IntrospectionProperty prop : this.elements) { + if (!prop.isAttribute()) { + continue; + } + if (prop.getBeanName().equals(propertyBeanName)) { + return prop; + } + } + return null; + } + + protected IntrospectionProperty findElement(final String beanName) { + for (IntrospectionProperty elem : this.elements) { + if (elem.getBeanName().equals(beanName)) { + return elem; + } + } + return null; + } + + protected IntrospectionProperty findNodeDescription(final String propertyName) throws ExmlBuilderException { + for (final IntrospectionProperty prop : this.elements) { + if (prop.isAttribute()) { + continue; + } + if (prop.isCompatible(propertyName)) { + return prop; + } + } + return null; + } + + protected IntrospectionProperty findPropertyDescription(final String propertyName) throws ExmlBuilderException { + for (final IntrospectionProperty prop : this.elements) { + if (!prop.isAttribute()) { + continue; + } + if (prop.isCompatible(propertyName)) { + return prop; + } + } + return null; + } + + @Override + public List getAttributes() { + List out = new ArrayList<>(); + for (IntrospectionProperty elem : this.elements) { + if (elem.isAttribute()) { + out.add(elem); + } + } + return out; + } + + @Override + public String getBeanName(final String nodeName) { + for (IntrospectionProperty elem : this.elements) { + if (elem.isCompatible(nodeName)) { + return elem.getBeanName(); + } + } + return null; + } + + @Override + public List getNodeAvaillable() { + List out = new ArrayList<>(); + for (final IntrospectionProperty prop : this.elements) { + if (prop.isAttribute()) { + continue; + } + out.add(prop.getNames()[0]); + } + return out; + } + + @Override + public List getNodes() { + List out = new ArrayList<>(); + for (IntrospectionProperty elem : this.elements) { + if (!elem.isAttribute()) { + out.add(elem); + } + } + return out; + } + + @Override + public String getTreeNameOfSubNode(final String nodeBeanName) throws ExmlBuilderException { + Log.debug(" nodeType='" + nodeBeanName + "'"); + final IntrospectionProperty propMethode = findBeanNodeDescription(nodeBeanName); + if (propMethode != null && propMethode.canSetValue()) { + Log.debug(" ==> find '" + propMethode.getNames()); + return propMethode.getListName(); + } + throw new ExmlBuilderException("can not find the field '" + nodeBeanName + "'"); + } + + @Override + public Class getTypeOfProperty(final String nodeName) throws ExmlBuilderException { + Log.debug("nodeType='" + nodeName + "'"); + final IntrospectionProperty propField = findPropertyDescription(nodeName); + if (propField != null && propField.canSetValue()) { + Log.debug(" ==> find '" + propField.getNames()); + return propField.getType(); + } + + throw new ExmlBuilderException("can not find the field '" + nodeName + "' availlable: " + getNodeAvaillable()); + } + + /** + * Detect a subNode, and ask the type of the node at the parent Class + * @param nodeBeanName Name of the node (bean name access ==> not the XML name) + * @return Class of the node to create + */ + @Override + public Class getTypeOfSubNode(final String nodeBeanName) throws ExmlBuilderException { + Log.debug(" nodeType='" + nodeBeanName + "'"); + final IntrospectionProperty propMethode = findBeanNodeDescription(nodeBeanName); + if (propMethode != null && propMethode.canSetValue()) { + Log.debug(" ==> find '" + propMethode.getNames()); + return propMethode.getType(); + } + throw new ExmlBuilderException("can not find the field '" + nodeBeanName + "' availlable: " + getNodeAvaillable()); + } + + @Override + public Class getTypeOfSubNodeList(final String nodeBeanName) throws ExmlBuilderException { + Log.debug(" nodeType='" + nodeBeanName + "'"); + final IntrospectionProperty propMethode = findBeanNodeDescription(nodeBeanName); + if (propMethode != null && propMethode.canSetValue()) { + Log.debug(" ==> find '" + propMethode.getNames()); + return propMethode.getSubType(); + } + throw new ExmlBuilderException("can not find the field '" + nodeBeanName + "' availlable: " + getNodeAvaillable()); + } + + @Override + public Class getTypeOfSubProperty(final String nodeName) throws ExmlBuilderException { + Log.debug(" nodeType='" + nodeName + "'"); + final IntrospectionProperty propField = findPropertyDescription(nodeName); + if (propField != null && propField.canSetValue()) { + Log.debug(" ==> find '" + propField.getNames()); + return propField.getSubType(); + } + throw new ExmlBuilderException("can not find the field '" + nodeName + "' availlable: " + getNodeAvaillable()); + } + + @Override + public Object getValue(final String propertyName, final String propertyValue) throws ExmlBuilderException { + Log.debug(" propertyName='" + propertyName + "' propertyValue='" + propertyValue + "' "); + // by default use setter to set the property + final IntrospectionProperty propMethode = findNodeDescription(propertyName); + if (propMethode != null && propMethode.canSetValue()) { + Log.verbose(" ==> find '" + propMethode.getNames()); + return propMethode.createValue(propertyValue); + } + // try with direct field + final IntrospectionProperty propField = findPropertyDescription(propertyName); + if (propField != null && propField.canSetValue()) { + Log.verbose(" ==> find '" + propField.getNames()); + return propField.createValue(propertyValue); + } + throw new ExmlBuilderException("can not find the field '" + propertyName + "'"); + } + + @Override + 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... + Class classTypeLocal = this.classType; + Log.debug("======>>>>>>> Get input type : " + this.classType.getCanonicalName()); + //Log.debug("======>>>>>>> Get input component type : " + this.classType.getComponentType().getCanonicalName()); + if (this.classType.isArray()) { + // generic array ... + classTypeLocal = this.classType.getComponentType(); + } else if (List.class == this.classType || Collection.class.isAssignableFrom(this.classType)) { + // a generic list .... + /*if (this.subClassType != null) { + classTypeLocal = this.subClassType; + }*/ + //Type[] tmpp = this.classType.getGenericInterfaces(); + //Class[] tmpp = this.classType.getNestMembers(); + //Class[] tmpp = this.classType.getClasses(); + //Class[] tmpp = this.classType.getDeclaredClasses(); + //Class[] tmpp = this.classType.getInterfaces(); + //Class tmpp = this.classType.getDeclaringClass(); + //TypeVariable[] tmpp = this.classType.getTypeParameters(); + /* + Class persistentClass =((ParameterizedType)classType.getGenericSuperclass()).getActualTypeArguments()[0]; + */ + //Type tmpp = classType.getGenericSuperclass(); + // Class tmpp = classType.getInterfaces(); + // Log.warning("======>>>>>>> Find List '" + tmpp + "'"); + // for (int iii = 0; iii < tmpp.length; iii++) { + // Log.warning(" - " + tmpp[iii]); + // } + } + Log.debug("======>>>>>>> subElement input type : " + classTypeLocal.getCanonicalName()); + + if (this.valueof == null) { + if (StringSerializer.contains(classTypeLocal)) { + throw new ExmlBuilderException("function 'valueOf' for '" + classTypeLocal.getCanonicalName() + "' is not defined and not registered for specific type"); + } + return StringSerializer.valueOf(classTypeLocal, text); + } + try { + return this.valueof.invoke(null, text); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + 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(); + throw new ExmlBuilderException("Error in call 'valueOf(String ...)' for '" + classTypeLocal.getCanonicalName() + "' " + e.getMessage()); + } + } + + @Override + public boolean isNative() { + return false; + } + + private void setValue(final Object data, final String beanName, final Object value) throws ExmlBuilderException { + Log.error(" Set value ='" + beanName + "' propertyValue='" + value + "' " + value.getClass().getCanonicalName()); + { + // by default use setter to set the property + final IntrospectionProperty propMethode = findBeanNodeDescription(beanName); + if (propMethode != null && propMethode.canSetValue()) { + Log.verbose(" ==> find '" + Arrays.toString(propMethode.getNames()) + " type=" + propMethode.getType() + " sub-type=" + propMethode.getSubType()); + if (propMethode.getType().isAssignableFrom(value.getClass())) { + propMethode.setExistingValue(data, value); + } else if (value instanceof List) { + @SuppressWarnings("unchecked") + List tmpp = (List) value; + if (propMethode.getType().isArray()) { + if (propMethode.getType().componentType().isPrimitive()) { + Object newData = ArraysTools.listToPrimitiveAuto(propMethode.getType().componentType(), tmpp); + propMethode.setExistingValue(data, newData); + } else { + Log.verbose(" datas type: " + autoCast(propMethode.getType().componentType(), tmpp).getClass().getCanonicalName()); + Log.verbose(" methode type: " + propMethode.getType().getCanonicalName()); + propMethode.setExistingValue(data, autoCast(propMethode.getType().componentType(), tmpp)); + } + } else if (tmpp.size() == 1) { + propMethode.setExistingValue(data, tmpp.get(0)); + } else { + // impossible case ... + } + } 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 if (propMethode.getType() == float.class) { + float dataPrimitive = (Float) value; + propMethode.setExistingValue(data, dataPrimitive); + } else if (propMethode.getType() == double.class) { + double dataPrimitive = (Double) value; + propMethode.setExistingValue(data, dataPrimitive); + } else { + + } + return; + } + } + // try with direct field + { + final IntrospectionProperty propField = findBeanPropertyDescription(beanName); + if (propField != null && propField.canSetValue()) { + Log.verbose(" ==> find '" + Arrays.toString(propField.getNames()) + " type=" + propField.getType() + " sub-type=" + propField.getSubType()); + if (propField.getType().isAssignableFrom(value.getClass())) { + 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() == float.class) { + float dataPrimitive = (Float) value; + propField.setExistingValue(data, dataPrimitive); + } else if (propField.getType() == double.class) { + Double dataPrimitive = (Double) value; + propField.setExistingValue(data, dataPrimitive); + } else if (propField.getType() == boolean.class) { + boolean dataPrimitive = (Boolean) value; + propField.setExistingValue(data, dataPrimitive); + } else { + @SuppressWarnings("unchecked") + List tmpp = (List) 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 if (propField.getType().componentType() == float.class) { + float[] datas = ArraysTools.listFloatToPrimitive(tmpp); + propField.setExistingValue(data, datas); + } else if (propField.getType().componentType() == double.class) { + double[] datas = ArraysTools.listDoubleToPrimitive(tmpp); + propField.setExistingValue(data, datas); + } else { + Log.verbose(" datas type: " + autoCast(propField.getType().componentType(), tmpp).getClass().getCanonicalName()); + Log.verbose(" methode type: " + propField.getType().getCanonicalName()); + propField.setExistingValue(data, autoCast(propField.getType().componentType(), tmpp)); + } + } else if (tmpp.size() == 1) { + propField.setExistingValue(data, tmpp.get(0)); + } else { + // impossible case ... + } + } + return; + } + } + throw new ExmlBuilderException("can not find the field '" + beanName + "'"); + } + + @Override + public String toString(final Object data) throws ExmlBuilderException { + if (this.tostring == null) { + if (StringSerializer.contains(this.classType)) { + throw new ExmlBuilderException("function 'toString' for '" + this.classType.getCanonicalName() + "' is not defined and not registered for specific type"); + } + return StringSerializer.toString(data); + } + try { + return (String) this.tostring.invoke(data); + } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { + if (Enum.class.isAssignableFrom(this.classType)) { + throw new ExmlBuilderException( + "Error in call 'toString()' for '" + this.classType.getCanonicalName() + "' ==> '????' ... availlable list: " + Arrays.asList(this.classType.getEnumConstants())); + } + e.printStackTrace(); + throw new ExmlBuilderException("Error in call 'toString()' for '" + this.classType.getCanonicalName() + "' " + e.getMessage()); + } + } + private IntrospectionProperty updateForMethod(final String name, final Method method, final Class[] types) throws Exception { IntrospectionProperty prop = findElement(name); if (prop == null) { String[] names = ReflectTools.getNames(method, null); prop = new IntrospectionProperty(name, types, names); - this.elements.add(prop); + this.elements.add(prop); } else { Class curentType = prop.getType(); Class curentSubType = prop.getSubType(); if (curentType != types[0] && curentSubType != types[1]) { - throw new ExmlBuilderException("Set 'return type' with a different value previous=" + curentType.getCanonicalName() + " / " + curentSubType.getCanonicalName() + " ==> new=" + types[0] + " / " + types[1] + " in " + method.toGenericString()); + throw new ExmlBuilderException("Set 'return type' with a different value previous=" + curentType.getCanonicalName() + " / " + curentSubType.getCanonicalName() + " ==> new=" + types[0] + + " / " + types[1] + " in " + method.toGenericString()); } String[] names = ReflectTools.getNames(method, null); if (names != null) { String[] curentValue = prop.getNames(); - if (curentValue != null && !checkIdenticalArray(curentValue,names)) { + if (curentValue != null && !checkIdenticalArray(curentValue, names)) { // TODO maybe set the value permissive if no change !!! like the others... throw new ExmlBuilderException("Set 'names' with a (already set!) " + method.toGenericString()); } @@ -634,464 +1095,4 @@ public class IntrospectionModelComplex extends IntrospectionModel { } return prop; } - - @Override - public Object createObject(final Map properties, final Map> nodes) throws ExmlBuilderException { - Object tmp = null; - // STEP 1: try to create the object with provided parameter (if a constructor exist....) - if (!this.constructors.isEmpty()) { - Object[] inputs = null; - ConstructorModel betterModel = null; - int lastEmpty = Integer.MAX_VALUE; - // try to find the constructor that fit with parameters ... - for (ConstructorModel elem : this.constructors) { - int offset = this.isSubClass?1:0; - Object[] inputsTmp = new Object[elem.values().length+offset]; - inputsTmp[0] = null; - int empty = 0; - for (int iii=0; iii tmppp = nodes.get(elem.values()[iii]); - if (tmppp != null) { - if (List.class == findBeanNodeDescription(elem.values()[iii]).getType() ) { - valueToInject = tmppp; - } else if (tmppp.size() >=1) { - valueToInject = tmppp.get(0); - } - } - } - if (valueToInject == null) { - empty++; - inputsTmp[iii+offset] = null; - continue; - } - inputsTmp[iii+offset] = valueToInject; - } - if (lastEmpty > empty) { - inputs = inputsTmp; - betterModel = elem; - lastEmpty = empty; - } - } - if (betterModel != null) { - if (isDefaultNullValue() || lastEmpty == 0) { - ConstructorModel elem = betterModel; - if (inputs != null) { - // here we find our constructor... - try { - switch(inputs.length) { - case 0: tmp = elem.constructor().newInstance(); break; - case 1: tmp = elem.constructor().newInstance(inputs[0]); break; - case 2: tmp = elem.constructor().newInstance(inputs[0],inputs[1]); break; - case 3: tmp = elem.constructor().newInstance(inputs[0],inputs[1],inputs[2]); break; - case 4: tmp = elem.constructor().newInstance(inputs[0],inputs[1],inputs[2],inputs[3]); break; - case 5: tmp = elem.constructor().newInstance(inputs[0],inputs[1],inputs[2],inputs[3],inputs[4]); break; - case 6: tmp = elem.constructor().newInstance(inputs[0],inputs[1],inputs[2],inputs[3],inputs[4],inputs[5]); break; - case 7: tmp = elem.constructor().newInstance(inputs[0],inputs[1],inputs[2],inputs[3],inputs[4],inputs[5],inputs[6]); break; - case 8: tmp = elem.constructor().newInstance(inputs[0],inputs[1],inputs[2],inputs[3],inputs[4],inputs[5],inputs[6],inputs[7]); break; - case 9: tmp = elem.constructor().newInstance(inputs[0],inputs[1],inputs[2],inputs[3],inputs[4],inputs[5],inputs[6],inputs[7],inputs[8]); break; - case 10: tmp = elem.constructor().newInstance(inputs[0],inputs[1],inputs[2],inputs[3],inputs[4],inputs[5],inputs[6],inputs[7],inputs[8],inputs[9]); break; - case 11: tmp = elem.constructor().newInstance(inputs[0],inputs[1],inputs[2],inputs[3],inputs[4],inputs[5],inputs[6],inputs[7],inputs[8],inputs[9],inputs[10]); break; - case 12: tmp = elem.constructor().newInstance(inputs[0],inputs[1],inputs[2],inputs[3],inputs[4],inputs[5],inputs[6],inputs[7],inputs[8],inputs[9],inputs[10],inputs[11]); break; - case 13: tmp = elem.constructor().newInstance(inputs[0],inputs[1],inputs[2],inputs[3],inputs[4],inputs[5],inputs[6],inputs[7],inputs[8],inputs[9],inputs[10],inputs[11],inputs[12]); break; - case 14: tmp = elem.constructor().newInstance(inputs[0],inputs[1],inputs[2],inputs[3],inputs[4],inputs[5],inputs[6],inputs[7],inputs[8],inputs[9],inputs[10],inputs[11],inputs[12],inputs[13]); break; - case 15: tmp = elem.constructor().newInstance(inputs[0],inputs[1],inputs[2],inputs[3],inputs[4],inputs[5],inputs[6],inputs[7],inputs[8],inputs[9],inputs[10],inputs[11],inputs[12],inputs[13],inputs[14]); break; - case 16: tmp = elem.constructor().newInstance(inputs[0],inputs[1],inputs[2],inputs[3],inputs[4],inputs[5],inputs[6],inputs[7],inputs[8],inputs[9],inputs[10],inputs[11],inputs[12],inputs[13],inputs[14],inputs[15]); break; - case 17: tmp = elem.constructor().newInstance(inputs[0],inputs[1],inputs[2],inputs[3],inputs[4],inputs[5],inputs[6],inputs[7],inputs[8],inputs[9],inputs[10],inputs[11],inputs[12],inputs[13],inputs[14],inputs[15],inputs[16]); break; - case 18: tmp = elem.constructor().newInstance(inputs[0],inputs[1],inputs[2],inputs[3],inputs[4],inputs[5],inputs[6],inputs[7],inputs[8],inputs[9],inputs[10],inputs[11],inputs[12],inputs[13],inputs[14],inputs[15],inputs[16],inputs[17]); break; - case 19: tmp = elem.constructor().newInstance(inputs[0],inputs[1],inputs[2],inputs[3],inputs[4],inputs[5],inputs[6],inputs[7],inputs[8],inputs[9],inputs[10],inputs[11],inputs[12],inputs[13],inputs[14],inputs[15],inputs[16],inputs[17],inputs[18]); break; - case 20: tmp = elem.constructor().newInstance(inputs[0],inputs[1],inputs[2],inputs[3],inputs[4],inputs[5],inputs[6],inputs[7],inputs[8],inputs[9],inputs[10],inputs[11],inputs[12],inputs[13],inputs[14],inputs[15],inputs[16],inputs[17],inputs[18],inputs[19]); break; - case 21: tmp = elem.constructor().newInstance(inputs[0],inputs[1],inputs[2],inputs[3],inputs[4],inputs[5],inputs[6],inputs[7],inputs[8],inputs[9],inputs[10],inputs[11],inputs[12],inputs[13],inputs[14],inputs[15],inputs[16],inputs[17],inputs[18],inputs[19],inputs[20]); break; - default: - //tmp = elem.constructor().newInstance(new Object[] {inputs}); break; - throw new ExmlBuilderException("to much parameter in the constructor... " + inputs.length); - } - //tmp = elem.constructor().newInstance(inputs); - } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - throw new ExmlBuilderException("Error when creating the Object ..." + this.classType.getCanonicalName()); - } - // Remove all previously added parameters - for (int iii=0; iii try with empty constructor... - if (tmp == null) { - if (this.constructorEmpty == null) { - throw new ExmlBuilderException("No constructor accessible for class: " + this.classType.getCanonicalName()); - } - try { - if (this.isSubClass) { - Object tmp2 = null; - tmp = this.constructorEmpty.newInstance(tmp2); - } else { - tmp = this.constructorEmpty.newInstance(); - } - } catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | SecurityException e) { - // TODO Auto-generated catch block - e.printStackTrace(); - return null; - } - } - // STEP 3: set the rest if the parameters... - for (Entry elem : properties.entrySet()) { - setValue(tmp, elem.getKey(), elem.getValue()); - } - for (Entry> elem : nodes.entrySet()) { - setValue(tmp, elem.getKey(), elem.getValue()); - } - return tmp; - } - - - @Override - public List getNodeAvaillable() { - List out = new ArrayList<>(); - for (final IntrospectionProperty prop : this.elements) { - if (prop.isAttribute()) { - continue; - } - out.add(prop.getNames()[0]); - } - return out; - } - protected IntrospectionProperty findBeanNodeDescription(final String propertyBeanName) throws ExmlBuilderException { - for (final IntrospectionProperty prop : this.elements) { - if (prop.isAttribute()) { - continue; - } - if (prop.getBeanName().equals(propertyBeanName)) { - return prop; - } - } - return null; - } - - protected IntrospectionProperty findBeanPropertyDescription(final String propertyBeanName) throws ExmlBuilderException { - for (final IntrospectionProperty prop : this.elements) { - if (!prop.isAttribute()) { - continue; - } - if (prop.getBeanName().equals(propertyBeanName)) { - return prop; - } - } - return null; - } - protected IntrospectionProperty findNodeDescription(final String propertyName) throws ExmlBuilderException { - for (final IntrospectionProperty prop : this.elements) { - if (prop.isAttribute()) { - continue; - } - if (prop.isCompatible(propertyName)) { - return prop; - } - } - return null; - } - - protected IntrospectionProperty findPropertyDescription(final String propertyName) throws ExmlBuilderException { - for (final IntrospectionProperty prop : this.elements) { - if (!prop.isAttribute()) { - continue; - } - if (prop.isCompatible(propertyName)) { - return prop; - } - } - return null; - } - - @SuppressWarnings("unchecked") - private T[] autoCast(final Class clazz, final List data) { - T[] out = (T[]) java.lang.reflect.Array.newInstance(clazz, data.size());// T[data.size()]; - - for(int iii=0; iii find '" + Arrays.toString(propMethode.getNames()) + " type=" + propMethode.getType() + " sub-type=" + propMethode.getSubType() ); - if (propMethode.getType().isAssignableFrom(value.getClass())) { - propMethode.setExistingValue(data, value); - } else if (value instanceof List){ - @SuppressWarnings("unchecked") - List tmpp = (List)value; - if (propMethode.getType().isArray()) { - if (propMethode.getType().componentType().isPrimitive()) { - Object newData = ArraysTools.listToPrimitiveAuto(propMethode.getType().componentType(), tmpp); - propMethode.setExistingValue(data, newData); - } else { - Log.verbose(" datas type: " + autoCast(propMethode.getType().componentType(), tmpp).getClass().getCanonicalName()); - Log.verbose(" methode type: " + propMethode.getType().getCanonicalName()); - propMethode.setExistingValue(data, autoCast(propMethode.getType().componentType(), tmpp)); - } - } else if (tmpp.size() == 1) { - propMethode.setExistingValue(data, tmpp.get(0)); - } else { - // impossible case ... - } - } 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 if (propMethode.getType() == float.class) { - float dataPrimitive = (Float)value; - propMethode.setExistingValue(data, dataPrimitive); - } else if (propMethode.getType() == double.class) { - double dataPrimitive = (Double)value; - propMethode.setExistingValue(data, dataPrimitive); - } else { - - } - return; - } - } - // try with direct field - { - final IntrospectionProperty propField = findBeanPropertyDescription(beanName); - if (propField != null && propField.canSetValue()) { - Log.verbose(" ==> find '" + Arrays.toString(propField.getNames()) + " type=" + propField.getType() + " sub-type=" + propField.getSubType() ); - if (propField.getType().isAssignableFrom(value.getClass())) { - 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() == float.class) { - float dataPrimitive = (Float)value; - propField.setExistingValue(data, dataPrimitive); - } else if (propField.getType() == double.class) { - Double dataPrimitive = (Double)value; - propField.setExistingValue(data, dataPrimitive); - } else if (propField.getType() == boolean.class) { - boolean dataPrimitive = (Boolean)value; - propField.setExistingValue(data, dataPrimitive); - } else { - @SuppressWarnings("unchecked") - List tmpp = (List)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 if (propField.getType().componentType() == float.class) { - float[] datas = ArraysTools.listFloatToPrimitive(tmpp); - propField.setExistingValue(data, datas); - } else if (propField.getType().componentType() == double.class) { - double[] datas = ArraysTools.listDoubleToPrimitive(tmpp); - propField.setExistingValue(data, datas); - } else { - Log.verbose(" datas type: " + autoCast(propField.getType().componentType(), tmpp).getClass().getCanonicalName()); - Log.verbose(" methode type: " + propField.getType().getCanonicalName()); - propField.setExistingValue(data, autoCast(propField.getType().componentType(), tmpp)); - } - } else if (tmpp.size() == 1) { - propField.setExistingValue(data, tmpp.get(0)); - } else { - // impossible case ... - } - } - return; - } - } - throw new ExmlBuilderException("can not find the field '" + beanName + "'"); - } - - /** - * Detect a subNode, and ask the type of the node at the parent Class - * @param nodeBeanName Name of the node (bean name access ==> not the XML name) - * @return Class of the node to create - */ - @Override - public Class getTypeOfSubNode(final String nodeBeanName) throws ExmlBuilderException { - Log.error(" nodeType='" + nodeBeanName + "'"); - final IntrospectionProperty propMethode = findBeanNodeDescription(nodeBeanName); - if (propMethode != null && propMethode.canSetValue()) { - Log.error(" ==> find '" + propMethode.getNames()); - return propMethode.getType(); - } - throw new ExmlBuilderException("can not find the field '" + nodeBeanName + "' availlable: " + getNodeAvaillable()); - } - @Override - public Class getTypeOfSubNodeList(final String nodeBeanName) throws ExmlBuilderException { - Log.error(" nodeType='" + nodeBeanName + "'"); - final IntrospectionProperty propMethode = findBeanNodeDescription(nodeBeanName); - if (propMethode != null && propMethode.canSetValue()) { - Log.error(" ==> find '" + propMethode.getNames()); - return propMethode.getSubType(); - } - throw new ExmlBuilderException("can not find the field '" + nodeBeanName + "' availlable: " + getNodeAvaillable()); - } - @Override - public String getTreeNameOfSubNode(final String nodeBeanName) throws ExmlBuilderException { - Log.error(" nodeType='" + nodeBeanName + "'"); - final IntrospectionProperty propMethode = findBeanNodeDescription(nodeBeanName); - if (propMethode != null && propMethode.canSetValue()) { - Log.error(" ==> find '" + propMethode.getNames()); - return propMethode.getListName(); - } - throw new ExmlBuilderException("can not find the field '" + nodeBeanName + "'"); - } - - - @Override - public Class getTypeOfProperty(final String nodeName) throws ExmlBuilderException { - Log.error("nodeType='" + nodeName + "'"); - final IntrospectionProperty propField = findPropertyDescription(nodeName); - if (propField != null && propField.canSetValue()) { - Log.error(" ==> find '" + propField.getNames()); - return propField.getType(); - } - - throw new ExmlBuilderException("can not find the field '" + nodeName + "' availlable: " + getNodeAvaillable()); - } - @Override - public Class getTypeOfSubProperty(final String nodeName) throws ExmlBuilderException { - Log.error(" nodeType='" + nodeName + "'"); - final IntrospectionProperty propField = findPropertyDescription(nodeName); - if (propField != null && propField.canSetValue()) { - Log.error(" ==> find '" + propField.getNames()); - return propField.getSubType(); - } - throw new ExmlBuilderException("can not find the field '" + nodeName + "' availlable: " + getNodeAvaillable()); - } - - - @Override - 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... - Class classTypeLocal = this.classType; - Log.warning("======>>>>>>> Get input type : " + this.classType.getCanonicalName()); - //Log.warning("======>>>>>>> Get input component type : " + this.classType.getComponentType().getCanonicalName()); - if (this.classType.isArray()){ - // generic array ... - classTypeLocal = this.classType.getComponentType(); - } else if (List.class == this.classType || Collection.class.isAssignableFrom(this.classType)) { - // a generic list .... - /*if (this.subClassType != null) { - classTypeLocal = this.subClassType; - }*/ - //Type[] tmpp = this.classType.getGenericInterfaces(); - //Class[] tmpp = this.classType.getNestMembers(); - //Class[] tmpp = this.classType.getClasses(); - //Class[] tmpp = this.classType.getDeclaredClasses(); - //Class[] tmpp = this.classType.getInterfaces(); - //Class tmpp = this.classType.getDeclaringClass(); - //TypeVariable[] tmpp = this.classType.getTypeParameters(); - /* - Class persistentClass =((ParameterizedType)classType.getGenericSuperclass()).getActualTypeArguments()[0]; - */ - //Type tmpp = classType.getGenericSuperclass(); -// Class tmpp = classType.getInterfaces(); -// Log.warning("======>>>>>>> Find List '" + tmpp + "'"); -// for (int iii = 0; iii < tmpp.length; iii++) { -// Log.warning(" - " + tmpp[iii]); -// } - } - Log.warning("======>>>>>>> subElement input type : " + classTypeLocal.getCanonicalName()); - - if (this.valueof == null) { - if (StringSerializer.contains(classTypeLocal)) { - throw new ExmlBuilderException("function 'valueOf' for '" + classTypeLocal.getCanonicalName() + "' is not defined and not registered for specific type"); - } - return StringSerializer.valueOf(classTypeLocal, text); - } - try { - return this.valueof.invoke(null, text); - } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { - 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(); - throw new ExmlBuilderException("Error in call 'valueOf(String ...)' for '" + classTypeLocal.getCanonicalName() + "' " + e.getMessage()); - } - } - - @Override - public Object getValue(final String propertyName, final String propertyValue) throws ExmlBuilderException { - Log.error(" propertyName='" + propertyName + "' propertyValue='" + propertyValue + "' "); - // by default use setter to set the property - final IntrospectionProperty propMethode = findNodeDescription(propertyName); - if (propMethode != null && propMethode.canSetValue()) { - Log.verbose(" ==> find '" + propMethode.getNames()); - return propMethode.createValue(propertyValue); - } - // try with direct field - final IntrospectionProperty propField = findPropertyDescription(propertyName); - if (propField != null && propField.canSetValue()) { - Log.verbose(" ==> find '" + propField.getNames()); - return propField.createValue(propertyValue); - } - throw new ExmlBuilderException("can not find the field '" + propertyName + "'"); - } - @Override - public boolean isNative() { - return false; - } - @Override - public String toString(final Object data) throws ExmlBuilderException { - if (this.tostring == null) { - if (StringSerializer.contains(this.classType)) { - throw new ExmlBuilderException("function 'toString' for '" + this.classType.getCanonicalName() + "' is not defined and not registered for specific type"); - } - return StringSerializer.toString(data); - } - try { - return (String) this.tostring.invoke(data); - } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) { - if (Enum.class.isAssignableFrom(this.classType)) { - throw new ExmlBuilderException("Error in call 'toString()' for '" + this.classType.getCanonicalName() + "' ==> '????' ... availlable list: " + Arrays.asList(this.classType.getEnumConstants())); - } - e.printStackTrace(); - throw new ExmlBuilderException("Error in call 'toString()' for '" + this.classType.getCanonicalName() + "' " + e.getMessage()); - } - } } - diff --git a/src/org/atriasoft/exml/builder/IntrospectionObject.java b/src/org/atriasoft/exml/builder/IntrospectionObject.java index 29be918..75e3620 100644 --- a/src/org/atriasoft/exml/builder/IntrospectionObject.java +++ b/src/org/atriasoft/exml/builder/IntrospectionObject.java @@ -20,80 +20,7 @@ public class IntrospectionObject { public IntrospectionObject(final IntrospectionModel dataInterface) { this.modelInterface = dataInterface; } - - public Object getData() { - return this.data; - } - public IntrospectionModel getModelIntrospection() { - return this.modelInterface; - } - - public void putProperty(final String propertyName, final Object propertyValue) throws ExmlException { - final String beanName = this.modelInterface.getBeanName(propertyName); - if (this.properties.containsKey(beanName)) { - throw new ExmlBuilderException("Property have multiple values ==> impossible case; A Node must contain only 1 attibutes"); - } - this.properties.put(beanName, propertyValue); - } - - public boolean isSubNodeOrPropertyExist(final String nodeName) { - final String beanName = this.modelInterface.getBeanName(nodeName); - if (beanName == null) { - return false; - } - return true; - } - - /** - * Detect a subNode, and ask the type of the node at the parent Class - * @param nodeName Name of the node - * @return Class of the node to create - */ - public Class getTypeOfSubNode(final String nodeName) throws ExmlException { - final String beanName = this.modelInterface.getBeanName(nodeName); - if (beanName == null) { - throw new ExmlNodeDoesNotExist("The node '" + nodeName + "' Does not exist..."); - } - return this.modelInterface.getTypeOfSubNode(beanName); - } - public Class getTypeOfSubNodeSubType(final String nodeName) throws ExmlException { - final String beanName = this.modelInterface.getBeanName(nodeName); - if (beanName == null) { - throw new ExmlNodeDoesNotExist("The node '" + nodeName + "' Does not exist..."); - } - return this.modelInterface.getTypeOfSubNodeList(beanName); - } - public String getTreeNameOfSubNode(final String nodeName) throws ExmlException { - final String beanName = this.modelInterface.getBeanName(nodeName); - if (beanName == null) { - throw new ExmlNodeDoesNotExist("The node '" + nodeName + "' Does not exist..."); - } - return this.modelInterface.getTreeNameOfSubNode(beanName); - } - - public Class getTypeOfProperty(final String nodeName) throws ExmlException { - final String beanName = this.modelInterface.getBeanName(nodeName); - if (beanName == null) { - throw new ExmlNodeDoesNotExist("The node '" + nodeName + "' Does not exist..."); - } - return this.modelInterface.getTypeOfProperty(beanName); - } - public Class getTypeOfSubProperty(final String nodeName) throws ExmlException { - final String beanName = this.modelInterface.getBeanName(nodeName); - if (beanName == null) { - throw new ExmlNodeDoesNotExist("The node '" + nodeName + "' Does not exist..."); - } - return this.modelInterface.getTypeOfSubProperty(beanName); - } - - public void setText(final String text) throws ExmlBuilderException { - if (this.data != null) { - throw new ExmlBuilderException("Can not set multiple text value in a single NODE ..."); - } - this.data = this.modelInterface.getValueFromText(text); - } - @SuppressWarnings("unchecked") public void addObject(final String nodeName, final Object value) throws ExmlException { if (value == null) { @@ -148,10 +75,87 @@ public class IntrospectionObject { // nothing to do ... ==> element already created return; } - Log.info("Create the element for the Specific node ... type = " + this.modelInterface.getClassType().getCanonicalName() + (this.modelInterface.isArray()?"[array]":"") + (this.modelInterface.isList()?"[List]":"")); - Log.info(" Properties : " + this.properties.keySet()); - Log.info(" Nodes : " + this.nodes.keySet()); - this.data = this.modelInterface.createObject(this.properties, this.nodes); + Log.debug("Create the element for the Specific node ... type = " + this.modelInterface.getClassType().getCanonicalName() + (this.modelInterface.isArray() ? "[array]" : "") + + (this.modelInterface.isList() ? "[List]" : "")); + Log.debug(" Properties : " + this.properties.keySet()); + Log.debug(" Nodes : " + this.nodes.keySet()); + this.data = this.modelInterface.createObject(this.properties, this.nodes); } - + + public Object getData() { + return this.data; + } + + public IntrospectionModel getModelIntrospection() { + return this.modelInterface; + } + + public String getTreeNameOfSubNode(final String nodeName) throws ExmlException { + final String beanName = this.modelInterface.getBeanName(nodeName); + if (beanName == null) { + throw new ExmlNodeDoesNotExist("The node '" + nodeName + "' Does not exist..."); + } + return this.modelInterface.getTreeNameOfSubNode(beanName); + } + + public Class getTypeOfProperty(final String nodeName) throws ExmlException { + final String beanName = this.modelInterface.getBeanName(nodeName); + if (beanName == null) { + throw new ExmlNodeDoesNotExist("The node '" + nodeName + "' Does not exist..."); + } + return this.modelInterface.getTypeOfProperty(beanName); + } + + /** + * Detect a subNode, and ask the type of the node at the parent Class + * @param nodeName Name of the node + * @return Class of the node to create + */ + public Class getTypeOfSubNode(final String nodeName) throws ExmlException { + final String beanName = this.modelInterface.getBeanName(nodeName); + if (beanName == null) { + throw new ExmlNodeDoesNotExist("The node '" + nodeName + "' Does not exist..."); + } + return this.modelInterface.getTypeOfSubNode(beanName); + } + + public Class getTypeOfSubNodeSubType(final String nodeName) throws ExmlException { + final String beanName = this.modelInterface.getBeanName(nodeName); + if (beanName == null) { + throw new ExmlNodeDoesNotExist("The node '" + nodeName + "' Does not exist..."); + } + return this.modelInterface.getTypeOfSubNodeList(beanName); + } + + public Class getTypeOfSubProperty(final String nodeName) throws ExmlException { + final String beanName = this.modelInterface.getBeanName(nodeName); + if (beanName == null) { + throw new ExmlNodeDoesNotExist("The node '" + nodeName + "' Does not exist..."); + } + return this.modelInterface.getTypeOfSubProperty(beanName); + } + + public boolean isSubNodeOrPropertyExist(final String nodeName) { + final String beanName = this.modelInterface.getBeanName(nodeName); + if (beanName == null) { + return false; + } + return true; + } + + public void putProperty(final String propertyName, final Object propertyValue) throws ExmlException { + final String beanName = this.modelInterface.getBeanName(propertyName); + if (this.properties.containsKey(beanName)) { + throw new ExmlBuilderException("Property have multiple values ==> impossible case; A Node must contain only 1 attibutes"); + } + this.properties.put(beanName, propertyValue); + } + + public void setText(final String text) throws ExmlBuilderException { + if (this.data != null) { + throw new ExmlBuilderException("Can not set multiple text value in a single NODE ..."); + } + this.data = this.modelInterface.getValueFromText(text); + } + } diff --git a/src/org/atriasoft/exml/builder/IntrospectionProperty.java b/src/org/atriasoft/exml/builder/IntrospectionProperty.java index a642f17..00281fd 100644 --- a/src/org/atriasoft/exml/builder/IntrospectionProperty.java +++ b/src/org/atriasoft/exml/builder/IntrospectionProperty.java @@ -26,42 +26,24 @@ public final class IntrospectionProperty { private boolean canBeSetByConstructor = false; private final Class type; private final Class subType; - + // can get the property, if null not gettable ... ==> TODO need to remove this property ??? // First function call // second field access IntrospectionPropertyGetter getter = null; - + // can get the property, if null not settable (otherwise use the constructor???) - // First constructor call + // First constructor call // second function call // third field access IntrospectionPropertySetter setter = null; - public String getListName() { - return this.listName; - } - public boolean isCanBeSetByConstructor() { - return this.canBeSetByConstructor; - } - - public void setCanBeSetByConstructor(final boolean canBeSetByConstructor) { - this.canBeSetByConstructor = canBeSetByConstructor; - } - public IntrospectionProperty(final String beanName, final Class[] type, final String[] names) { this.beanName = beanName; this.type = type[0]; this.subType = type[1]; this.names = names; } - - public void setSetter(final IntrospectionPropertySetter setter) { - this.setter = setter; - } - public void setGetter(final IntrospectionPropertyGetter getter) { - this.getter = getter; - } public boolean canGetValue() { return this.getter != null; @@ -71,80 +53,6 @@ public final class IntrospectionProperty { return this.canBeSetByConstructor || this.setter != null; } - /** - * Get list of all names of the property/node (minimal 1 name) - * @return Array of names available - */ - public String[] getNames() { - return this.names; - } - - /** - * Get basic type of the property - * @return property type detected. - */ - public Class getType() { - return this.type; - } - /** - * Get the type of the property (if list ==> need to be get on method otherwise it is an Object...) - * @return Type of the list element. - */ - public Class getSubType() { - return this.subType; - } - /** - * Get the value in the object. - * @param object Object that is invoke to get the value. - * @return The generate value of the object - * @throws ExmlBuilderException in an error occured - */ - public Object getValue(final Object object) throws ExmlBuilderException { - if (this.getter != null) { - return this.getter.getValue(object); - } - throw new ExmlBuilderException("Property: " + this.names + " have no getter"); - } - - /** - * Check if the input name is compatible win an element in the list availlable (respect case sensitive if needed) - * @param name Name to check - * @return true if the element is compatible, false otherwise - */ - public boolean isCompatible(final String name) { - Log.warning("Check compatible : '" + name + "' in " + Arrays.toString(this.names)); - if (this.caseSensitive) { - for (final String elem : this.names) { - if (elem.contentEquals(name)) { - Log.warning(" - '" + elem + "' ==> true"); - return true; - } - Log.warning(" - '" + elem + "' == false"); - } - } else { - for (final String elem : this.names) { - if (elem.equalsIgnoreCase(name)) { - Log.warning(" - '" + elem + "' ==> true"); - return true; - } - Log.warning(" - '" + elem + "' == false"); - } - } - return false; - } - /** - * set the specific string value in the specified object - * @param object Object to add the value - * @param value Value to set in the Object - * @throws Exception An error occurred - */ - public void setExistingValue(final Object object, final Object value) throws ExmlBuilderException { - if (this.setter != null) { - this.setter.setValue(object, value); - return; - } - throw new ExmlBuilderException("Property: " + this.names + " have no setter"); - } /** * Create a value adapted to the property type. * @apiNote generic type is transformed byte -> Byte, int -> Integer ... @@ -175,38 +83,146 @@ public final class IntrospectionProperty { } } - public Boolean isCaseSensitive() { - return this.caseSensitive; - } - public void setCaseSensitive(final Boolean caseSensitive) { - this.caseSensitive = caseSensitive; - } - public Boolean isOptionnal() { - return this.optionnal; - } - public void setOptionnal(final Boolean optionnal) { - this.optionnal = optionnal; - } - public Boolean isAttribute() { - return this.attribute; - } - public void setAttribute(final Boolean attribute) { - this.attribute = attribute; - } public String getBeanName() { return this.beanName; } - public void setNames(final String[] names) { - this.names = names; + + public String getListName() { + return this.listName; } - public void setListName(final String listName) { - this.listName = listName; + + /** + * Get list of all names of the property/node (minimal 1 name) + * @return Array of names available + */ + public String[] getNames() { + return this.names; } + + /** + * Get the type of the property (if list ==> need to be get on method otherwise it is an Object...) + * @return Type of the list element. + */ + public Class getSubType() { + return this.subType; + } + + /** + * Get basic type of the property + * @return property type detected. + */ + public Class getType() { + return this.type; + } + + /** + * Get the value in the object. + * @param object Object that is invoke to get the value. + * @return The generate value of the object + * @throws ExmlBuilderException in an error occured + */ + public Object getValue(final Object object) throws ExmlBuilderException { + if (this.getter != null) { + return this.getter.getValue(object); + } + throw new ExmlBuilderException("Property: " + this.names + " have no getter"); + } + + public Boolean isAttribute() { + return this.attribute; + } + + public boolean isCanBeSetByConstructor() { + return this.canBeSetByConstructor; + } + + public Boolean isCaseSensitive() { + return this.caseSensitive; + } + + /** + * Check if the input name is compatible win an element in the list availlable (respect case sensitive if needed) + * @param name Name to check + * @return true if the element is compatible, false otherwise + */ + public boolean isCompatible(final String name) { + Log.verbose("Check compatible : '" + name + "' in " + Arrays.toString(this.names)); + if (this.caseSensitive) { + for (final String elem : this.names) { + if (elem.contentEquals(name)) { + Log.verbose(" - '" + elem + "' ==> true"); + return true; + } + Log.verbose(" - '" + elem + "' == false"); + } + } else { + for (final String elem : this.names) { + if (elem.equalsIgnoreCase(name)) { + Log.verbose(" - '" + elem + "' ==> true"); + return true; + } + Log.verbose(" - '" + elem + "' == false"); + } + } + return false; + } + public Boolean isManaged() { return this.managed; } + + public Boolean isOptionnal() { + return this.optionnal; + } + + public void setAttribute(final Boolean attribute) { + this.attribute = attribute; + } + + public void setCanBeSetByConstructor(final boolean canBeSetByConstructor) { + this.canBeSetByConstructor = canBeSetByConstructor; + } + + public void setCaseSensitive(final Boolean caseSensitive) { + this.caseSensitive = caseSensitive; + } + + /** + * set the specific string value in the specified object + * @param object Object to add the value + * @param value Value to set in the Object + * @throws Exception An error occurred + */ + public void setExistingValue(final Object object, final Object value) throws ExmlBuilderException { + if (this.setter != null) { + this.setter.setValue(object, value); + return; + } + throw new ExmlBuilderException("Property: " + this.names + " have no setter"); + } + + public void setGetter(final IntrospectionPropertyGetter getter) { + this.getter = getter; + } + + public void setListName(final String listName) { + this.listName = listName; + } + public void setManaged(final Boolean managed) { this.managed = managed; } - + + public void setNames(final String[] names) { + this.names = names; + } + + public void setOptionnal(final Boolean optionnal) { + this.optionnal = optionnal; + } + + public void setSetter(final IntrospectionPropertySetter setter) { + this.setter = setter; + } + } \ No newline at end of file