jira.codehaus.org

  • Log In Access more options
    • Online Help
    • Keyboard Shortcuts
    • About JIRA
    • JIRA Credits
    • What?s New
  • Dashboards Access more options (Alt+d)
  • Projects Access more options (Alt+p)
  • Issues Access more options (Alt+i)
  • XStream
  • XSTR-239

Xstream fails to deserialize elements in a CGLIB based HashMap proxy

  • Log In
  • Views
    • XML
    • Word
    • Printable

Details

  • Type: Bug Bug
  • Status: Closed Closed
  • Resolution: Fixed
  • Affects Version/s: None
  • Fix Version/s: 1.2
  • Component/s: None
  • Labels:
    None

Description

XStream seems to have trouble with CGLIB proxies based on real classes. See following effect for a proxy extending HashMap, where the ObjectName element gets lost, that is stored in the HashMap of the DelegatingHandler:

public class DelegatingHandler implements InvocationHandler, Serializable {
private final Object delegate;

public DelegatingHandler(Object delegate) { this.delegate = delegate; }

public Object invoke(Object obj, Method method, Object[] args) throws Throwable { return method.invoke(delegate, args); }
}

/**

  • @throws Exception
    */
    public void testCGLib() throws Exception
    Unknown macro: { final Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(HashMap.class); enhancer.setInterfaces(new Class[]{Map.class}); enhancer.setCallback(new DelegatingHandler(new HashMap())); final Map orig = (Map)enhancer.create(); orig.put("ObjectName", new ObjectName("domain}

Issue Links

supercedes

New Feature - A new feature of the product, which has yet to be developed. XSTR-238 mapper for CGLib classes

  • Closed - The issue is considered finished, the resolution is correct. Issues which are not closed can be reopened.

Improvement - An improvement or enhancement to an existing feature or task. XSTR-157 Hard to allow xstream to have a converter supporting generated classes

  • Closed - The issue is considered finished, the resolution is correct. Issues which are not closed can be reopened.

Activity

Ascending order - Click to sort in descending order
  • All
  • Comments
  • History
  • Activity
Hide
Permalink
Joerg Schaible added a comment - 05/Apr/06 4:52 PM

A really bad coincidence happen for CGLIB proxies of real classes. A CGLIB class proxy will delegate all method calls, but represents still a complete instance of the original class. If this class is Serializable and has a readObject/writeObject methods two things may happen:
a) any direct access to a field will reference the element in the proxied instance
b) any indirect access will be delegated by the proxy
This may leed to the situation, that the values written into the stream might be from different objects.

In the above case the proxied HashMap writes a size of 0 into the stream and writes afterwards the elements of the delegate. Since those elements are written again later, XStream creates a reference. Unfortunately the readObject method of the HashMap will recognize, that it has no elements and just skip all the written values ... and all references will suddenly point to nothing.

Show
Joerg Schaible added a comment - 05/Apr/06 4:52 PM A really bad coincidence happen for CGLIB proxies of real classes. A CGLIB class proxy will delegate all method calls, but represents still a complete instance of the original class. If this class is Serializable and has a readObject/writeObject methods two things may happen: a) any direct access to a field will reference the element in the proxied instance b) any indirect access will be delegated by the proxy This may leed to the situation, that the values written into the stream might be from different objects. In the above case the proxied HashMap writes a size of 0 into the stream and writes afterwards the elements of the delegate. Since those elements are written again later, XStream creates a reference. Unfortunately the readObject method of the HashMap will recognize, that it has no elements and just skip all the written values ... and all references will suddenly point to nothing.
Hide
Permalink
Joerg Schaible added a comment - 05/Apr/06 4:57 PM

A workaround for the above case is a Converter for CGLIB proxies, that skips the SerializationConverter. In the sample a modified ReflectionConverter is registered with a higher priority, that handles all CGLIB-based proxies.

xstream.registerConverter(new ReflectionConverter(xstream.getMapper(), new JVM().bestReflectionProvider()){
public boolean canConvert(Class type) { return Factory.class.isAssignableFrom(type); }
});

Note: It is not yet clear if this handles all the CGLIB proxy problems. Some proxies might not be initializable anymore, others have writeReplace and readResolve methods, that can/will have additionally effects.

Show
Joerg Schaible added a comment - 05/Apr/06 4:57 PM A workaround for the above case is a Converter for CGLIB proxies, that skips the SerializationConverter. In the sample a modified ReflectionConverter is registered with a higher priority, that handles all CGLIB-based proxies. xstream.registerConverter(new ReflectionConverter(xstream.getMapper(), new JVM().bestReflectionProvider()){ public boolean canConvert(Class type) { return Factory.class.isAssignableFrom(type); } }); Note: It is not yet clear if this handles all the CGLIB proxy problems. Some proxies might not be initializable anymore, others have writeReplace and readResolve methods, that can/will have additionally effects.
Hide
Permalink
Joerg Schaible added a comment - 07/Apr/06 8:58 AM

Next chapter: The workaround in the last comment is only valid for the current process. If another process tries to deserialize the stream, the CGLIB proxy classes are no longer known. A combination of Mapper and Converter is necessary, although it is not yet clear if such a proxy can be properly recreated at all.

Show
Joerg Schaible added a comment - 07/Apr/06 8:58 AM Next chapter: The workaround in the last comment is only valid for the current process. If another process tries to deserialize the stream, the CGLIB proxy classes are no longer known. A combination of Mapper and Converter is necessary, although it is not yet clear if such a proxy can be properly recreated at all.
Hide
Permalink
Joerg Schaible added a comment - 08/Apr/06 2:36 PM

Support for the CGLIB Enhancer has been added. Supported is limited to Enhancer created proxies using CGLIB's DefaultNamingStrategy, no super class or a superclass with an accessible default constructor and a single Callback.

Show
Joerg Schaible added a comment - 08/Apr/06 2:36 PM Support for the CGLIB Enhancer has been added. Supported is limited to Enhancer created proxies using CGLIB's DefaultNamingStrategy, no super class or a superclass with an accessible default constructor and a single Callback.
Hide
Permalink
Shahiduzzaman added a comment - 21/May/08 10:38 PM

I guess the limitation for single callback can be removed in cases where the 2nd callback is null (e.g. for hibernate lazy loaded classes) . see - http://jira.codehaus.org/browse/XSTR-423 for more.

Show
Shahiduzzaman added a comment - 21/May/08 10:38 PM I guess the limitation for single callback can be removed in cases where the 2nd callback is null (e.g. for hibernate lazy loaded classes) . see - http://jira.codehaus.org/browse/XSTR-423 for more.

People

  • Assignee:
    Unassigned
    Reporter:
    Joerg Schaible
Vote (0)
Watch (1)

Dates

  • Created:
    19/Aug/05 5:39 AM
    Updated:
    21/May/08 10:38 PM
    Resolved:
    08/Apr/06 2:36 PM
  • Atlassian JIRA (v5.0.4#731-sha1:3aa7374)
  • Report a problem
  • Powered by a free Atlassian JIRA open source license for Codehaus. Try JIRA - bug tracking software for your team.