[DEV] add introspection interface

This commit is contained in:
Edouard DUPIN 2022-05-11 00:53:12 +02:00
parent 25ae6a94a0
commit 4badf7d29e
22 changed files with 2466 additions and 7 deletions

View File

@ -5,7 +5,8 @@
*/ */
open module org.atriasoft.aknot { open module org.atriasoft.aknot {
exports org.atriasoft.aknot.reflect; exports org.atriasoft.aknot;
exports org.atriasoft.aknot.pojo;
exports org.atriasoft.aknot.annotation; exports org.atriasoft.aknot.annotation;
exports org.atriasoft.aknot.model; exports org.atriasoft.aknot.model;
exports org.atriasoft.aknot.exception; exports org.atriasoft.aknot.exception;

View File

@ -1,5 +1,6 @@
package org.atriasoft.aknot.reflect; package org.atriasoft.aknot;
import java.lang.reflect.Field;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.util.ArrayList; import java.util.ArrayList;
@ -7,6 +8,22 @@ import java.util.List;
import java.util.stream.Collectors; import java.util.stream.Collectors;
public class ReflectClass { public class ReflectClass {
// TODO ploàp ...
public class PojoModelData {
public final String name;
public final Class<?> typeData;
public Field field = null;
public Method getMethod = null;
public Method setMethod = null;
public Method isMethod = null;
public PojoModelData(final String name, final Class<?> typeData) {
this.name = name;
this.typeData = typeData;
}
}
// Separate the methods and filer as: // Separate the methods and filer as:
// - XXX GetXxx(); & XXX != boolean // - XXX GetXxx(); & XXX != boolean
// - void setXxx(XXX elem); // - void setXxx(XXX elem);

View File

@ -1,4 +1,4 @@
package org.atriasoft.aknot.reflect; package org.atriasoft.aknot;
import java.lang.annotation.Annotation; import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
@ -59,10 +59,10 @@ public class ReflectTools {
return tmp; return tmp;
} }
public static String getDescription(final Field element) throws Exception { public static String getDescription(final Field element, final String parentValue) throws Exception {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(AknotDescription.class); final Annotation[] annotation = element.getDeclaredAnnotationsByType(AknotDescription.class);
if (annotation.length == 0) { if (annotation.length == 0) {
return ""; return parentValue;
} }
if (annotation.length > 1) { if (annotation.length > 1) {
throw new Exception("Must not have more than 1 element @AknotDescription on " + element.getClass().getCanonicalName()); throw new Exception("Must not have more than 1 element @AknotDescription on " + element.getClass().getCanonicalName());
@ -74,10 +74,10 @@ public class ReflectTools {
return tmp; return tmp;
} }
public static String getDescription(final Method element) throws Exception { public static String getDescription(final Method element, final String parentValue) throws Exception {
final Annotation[] annotation = element.getDeclaredAnnotationsByType(AknotDescription.class); final Annotation[] annotation = element.getDeclaredAnnotationsByType(AknotDescription.class);
if (annotation.length == 0) { if (annotation.length == 0) {
return ""; return parentValue;
} }
if (annotation.length > 1) { if (annotation.length > 1) {
throw new Exception("Must not have more than 1 element @AknotDescription on " + element.getClass().getCanonicalName()); throw new Exception("Must not have more than 1 element @AknotDescription on " + element.getClass().getCanonicalName());

View File

@ -0,0 +1,230 @@
package org.atriasoft.aknot;
import java.util.HashMap;
import java.util.Map;
import org.atriasoft.aknot.model.StringConverter;
public class StringSerializer {
private static final Map<Class<?>, StringConverter> VALUES_OF = new HashMap<>();
static {
StringSerializer.VALUES_OF.put(byte.class, new StringConverter() {
@Override
public String toString(final Object data) {
return Byte.toString((Byte) data);
}
@Override
public Object valueOf(final String value) {
return Byte.valueOf(value.trim());
}
});
StringSerializer.VALUES_OF.put(Byte.class, new StringConverter() {
@Override
public String toString(final Object data) {
return Byte.toString((Byte) data);
}
@Override
public Object valueOf(final String value) {
return Byte.valueOf(value.trim());
}
});
StringSerializer.VALUES_OF.put(int.class, new StringConverter() {
@Override
public String toString(final Object data) {
return Integer.toString((Integer) data);
}
@Override
public Object valueOf(final String value) {
return Integer.valueOf(value.trim());
}
});
StringSerializer.VALUES_OF.put(Integer.class, new StringConverter() {
@Override
public String toString(final Object data) {
return Integer.toString((Integer) data);
}
@Override
public Object valueOf(final String value) {
return Integer.valueOf(value.trim());
}
});
StringSerializer.VALUES_OF.put(long.class, new StringConverter() {
@Override
public String toString(final Object data) {
return Long.toString((Long) data);
}
@Override
public Object valueOf(final String value) {
return Long.valueOf(value.trim());
}
});
StringSerializer.VALUES_OF.put(Long.class, new StringConverter() {
@Override
public String toString(final Object data) {
return Long.toString((Long) data);
}
@Override
public Object valueOf(final String value) {
return Long.valueOf(value.trim());
}
});
StringSerializer.VALUES_OF.put(short.class, new StringConverter() {
@Override
public String toString(final Object data) {
return Short.toString((Short) data);
}
@Override
public Object valueOf(final String value) {
return Short.valueOf(value.trim());
}
});
StringSerializer.VALUES_OF.put(Short.class, new StringConverter() {
@Override
public String toString(final Object data) {
return Short.toString((Short) data);
}
@Override
public Object valueOf(final String value) {
return Short.valueOf(value.trim());
}
});
StringSerializer.VALUES_OF.put(float.class, new StringConverter() {
@Override
public String toString(final Object data) {
return Float.toString((Float) data);
}
@Override
public Object valueOf(final String value) {
return Float.valueOf(value.trim());
}
});
StringSerializer.VALUES_OF.put(Float.class, new StringConverter() {
@Override
public String toString(final Object data) {
return Float.toString((Float) data);
}
@Override
public Object valueOf(final String value) {
return Float.valueOf(value.trim());
}
});
StringSerializer.VALUES_OF.put(double.class, new StringConverter() {
@Override
public String toString(final Object data) {
return Double.toString((Double) data);
}
@Override
public Object valueOf(final String value) {
return Double.valueOf(value.trim());
}
});
StringSerializer.VALUES_OF.put(Double.class, new StringConverter() {
@Override
public String toString(final Object data) {
return Double.toString((Double) data);
}
@Override
public Object valueOf(final String value) {
return Double.valueOf(value.trim());
}
});
StringSerializer.VALUES_OF.put(boolean.class, new StringConverter() {
@Override
public String toString(final Object data) {
return Boolean.toString((Boolean) data);
}
@Override
public Object valueOf(final String value) {
return Boolean.valueOf(value.trim());
}
});
StringSerializer.VALUES_OF.put(Boolean.class, new StringConverter() {
@Override
public String toString(final Object data) {
return Boolean.toString((Boolean) data);
}
@Override
public Object valueOf(final String value) {
return Boolean.valueOf(value.trim());
}
});
StringSerializer.VALUES_OF.put(String.class, new StringConverter() {
@Override
public String toString(final Object data) {
return (String) data;
}
@Override
public Object valueOf(final String value) {
return value;
}
});
}
public static boolean contains(final Class<?> clazz) {
return StringSerializer.VALUES_OF.containsKey(clazz);
}
public static String toString(final boolean data) {
return Boolean.toString(data);
}
public static String toString(final byte data) {
return Byte.toString(data);
}
public static String toString(final int data) {
return Integer.toString(data);
}
public static String toString(final long data) {
return Long.toString(data);
}
/**
* Serialize in a string the require data
* @param data Object to serialize
* @return The new data...
*/
public static String toString(final Object data) {
if (data == null) {
return null;
}
final Class<?> clazz = data.getClass();
final StringConverter conv = StringSerializer.VALUES_OF.get(clazz);
return conv.toString(data);
}
public static String toString(final short data) {
return Short.toString(data);
}
/**
* Un-serialize a String in a specified Object
* @param value String to parse
* @return Data generated or Null
*/
public static Object valueOf(final Class<?> clazz, final String value) {
if (value == null) {
return null;
}
final StringConverter conv = StringSerializer.VALUES_OF.get(clazz);
return conv.valueOf(value);
}
private StringSerializer() {}
}

View File

@ -0,0 +1,8 @@
package org.atriasoft.aknot.model;
import java.lang.reflect.Constructor;
public record ConstructorModel(
String[] values,
Boolean[] isAttributes,
Constructor<?> constructor) {}

View File

@ -0,0 +1,137 @@
package org.atriasoft.aknot.model;
import java.util.List;
import java.util.Map;
import org.atriasoft.aknot.exception.AknotException;
import org.atriasoft.aknot.pojo.IntrospectionProperty;
public abstract class IntrospectionModel {
protected static final Boolean DEFAULT_ATTRIBUTE = false;
protected static final Boolean DEFAULT_IGNORE_UNBKNOWN = false;
protected static final Boolean DEFAULT_DEFAULT_NULL_VALUE = false;
protected static final Boolean DEFAULT_CASE_SENSITIVE = true;
protected static final Boolean DEFAULT_MANAGED = true;
protected static final Boolean DEFAULT_OPTIONAL = false;
protected boolean defaultNullValue = false;
protected boolean ignoreUnknown = false;
protected final Class<?> classType;
public IntrospectionModel(final Class<?> classType) {
this.classType = classType;
}
public Object createObject(final Map<String, Object> properties, final Map<String, List<Object>> nodes) throws AknotException {
return null;
}
public List<IntrospectionProperty> getAttributes() {
return null;
}
public String getBeanName(final String nodeName) {
return nodeName;
}
public String getBeanNameModel(final String nodeName) {
return getBeanName(nodeName);
}
public Class<?> getClassType() {
return this.classType;
}
public List<String> getNodeAvaillable() {
return null;
}
public List<IntrospectionProperty> getNodes() {
return null;
}
public List<IntrospectionProperty> getSignals() {
return null;
}
public String getTextBeanName() {
// TODO Auto-generated method stub
return null;
}
public String getTreeNameOfSubNode(final String nodeName) throws AknotException {
return null;
}
public Class<?> getTypeOfProperty(final String nodeName) throws AknotException {
return null;
}
public Class<?> getTypeOfSubNode(final String nodeName) throws AknotException {
return null;
}
public Class<?> getTypeOfSubNodeList(final String nodeName) throws AknotException {
return null;
}
public Class<?> getTypeOfSubProperty(final String nodeName) throws AknotException {
return null;
}
public Class<?> getTypeOfText() {
return null;
}
public Object getValue(final String propertyName, final String propertyValue) throws AknotException {
return null;
}
public Object getValueFromText(final String text) throws AknotException {
return null;
}
/**
* This permit to know if an element in the property is able to manage the Whole text under (this remove all parsing of xml inside the model...) Annotation @XmlText
* @return true if a parameter manage the text (otherwise the text is sended to the fromString() function.
*/
public boolean hasTextModel() {
return false;
}
public boolean isArray() {
return false;
}
protected boolean isDefaultNullValue() {
return this.defaultNullValue;
}
public boolean isEnum() {
return this.classType.isEnum();
}
public boolean isIgnoreUnknown() {
return this.ignoreUnknown;
}
public boolean isList() {
return false;
}
public boolean isNative() {
return false;
}
public boolean isObject(final String propertyName) {
return Object.class.isAssignableFrom(this.classType);
}
public boolean isRecord(final String propertyName) {
return Record.class.isAssignableFrom(this.classType);
}
public abstract String toString(final Object data) throws AknotException;
}

View File

@ -0,0 +1,7 @@
package org.atriasoft.aknot.model;
import org.atriasoft.aknot.exception.AknotException;
public interface IntrospectionPropertyGetter {
Object getValue(Object object) throws AknotException;
}

View File

@ -0,0 +1,13 @@
package org.atriasoft.aknot.model;
import org.atriasoft.aknot.exception.AknotException;
public interface IntrospectionPropertySetter {
/**
* 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
*/
void setValue(Object object, Object value) throws AknotException;
}

View File

@ -0,0 +1,14 @@
package org.atriasoft.aknot.model;
public record MapKey (ModelType model,
String nodeName,
Class<?> type) {
public MapKey(final ModelType model, final String nodeName, final Class<?> type) {
this.model = model;
this.nodeName = nodeName;
this.type = type;
}
public MapKey(final ModelType model, final Class<?> type) {
this(model, null, type);
}
}

View File

@ -0,0 +1,7 @@
package org.atriasoft.aknot.model;
public enum ModelType {
NORMAL,
ARRAY,
LIST
}

View File

@ -0,0 +1,16 @@
package org.atriasoft.aknot.model;
public interface StringConverter {
/**
* Un-serialize a String in a specified Object
* @param value String to parse
* @return Data generated or Null
*/
Object valueOf(final String value);
/**
* Serialize in a string the require data
* @param data Object to serialize
* @return The new data...
*/
String toString(final Object data);
}

View File

@ -0,0 +1,36 @@
package org.atriasoft.aknot.pojo;
import java.util.HashMap;
import java.util.Map;
import org.atriasoft.aknot.exception.AknotException;
import org.atriasoft.aknot.model.IntrospectionModel;
import org.atriasoft.aknot.model.MapKey;
import org.atriasoft.aknot.model.ModelType;
public class CacheIntrospectionModel {
final Map<MapKey, IntrospectionModel> elements = new HashMap<>();
public CacheIntrospectionModel() {
}
public IntrospectionModel findOrCreate(final ModelType model, final String name, final Class<?> classType) throws AknotException {
final MapKey key = new MapKey(model, name, classType);
IntrospectionModel out = this.elements.get(key);
if (out != null) {
return out;
}
if (model == ModelType.ARRAY) {
out = IntrospectionModelFactory.createModelArray(key.nodeName(), key);
} else if (model == ModelType.LIST) {
out = IntrospectionModelFactory.createModelList(key.nodeName(), key);
} else if (classType.isEnum()) {
out = IntrospectionModelFactory.createModelEnum(key);
} else {
out = IntrospectionModelFactory.createModel(key);
}
this.elements.put(key, out);
return out;
}
}

View File

@ -0,0 +1,77 @@
package org.atriasoft.aknot.pojo;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.atriasoft.aknot.exception.AknotException;
import org.atriasoft.aknot.model.IntrospectionModel;
import org.atriasoft.etk.util.ArraysTools;
public class IntrospectionModelArray extends IntrospectionModel {
@SuppressWarnings("unchecked")
public static <T> T[] convertList(final Class<T> classType, final List<Object> data) {
final List<T> rootList = (List<T>) data;
final T[] strarr = (T[]) Array.newInstance(classType, 0);
return rootList.toArray(strarr);
}
final String nodeName;
public IntrospectionModelArray(final String nodeName, final Class<?> classType) {
super(classType);
this.nodeName = nodeName;
}
@Override
public Object createObject(final Map<String, Object> properties, final Map<String, List<Object>> nodes) throws AknotException {
List<Object> tmp = null;
if (this.nodeName == null) {
tmp = nodes.get(IntrospectionObject.STUPID_TOCKEN);
} else {
tmp = nodes.get(this.nodeName);
}
if (tmp == null) {
return null;
}
if (this.classType.isPrimitive()) {
return ArraysTools.listToPrimitiveAuto(this.classType, tmp);
}
return IntrospectionModelArray.convertList(this.classType, tmp);
}
@Override
public List<String> getNodeAvaillable() {
if (this.nodeName != null) {
return Arrays.asList(this.nodeName);
}
return null;
}
@Override
public Object getValue(final String propertyName, final String propertyValue) throws AknotException {
return null;
}
@Override
public Object getValueFromText(final String text) throws AknotException {
return new Object[0];
}
@Override
public boolean hasTextModel() {
return false;
}
@Override
public boolean isArray() {
return true;
}
@Override
public String toString(final Object data) {
return null;
}
}

View File

@ -0,0 +1,47 @@
package org.atriasoft.aknot.pojo;
import java.util.List;
import java.util.Map;
import org.atriasoft.aknot.StringSerializer;
import org.atriasoft.aknot.exception.AknotException;
import org.atriasoft.aknot.model.IntrospectionModel;
public class IntrospectionModelBaseType extends IntrospectionModel {
public IntrospectionModelBaseType(final Class<?> classType) {
super(classType);
}
@Override
public Object createObject(final Map<String, Object> properties, final Map<String, List<Object>> nodes) throws AknotException {
throw new AknotException("Base type model can not have properties and nodes ... ");
}
@Override
public List<String> getNodeAvaillable() {
return null;
}
@Override
public Object getValue(final String propertyName, final String propertyValue) throws AknotException {
return null;
}
@Override
public Object getValueFromText(final String text) throws AknotException {
//il y a un bug ici ...
return StringSerializer.valueOf(this.classType, text);
}
@Override
public boolean isNative() {
return true;
}
@Override
public String toString(final Object data) {
return StringSerializer.toString(data);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,29 @@
package org.atriasoft.aknot.pojo;
import org.atriasoft.aknot.StringSerializer;
import org.atriasoft.aknot.exception.AknotException;
import org.atriasoft.aknot.model.IntrospectionModel;
import org.atriasoft.aknot.model.MapKey;
public class IntrospectionModelFactory {
public static IntrospectionModel createModel(final MapKey modelType) throws AknotException {
if (StringSerializer.contains(modelType.type())) {
return new IntrospectionModelBaseType(modelType.type());
}
return new IntrospectionModelComplex(modelType.type());
}
public static IntrospectionModel createModelArray(final String nodeName, final MapKey modelType) throws AknotException {
return new IntrospectionModelArray(nodeName, modelType.type());
}
public static IntrospectionModel createModelEnum(final MapKey modelType) throws AknotException {
return new IntrospectionModelComplex(modelType.type());
}
public static IntrospectionModel createModelList(final String nodeName, final MapKey modelType) throws AknotException {
return new IntrospectionModelList(nodeName, modelType.type());
}
private IntrospectionModelFactory() {}
}

View File

@ -0,0 +1,55 @@
package org.atriasoft.aknot.pojo;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import org.atriasoft.aknot.exception.AknotException;
import org.atriasoft.aknot.model.IntrospectionModel;
public class IntrospectionModelList extends IntrospectionModel {
final String nodeName;
public IntrospectionModelList(final String nodeName, final Class<?> classType) {
super(classType);
this.nodeName = nodeName;
}
@Override
public Object createObject(final Map<String, Object> properties, final Map<String, List<Object>> nodes) throws AknotException {
if (this.nodeName == null) {
return nodes.get(IntrospectionObject.STUPID_TOCKEN);
}
return nodes.get(this.nodeName);
}
@Override
public List<String> getNodeAvaillable() {
if (this.nodeName != null) {
return Arrays.asList(this.nodeName);
}
return null;
}
@Override
public Object getValue(final String propertyName, final String propertyValue) throws AknotException {
return null;
}
@Override
public Object getValueFromText(final String text) throws AknotException {
return new ArrayList<>();
}
@Override
public boolean isList() {
return true;
}
@Override
public String toString(final Object data) {
return null;
}
}

View File

@ -0,0 +1,167 @@
package org.atriasoft.aknot.pojo;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.atriasoft.aknot.exception.AknotException;
import org.atriasoft.aknot.internal.Log;
import org.atriasoft.aknot.model.IntrospectionModel;
public class IntrospectionObject {
public static final String PUBLIC_TEXT_NAME = "##<< ** TEXT-ZONE ** >>##";
public static final String STUPID_TOCKEN = "___aé\"'__-è==**ù!^$:;,;AZEARTYUIOPMLKJHGFDSQW>XCVBN?"; // can not exist ....
private final IntrospectionModel modelInterface;
private Object data = null;
private final Map<String, Object> properties = new HashMap<>();
private final Map<String, List<Object>> nodes = new HashMap<>();
public IntrospectionObject(final IntrospectionModel dataInterface) {
this.modelInterface = dataInterface;
}
@SuppressWarnings("unchecked")
public void addObject(final String nodeName, final Object value) throws AknotException {
if (value == null) {
// specific case when a List is empty <links></links> but define for a specific list ==> need no action
return;
}
final String beanName = this.modelInterface.getBeanName(nodeName);
if (beanName == null) {
throw new AknotException("The node '" + nodeName + "' Does not exist...");
}
List<Object> node = this.nodes.get(beanName);
if (node == null) {
if (List.class.isAssignableFrom(value.getClass())) {
node = (List<Object>) value;
} else if (value.getClass().isArray()) {
Log.error("this is a big problem ...");
Log.error("this is a big problem ...");
Log.error("this is a big problem ...");
Log.error("this is a big problem ...");
Log.error("this is a big problem ...");
Log.error("this is a big problem ...");
Log.error("this is a big problem ...");
Log.error("this is a big problem ...");
Log.error("this is a big problem ...");
Log.error("this is a big problem ...");
} else {
node = new ArrayList<>();
node.add(value);
}
this.nodes.put(beanName, node);
} else if (value.getClass().isArray()) {
Log.error("this is a big problem ...");
Log.error("this is a big problem ...");
Log.error("this is a big problem ...");
Log.error("this is a big problem ...");
Log.error("this is a big problem ...");
Log.error("this is a big problem ...");
Log.error("this is a big problem ...");
Log.error("this is a big problem ...");
Log.error("this is a big problem ...");
Log.error("this is a big problem ...");
} else if (List.class.isAssignableFrom(value.getClass())) {
final List<Object> nodeIn = (List<Object>) value;
node.addAll(nodeIn);
} else {
node.add(value);
}
}
public void generateTheObject() throws AknotException {
if (this.data != null) {
// 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]" : "")
+ (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 AknotException {
final String beanName = this.modelInterface.getBeanName(nodeName);
if (beanName == null) {
throw new AknotException("The node '" + nodeName + "' Does not exist...");
}
return this.modelInterface.getTreeNameOfSubNode(beanName);
}
public Class<?> getTypeOfProperty(final String nodeName) throws AknotException {
final String beanName = this.modelInterface.getBeanName(nodeName);
if (beanName == null) {
throw new AknotException("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 AknotException {
final String beanName = this.modelInterface.getBeanNameModel(nodeName);
if (beanName == null) {
throw new AknotException("The node '" + nodeName + "' Does not exist...");
}
return this.modelInterface.getTypeOfSubNode(beanName);
}
public Class<?> getTypeOfSubNodeSubType(final String nodeName) throws AknotException {
final String beanName = this.modelInterface.getBeanNameModel(nodeName);
if (beanName == null) {
throw new AknotException("The node '" + nodeName + "' Does not exist...");
}
return this.modelInterface.getTypeOfSubNodeList(beanName);
}
public Class<?> getTypeOfSubProperty(final String nodeName) throws AknotException {
final String beanName = this.modelInterface.getBeanName(nodeName);
if (beanName == null) {
throw new AknotException("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 AknotException {
String beanName = null;
if (propertyName == PUBLIC_TEXT_NAME) {
beanName = this.modelInterface.getTextBeanName();
} else {
beanName = this.modelInterface.getBeanName(propertyName);
}
if (this.properties.containsKey(beanName)) {
throw new AknotException("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 AknotException {
if (this.data != null) {
throw new AknotException("Can not set multiple text value in a single NODE ...");
}
this.data = this.modelInterface.getValueFromText(text);
}
}

View File

@ -0,0 +1,344 @@
package org.atriasoft.aknot.pojo;
import java.lang.reflect.InvocationTargetException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map.Entry;
import org.atriasoft.aknot.StringSerializer;
import org.atriasoft.aknot.exception.AknotException;
import org.atriasoft.aknot.internal.Log;
import org.atriasoft.aknot.model.InterfaceFactoryAccess;
import org.atriasoft.aknot.model.IntrospectionPropertyGetter;
import org.atriasoft.aknot.model.IntrospectionPropertySetter;
public final class IntrospectionProperty {
// if the element is not managed by us (set at null while not define by a function attribute, parameter ...)
private Boolean managed = null;
// Case sensitive in parsing XML or not (set at null while not define by a function attribute, parameter ...)
private Boolean caseSensitive = null;
// Optional or not (set at null while not define by a function attribute, parameter ...)
private Boolean optionnal = null;
// Attribute or Node (set at null while not define by a function attribute, parameter ...)
private Boolean attribute = null;
// this is a Signal interface
private Boolean signal = null;
private Boolean textMode = null;
// Decription of the element @AknotDescription
private String description = null;
// name of the field or the function before renaming...
private final String beanName;
// names that can take the Node or the attibute
private String[] names = null;
// if organized in sublist (!= null) then the subNode have this value
private String listName = null;
private boolean canBeSetByConstructor = false;
private Class<?> factory = null;
private InterfaceFactoryAccess factoryCreated = null;
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
// second function call
// third field access
IntrospectionPropertySetter setter = null;
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 boolean canGetValue() {
return this.getter != null;
}
public boolean canSetValue() {
return this.canBeSetByConstructor || this.setter != null;
}
/**
* Create a value adapted to the property type.
* @apiNote generic type is transformed byte -> Byte, int -> Integer ...
* @param value Value to set in the Object
* @throws Exception An error occurred
* @return The object created
*/
public Object createValue(final String value) throws AknotException {
try {
if (StringSerializer.contains(this.type)) {
// TODO This might be a deprecated code ....
return StringSerializer.valueOf(this.type, value);
}
if (this.type.isEnum()) {
} else if ((this.type != List.class) || !StringSerializer.contains(this.subType)) {
throw new AknotException("Can not parse the specific element ... need to introspect and find the 'xxx valueOf(String data);'");
}
final ArrayList<Object> out = new ArrayList<>();
for (final String elem : value.split(";")) {
out.add(StringSerializer.valueOf(this.subType, elem));
}
return out;
} catch (final IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
throw new AknotException("Error in parsing the property value ... " + e.getMessage());
}
}
public String getBeanName() {
return this.beanName;
}
public Class<?> getCompatible(final String name) {
final InterfaceFactoryAccess factoryGenerator = getFactory();
if (factoryGenerator != null) {
if (this.caseSensitive) {
for (final Entry<String, Class<?>> elem : factoryGenerator.getConversionMap().entrySet()) {
if (elem.getKey().contentEquals(name)) {
return elem.getValue();
}
}
} else {
for (final Entry<String, Class<?>> elem : factoryGenerator.getConversionMap().entrySet()) {
if (elem.getKey().equalsIgnoreCase(name)) {
return elem.getValue();
}
}
}
return null;
}
if (this.caseSensitive) {
for (final String elem : this.names) {
if (elem.contentEquals(name)) {
Log.verbose(" - '{}' ==> true", elem);
return getType();
}
Log.verbose(" - '{}' == false", elem);
}
} else {
for (final String elem : this.names) {
if (elem.equalsIgnoreCase(name)) {
Log.verbose(" - '{}' ==> true", elem);
return getType();
}
Log.verbose(" - '{}' == false", elem);
}
}
return null;
}
public String getDescription() {
return this.description;
}
public InterfaceFactoryAccess getFactory() {
if (this.factoryCreated == null && this.factory != null) {
try {
this.factoryCreated = (InterfaceFactoryAccess) this.factory.getConstructor().newInstance();
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) {
// TODO Auto-generated catch block
e.printStackTrace();
this.factoryCreated = null;
this.factory = null;
}
}
return this.factoryCreated;
}
public String getListName() {
return this.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 AknotException in an error occured
*/
public Object getValue(final Object object) throws AknotException {
if (this.getter != null) {
return this.getter.getValue(object);
}
throw new AknotException("Property: " + this.names + " have no getter");
}
public boolean hasFactory() {
return this.factory != null;
}
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 : '{}' in {}", name, Arrays.toString(this.names));
final InterfaceFactoryAccess factoryGenerator = getFactory();
if (factoryGenerator != null) {
Log.verbose(" ===> Detect factory !!!!");
if (this.caseSensitive) {
for (final Entry<String, Class<?>> elem : factoryGenerator.getConversionMap().entrySet()) {
if (elem.getKey().contentEquals(name)) {
Log.verbose(" + '{}' ==> true", elem.getKey());
return true;
}
Log.verbose(" + '{}' == false", elem.getKey());
}
} else {
for (final Entry<String, Class<?>> elem : factoryGenerator.getConversionMap().entrySet()) {
if (elem.getKey().equalsIgnoreCase(name)) {
Log.verbose(" + '{}' ==> true", elem.getKey());
return true;
}
Log.verbose(" + '{}' == false", elem.getKey());
}
}
return false;
}
if (this.caseSensitive) {
for (final String elem : this.names) {
if (elem.contentEquals(name)) {
Log.verbose(" - '{}' ==> true", elem);
return true;
}
Log.verbose(" - '{}' == false", elem);
}
} else {
for (final String elem : this.names) {
if (elem.equalsIgnoreCase(name)) {
Log.verbose(" - '{}' ==> true", elem);
return true;
}
Log.verbose(" - '{}' == false", elem);
}
}
return false;
}
public Boolean isManaged() {
return this.managed;
}
public Boolean isOptionnal() {
return this.optionnal;
}
public Boolean isSignal() {
return this.signal;
}
public Boolean isText() {
return this.textMode;
}
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;
}
public void setDescription(final String description) {
this.description = description;
}
/**
* 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 AknotException {
if (this.setter != null) {
this.setter.setValue(object, value);
return;
}
throw new AknotException("Property: " + this.names + " have no setter");
}
public void setFactory(final Class<?> factory) {
this.factory = factory;
}
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;
}
public void setSignal(final Boolean signal) {
this.signal = signal;
}
public void setTextMode(final Boolean isText) {
this.textMode = isText;
}
}

View File

@ -0,0 +1,44 @@
package org.atriasoft.aknot.pojo;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import org.atriasoft.aknot.exception.AknotException;
import org.atriasoft.aknot.model.IntrospectionPropertyGetter;
import org.atriasoft.aknot.model.IntrospectionPropertySetter;
public class IntrospectionPropertyField implements IntrospectionPropertyGetter, IntrospectionPropertySetter {
private final Field fieldDescription;
private final boolean finalValue;
public IntrospectionPropertyField(final Field fieldDescription) {
this.fieldDescription = fieldDescription;
this.finalValue = Modifier.isFinal(fieldDescription.getModifiers());
}
@Override
public Object getValue(final Object object) throws AknotException {
try {
return this.fieldDescription.get(object);
} catch (IllegalArgumentException | IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
throw new AknotException("Can not set value ... " + e.getMessage());
}
}
@Override
public void setValue(final Object object, final Object value) throws AknotException {
if (this.finalValue) {
throw new AknotException("Can not set value The value is FINAL!!!");
}
try {
this.fieldDescription.set(object, value);
} catch (IllegalArgumentException | IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
throw new AknotException("Can not set value ... " + e.getMessage());
}
}
}

View File

@ -0,0 +1,75 @@
package org.atriasoft.aknot.pojo;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.atriasoft.aknot.exception.AknotException;
import org.atriasoft.aknot.model.IntrospectionPropertyGetter;
public class IntrospectionPropertyMethodGetter implements IntrospectionPropertyGetter {
// private static Class<?>[] getTypefunction(final Method setter, final Method getter) throws Exception {
// Class<?> type = null;
// Class<?> subType = null;
// if (setter == null && getter == null) {
// // impossible case...
// throw new Exception("kjhkhjkj");
// }
// if (getter != null) {
// type = getter.getReturnType();
// if (Enum.class.isAssignableFrom(type)) {
// Log.verbose("Find an enum ...");
// } else {
// Type empppe = getter.getGenericReturnType();
// if (empppe instanceof ParameterizedType plopppppp) {
// Type[] realType = plopppppp.getActualTypeArguments();
// if (realType.length > 0) {
// subType = Class.forName(realType[0].getTypeName());
// }
// }
// }
// }
// 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 ...");
// }
// type = setter.getParameters()[0].getType();
// if (List.class.isAssignableFrom(type)) {
// Class<?> internalModelClass = null;
// Type[] empppe = setter.getGenericParameterTypes();
// if (empppe.length > 0) {
// if (empppe[0] instanceof ParameterizedType plopppppp) {
// Type[] realType = plopppppp.getActualTypeArguments();
// if (realType.length > 0) {
// Log.warning(" -->> " + realType[0]);
// internalModelClass = Class.forName(realType[0].getTypeName());
// }
// }
// }
// if (getter!=null && internalModelClass != subType) {
// throw new Exception("The type of the setter and the type return by the getter are not the same ...");
// }
// subType = internalModelClass;
// }
// }
// return new Class<?>[] {type, subType};
// }
//
protected Method getter;
public IntrospectionPropertyMethodGetter(final Method getter) throws Exception {
this.getter = getter;
}
@Override
public Object getValue(final Object object) throws AknotException {
if (this.getter == null) {
throw new AknotException("no getter availlable");
}
try {
return this.getter.invoke(object);
} catch (InvocationTargetException | IllegalAccessException | IllegalArgumentException e) {
e.printStackTrace();
throw new AknotException("Can not set value ... " + e.getMessage());
}
}
}

View File

@ -0,0 +1,29 @@
package org.atriasoft.aknot.pojo;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import org.atriasoft.aknot.exception.AknotException;
import org.atriasoft.aknot.model.IntrospectionPropertySetter;
public class IntrospectionPropertyMethodSetter implements IntrospectionPropertySetter {
protected Method setter;
public IntrospectionPropertyMethodSetter(final Method setter) throws Exception {
this.setter = setter;
}
@Override
public void setValue(final Object object, final Object value) throws AknotException {
if (this.setter == null) {
throw new AknotException("no setter availlable");
}
try {
this.setter.invoke(object, value);
} catch (InvocationTargetException | IllegalAccessException | IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
throw new AknotException("Can not set value ... " + e.getMessage());
}
}
}