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-19 10:10:38
|
It works as I intended it to, feel free to refactor as you wish.
--- On Mon, 19/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" <gal...@ya...>
> Cc: "Niall Gallagher - Yieldbroker" <Nia...@yi...>, "sim...@li..." <sim...@li...>
> Received: Monday, 19 November, 2012, 1:31 AM
>
>
>
>
>
>
> Hi Naill,
>
>
>
> you do a great job.
>
>
>
> But the converter works not correctly.
>
>
>
> The read method fill all attributes of the SOURCE Xml
> into the
> hashmap "furtherAttributes" as you can see
> on the screen shot.
>
> So I have added 4 asserts to your test case and they
> fail.
>
>
>
> Only because of that "error" the write
> method works.
>
> Only the further attributes are written out and not of
> the normal
> attributes.
>
>
>
> Your asserts "assertElementHasAttribute" do
> not throw an failure,
> because the read method filled the HashMap
>
> "car.furtherAttributes" with all five
> attributes.
>
>
>
>
>
>
>
>
>
> public void testConverter() throws Exception
>
> {
>
> Strategy
> strategy = new AnnotationStrategy();
>
> Serializer
> serializer = new Persister(strategy);
>
> StringWriter
> buffer = new StringWriter();
>
> Car car =
> serializer.read(Car.class, SOURCE, false);
>
>
>
>
> assertNotNull(car);
>
>
> assertEquals(car.length, 3.3);
>
>
> assertEquals(car.color, "green");
>
>
> assertEquals(car.nrOfDoors, 2);
>
>
> assertEquals(car.furtherAttributes.get("topSpeed"),
> "190");
>
>
> assertEquals(car.furtherAttributes.get("brand"),
> "audi");
>
>
>
> // Asserts by
> Christian
>
>
> assertEquals(car.furtherAttributes.size(), 2);
>
>
> assertEquals(car.furtherAttributes.containsKey("length"),
> false);
>
>
> assertEquals(car.furtherAttributes.containsKey("color"),
> false);
>
>
>
> assertEquals(car.furtherAttributes.containsKey("nrOfDoors"),
> false);
>
>
>
>
> serializer.write(car, System.out);
>
>
> serializer.write(car, buffer);
>
>
>
> String text =
> buffer.toString();
>
>
> assertElementExists(text, "/Car");
>
>
> assertElementHasAttribute(text, "/Car",
> "length", "3.3");
>
>
> assertElementHasAttribute(text, "/Car",
> "color", "green");
>
>
> assertElementHasAttribute(text, "/Car",
> "nrOfDoors", "2");
>
>
> assertElementHasAttribute(text, "/Car",
> "topSpeed",
> "190");
>
>
> assertElementHasAttribute(text, "/Car",
> "brand", "audi");
>
> }
>
>
>
>
>
> Thanks
>
>
>
> Christian
>
>
>
> Am 17.11.2012 04:03, schrieb Niall Gallagher:
>
>
>
> 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
>
>
>
>
>
>
>
>
>
>
> --
> 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
>
>
>
>
|