XStream fails to de-serialize java.util.HashSet

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

XStream fails to de-serialize java.util.HashSet

Tobias Gierke
Hi,

We recently started getting weird XStream errors on code that was
previously working fine. IMHO some (seemingly unreleated) change causes
the serialization to output bad XML and this in turn makes the
deserialization fall over later on.

The error message I'm getting is:

com.thoughtworks.xstream.converters.ConversionException: Cannot
deserialize object with new readObject()/writeObject() methods
---- Debugging information ----
class               : java.util.HashSet
required-type       : java.util.HashSet
converter-type      :
com.thoughtworks.xstream.converters.reflection.SerializableConverter
path                :
/com.vodecc.voipmng.boundary.wicket.streamsearch.StreamSearchResultsPage/children/com.vodecc.voipmng.boundary.wicket.general.UserInfoPanel/children/com.vodecc.voipmng.boundary.wicket.general.UserInfoPanel$UserEditableFragment/children/children/data/org.apache.wicket.model.PropertyModel/target/roles
line number         : 1
class[1]            : com.vodecc.voipmng.core.usermng.entity.CVod_UserBean
converter-type[1]   :
com.thoughtworks.xstream.converters.reflection.ReflectionConverter
class[2]            : org.apache.wicket.model.PropertyModel
class[3]            : [Ljava.lang.Object;
converter-type[2]   :
com.thoughtworks.xstream.converters.collections.ArrayConverter
class[4]            : org.apache.wicket.markup.html.basic.Label
class[5]            :
com.vodecc.voipmng.boundary.wicket.integration.StrutsActionLink
class[6]            :
com.vodecc.voipmng.boundary.wicket.general.UserInfoPanel$UserEditableFragment
class[7]            :
com.vodecc.voipmng.boundary.wicket.general.UserInfoPanel
class[8]            :
com.vodecc.voipmng.boundary.wicket.streamsearch.StreamSearchResultsPage
version             : not available

The weird thing is this:

I created a stand-alone unit-test that serializes & deserializes a
org.apache.wicket.model.PropertyModel that wraps a "CVod_UserBean"
instance with a non-empty "roles" HashSet and it works just fine (see
attached file working.xml). It's just not working when serializing the
whole Apache Wicket page.

As a side note, the "roles" attribute actually holds a Hibernate
PersistentSet. I'm using the HibernatePersistentCollectionConverter to
handle this , after changing my unit-test to use PersistentSet instead
of java.util.HashSet it still working correctly.

Comparing the working/broken (see attachments) I see that the *broken*
XML lacks 'serialization='custom' attributes ... what is the meaning of
these attributes and what might be the reason why their missing in the
broken XML (both using an XStream instance with identical
mappers/converters) ?

This is with XStream 1.4.8 and JDK 1.8.0_40 on 64-bit Linux.

Thanks,
Tobias


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

    http://xircles.codehaus.org/manage_email

broken.xml (2K) Download Attachment
working.xml (1K) Download Attachment
Reply | Threaded
Open this post in threaded view
|

Re: XStream fails to de-serialize java.util.HashSet

Jörg Schaible-4
Hi Tobias,

Tobias Gierke wrote:

> Hi,
>
> We recently started getting weird XStream errors on code that was
> previously working fine. IMHO some (seemingly unreleated) change causes
> the serialization to output bad XML and this in turn makes the
> deserialization fall over later on.
>
> The error message I'm getting is:
>
> com.thoughtworks.xstream.converters.ConversionException: Cannot
> deserialize object with new readObject()/writeObject() methods
> ---- Debugging information ----
> class               : java.util.HashSet
> required-type       : java.util.HashSet
> converter-type      :
> com.thoughtworks.xstream.converters.reflection.SerializableConverter
> path                :
>
/com.vodecc.voipmng.boundary.wicket.streamsearch.StreamSearchResultsPage/children/com.vodecc.voipmng.boundary.wicket.general.UserInfoPanel/children/com.vodecc.voipmng.boundary.wicket.general.UserInfoPanel$UserEditableFragment/children/children/data/org.apache.wicket.model.PropertyModel/target/roles

> line number         : 1
> class[1]            : com.vodecc.voipmng.core.usermng.entity.CVod_UserBean
> converter-type[1]   :
> com.thoughtworks.xstream.converters.reflection.ReflectionConverter
> class[2]            : org.apache.wicket.model.PropertyModel
> class[3]            : [Ljava.lang.Object;
> converter-type[2]   :
> com.thoughtworks.xstream.converters.collections.ArrayConverter
> class[4]            : org.apache.wicket.markup.html.basic.Label
> class[5]            :
> com.vodecc.voipmng.boundary.wicket.integration.StrutsActionLink
> class[6]            :
>
com.vodecc.voipmng.boundary.wicket.general.UserInfoPanel$UserEditableFragment

> class[7]            :
> com.vodecc.voipmng.boundary.wicket.general.UserInfoPanel
> class[8]            :
> com.vodecc.voipmng.boundary.wicket.streamsearch.StreamSearchResultsPage
> version             : not available
>
> The weird thing is this:
>
> I created a stand-alone unit-test that serializes & deserializes a
> org.apache.wicket.model.PropertyModel that wraps a "CVod_UserBean"
> instance with a non-empty "roles" HashSet and it works just fine (see
> attached file working.xml). It's just not working when serializing the
> whole Apache Wicket page.
>
> As a side note, the "roles" attribute actually holds a Hibernate
> PersistentSet. I'm using the HibernatePersistentCollectionConverter to
> handle this , after changing my unit-test to use PersistentSet instead
> of java.util.HashSet it still working correctly.
>
> Comparing the working/broken (see attachments) I see that the *broken*
> XML lacks 'serialization='custom' attributes ... what is the meaning of
> these attributes and what might be the reason why their missing in the
> broken XML (both using an XStream instance with identical
> mappers/converters) ?
>
> This is with XStream 1.4.8 and JDK 1.8.0_40 on 64-bit Linux.

You face a version problem in your object model. The problem simply
indicates that the type of the instance used in the "roles" field of
CVod_UserBean is different now.

Compare the following output:

 HashSet<EVF_Permission> hs1 = new HashSet<>();
 hs1.add(EVF_Permission.EXPORT_SIP_TRUNKS);
 HashSet<EVF_Permission> hs2 = new HashSet<>() {};
 hs2.add(EVF_Permission.EXPORT_SIP_TRUNKS);
 System.out.println(xstream.toXML(hs1));
 System.out.println(xstream.toXML(hs2));

You will see in the similar differences to your XML examples.

The first instance is actually handled by the CollectionConverter while the
second instance is handled by the SerializationConverter. Therefore you see
a different XML representation.

So, what has actually be changed?

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: XStream fails to de-serialize java.util.HashSet

Tobias Gierke
Hi Jörg,

> Hi Tobias,
>
> Tobias Gierke wrote:
>
>> Hi,
>>
>> We recently started getting weird XStream errors on code that was
>> previously working fine. IMHO some (seemingly unreleated) change causes
>> the serialization to output bad XML and this in turn makes the
>> deserialization fall over later on.
>>
>> The error message I'm getting is:
>>
>> com.thoughtworks.xstream.converters.ConversionException: Cannot
>> deserialize object with new readObject()/writeObject() methods
>> ---- Debugging information ----
>> class               : java.util.HashSet
>> required-type       : java.util.HashSet
>> converter-type      :
>> com.thoughtworks.xstream.converters.reflection.SerializableConverter
>> path                :
>>
> /com.vodecc.voipmng.boundary.wicket.streamsearch.StreamSearchResultsPage/children/com.vodecc.voipmng.boundary.wicket.general.UserInfoPanel/children/com.vodecc.voipmng.boundary.wicket.general.UserInfoPanel$UserEditableFragment/children/children/data/org.apache.wicket.model.PropertyModel/target/roles
>> line number         : 1
>> class[1]            : com.vodecc.voipmng.core.usermng.entity.CVod_UserBean
>> converter-type[1]   :
>> com.thoughtworks.xstream.converters.reflection.ReflectionConverter
>> class[2]            : org.apache.wicket.model.PropertyModel
>> class[3]            : [Ljava.lang.Object;
>> converter-type[2]   :
>> com.thoughtworks.xstream.converters.collections.ArrayConverter
>> class[4]            : org.apache.wicket.markup.html.basic.Label
>> class[5]            :
>> com.vodecc.voipmng.boundary.wicket.integration.StrutsActionLink
>> class[6]            :
>>
> com.vodecc.voipmng.boundary.wicket.general.UserInfoPanel$UserEditableFragment
>> class[7]            :
>> com.vodecc.voipmng.boundary.wicket.general.UserInfoPanel
>> class[8]            :
>> com.vodecc.voipmng.boundary.wicket.streamsearch.StreamSearchResultsPage
>> version             : not available
>>
>> The weird thing is this:
>>
>> I created a stand-alone unit-test that serializes & deserializes a
>> org.apache.wicket.model.PropertyModel that wraps a "CVod_UserBean"
>> instance with a non-empty "roles" HashSet and it works just fine (see
>> attached file working.xml). It's just not working when serializing the
>> whole Apache Wicket page.
>>
>> As a side note, the "roles" attribute actually holds a Hibernate
>> PersistentSet. I'm using the HibernatePersistentCollectionConverter to
>> handle this , after changing my unit-test to use PersistentSet instead
>> of java.util.HashSet it still working correctly.
>>
>> Comparing the working/broken (see attachments) I see that the *broken*
>> XML lacks 'serialization='custom' attributes ... what is the meaning of
>> these attributes and what might be the reason why their missing in the
>> broken XML (both using an XStream instance with identical
>> mappers/converters) ?
>>
>> This is with XStream 1.4.8 and JDK 1.8.0_40 on 64-bit Linux.
> You face a version problem in your object model. The problem simply
> indicates that the type of the instance used in the "roles" field of
> CVod_UserBean is different now.
>
> Compare the following output:
>
>   HashSet<EVF_Permission> hs1 = new HashSet<>();
>   hs1.add(EVF_Permission.EXPORT_SIP_TRUNKS);
>   HashSet<EVF_Permission> hs2 = new HashSet<>() {};
>   hs2.add(EVF_Permission.EXPORT_SIP_TRUNKS);
>   System.out.println(xstream.toXML(hs1));
>   System.out.println(xstream.toXML(hs2));
>
> You will see in the similar differences to your XML examples.
>
> The first instance is actually handled by the CollectionConverter while the
> second instance is handled by the SerializationConverter. Therefore you see
> a different XML representation.
>
> So, what has actually be changed?

Thanks for your quick response ! We changed too many things
unfortunately :/ We upgraded from XStream 1.4.3 to 1.4.8 because of the
JDK8 fixes and at the same time also did a lot of changes to our
application.

I just managed to "fix" the issue by changing the priorities and set of
converters I registered like so:

========== 1.4.3 =========

         final XStream xstream = new XStream( new StaxDriver() ) {
             @Override
             protected MapperWrapper wrapMapper(MapperWrapper next) {
                 return new WicketProxyMapper( new CGLIBMapper( new
HibernateMapper(next) ) );
             }
         };

          xstream.registerConverter( new WicketProxyConverter() ,
XStream.PRIORITY_VERY_HIGH );
          xstream.registerConverter( new EnumConverter() ,
XStream.PRIORITY_VERY_HIGH );
         xstream.registerConverter(new
HibernatePersistentCollectionConverter(xstream.getMapper()) ,
XStream.PRIORITY_VERY_HIGH );
         xstream.registerConverter(new
HibernatePersistentMapConverter(xstream.getMapper()) ,
XStream.PRIORITY_VERY_HIGH );
         xstream.registerConverter(new
HibernatePersistentSortedMapConverter(xstream.getMapper()) ,
XStream.PRIORITY_VERY_HIGH );
         xstream.registerConverter(new
HibernatePersistentSortedSetConverter(xstream.getMapper()) ,
XStream.PRIORITY_VERY_HIGH );
         xstream.registerConverter(new HibernateProxyConverter() ,
XStream.PRIORITY_VERY_HIGH );
         xstream.registerConverter(new
CGLIBEnhancedConverter(xstream.getMapper(),
xstream.getReflectionProvider() , getClass().getClassLoader() ) );
         xstream.registerConverter( new
SerializableConverter(xstream.getMapper(),
xstream.getReflectionProvider() , getClass().getClassLoader() ) );


========== 1.4.8 =========

         final XStream xstream = new XStream( new StaxDriver() ) {
             @Override
             protected MapperWrapper wrapMapper(MapperWrapper next) {
                 return new WicketProxyMapper( new CGLIBMapper( new
HibernateMapper(next) ) );
             }
         };

         xstream.registerConverter( new WicketProxyConverter() ,
XStream.PRIORITY_VERY_HIGH );
         xstream.registerConverter(new
HibernatePersistentCollectionConverter(xstream.getMapper()) );
         xstream.registerConverter(new
HibernatePersistentMapConverter(xstream.getMapper()) );
         xstream.registerConverter(new
HibernatePersistentSortedMapConverter(xstream.getMapper()) );
         xstream.registerConverter(new
HibernatePersistentSortedSetConverter(xstream.getMapper()) );
         xstream.registerConverter(new HibernateProxyConverter() );
         xstream.registerConverter(new
CGLIBEnhancedConverter(xstream.getMapper(),
xstream.getReflectionProvider() , getClass().getClassLoader() ) );

It *seems* like the issue was caused by an interesting interaction
between the converters but I admit I know far too much about XStreams
inner workings to make sense of this.

Cheers,
Tobias


>
> Cheers,
> Jörg
>
>
> ---------------------------------------------------------------------
> To unsubscribe from this list, please visit:
>
>      http://xircles.codehaus.org/manage_email
>
>


--
Tobias Gierke
Development

VOIPFUTURE GmbH   Wendenstraße 4   20097 Hamburg,  Germany
Phone +49 40 688 900 164 Fax +49 40 688 900 199
Email [hidden email]   Web http://www.voipfuture.com
 
CEO Jan Bastian
       
Commercial Court AG Hamburg   HRB 109896, VAT ID DE263738086



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

    http://xircles.codehaus.org/manage_email


Reply | Threaded
Open this post in threaded view
|

Re: XStream fails to de-serialize java.util.HashSet

Tobias Gierke

> It *seems* like the issue was caused by an interesting interaction
> between the converters but I admit I know far too much about XStreams
> inner workings to make sense of this.
This should've read "[...] know far too little" ofc ;)

>
> Cheers,
> Tobias
>
>
>>
>> Cheers,
>> Jörg
>>
>>
>> ---------------------------------------------------------------------
>> To unsubscribe from this list, please visit:
>>
>>      http://xircles.codehaus.org/manage_email
>>
>>
>
>


--
Tobias Gierke
Development

VOIPFUTURE GmbH   Wendenstraße 4   20097 Hamburg,  Germany
Phone +49 40 688 900 164 Fax +49 40 688 900 199
Email [hidden email]   Web http://www.voipfuture.com
 
CEO Jan Bastian
       
Commercial Court AG Hamburg   HRB 109896, VAT ID DE263738086



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

    http://xircles.codehaus.org/manage_email


Reply | Threaded
Open this post in threaded view
|

Re: Re: XStream fails to de-serialize java.util.HashSet

Jörg Schaible-2
In reply to this post by Tobias Gierke
Hi Tobias,

Tobias Gierke wrote:

[snip]
 

> Thanks for your quick response ! We changed too many things
> unfortunately :/ We upgraded from XStream 1.4.3 to 1.4.8 because of the
> JDK8 fixes and at the same time also did a lot of changes to our
> application.
>
> I just managed to "fix" the issue by changing the priorities and set of
> converters I registered like so:
>
> ========== 1.4.3 =========
>
>          final XStream xstream = new XStream( new StaxDriver() ) {
>              @Override
>              protected MapperWrapper wrapMapper(MapperWrapper next) {
>                  return new WicketProxyMapper( new CGLIBMapper( new
> HibernateMapper(next) ) );
>              }
>          };
>
>           xstream.registerConverter( new WicketProxyConverter() ,
> XStream.PRIORITY_VERY_HIGH );
>           xstream.registerConverter( new EnumConverter() ,
> XStream.PRIORITY_VERY_HIGH );
>          xstream.registerConverter(new
> HibernatePersistentCollectionConverter(xstream.getMapper()) ,
> XStream.PRIORITY_VERY_HIGH );
>          xstream.registerConverter(new
> HibernatePersistentMapConverter(xstream.getMapper()) ,
> XStream.PRIORITY_VERY_HIGH );
>          xstream.registerConverter(new
> HibernatePersistentSortedMapConverter(xstream.getMapper()) ,
> XStream.PRIORITY_VERY_HIGH );
>          xstream.registerConverter(new
> HibernatePersistentSortedSetConverter(xstream.getMapper()) ,
> XStream.PRIORITY_VERY_HIGH );
>          xstream.registerConverter(new HibernateProxyConverter() ,
> XStream.PRIORITY_VERY_HIGH );
>          xstream.registerConverter(new
> CGLIBEnhancedConverter(xstream.getMapper(),
> xstream.getReflectionProvider() , getClass().getClassLoader() ) );
>          xstream.registerConverter( new
> SerializableConverter(xstream.getMapper(),
> xstream.getReflectionProvider() , getClass().getClassLoader() ) );
>
>
> ========== 1.4.8 =========
>
>          final XStream xstream = new XStream( new StaxDriver() ) {
>              @Override
>              protected MapperWrapper wrapMapper(MapperWrapper next) {
>                  return new WicketProxyMapper( new CGLIBMapper( new
> HibernateMapper(next) ) );
>              }
>          };
>
>          xstream.registerConverter( new WicketProxyConverter() ,
> XStream.PRIORITY_VERY_HIGH );
>          xstream.registerConverter(new
> HibernatePersistentCollectionConverter(xstream.getMapper()) );
>          xstream.registerConverter(new
> HibernatePersistentMapConverter(xstream.getMapper()) );
>          xstream.registerConverter(new
> HibernatePersistentSortedMapConverter(xstream.getMapper()) );
>          xstream.registerConverter(new
> HibernatePersistentSortedSetConverter(xstream.getMapper()) );
>          xstream.registerConverter(new HibernateProxyConverter() );
>          xstream.registerConverter(new
> CGLIBEnhancedConverter(xstream.getMapper(),
> xstream.getReflectionProvider() , getClass().getClassLoader() ) );
>
> It *seems* like the issue was caused by an interesting interaction
> between the converters but I admit I know far too much about XStreams
> inner workings to make sense of this.


The most problematic action was/is the registration of the
SerializationConverter with normal priority. That will prefer it over any
other converter with same priority (see default priority in  
http://xstream.codehaus.org/converters.html) i.e. any Serializable with a
readObject/writeObject method will now be handled by the generic
SerializationConverter instead of the more specialized one (e.g. the
CollectionConverter for a HashSet).

Try yourself:

 HashSet<String> hs = new HashSet<>();
 hs.add("test");

 XStream xstream = new XStream();
 xstream.registerConverter(
   new SerializableConverter(xstream.getMapper(),
   xstream.getReflectionProvider(), xstream.getClassLoaderReference()));
 System.out.Println(xstream.toXML(hs));
 System.out.Println(new XStream().toXML(hs)); // vanilla instance

That should make a difference.

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: XStream fails to de-serialize java.util.HashSet

Jörg Schaible-2
In reply to this post by Tobias Gierke
Tobias Gierke wrote:

>
>> It *seems* like the issue was caused by an interesting interaction
>> between the converters but I admit I know far too much about XStreams
>> inner workings to make sense of this.
> This should've read "[...] know far too little" ofc ;)

;-)

Cheers,
Jörg


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

    http://xircles.codehaus.org/manage_email