Re: [Simple-support] Serialize and deserialize undefined Xml attributes into a HashMap<String, Stri
Brought to you by:
niallg
|
From: Christian K. <c....@sp...> - 2012-11-19 09:31:39
|
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
|