Problem using the NamedMapconverter

classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|

Problem using the NamedMapconverter

Johann Kerdal
Hi guys,

I need to unmarshall an XML document to a linkedHashMap<String,ColumnAttributes>

The XML document I get from the server system is containing the list of objects:
<ColumnAttributes key="BSI_REFIN_INTR_BU_CURRY_AMT">
      <name>BSI_REFIN_INTR_BU_CURRY_AMT</name>
      <label>Refinancing interest amount in BU currency</label>
      <length>8.0</length>
      <format>NLNUM18.</format>
      <inFormat>NLNUM18.</inFormat>
  </ColumnAttributes>

As you can see, the key is an attribute of the ColumnAttributes Element.

I have tested this code:
new NamedMapConverter(LinkedHashMap.class,xstream.getMapper(), 
"column", "key", String.class, "column", ColumnAttributes.class, true, false, xstream.getConverterLookup())

but it generates one element for the key and one for the value.

If I use this one:
new NamedMapConverter(LinkedHashMap.class,xstream.getMapper(), 
"column", "key", String.class, null, ColumnAttributes.class, true, false, xstream.getConverterLookup())

Here is the complete code:
XStream xstream = new XStream(new DomDriver());
        // XStream xstream = new XStream(new DomDriver());
        xstream.alias("columns",LinkedHashMap.class) ;
        xstream.alias("column",ColumnAttributes.class) ;
        ConverterLookup lookup = xstream.getConverterLookup() ;
        Converter conv = xstream.getConverterLookup().lookupConverterForType(String.class) ;
        System.out.println(conv.canConvert(String.class)) ;
        xstream.registerConverter(
         new NamedMapConverter(LinkedHashMap.class,xstream.getMapper(), "column", "key", String.class, null, ColumnAttributes.class, true, false, xstream.getConverterLookup()
        ));
        // String xml = xstream.toXML(rulesBook.getColumnsAttributes());
        // System.out.println(xml);
        String xml="<columns><column key=\"BSI_REFIN_INTR_BU_CURRY_AMT\"><name>BSI_REFIN_INTR_BU_CURRY_AMT</name><label>Refinancing interest amount in BU currency</label><length>8.0</length></column></columns>" ;
        LinkedHashMap<String,ColumnAttributes> test = (LinkedHashMap<String,ColumnAttributes>)xstream.fromXML(xml) ;
        
I get the following error:
Exception in thread "main" com.thoughtworks.xstream.converters.ConversionException: No SingleValueConverter for key available
---- Debugging information ----
class               : java.util.LinkedHashMap
required-type       : java.util.LinkedHashMap
converter-type      : com.thoughtworks.xstream.converters.extended.NamedMapConverter
path                : /columns
version             : 1.4.7
-------------------------------
at com.thoughtworks.xstream.converters.extended.NamedMapConverter.getSingleValueConverter(NamedMapConverter.java:359)
at com.thoughtworks.xstream.converters.extended.NamedMapConverter.populateMap(NamedMapConverter.java:293)
at com.thoughtworks.xstream.converters.collections.MapConverter.populateMap(MapConverter.java:92)
at com.thoughtworks.xstream.converters.collections.MapConverter.unmarshal(MapConverter.java:87)
at com.thoughtworks.xstream.core.TreeUnmarshaller.convert(TreeUnmarshaller.java:72)
at com.thoughtworks.xstream.core.AbstractReferenceUnmarshaller.convert(AbstractReferenceUnmarshaller.java:65)
at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:66)
at com.thoughtworks.xstream.core.TreeUnmarshaller.convertAnother(TreeUnmarshaller.java:50)
at com.thoughtworks.xstream.core.TreeUnmarshaller.start(TreeUnmarshaller.java:134)
at com.thoughtworks.xstream.core.AbstractTreeMarshallingStrategy.unmarshal(AbstractTreeMarshallingStrategy.java:32)
at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1185)
at com.thoughtworks.xstream.XStream.unmarshal(XStream.java:1169)
at com.thoughtworks.xstream.XStream.fromXML(XStream.java:1040)
at com.thoughtworks.xstream.XStream.fromXML(XStream.java:1031)
at com.keinavo.cse.excel.ExcelReaderSample.main(ExcelReaderSample.java:65)



Is it possible to have the key as an attribute of the value element in the XML using the NamedMapconverter?

If not, do you have any suggestion for me?

Any feedback is welcome..


TIA 

Johann
Reply | Threaded
Open this post in threaded view
|

fromXML exception on the client when a new field is added to the incoming object/xml

Kilakkencherry, Hariharan G

Hi,

 

I have a client which is using an old interface and the provider has added a new field to the class. So when I am trying to deserialize the incoming object using the method fromXML I get an exception. What can be done on the client side to work around this issue without having to update the interface to match with the server every time there is a change?

 

Thanks

Hari

 

This communication is for informational purposes only. It is not intended as an offer or solicitation for the purchase or sale of any financial instrument or as an official confirmation of any transaction. All market prices, data and other information are not warranted as to completeness or accuracy and are subject to change without notice. Any comments or statements made herein do not necessarily reflect those of JPMorgan Chase & Co., its subsidiaries and affiliates. This transmission may contain information that is proprietary, privileged, confidential and/or exempt from disclosure under applicable law. If you are not the intended recipient, you are hereby notified that any disclosure, copying, distribution, or use of the information contained herein (including any reliance thereon) is STRICTLY PROHIBITED. Although this transmission and any attachments are believed to be free of any virus or other defect that might affect any computer system into which it is received and opened, it is the responsibility of the recipient to ensure that it is virus free and no responsibility is accepted by JPMorgan Chase & Co., its subsidiaries and affiliates, as applicable, for any loss or damage arising in any way from its use. If you received this transmission in error, please immediately contact the sender and destroy the material in its entirety, whether in electronic or hard copy format. Thank you. Please refer to http://www.jpmorgan.com/pages/disclosures for disclosures relating to European legal entities.

Reply | Threaded
Open this post in threaded view
|

Re: Problem using the NamedMapconverter

Jörg Schaible-4
In reply to this post by Johann Kerdal
Hi Johann,

sorry for the late response, but I was on holidays and try to clear the
backlog slowly again.

Johann Kerdal wrote:

> Hi guys,
>
> I need to unmarshall an XML document to a
> linkedHashMap<String,ColumnAttributes>
>
> The XML document I get from the server system is containing the list of
> objects:
> <ColumnAttributes key="BSI_REFIN_INTR_BU_CURRY_AMT">
>       <name>BSI_REFIN_INTR_BU_CURRY_AMT</name>
>       <label>Refinancing interest amount in BU currency</label>
>       <length>8.0</length>
>       <format>NLNUM18.</format>
>       <inFormat>NLNUM18.</inFormat>
>   </ColumnAttributes>
>
> As you can see, the key is an attribute of the ColumnAttributes Element.
>
> I have tested this code:
> new NamedMapConverter(LinkedHashMap.class,xstream.getMapper(),
> "column", "key", String.class, *"column"*, ColumnAttributes.class, true,
> false, xstream.getConverterLookup())
>
> but it generates one element for the key and one for the value.
>
> If I use this one:
> new NamedMapConverter(LinkedHashMap.class,xstream.getMapper(),
> "column", "key", String.class, *null*, ColumnAttributes.class, true,
> false, xstream.getConverterLookup())
>
> Here is the complete code:
> XStream xstream = new XStream(new DomDriver());
>         // XStream xstream = new XStream(new DomDriver());
>         xstream.alias("columns",LinkedHashMap.class) ;
>         xstream.alias("column",ColumnAttributes.class) ;
>         ConverterLookup lookup = xstream.getConverterLookup() ;
>         Converter conv =
> xstream.getConverterLookup().lookupConverterForType(String.class) ;
>         System.out.println(conv.canConvert(String.class)) ;
>         xstream.registerConverter(
>          new NamedMapConverter(LinkedHashMap.class,xstream.getMapper(),
> "column", "key", String.class, null, ColumnAttributes.class, true, false,
> xstream.getConverterLookup()
>         ));
>         // String xml = xstream.toXML(rulesBook.getColumnsAttributes());
>         // System.out.println(xml);
>         String xml="<columns><column
>
key=\"BSI_REFIN_INTR_BU_CURRY_AMT\"><name>BSI_REFIN_INTR_BU_CURRY_AMT</name><label>Refinancing
> interest amount in BU
> currency</label><length>8.0</length></column></columns>" ;
>         LinkedHashMap<String,ColumnAttributes> test =
> (LinkedHashMap<String,ColumnAttributes>)xstream.fromXML(xml) ;
>

[snip]

>
>
> Is it possible to have the key as an attribute of the value element in the
> XML using the NamedMapconverter?

No. See, a map has normally following XML representation:

 <map>
  <entry>
    <key>K</key>
    <value>V</value>
  </entry>
 </map>

where K and/or V might either be a String or another XML structure. The
NamedMapConverter allows you to use different names for the inner elements
entry, key and value.

A special mode is offered to drop the entry element:

 <map>
  <key>K</key>
  <value>V</value>
 </map>

Or you might use attributes for key and/or value *if* K resp. V is a String
i.e. the converter for those objects returns a single value. However, then
you have to keep the entry element:

 <map>
  <entry key="K">
    <value>V</value>
  </entry>
 </map>

or:

 <map>
  <entry key="K" value="V"/>
 </map>

Nevertheless, the representation for key and value is always present either
as XML element or attribute.

Since your value type contains the key, you try to drop the key element of
the map and use the value as entry element instead with an attribute for the
key property. Obviously your situation does not match the functionality of
this converter.

> If not, do you have any suggestion for me?
>
> Any feedback is welcome..

I would actually just use a custom converter for the LinkedHashMap (register
locally if the LinkedHashMap is an element of a higher level, otherwise all
LinkedHashMaps will be handled):

================== %< =======================
 class AttributesConverter implements Converter {
   Converter listConverter;
   AttributesConverter(Mapper mapper) {
     listConverter = new CollectionConverter(mapper);
   }
   boolean canConvert(Class t) {
     return LinkedHashMap.class.equals(t);
   }
   void marshal(Object source, HierarchicalStreamWriter writer,
MarshallingContext context) {
     Map map = (Map)source;
     listConverter.marshal(map.values(), writer, context);
   }
   Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext
context) {
     Collection<ColumnAttributes> values =
       listConverter.unmarshal(reader, context);
     Map<String, ColumnAttributes> map = new LinkedHashMap<>();
     for(ColumnAttributes attr : values) {
       map.put(attr.getKey(), attr);
     }
     return map;
   }
 }
 xstream.registerConverter(
   new AttributesConverter(xstream.getMapper()));
 xstream.useAttributeFor(ColumnAttributes.class, "key");
 xstream.alias("ColumnAttributes", ColumnAttributes.class);
================== %< =======================

Hope this helps,
Jörg



---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email


Reply | Threaded
Open this post in threaded view
|

Re: fromXML exception on the client when a new field is added to the incoming object/xml

Jörg Schaible-4
In reply to this post by Kilakkencherry, Hariharan G
Hi Hari,

sorry for the late response, but I was on holidays and work through the
backlog now.

Kilakkencherry, Hariharan G wrote:

> Hi,
>
> I have a client which is using an old interface and the provider has added
> a new field to the class. So when I am trying to deserialize the incoming
> object using the method fromXML I get an exception.

This is the intended behavior.

> What can be done on
> the client side to work around this issue without having to update the
> interface to match with the server every time there is a change?

See http://xstream.codehaus.org/faq.html#Serialization_newer_class_versions
As an additional alternative you can setup XStream to omit the field for the
class (even if the class does not have the member at all).

Cheers,
Jörg



---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email


Reply | Threaded
Open this post in threaded view
|

Re: Problem using the NamedMapconverter

Johann Kerdal
In reply to this post by Jörg Schaible-4
Hi Jorg,

Thanks a lot for your feedback. I will give it a try.

Cheers

Johann

On Wed, Sep 17, 2014 at 2:29 PM, Jörg Schaible <[hidden email]> wrote:
Hi Johann,

sorry for the late response, but I was on holidays and try to clear the
backlog slowly again.

Johann Kerdal wrote:

> Hi guys,
>
> I need to unmarshall an XML document to a
> linkedHashMap<String,ColumnAttributes>
>
> The XML document I get from the server system is containing the list of
> objects:
> <ColumnAttributes key="BSI_REFIN_INTR_BU_CURRY_AMT">
>       <name>BSI_REFIN_INTR_BU_CURRY_AMT</name>
>       <label>Refinancing interest amount in BU currency</label>
>       <length>8.0</length>
>       <format>NLNUM18.</format>
>       <inFormat>NLNUM18.</inFormat>
>   </ColumnAttributes>
>
> As you can see, the key is an attribute of the ColumnAttributes Element.
>
> I have tested this code:
> new NamedMapConverter(LinkedHashMap.class,xstream.getMapper(),
> "column", "key", String.class, *"column"*, ColumnAttributes.class, true,
> false, xstream.getConverterLookup())
>
> but it generates one element for the key and one for the value.
>
> If I use this one:
> new NamedMapConverter(LinkedHashMap.class,xstream.getMapper(),
> "column", "key", String.class, *null*, ColumnAttributes.class, true,
> false, xstream.getConverterLookup())
>
> Here is the complete code:
> XStream xstream = new XStream(new DomDriver());
>         // XStream xstream = new XStream(new DomDriver());
>         xstream.alias("columns",LinkedHashMap.class) ;
>         xstream.alias("column",ColumnAttributes.class) ;
>         ConverterLookup lookup = xstream.getConverterLookup() ;
>         Converter conv =
> xstream.getConverterLookup().lookupConverterForType(String.class) ;
>         System.out.println(conv.canConvert(String.class)) ;
>         xstream.registerConverter(
>          new NamedMapConverter(LinkedHashMap.class,xstream.getMapper(),
> "column", "key", String.class, null, ColumnAttributes.class, true, false,
> xstream.getConverterLookup()
>         ));
>         // String xml = xstream.toXML(rulesBook.getColumnsAttributes());
>         // System.out.println(xml);
>         String xml="<columns><column
>
key=\"BSI_REFIN_INTR_BU_CURRY_AMT\"><name>BSI_REFIN_INTR_BU_CURRY_AMT</name><label>Refinancing
> interest amount in BU
> currency</label><length>8.0</length></column></columns>" ;
>         LinkedHashMap<String,ColumnAttributes> test =
> (LinkedHashMap<String,ColumnAttributes>)xstream.fromXML(xml) ;
>

[snip]

>
>
> Is it possible to have the key as an attribute of the value element in the
> XML using the NamedMapconverter?

No. See, a map has normally following XML representation:

 <map>
  <entry>
    <key>K</key>
    <value>V</value>
  </entry>
 </map>

where K and/or V might either be a String or another XML structure. The
NamedMapConverter allows you to use different names for the inner elements
entry, key and value.

A special mode is offered to drop the entry element:

 <map>
  <key>K</key>
  <value>V</value>
 </map>

Or you might use attributes for key and/or value *if* K resp. V is a String
i.e. the converter for those objects returns a single value. However, then
you have to keep the entry element:

 <map>
  <entry key="K">
    <value>V</value>
  </entry>
 </map>

or:

 <map>
  <entry key="K" value="V"/>
 </map>

Nevertheless, the representation for key and value is always present either
as XML element or attribute.

Since your value type contains the key, you try to drop the key element of
the map and use the value as entry element instead with an attribute for the
key property. Obviously your situation does not match the functionality of
this converter.

> If not, do you have any suggestion for me?
>
> Any feedback is welcome..

I would actually just use a custom converter for the LinkedHashMap (register
locally if the LinkedHashMap is an element of a higher level, otherwise all
LinkedHashMaps will be handled):

================== %< =======================
 class AttributesConverter implements Converter {
   Converter listConverter;
   AttributesConverter(Mapper mapper) {
     listConverter = new CollectionConverter(mapper);
   }
   boolean canConvert(Class t) {
     return LinkedHashMap.class.equals(t);
   }
   void marshal(Object source, HierarchicalStreamWriter writer,
MarshallingContext context) {
     Map map = (Map)source;
     listConverter.marshal(map.values(), writer, context);
   }
   Object unmarshal(HierarchicalStreamReader reader, UnmarshallingContext
context) {
     Collection<ColumnAttributes> values =
       listConverter.unmarshal(reader, context);
     Map<String, ColumnAttributes> map = new LinkedHashMap<>();
     for(ColumnAttributes attr : values) {
       map.put(attr.getKey(), attr);
     }
     return map;
   }
 }
 xstream.registerConverter(
   new AttributesConverter(xstream.getMapper()));
 xstream.useAttributeFor(ColumnAttributes.class, "key");
 xstream.alias("ColumnAttributes", ColumnAttributes.class);
================== %< =======================

Hope this helps,
Jörg



---------------------------------------------------------------------
To unsubscribe from this list, please visit:

    http://xircles.codehaus.org/manage_email