From 32eb06278476b58d20b104a650832e039bd0d65d Mon Sep 17 00:00:00 2001 From: Edouard DUPIN Date: Mon, 16 May 2022 23:42:31 +0200 Subject: [PATCH] [DEV] correct managed elements --- src/org/atriasoft/aknot/ReflectTools.java | 40 ++++++++ .../aknot/annotation/AknotManaged.java | 4 +- .../atriasoft/aknot/annotation/AknotName.java | 2 +- .../aknot/model/IntrospectionModel.java | 11 +++ .../aknot/pojo/IntrospectionModelComplex.java | 96 ++++++++++++++----- .../aknot/pojo/IntrospectionObject.java | 6 +- 6 files changed, 129 insertions(+), 30 deletions(-) diff --git a/src/org/atriasoft/aknot/ReflectTools.java b/src/org/atriasoft/aknot/ReflectTools.java index ab3de9b..31a8ff6 100644 --- a/src/org/atriasoft/aknot/ReflectTools.java +++ b/src/org/atriasoft/aknot/ReflectTools.java @@ -243,6 +243,17 @@ public class ReflectTools { return ((AknotIgnoreUnknown) annotation[0]).value(); } + public static Boolean getIsManaged(final Constructor element, final Boolean parentValue) throws AknotException { + final Annotation[] annotation = element.getDeclaredAnnotationsByType(AknotManaged.class); + if (annotation.length == 0) { + return parentValue; + } + if (annotation.length > 1) { + throw new AknotException("Must not have more than 1 element @ on " + element.getClass().getCanonicalName()); + } + return ((AknotManaged) annotation[0]).value(); + } + public static Boolean getIsManaged(final Constructor constructor, final Parameter element, final Boolean parentValue) throws AknotException { final Annotation[] annotation = element.getDeclaredAnnotationsByType(AknotManaged.class); if (annotation.length == 0) { @@ -383,6 +394,35 @@ public class ReflectTools { return tmp; } + public static String[] getNames(final Class element, final String defaultValue) throws Exception { + final Annotation[] annotation = element.getDeclaredAnnotationsByType(AknotName.class); + if (annotation.length == 0) { + if (defaultValue == null) { + return null; + } + return new String[] { defaultValue }; + } + if (annotation.length > 1) { + throw new Exception("Must not have more than 1 element @AknotName on " + element.getClass().getCanonicalName()); + } + final String[] tmp = ((AknotName) annotation[0]).value(); + if (tmp == null) { + throw new Exception("Set null value in decorator @AknotName is not availlable on: " + element.toGenericString()); + } + if (tmp.length == 0) { + throw new Exception("Set empty list value in decorator @AknotName 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 @AknotName is not availlable on: " + element.toGenericString()); + } + if (elem.isEmpty()) { + throw new Exception("Set empty String in list of value in decorator @AknotName is not availlable on: " + element.toGenericString()); + } + } + return tmp; + } + public static String[] getNames(final Constructor constructor, final Parameter element, final String defaultValue) throws Exception { final Annotation[] annotation = element.getDeclaredAnnotationsByType(AknotName.class); if (annotation.length == 0) { diff --git a/src/org/atriasoft/aknot/annotation/AknotManaged.java b/src/org/atriasoft/aknot/annotation/AknotManaged.java index 3f1c174..3e89807 100644 --- a/src/org/atriasoft/aknot/annotation/AknotManaged.java +++ b/src/org/atriasoft/aknot/annotation/AknotManaged.java @@ -9,12 +9,12 @@ import java.lang.annotation.Target; * Marker annotation that force the xml Parser to manage this element (used when the class is mark as @XmldefaultNotManaged). * */ -@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER}) +@Target({ ElementType.FIELD, ElementType.CONSTRUCTOR, ElementType.METHOD, ElementType.PARAMETER }) @Retention(RetentionPolicy.RUNTIME) @AknotAnnotation public @interface AknotManaged { /** - * Set this at false to remove this function or this field form the XML parsing system + * 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; diff --git a/src/org/atriasoft/aknot/annotation/AknotName.java b/src/org/atriasoft/aknot/annotation/AknotName.java index 90d574f..734c4f4 100644 --- a/src/org/atriasoft/aknot/annotation/AknotName.java +++ b/src/org/atriasoft/aknot/annotation/AknotName.java @@ -9,7 +9,7 @@ import java.lang.annotation.Target; * Marker annotation that can be used to define an other name of the attribute or the Element name. * */ -@Target({ ElementType.FIELD, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.PARAMETER }) +@Target({ ElementType.FIELD, ElementType.TYPE, ElementType.METHOD, ElementType.CONSTRUCTOR, ElementType.PARAMETER }) @Retention(RetentionPolicy.RUNTIME) @AknotAnnotation public @interface AknotName { diff --git a/src/org/atriasoft/aknot/model/IntrospectionModel.java b/src/org/atriasoft/aknot/model/IntrospectionModel.java index 90798aa..f6e581c 100644 --- a/src/org/atriasoft/aknot/model/IntrospectionModel.java +++ b/src/org/atriasoft/aknot/model/IntrospectionModel.java @@ -18,9 +18,12 @@ public abstract class IntrospectionModel { protected boolean ignoreUnknown = false; protected final Class classType; + protected String[] names; public IntrospectionModel(final Class classType) { this.classType = classType; + this.names = new String[1]; + this.names[0] = classType.getSimpleName(); } public Object createObject(final Map properties, final Map> nodes) throws AknotException { @@ -43,6 +46,10 @@ public abstract class IntrospectionModel { return this.classType; } + public String[] getNames() { + return this.names; + } + public List getNodeAvaillable() { return null; } @@ -132,6 +139,10 @@ public abstract class IntrospectionModel { return Record.class.isAssignableFrom(this.classType); } + public void setNames(final String[] names) { + this.names = names; + } + public abstract String toString(final Object data) throws AknotException; } diff --git a/src/org/atriasoft/aknot/pojo/IntrospectionModelComplex.java b/src/org/atriasoft/aknot/pojo/IntrospectionModelComplex.java index 0012d8e..c1c5a43 100644 --- a/src/org/atriasoft/aknot/pojo/IntrospectionModelComplex.java +++ b/src/org/atriasoft/aknot/pojo/IntrospectionModelComplex.java @@ -13,6 +13,7 @@ import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Map.Entry; +import java.util.stream.Collectors; import org.atriasoft.aknot.ReflectClass; import org.atriasoft.aknot.ReflectTools; @@ -32,11 +33,17 @@ public class IntrospectionModelComplex extends IntrospectionModel { 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<>(); + private List elements = new ArrayList<>(); + private List elementUnManaged = new ArrayList<>(); public IntrospectionModelComplex(final Class classType) throws AknotException { super(classType); try { + final String[] className = ReflectTools.getNames(classType, null); + if (className != null) { + this.names = className; + } + if (classType.getNestHost() == classType) { this.isSubClass = false; } else if (!Modifier.isStatic(classType.getModifiers())) { @@ -48,12 +55,13 @@ public class IntrospectionModelComplex extends IntrospectionModel { if (classType.isPrimitive()) { Log.critical("Detect primitive ==> impossible case !!! "); } + final Boolean isDefaultManaged = ReflectTools.getIsDefaultManaged(classType, IntrospectionModel.DEFAULT_MANAGED); // ------------------------------------------------------------------------ // -- Parse constructor // ------------------------------------------------------------------------ Log.error("Introspect class: '" + classType.getCanonicalName() + "'"); final Constructor[] constructors = this.classType.getConstructors(); - Log.verbose(" Constructors: (" + constructors.length + ")"); + Log.warning(" Constructors: (" + constructors.length + ")"); Constructor emptyConstructorTmp = null; for (final Constructor elem : constructors) { Log.error(" Constructor ??? : {}", elem.toGenericString()); @@ -61,6 +69,11 @@ public class IntrospectionModelComplex extends IntrospectionModel { if (!Modifier.isPublic(elem.getModifiers())) { continue; } + // check if the constructor is rejected ! + final Boolean managedConstructor = ReflectTools.getIsManaged(elem, isDefaultManaged); + if (managedConstructor != null && !managedConstructor) { + continue; + } if (elem.getParameterCount() == 0) { emptyConstructorTmp = elem; Log.error(" >>> " + elem.toGenericString()); @@ -104,6 +117,17 @@ public class IntrospectionModelComplex extends IntrospectionModel { namesBeans[iii - offsetSubClass] = namesParam[0]; } } + // The constructor can not be managed if One of the element is mark as unmanaged... + boolean managedParameters = true; + for (int iii = 0; iii < isManageds.length; iii++) { + if (isManageds[iii] != null && !isManageds[iii]) { + managedParameters = false; + break; + } + } + if (!managedParameters) { + continue; + } if (checkIfOneIsNull(namesBeans, 0)) { Log.verbose(" - " + elem.toGenericString()); Log.verbose(" ==> unmanaged (missing names description: " + Arrays.toString(namesBeans) + ")"); @@ -346,7 +370,6 @@ public class IntrospectionModelComplex extends IntrospectionModel { prop.setAttribute(isDefaultAttribute); } } - final Boolean isDefaultManaged = ReflectTools.getIsDefaultManaged(classType, IntrospectionModel.DEFAULT_MANAGED); for (final IntrospectionProperty prop : this.elements) { if (prop.isManaged() == null) { prop.setManaged(isDefaultManaged); @@ -375,29 +398,12 @@ public class IntrospectionModelComplex extends IntrospectionModel { ex.printStackTrace(); throw new AknotException("Error in creating introspection data ... " + ex.getMessage()); } - // Sort the parameters to generate all time the same XML.. Collections.sort(this.elements, (a, b) -> a.getNames()[0].compareTo(b.getNames()[0])); - - for (final IntrospectionProperty prop : this.elements) { - Log.verbose("Property/node : " + prop.getBeanName()); - Log.verbose(" names: " + Arrays.toString(prop.getNames())); - Log.verbose(" list: " + prop.getListName()); - Log.verbose(" managed: " + prop.isManaged()); - Log.verbose(" attribute: " + prop.isAttribute()); - Log.verbose(" text: " + prop.isText()); - Log.verbose(" case-sensitive: " + prop.isCaseSensitive()); - Log.verbose(" optionnal: " + prop.isOptionnal()); - Log.verbose(" constructor: " + prop.isCanBeSetByConstructor()); - Log.verbose(" get/set: " + prop.canGetValue() + " / " + prop.canSetValue()); - Log.verbose(" type: " + prop.getType().getCanonicalName()); - if (prop.getSubType() != null) { - Log.verbose(" sub-type: " + prop.getSubType().getCanonicalName()); - } else { - Log.verbose(" sub-type: null"); - } - - } + // separate managed and unmanaged to optimize performances... + this.elementUnManaged = this.elements.stream().filter(o -> !o.isManaged()).collect(Collectors.toList()); + this.elements = this.elements.stream().filter(o -> o.isManaged()).collect(Collectors.toList()); + //display(); } @SuppressWarnings("unchecked") @@ -566,6 +572,48 @@ public class IntrospectionModelComplex extends IntrospectionModel { return tmp; } + public void display() { + Log.print("Class: {} nbProperty:{}", this.classType.getCanonicalName(), this.elements.size()); + Log.print("Managed:"); + for (final IntrospectionProperty prop : this.elements) { + Log.print(" * Property/node : {}", prop.getBeanName()); + Log.print(" names: {}", Arrays.toString(prop.getNames())); + Log.print(" list: {}", prop.getListName()); + //Log.print(" managed: {}", prop.isManaged()); + Log.print(" attribute: {}", prop.isAttribute()); + Log.print(" text: {}", prop.isText()); + Log.print(" case-sensitive: {}", prop.isCaseSensitive()); + Log.print(" optionnal: {}", prop.isOptionnal()); + Log.print(" constructor: {}", prop.isCanBeSetByConstructor()); + Log.print(" get/set: {} / {}", prop.canGetValue(), prop.canSetValue()); + Log.print(" type: {}", prop.getType().getCanonicalName()); + if (prop.getSubType() != null) { + Log.print(" sub-type: {}", prop.getSubType().getCanonicalName()); + } else { + Log.print(" sub-type: null"); + } + } + Log.info("Un-Managed:"); + for (final IntrospectionProperty prop : this.elementUnManaged) { + Log.print(" * Property/node : {}", prop.getBeanName()); + Log.print(" names: {}", Arrays.toString(prop.getNames())); + Log.print(" list: {}", prop.getListName()); + //Log.print(" managed: {}", prop.isManaged()); + Log.print(" attribute: {}", prop.isAttribute()); + Log.print(" text: {}", prop.isText()); + Log.print(" case-sensitive: {}", prop.isCaseSensitive()); + Log.print(" optionnal: {}", prop.isOptionnal()); + Log.print(" constructor: {}", prop.isCanBeSetByConstructor()); + Log.print(" get/set: {} / {}", prop.canGetValue(), prop.canSetValue()); + Log.print(" type: {}", prop.getType().getCanonicalName()); + if (prop.getSubType() != null) { + Log.print(" sub-type: {}", prop.getSubType().getCanonicalName()); + } else { + Log.print(" sub-type: null"); + } + } + } + protected IntrospectionProperty findBeanNodeDescription(final String propertyBeanName) throws AknotException { for (final IntrospectionProperty prop : this.elements) { if (prop.isAttribute()) { diff --git a/src/org/atriasoft/aknot/pojo/IntrospectionObject.java b/src/org/atriasoft/aknot/pojo/IntrospectionObject.java index ff84998..92b25c2 100644 --- a/src/org/atriasoft/aknot/pojo/IntrospectionObject.java +++ b/src/org/atriasoft/aknot/pojo/IntrospectionObject.java @@ -75,10 +75,10 @@ public class IntrospectionObject { // nothing to do ... ==> element already created return; } - Log.debug("Create the element for the Specific node ... type = " + this.modelInterface.getClassType().getCanonicalName() + (this.modelInterface.isArray() ? "[array]" : "") + Log.warning("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()); + Log.warning(" Properties : " + this.properties.keySet()); + Log.warning(" Nodes : " + this.nodes.keySet()); this.data = this.modelInterface.createObject(this.properties, this.nodes); }