Using CollectionConverter with @XStreamConverter

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

Using CollectionConverter with @XStreamConverter

depstein

Hi,

 

When CollectionConverter is used with the @XStreamConverter annotation, the converter is set up so that it will only accept the TreeMap collection type. This is an odd behavior! Is there any way to suppress this initialization (CollectionConverter has a constructor that doesn’t limit it to just one particular type), or to specify some other type, such as ArrayList?

 

public class ItemList {

    @XStreamConverter(value = CollectionConverter.class)

    public List<String> items;

}

 

As a workaround, I subclassed CollectionConverter:

 

public class ItemList {

    @XStreamConverter(value = ListCollectionConverter.class)

    public List<String> items;

 

    public static class ListCollectionConverter extends CollectionConverter {

        public ListCollectionConverter(Mapper mapper) {

            super(mapper);

        }

    }

}

 

This did the trick, but it is very counterintuitive.

 

Dmitry Epstein | Developer

Allied Testing

T + 7 495 544 3694 Ext 443

M + 7 926 215 73 36

 

www.alliedtesting.com

We Deliver Quality.

 

Reply | Threaded
Open this post in threaded view
|

Re: Using CollectionConverter with @XStreamConverter

Jörg Schaible-2
Hi Dmitry,

[hidden email] wrote:

> Hi,
>
> When CollectionConverter is used with the @XStreamConverter annotation,
> the converter is set up so that it will only accept the TreeMap collection
> type.

?? Sorry, I don't understand, what you try to tell me here.

> This is an odd behavior! Is there any way to suppress this
> initialization (CollectionConverter has a constructor that doesn't limit
> it to just one particular type), or to specify some other type, such as
> ArrayList?
>
> public class ItemList {
>     @XStreamConverter(value = CollectionConverter.class)
>     public List<String> items;
> }

I don't understand this example either. You setup an own CollectionConverter
for the list, but that's the default anyway.


>
> As a workaround, I subclassed CollectionConverter:
>
> public class ItemList {
>     @XStreamConverter(value = ListCollectionConverter.class)
>     public List<String> items;
>
>     public static class ListCollectionConverter extends
>     CollectionConverter {
>         public ListCollectionConverter(Mapper mapper) {
>             super(mapper);
>         }
>     }
> }
>
> This did the trick, but it is very counterintuitive.

Where's the difference?

Maybe you tell me first, what you actually try to accomplish...

- Jörg


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

    http://xircles.codehaus.org/manage_email


Reply | Threaded
Open this post in threaded view
|

Re: Using CollectionConverter with @XStreamConverter

depstein
OK, I just realized that I misdiagnozed the problem. What actually happens is that CollectionConverter is initialized with the List type, because that is the declared type of the field. The actual type of the field (ArrayList) differs from the type with which the converter was initialized, which is why it won't work. Here is the canConvert method in CollectionConverter:

    public boolean canConvert(Class type) {
        if (this.type != null) {
            return type.equals(this.type);
        }
        return type.equals(ArrayList.class)
            || type.equals(HashSet.class)
            || type.equals(LinkedList.class)
            || type.equals(Vector.class)
            || (JVM.is14() && type.getName().equals("java.util.LinkedHashSet"));
    }

this.type is List, and type is ArrayList. Perhaps this would be better?

            return type.isAssignableFrom(this.type);


Here is a complete example:

import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

import com.thoughtworks.xstream.XStream;
import com.thoughtworks.xstream.annotations.XStreamConverter;
import com.thoughtworks.xstream.converters.collections.CollectionConverter;
import com.thoughtworks.xstream.io.xml.PrettyPrintWriter;
import com.thoughtworks.xstream.io.xml.StaxDriver;

public class ItemList {

        @XStreamConverter(CollectionConverter.class)
        public List<String> items = new ArrayList<String>();

        public static void main(String[] args) throws FileNotFoundException {
                ItemList ilist = new ItemList();
                ilist.items.add("One");
                ilist.items.add("Two");
                XStream x = new XStream(new StaxDriver());
                x.autodetectAnnotations(true);
                PrintWriter writer = null;
                try {
                        writer = new PrintWriter(new File("items.xml"));
                        x.marshal(ilist, new PrettyPrintWriter(writer));
                } finally {
                        if (writer != null)
                                writer.close();
                }
        }
}

I get an exception with XStream 1.4.6.1:

Exception in thread "main" com.thoughtworks.xstream.converters.ConversionException: Explicit selected converter cannot handle item
---- Debugging information ----
item-type           : java.util.ArrayList
converter-type      : com.thoughtworks.xstream.converters.collections.CollectionConverter
-------------------------------

If I use a custom converter instead:

        @XStreamConverter(MyCollectionConverter.class)
        public List<String> items = new ArrayList<String>();

        public static class MyCollectionConverter extends CollectionConverter {
                public MyCollectionConverter(Mapper mapper) {
                        super(mapper);
                }
        }

then the CollectionConverter is not initialized with a specific type (type == null), which leads to a different branch in canConvert.

-----Original Message-----
From: Jörg Schaible [mailto:[hidden email]]
Sent: Friday, February 21, 2014 1:36 AM
To: [hidden email]
Subject: [xstream-user] Re: Using CollectionConverter with @XStreamConverter

Hi Dmitry,

[hidden email] wrote:

> Hi,
>
> When CollectionConverter is used with the @XStreamConverter
> annotation, the converter is set up so that it will only accept the
> TreeMap collection type.

?? Sorry, I don't understand, what you try to tell me here.

> This is an odd behavior! Is there any way to suppress this
> initialization (CollectionConverter has a constructor that doesn't
> limit it to just one particular type), or to specify some other type,
> such as ArrayList?
>
> public class ItemList {
>     @XStreamConverter(value = CollectionConverter.class)
>     public List<String> items;
> }

I don't understand this example either. You setup an own CollectionConverter for the list, but that's the default anyway.


>
> As a workaround, I subclassed CollectionConverter:
>
> public class ItemList {
>     @XStreamConverter(value = ListCollectionConverter.class)
>     public List<String> items;
>
>     public static class ListCollectionConverter extends
>     CollectionConverter {
>         public ListCollectionConverter(Mapper mapper) {
>             super(mapper);
>         }
>     }
> }
>
> This did the trick, but it is very counterintuitive.

Where's the difference?

Maybe you tell me first, what you actually try to accomplish...

- Jörg
Reply | Threaded
Open this post in threaded view
|

RE: Re: Using CollectionConverter with @XStreamConverter

Jörg Schaible-4

Hi Dmitry,

[hidden email] wrote:

> OK, I just realized that I misdiagnozed the problem. What actually happens
> is that CollectionConverter is initialized with the List type, because
> that is the declared type of the field. The actual type of the field
> (ArrayList) differs from the type with which the converter was
> initialized, which is why it won't work. Here is the canConvert method in
> CollectionConverter:
>
>     public boolean canConvert(Class type) {
>         if (this.type != null) {
>             return type.equals(this.type);
>         }
>         return type.equals(ArrayList.class)
>             || type.equals(HashSet.class)
>             || type.equals(LinkedList.class)
>             || type.equals(Vector.class)
>             || (JVM.is14() &&
>             || type.getName().equals("java.util.LinkedHashSet"));
>     }
>
> this.type is List, and type is ArrayList. Perhaps this would be better?
>
>             return type.isAssignableFrom(this.type);

Definitely not, because XStream cannot know what else a different Collection
implementation keeps internally. E.g. it would forget about a TreeSet's
comparator or an unmodifiable list would no longer be unmodifiable.

> Here is a complete example:
>
> import java.io.File;
> import java.io.FileNotFoundException;
> import java.io.PrintWriter;
> import java.util.ArrayList;
> import java.util.List;
>
> import com.thoughtworks.xstream.XStream;
> import com.thoughtworks.xstream.annotations.XStreamConverter;
> import
> com.thoughtworks.xstream.converters.collections.CollectionConverter;
> import com.thoughtworks.xstream.io.xml.PrettyPrintWriter; import
> com.thoughtworks.xstream.io.xml.StaxDriver;
>
> public class ItemList {
>
> @XStreamConverter(CollectionConverter.class)
> public List<String> items = new ArrayList<String>();

[snip]

Look at the Javadoc for the XStreamConverter annotation. XStream performs a
poor man's constructor dependency injection. The constructor with the most
arguments is considered first, possible parameters are the current type (in
your case List.class), some standard XStream objects and anything you
provide as static parameter for the annotation.

The declaration to initialize a CollectionConverter is a bit tricky though,
because you do *not* want to consider the current type:

@XStreamConverter(value=CollectionConverter.class, types={ArrayList.class},
useImplicitType = false)

Have a look at
com.thoughtworks.acceptance.annotations.ParametrizedConverterTest for more
examples.

[snip]

> I get an exception with XStream 1.4.6.1:

?!? What is XStream 1.4.6.1? We release 1.4.6 and 1.4.7, but nothing
inbetween.

[snip]

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: Re: Using CollectionConverter with @XStreamConverter

depstein
H Jörg,

> Look at the Javadoc for the XStreamConverter annotation. XStream performs a poor man's constructor dependency injection. The constructor with the most arguments is considered first, possible parameters are the current type (in your case List.class), some standard XStream objects and anything you provide as static parameter for the annotation.

> The declaration to initialize a CollectionConverter is a bit tricky though, because you do *not* want to consider the current type:

> @XStreamConverter(value=CollectionConverter.class, types={ArrayList.class}, useImplicitType = false)

> Have a look at
> com.thoughtworks.acceptance.annotations.ParametrizedConverterTest for more examples.

OK, thanks. I was trying to do something like that, but didn't quite come up with the right combination of parameters. The docs on annotations are rather skimpy.

> [snip]

> > I get an exception with XStream 1.4.6.1:

> ?!? What is XStream 1.4.6.1? We release 1.4.6 and 1.4.7, but nothing inbetween.

Yeah, sorry, that was an OSGi bundle version. The XStream version is 1.4.6.

Dmitry

Reply | Threaded
Open this post in threaded view
|

RE: RE: Re: Using CollectionConverter with @XStreamConverter

Jörg Schaible-4
Hi Dmitry,

[hidden email] wrote:


[snip]

>> ?!? What is XStream 1.4.6.1? We release 1.4.6 and 1.4.7, but nothing
>> inbetween.
>
> Yeah, sorry, that was an OSGi bundle version. The XStream version is
> 1.4.6.

Is there something wrong with the OSGi info in 1.4.6?

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: RE: Re: Using CollectionConverter with @XStreamConverter

depstein
>>> ?!? What is XStream 1.4.6.1? We release 1.4.6 and 1.4.7, but nothing
>>> inbetween.
>>
>> Yeah, sorry, that was an OSGi bundle version. The XStream version is
>> 1.4.6.

>Is there something wrong with the OSGi info in 1.4.6?

I don't know. Has XStream released an OSGi bundle for 1.4.6? Mine comes from a different source (Apache). I don't remember the reasons why we get our bundles from a third party.

Dmitry
Reply | Threaded
Open this post in threaded view
|

RE: RE: RE: Re: Using CollectionConverter with @XStreamConverter

Jörg Schaible-4
Hi Dmtry,

[hidden email] wrote:

>>>> ?!? What is XStream 1.4.6.1? We release 1.4.6 and 1.4.7, but nothing
>>>> inbetween.
>>>
>>> Yeah, sorry, that was an OSGi bundle version. The XStream version is
>>> 1.4.6.
>
>>Is there something wrong with the OSGi info in 1.4.6?
>
> I don't know. Has XStream released an OSGi bundle for 1.4.6? Mine comes
> from a different source (Apache). I don't remember the reasons why we get
> our bundles from a third party.

OSGi bundle is present since version 1.4.5 (see minor changes of
http://xstream.codehaus.org/changes.html#1.4.5):

================== %< ======================
$ catmf xstream-1.4.6.jar
Manifest-Version: 1.0
Archiver-Version: Plexus Archiver
Created-By: Apache Maven Bundle Plugin
Built-By: joehni
Build-Jdk: 1.7.0_45
Specification-Title: XStream Core
Specification-Vendor: XStream
Implementation-Title: XStream Core
Implementation-Version: 1.4.6
Implementation-Vendor-Id: com.thoughtworks.xstream
Implementation-Vendor: XStream
Specification-Version: 1.4
X-Build-Os: Linux
X-Build-Time: 20131212-1854
X-Builder: Maven 3.0.5
X-Compile-Source: 1.5
X-Compile-Target: 1.5
Bnd-LastModified: 1386870879781
Bundle-Description: XStream is a serialization library from Java objec
 ts to XML and back.
Bundle-DocURL: http://xstream.codehaus.org
Bundle-License: http://xstream.codehaus.org/license.html
Bundle-ManifestVersion: 2
Bundle-Name: XStream Core
Bundle-SymbolicName: xstream
Bundle-Vendor: XStream
Bundle-Version: 1.4.6
Export-Package: com.thoughtworks.xstream.io.copy;version="1.4.6",com.t
 houghtworks.xstream.io.path;version="1.4.6",com.thoughtworks.xstream.
 converters.basic;version="1.4.6",com.thoughtworks.xstream.io.xml.xppd
 om;version="1.4.6",com.thoughtworks.xstream;version="1.4.6",com.thoug
 htworks.xstream.io.json;version="1.4.6",com.thoughtworks.xstream.conv
 erters.javabean;version="1.4.6",com.thoughtworks.xstream.io;version="
 1.4.6",com.thoughtworks.xstream.converters.extended;version="1.4.6",c
 om.thoughtworks.xstream.converters;version="1.4.6",com.thoughtworks.x
 stream.converters.reflection;version="1.4.6",com.thoughtworks.xstream
 .annotations;version="1.4.6",com.thoughtworks.xstream.io.binary;versi
 on="1.4.6",com.thoughtworks.xstream.io.xml;version="1.4.6",com.though
 tworks.xstream.mapper;version="1.4.6",com.thoughtworks.xstream.persis
 tence;version="1.4.6",com.thoughtworks.xstream.converters.collections
 ;version="1.4.6",com.thoughtworks.xstream.core;version="1.4.6",com.th
 oughtworks.xstream.io.naming;version="1.4.6",com.thoughtworks.xstream
 .converters.enums;version="1.4.6"
Import-Package: com.bea.xml.stream;resolution:=optional,com.ctc.wstx.s
 tax;resolution:=optional,javax.security.auth,javax.swing,javax.swing.
 plaf,javax.xml.datatype,javax.xml.namespace;resolution:=optional,java
 x.xml.parsers,javax.xml.stream;resolution:=optional,javax.xml.transfo
 rm,javax.xml.transform.sax,javax.xml.transform.stream,net.sf.cglib.pr
 oxy;resolution:=optional,nu.xom;resolution:=optional,org.codehaus.jet
 tison;version="[1.2,2)";resolution:=optional,org.codehaus.jettison.ma
 pped;version="[1.2,2)";resolution:=optional,org.dom4j;resolution:=opt
 ional,org.dom4j.io;resolution:=optional,org.dom4j.tree;resolution:=op
 tional,org.jdom;resolution:=optional,org.jdom.input;resolution:=optio
 nal,org.jdom2;resolution:=optional,org.jdom2.input;resolution:=option
 al,org.joda.time;version="[1.6,2)";resolution:=optional,org.joda.time
 .format;version="[1.6,2)";resolution:=optional,org.kxml2.io;resolutio
 n:=optional,org.w3c.dom;resolution:=optional,org.xml.sax,org.xml.sax.
 helpers,org.xmlpull.mxp1,org.xmlpull.v1,sun.misc
Tool: Bnd-1.50.0
================== %< ======================

Just curious,
Jörg


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

    http://xircles.codehaus.org/manage_email