Re: [Simple-support] Serialize and deserialize undefined Xml attributes into a HashMap<String, Stri
Brought to you by:
niallg
|
From: Niall G. <gal...@ya...> - 2012-11-17 03:03:38
|
You are doing far too much work here, let the framework handle most of it. I normally would not do this, but since there is no good example in the test cases I have implemented it and added it here. I does your Car schema. https://niallg@simple.svn.sourceforge.net/svnroot/simple/trunk/download/stream/src/test/java/org/simpleframework/xml/convert/DynamicMapOfAttributesTest.java --- On Fri, 16/11/12, Christian Klotz <c....@sp...> wrote: > From: Christian Klotz <c....@sp...> > Subject: Re: [Simple-support] Serialize and deserialize undefined Xml attributes into a HashMap<String, String> > To: "Niall Gallagher - Yieldbroker" <Nia...@yi...> > Cc: "sim...@li..." <sim...@li...> > Received: Friday, 16 November, 2012, 9:41 AM > > > > > > > Ah ok, thanks. > > > > Now I tried it with two converters. > > > > The first one is this: > > public class HashMapConverter implements > Converter<HashMap<String, String>> > > { > > @Override > > public HashMap<String, > String> read(InputNode node) > throws Exception > > { > > // Is never > called > > return null; > > } > > > > @Override > > public void write(OutputNode node, > HashMap<String, > String> hashMap) > > > throws Exception > > { > > OutputNode > parent = node.getParent(); > > > > for > (Entry<String, String> entry : > hashMap.entrySet()) > > { > > > //Does not work > > > parent.setAttribute(entry.getKey(), > entry.getValue()); > > } > > > > node.remove(); > > } > > } > > > > This is the car class: > > @Root(strict = false, name = "Car") > > public class Car > > { > > @Attribute > > public double length; > > > > @Attribute > > public String color; > > > > @Attribute > > public int nrOfDoors; > > > > @ElementMap(required = false) > > public HashMap<String, > String> furtherAttributes; > > } > > > > And this how I set the converter. Set the converter by > AnnotationStategy and @Convert never works. > > public void testCar() throws > Exception > > { > > Car car = new > Car(); > > car.color = > "red"; > > car.length = > 4.3; > > car.nrOfDoors = > 4; > > > > > car.furtherAttributes = new HashMap<String, > String>(); > > > car.furtherAttributes.put("fuelConsumption", > "7.8"); > > > car.furtherAttributes.put("fopSpeed", > "190"); > > > > Registry > registry = new Registry(); > > RegistryStrategy > strategy = new > RegistryStrategy(registry); > > > > > registry.bind(HashMap.class, HashMapConverter.class); > > > //registry.bind(Car.class, CarConverter.class); > > > > StringWriter > stringwriter = new StringWriter(); > > Serializer > serializer = new Persister(strategy); > > > serializer.write(car, stringwriter); > > > > String xml = > stringwriter.toString(); > > } > > > > But on this try, the read method of the converter is > never called > (There is not furtherAttributes xml element) and I > can't set > attributes on the parent node. (See comments in the > HashMapConverter) > > > > The second try was a converter for the car class: > > public class CarConverter implements > Converter<Car> > > { > > @Override > > public Car read(InputNode node) > throws Exception > > { > > Car car = new > Car(); > > > car.furtherAttributes = new HashMap<String, > String>(); > > > > > ArrayList<String> attributesWithAnnotation = new > ArrayList<String>(); > > for (Field field > : car.getClass().getFields()) > > { > > > if (field.getAnnotation(Attribute.class) > != null) > > > { > > > String name = > field.getAnnotation(Attribute.class).name(); > > > > > if (name == null || > name.equals("")) > > > { > > > > name = field.getName(); > > > } > > > > > > attributesWithAnnotation.add(name); > > > } > > } > > > > for (String > entry : node.getAttributes()) > > { > > > if > (!attributesWithAnnotation.contains(entry)) > > > { > > > String > furtherAttributeKey = entry; > > > String > furtherAttributeValue = > node.getAttribute(entry) > > > > .getValue(); > > > > > > car.furtherAttributes.put(furtherAttributeKey, > > > > furtherAttributeValue); > > > } > > } > > > > return car; > > } > > > > @Override > > public void write(OutputNode > outputNode, Car car) throws > Exception > > { > > if > (car.furtherAttributes != null && > car.furtherAttributes.size() > 0) > > { > > > for (Entry<String, String> entry : > car.furtherAttributes.entrySet()) > > > { > > > > outputNode.setAttribute(entry.getKey(), > entry.getValue()); > > > } > > } > > } > > } > > > > But there is the problem that only futherAttributes > are serialised > and deserialised correctly. > > In the read method I create the car object myself. So > color, > length and the other field have the default value. > > But I want, that all that fields are filled by > SimpleXml. > > > > What converter do you recommend? > > > > > > Am 15.11.2012 23:45, schrieb Niall Gallagher - > Yieldbroker: > > > > Sorry, my mistake I should have suggested a > converter. Here you can use @Convert annotation like so. > > @Convert(CarConverter.class) > Map<String, String> var; > > Take a look at the following converters > > https://simple.svn.sf.net/svnroot/simple/trunk/download/stream/src/test/java/org/simpleframework/xml/convert/HideEnclosingConverterTest.java > https://simple.svn.sf.net/svnroot/simple/trunk/download/stream/src/test/java/org/simpleframework/xml/convert/ExampleConverters.java > > > -----Original Message----- > From: Christian Klotz [mailto:c....@sp...] > > Sent: Friday, 16 November 2012 12:28 AM > To: Niall Gallagher - Yieldbroker > Cc: sim...@li... > Subject: Re: [Simple-support] Serialize and deserialize > undefined Xml attributes into a HashMap<String, > String> > > Hi Niall, > > thanks for your quick response. > > > Now I have implemented an Visitor. > In the read method, I can get a nodeMap with all xml > attributes. > > I can also detect via refection which attributes have the > annotation @Attribute. > All other attributes should be stored in the HashMap > "furtherAttributes". > > But I don't known how to put them into the HashMap > "furtherAttributes". > I do not have the resulting car object. Do you have any tip? > > public class AnyAttributesVisitor implements Visitor { > @Override > public void read(Type type, NodeMap<InputNode> > nodeMap) throws Exception > { > // nodeMap contains all xml attributes of the car > xml > // Content is: > // {color=attribute color='red', > length=attribute length='4.3', > // nrOfDoors=attribute nrOfDoors='4', > fuelConsumption=attribute > // fuelConsumption='7.8', > topSpeed=attribute topSpeed='190'} > > > //Detect attributes with Annotation @Attribute > ArrayList<String> attributesWithAnnotation = > new > ArrayList<String>(); > for (Field field : type.getType().getFields()) > { > if (field.getAnnotation(Attribute.class) != > null) > { > String name = > field.getAnnotation(Attribute.class).name(); > > if (name == null || > name.equals("")) > { > name = field.getName(); > } > > attributesWithAnnotation.add(name); > } > } > > for (String entry : > nodeMap.getNode().getAttributes()) > { > if (!attributesWithAnnotation.contains(entry)) > { > String furtherAttributeKey = entry; > String furtherAttributeValue = > nodeMap.getNode() > .getAttribute(entry).getValue(); > > // TODO: Add Key and Value to the Hashmap > furtherAttributes > > nodeMap.remove(furtherAttributeKey); > } > } > } > > @Override > public void write(Type type, NodeMap<OutputNode> > nodeMap) throws > Exception > { > > } > } > > This is my test case: > public void testCarDeserialisation() throws Exception > { > String xml = "<Car > color=\"red\" > length=\"4.3\" > nrOfDoors=\"4\" > fuelConsumption=\"7.8\" > topSpeed=\"190\" />"; > > Serializer serializer = new Persister(new > VisitorStrategy( > new AnyAttributesVisitor())); > > Car car = serializer.read(Car.class, xml); > } > > Thanks Christian > > Am 15.11.2012 00:33, schrieb Niall Gallagher - Yieldbroker: > > > I think a Visitor would be simpler than a > Strategy, there are many test cases doing this very thing. > Just browse through them, I am sure you will find a > template. You can browse them here http://simple.svn.sourceforge.net/viewvc/simple/trunk/download/stream/src/test/java/org/simpleframework/xml/ > > -----Original Message----- > From: Christian Klotz [mailto:c....@sp...] > Sent: Wednesday, 14 November 2012 8:26 PM > To: sim...@li... > Subject: [Simple-support] Serialize and deserialize > undefined Xml attributes into a HashMap<String, > String> > > Hi SimpleXml Team, > > I use SimpleXml frequently on android and it is great. > > Now I have a question how to do that job: > All XML attributes that are not defined in the Java class > with @Attribute should be serialized and deserialized into a > HashMap<String,String>. > > Here is an example: > > This is out test class "Car" > > @Root(strict = false, name = "Car") > public class Car > { > @Attribute > public double length; > > @Attribute > public String color; > > @Attribute > public int nrOfDoors; > > public HashMap<String, String> furtherAttributes > = new HashMap<String, String>(); } > > And this is the serialization test method: > public void testCar() throws Exception > { > Car car = new Car(); > > car.color = "red"; > car.length = 4.3; > car.nrOfDoors = 4; > > > car.furtherAttributes.put("fuelConsumption", > "7.8"); > car.furtherAttributes.put("topSpeed", > "190"); > > Serializer serializer = new Persister(); > StringWriter stringwriter = new StringWriter(); > serializer.write(car, stringwriter); > > String xml = stringwriter.toString(); > } > > > The result of the serialization is: > <Car color="red" length="4.3" > nrOfDoors="4"/> > > So the furtherAttributes of the HashMap are missing. The > result should be: > <Car color="red" length="4.3" > nrOfDoors="4" fuelConsumption="7.8" > topSpeed="190" /> > > And the way back should also work: > So if we have a xml like this: > <Car color="green" length="3.3" > nrOfDoors="2" topSpeed="190" > brand="audi" /> After the deserialization the > HashMap "furtherAttributes" should have the two > undefined attributes "topSpeed" and > "brand". > > I already read the mailing list and some SimpleXml test > cases. > So I try implement a new Strategy to solve that problem. > > The AnyAttributeRegistryStrategy looks for classes with > annotation "AnyClass" and inside that class > searches for the annotation "Any". > The annotation "Any" is used to tag the HashMap, > where the futher attributes should be serialized to. > > public class AnyAttributeRegistryStrategy extends > RegistryStrategy { > public AnyAttributeRegistryStrategy(Registry registry) > { > super(registry); > } > > @Override > public boolean write(Type type, Object value, > NodeMap<OutputNode> node, > @SuppressWarnings("rawtypes") Map > map) throws Exception > { > > if (value.getClass().getAnnotation(AnyClass.class) > != null) > { > for (Field field : > value.getClass().getFields()) > { > if (field.getAnnotation(Any.class) != > null) > { > Object mapObject = field.get(value); > if (mapObject instanceof Map<?, > ?>) > { > Map<?, ?> keyValueMap = > (Map<?, ?>) mapObject; > for (Entry<?, ?> > keyValuePair : > keyValueMap.entrySet()) > { > if (keyValuePair.getKey() != > null > && > keyValuePair.getValue() != null) > { > > node.getNode().setAttribute( > keyValuePair.getKey().toString(), > keyValuePair.getValue().toString()); > } > } > > } > } > } > } > > return super.write(type, value, node, map); > } > } > > And this is the Car class with the new annotations: > @AnyClass > @Root(strict = false, name = "Car") > public class Car > { > @Attribute > public double length; > > @Attribute > public String color; > > @Attribute > public int nrOfDoors; > > @Any > public HashMap<String, String> furtherAttributes > = new HashMap<String, String>(); } > > Now the serialisation of the class to xml works. > But I do not have a correctly working solution for the > deserialisation. > Do you have any ideas? > > Thanks for you help > > Christian Klotz > > > > > > > ------------------------------------------------------------------------------ > Monitor your physical, virtual and cloud infrastructure from > a single web console. Get in-depth insight into apps, > servers, databases, vmware, SAP, cloud infrastructure, etc. > Download 30-day Free Trial. > Pricing starts from $795 for 25 servers or applications! > http://p.sf.net/sfu/zoho_dev2dev_nov > _______________________________________________ > Simple-support mailing list > Sim...@li... > https://lists.sourceforge.net/lists/listinfo/simple-support > > > > > > > > > > > > -- > Mit freundlichen Grüßen / Kind regards > > Christian Klotz > Software Engineer > > > SPEDION GmbH > Industriestraße 7 > D - 63829 Krombach > Fon: +49 (0) 6024 / 50990-132 > Fax: +49 (0) 6024 / 50990-121 > mailto:c....@sp... > > SPEDION GmbH - Industriestraße 7 - 63829 Krombach - > Germany > Amtsgericht Aschaffenburg, HRB 8647 > Geschäftsführer: Günter Englert, Wolfram > Grohse > > > > > -----Inline Attachment Follows----- > > ------------------------------------------------------------------------------ > Monitor your physical, virtual and cloud infrastructure from > a single > web console. Get in-depth insight into apps, servers, > databases, vmware, > SAP, cloud infrastructure, etc. Download 30-day Free Trial. > Pricing starts from $795 for 25 servers or applications! > http://p.sf.net/sfu/zoho_dev2dev_nov > -----Inline Attachment Follows----- > > _______________________________________________ > Simple-support mailing list > Sim...@li... > https://lists.sourceforge.net/lists/listinfo/simple-support > |