diff --git a/src/org/atriasoft/exml/Exml.java b/src/org/atriasoft/exml/Exml.java index 4e0bd8d..261a37a 100644 --- a/src/org/atriasoft/exml/Exml.java +++ b/src/org/atriasoft/exml/Exml.java @@ -21,6 +21,7 @@ import org.atriasoft.exml.builder.BuilderIntrospection; import org.atriasoft.exml.builder.IntrospectionObject; import org.atriasoft.exml.exception.ExmlBuilderException; import org.atriasoft.exml.exception.ExmlParserErrorMulti; +import org.atriasoft.exml.generator.GeneratorIntrospection; import org.atriasoft.exml.internal.Log; import org.atriasoft.exml.model.XmlElement; import org.atriasoft.exml.model.XmlNode; @@ -38,8 +39,24 @@ public class Exml { Log.info("Generated XML : \n" + tmpp.toString()); } - public static void generate(final Object root, final StringBuilder data) { - // TODO ... + public static void generate(final Object root, final String rootNodeName, final StringBuilder data) throws ExmlBuilderException { + GeneratorIntrospection generator; + try { + generator = new GeneratorIntrospection(root.getClass(), rootNodeName); + generator.generate(root, data); + /* + final SerializerXmlIntrospection serializer = new SerializerXmlIntrospection(generator); + final ParsingProperty property = new ParsingProperty(); + property.setDisplayError(true); + + serializer.generate(root, property, tmpp); + */ + } catch (final ExmlBuilderException ex) { + throw ex; + } catch (final Exception e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } } /** diff --git a/src/org/atriasoft/exml/builder/IntrospectionData.java b/src/org/atriasoft/exml/builder/IntrospectionData.java index bc50abd..c16e063 100644 --- a/src/org/atriasoft/exml/builder/IntrospectionData.java +++ b/src/org/atriasoft/exml/builder/IntrospectionData.java @@ -174,6 +174,12 @@ public class IntrospectionData { private final List properties = new ArrayList<>(); + public List getMethods() { + return this.methods; + } + public List getProperties() { + return this.properties; + } public Class getClassType() { return this.classType; } diff --git a/src/org/atriasoft/exml/builder/IntrospectionProperty.java b/src/org/atriasoft/exml/builder/IntrospectionProperty.java index c0bce17..d546f9e 100644 --- a/src/org/atriasoft/exml/builder/IntrospectionProperty.java +++ b/src/org/atriasoft/exml/builder/IntrospectionProperty.java @@ -41,7 +41,7 @@ public abstract class IntrospectionProperty { return this.subType; } - public abstract String getValue(Object object) throws Exception; + public abstract String getValue(Object object) throws ExmlBuilderException; public boolean isCaseSensitive() { return this.caseSensitive; diff --git a/src/org/atriasoft/exml/builder/IntrospectionPropertyField.java b/src/org/atriasoft/exml/builder/IntrospectionPropertyField.java index 8f016d3..dd7d3be 100644 --- a/src/org/atriasoft/exml/builder/IntrospectionPropertyField.java +++ b/src/org/atriasoft/exml/builder/IntrospectionPropertyField.java @@ -45,9 +45,69 @@ public class IntrospectionPropertyField extends IntrospectionProperty { } @Override - public String getValue(final Object object) { - // TODO Auto-generated method stub - return null; + public String getValue(final Object object) throws ExmlBuilderException { + try { + Object value = this.fieldDescription.get(object); + + if (this.type == byte.class) { + return Byte.toString((byte)value); + } + if (this.type == short.class) { + return Short.toString((short)value); + } + if (this.type == int.class) { + return Integer.toString((int)value); + } + if (this.type == long.class) { + return Long.toString((long)value); + } + if (this.type == boolean.class) { + return Boolean.toString((boolean)value); + } + if (this.type == String.class) { + return (String)value; + } + if (this.type == Byte.class) { + return Byte.toString((Byte)value); + } + if (this.type == Short.class) { + return Short.toString((short)value); + } + if (this.type == Integer.class) { + return Integer.toString((Integer)value); + } else if (this.type == Long.class) { + return Long.toString((Long)value); + } else if (this.type == Boolean.class) { + return Boolean.toString((Boolean)value); + } /* else if (this.type == byte[].class) { + return Tools.parseByteStringList(value); + } else if (this.type == Byte[].class) { + return Tools.parseByteClassStringList(value); + } else if (this.type == short[].class) { + return Tools.parseShortStringList(value); + } else if (this.type == Short[].class) { + return Tools.parseShortClassStringList(value); + } else if (this.type == int[].class) { + return Tools.parseIntegerStringList(value); + } else if (this.type == Integer[].class) { + return Tools.parseIntegerClassStringList(value); + } else if (this.type == long[].class) { + return Tools.parseLongStringList(value); + } else if (this.type == Long[].class) { + return Tools.parseLongClassStringList(value); + } else if (this.type == boolean[].class) { + return Tools.parseBooleanStringList(value); + } else if (this.type == Boolean[].class) { + return Tools.parseBooleanClassStringList(value); + } */else { + //throw new ExmlBuilderException("Can not parse the specific element ... need to introspect and find the 'xxx valueOf(String data);'"); + } + return value.toString(); + } catch (IllegalArgumentException | IllegalAccessException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + throw new ExmlBuilderException("Can not set value ... " + e.getMessage()); + } } @Override @@ -126,17 +186,23 @@ public class IntrospectionPropertyField extends IntrospectionProperty { } if (this.type == int.class) { return Integer.valueOf(value); - } else if (this.type == long.class) { + } + if (this.type == long.class) { return Long.valueOf(value); - } else if (this.type == boolean.class) { + } + if (this.type == boolean.class) { return Boolean.valueOf(value); - } else if (this.type == String.class) { + } + if (this.type == String.class) { return value; - } else if (this.type == Byte.class) { + } + if (this.type == Byte.class) { return Byte.valueOf(value); - } else if (this.type == Short.class) { + } + if (this.type == Short.class) { return Short.valueOf(value); - } else if (this.type == Integer.class) { + } + if (this.type == Integer.class) { return Integer.valueOf(value); } else if (this.type == Long.class) { return Long.valueOf(value); diff --git a/src/org/atriasoft/exml/generator/Generator.java b/src/org/atriasoft/exml/generator/Generator.java new file mode 100644 index 0000000..c38359e --- /dev/null +++ b/src/org/atriasoft/exml/generator/Generator.java @@ -0,0 +1,5 @@ +package org.atriasoft.exml.generator; + +public interface Generator { + +} diff --git a/src/org/atriasoft/exml/generator/GeneratorIntrospection.java b/src/org/atriasoft/exml/generator/GeneratorIntrospection.java new file mode 100644 index 0000000..3576cf1 --- /dev/null +++ b/src/org/atriasoft/exml/generator/GeneratorIntrospection.java @@ -0,0 +1,69 @@ +package org.atriasoft.exml.generator; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import org.atriasoft.exml.builder.IntrospectionData; +import org.atriasoft.exml.builder.IntrospectionProperty; + +public class GeneratorIntrospection implements Generator { + // Keep in cach all the object alredy parsed ==> optimize CPU + final Map, IntrospectionData> elements = new HashMap<>(); + // The root class (need to keep it if we use 2 time the builder, the root class is no more accessible). + final Class rootClassType; + final String rootNodeName; + + public GeneratorIntrospection(final Class classType, final String rootNodeName) throws Exception { + this.rootNodeName = rootNodeName; + this.rootClassType = classType; + this.elements.put(classType, new IntrospectionData(classType, null)); + } + + IntrospectionData findOrCreate(final Class classType) throws Exception { + IntrospectionData out = this.elements.get(classType); + if (out != null) { + return out; + } + out = new IntrospectionData(classType); + this.elements.put(classType, out); + return out; + } + + public void generateProperties(final Object node, final IntrospectionData introspection, final StringBuilder tmpp) throws Exception { + List elements = introspection.getProperties(); + for (IntrospectionProperty elem : elements) { + if (!elem.canGetValue()) { + continue; + } + String name = elem.getNames()[0]; + String data=elem.getValue(node); + tmpp.append(" "); + tmpp.append(name); + tmpp.append("=\""); + tmpp.append(data); + tmpp.append("\""); + } + } + public void generateSubNodes(final Object node, final IntrospectionData introspection, final StringBuilder tmpp) { + List elements = introspection.getMethods(); + for (IntrospectionProperty elem : elements) { + + } + } + public void generateNode(final Object node, final String nodeName, final StringBuilder tmpp) throws Exception { + IntrospectionData introspection = findOrCreate(node.getClass()); + tmpp.append("<"); + tmpp.append(nodeName); + generateProperties(node, introspection, tmpp); + tmpp.append(">\n"); + generateSubNodes(node, introspection, tmpp); + tmpp.append("\n"); + + } + public void generate(final Object root, final StringBuilder tmpp) throws Exception { + generateNode(root, this.rootNodeName, tmpp); + } +} diff --git a/src/org/atriasoft/exml/serializer/SerializerXmlIntrospection.java b/src/org/atriasoft/exml/serializer/SerializerXmlIntrospection.java new file mode 100644 index 0000000..f49b798 --- /dev/null +++ b/src/org/atriasoft/exml/serializer/SerializerXmlIntrospection.java @@ -0,0 +1,116 @@ +package org.atriasoft.exml.serializer; + +import java.util.List; + +import org.atriasoft.exml.generator.Generator; +import org.atriasoft.exml.internal.Log; +import org.atriasoft.exml.model.XmlAttribute; +import org.atriasoft.exml.model.XmlAttributeList; +import org.atriasoft.exml.model.XmlComment; +import org.atriasoft.exml.model.XmlDeclaration; +import org.atriasoft.exml.model.XmlElement; +import org.atriasoft.exml.model.XmlNode; +import org.atriasoft.exml.model.XmlNodeType; +import org.atriasoft.exml.model.XmlText; +import org.atriasoft.exml.parser.ParsingProperty; +import org.atriasoft.exml.parser.Tools; + +public class SerializerXmlIntrospection { + public static void serialize(final XmlNode node, final StringBuilder data, final int indent) { + if (node instanceof XmlElement) { + SerializerXmlIntrospection.serializeElement((XmlElement) node, data, indent); + } else if (node instanceof XmlText) { + SerializerXmlIntrospection.serializeText((XmlText) node, data, indent); + } else if (node instanceof XmlDeclaration) { + SerializerXmlIntrospection.serializeDeclaration((XmlDeclaration) node, data, indent); + } else if (node instanceof XmlComment) { + SerializerXmlIntrospection.serializeComment((XmlComment) node, data, indent); + } else { + // TODO throw an error ... + } + } + + private static void serializeAttribute(final XmlAttribute attribute, final StringBuilder data, final int indent) { + data.append(" "); + data.append(attribute.getName()); + data.append("=\""); + data.append(attribute.getValue()); + data.append("\""); + } + + private static void serializeAttributeList(final XmlAttributeList list, final StringBuilder data, final int indent) { + for (int iii = 0; iii < list.getAttributes().size(); iii++) { + SerializerXmlIntrospection.serializeAttribute(list.getAttributes().get(iii), data, indent); + } + } + + private static void serializeComment(final XmlComment comment, final StringBuilder data, final int indent) { + Tools.addIndent(data, indent); + data.append("\n"); + } + + private static void serializeDeclaration(final XmlDeclaration declaration, final StringBuilder data, final int indent) { + Tools.addIndent(data, indent); + data.append("\n"); + + } + + private static void serializeElement(final XmlElement element, final StringBuilder data, final int indent) { + + Tools.addIndent(data, indent); + data.append("<"); + data.append(element.getValue()); + SerializerXmlIntrospection.serializeAttributeList(element, data, indent); + + final List nodes = element.getNodes(); + if (nodes.size() > 0) { + if (nodes.size() == 1 && nodes.get(0) != null && nodes.get(0).getType() == XmlNodeType.TEXT && ((XmlText) nodes.get(0)).countLines() == 1) { + data.append(">"); + SerializerXmlIntrospection.serialize(nodes.get(0), data, 0); + Log.verbose(" generate : '" + data + "'"); + } else { + data.append(">\n"); + for (XmlNode node : nodes) { + if (node != null) { + SerializerXmlIntrospection.serialize(node, data, indent + 1); + } + } + Tools.addIndent(data, indent); + } + data.append("\n"); + } else { + data.append("/>\n"); + } + } + + public static void serializeRoot(final XmlElement root, final StringBuilder data) { + for (int iii = 0; iii < root.getNodes().size(); iii++) { + final XmlNode node = root.getNodes().get(iii); + SerializerXmlIntrospection.serialize(node, data, 0); + } + + } + + private static void serializeText(final XmlText text, final StringBuilder data, final int indent) { + data.append(Tools.replaceSpecialCharOut(text.getValue())); + } + + private final Generator generator; + public SerializerXmlIntrospection(final Generator generator) { + this.generator = generator; + } + + public void generate(final Object root, final ParsingProperty property, final StringBuilder tmpp) { + //property.append(Tools.replaceSpecialCharOut(root.getValue())); + + + + } +} diff --git a/test/src/test/atriasoft/exml/ExmlTestIntrospectionGenerate.java b/test/src/test/atriasoft/exml/ExmlTestIntrospectionGenerate.java new file mode 100644 index 0000000..dfad5ac --- /dev/null +++ b/test/src/test/atriasoft/exml/ExmlTestIntrospectionGenerate.java @@ -0,0 +1,54 @@ +/** @file + * @author Edouard DUPIN + * @copyright 2021, Edouard DUPIN, all right reserved + * @license MPL v2.0 (see license file) + */ +package test.atriasoft.exml; + +import org.atriasoft.exml.Exml; +import org.atriasoft.exml.exception.ExmlBuilderException; +import org.atriasoft.exml.exception.ExmlParserErrorMulti; + +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.Test; + +import test.atriasoft.exml.introspection.ClassPublicMemberOnly; + +public class ExmlTestIntrospectionGenerate { + @BeforeAll + public static void beforeClass() { + Log.verbose("----------------------------------------------------------------"); + } + + @Test + public void test1() throws ExmlParserErrorMulti, ExmlBuilderException { + ClassPublicMemberOnly elem = new ClassPublicMemberOnly(); + elem.memberArrayBoolean = new boolean[] {false, true}; + elem.memberArrayBooleanClass = new Boolean[] {false, true, true}; + elem.memberArrayByte = new byte[] {21,21,58}; + elem.memberArrayByteClass = new Byte[] {54,21,65,32}; + elem.memberArrayInteger = new int[] { 1521,2151,2156,216354}; + elem.memberArrayIntegerClass = new Integer[] {5564,6546321,654564,231321,54654}; + elem.memberArrayLong = new long[] {6546544L,654654651L,5646546541L,5465465163L} ; + elem.memberArrayLongClass = new Long[] {561651L, 6541321L, 651351L}; + elem.memberArrayShort = new short[] {4564, -54,-564}; + elem.memberArrayShortClass = new Short[] {-54, 5646, -8465, 852}; + elem.memberBoolean = false; + elem.memberBooleanClass = true; + elem.memberByte = 12; + elem.memberByteClass = 54; + elem.memberInteger = 6543524; + elem.memberIntegerClass = 545666; + elem.memberLong = 400000055L; + elem.memberLongClass = 54654546L; + elem.memberShort = 31252; + elem.memberShortClass =-25212; + elem.memberStringClass ="lkjhlkjlkjlkj"; + + StringBuilder builder = new StringBuilder(); + Exml.generate(elem, "elem", builder); + Log.warning("data generated: " + builder.toString()); + } + +} +