XStream

CGLIBEnhancedConverter "only one CAllback is registered"

Details

  • Type: Bug Bug
  • Status: Closed Closed
  • Priority: Minor Minor
  • Resolution: Fixed
  • Affects Version/s: 1.2.2
  • Fix Version/s: 1.3.1
  • Component/s: Converters
  • Labels:
    None

Description

According to the api for CGLIBEnhancedConverter, this converter can only be used if "only one CAllback is registered". The code to check this condition is actually incorrect:

line 84:
if (callbacks.length > 1) {

it should be:

if (Arrays.asList(callbacks).size() > 1){

This makes the code break with Hibernate proxies, even though it shouldn't.

  1. 423.patch
    04/Aug/09 9:17 PM
    0.8 kB
    Jerry Shea
  2. XSTR-423.patch
    23/Oct/08 12:08 AM
    0.9 kB
    Jerry Shea

Issue Links

Activity

Hide
Joerg Schaible added a comment -

Sorry, but I don't see a difference. Why should the first condition break Hibernate proxies ?

Show
Joerg Schaible added a comment - Sorry, but I don't see a difference. Why should the first condition break Hibernate proxies ?
Hide
Joerg Schaible added a comment -

No further response, reopen if you want to answer my question.

Show
Joerg Schaible added a comment - No further response, reopen if you want to answer my question.
Hide
Joerg Schaible added a comment -

Closed after no further comment has been given.

Show
Joerg Schaible added a comment - Closed after no further comment has been given.
Hide
Shahiduzzaman added a comment -

Actually CGLIBEnhancedConverter does not work for lazy loaded collections. Actually when adding callbacks Hibernate (I am using Hibernate 3.2.5) two callback types are registered - the 2nd callback type is NoOp.class which is basically No Operation. (See the CGLIBLazyInitilaizer class of hibernate source for more details). In the CGLIBEnhancedConverter of xstream callbacks are retrieved in the following way -

Callback[] callbacks = hasFactory ? ((Factory)source).getCallbacks() : getCallbacks(source);

In the callbacks array the 2nd callback is always null for Hibernate lazy loaded classes. But as the callbacks.length is checked for >1, it throws an exception. I have changed the condition from -

if (Arrays.asList(callbacks).size() > 1) {

to

if (callbacks.length > 1 && (callbacks[1] !=null && callbacks.length != 2)) {

In this case this worked perfectly. I would appreciate comments on this.

Show
Shahiduzzaman added a comment - Actually CGLIBEnhancedConverter does not work for lazy loaded collections. Actually when adding callbacks Hibernate (I am using Hibernate 3.2.5) two callback types are registered - the 2nd callback type is NoOp.class which is basically No Operation. (See the CGLIBLazyInitilaizer class of hibernate source for more details). In the CGLIBEnhancedConverter of xstream callbacks are retrieved in the following way - Callback[] callbacks = hasFactory ? ((Factory)source).getCallbacks() : getCallbacks(source); In the callbacks array the 2nd callback is always null for Hibernate lazy loaded classes. But as the callbacks.length is checked for >1, it throws an exception. I have changed the condition from - if (Arrays.asList(callbacks).size() > 1) { to if (callbacks.length > 1 && (callbacks[1] !=null && callbacks.length != 2)) { In this case this worked perfectly. I would appreciate comments on this.
Hide
Joerg Schaible added a comment -

This is an interesting detail. Thanks!

Show
Joerg Schaible added a comment - This is an interesting detail. Thanks!
Hide
Shahiduzzaman added a comment -

I have tried to find out the CGLIB proxy policy of Hibernate (as I am not a Hibernate Pro, and actually there is almost no documentation or javadoc about Hibernate's use of CGLIB, I failed). Later I posted to hibernate-dev mailing list to find out the detail (http://lists.jboss.org/pipermail/hibernate-dev/2008-May/003085.html), but seems they are bit busy right now. Anyways I checked the previous versions of Hibernate and that specific code sits there for long time (so it is less likely that there is any bug in it).

Do you have plan to work on this in the next release of Xstream (If you are busy, I would be happy to submit a patch)? This will really help in this field as I have tried JDK xmlEncoder/decoder, Commons Betwixt, Castor, Simple framework, but failed to serialize Java beans to XML with simple converter or persistentDelegates. Only Xstream with the above change is able to correctly handle Hibernate lazy loaded collections (i.e. CGLIB enhanced classes) properly.

Show
Shahiduzzaman added a comment - I have tried to find out the CGLIB proxy policy of Hibernate (as I am not a Hibernate Pro, and actually there is almost no documentation or javadoc about Hibernate's use of CGLIB, I failed). Later I posted to hibernate-dev mailing list to find out the detail (http://lists.jboss.org/pipermail/hibernate-dev/2008-May/003085.html), but seems they are bit busy right now. Anyways I checked the previous versions of Hibernate and that specific code sits there for long time (so it is less likely that there is any bug in it). Do you have plan to work on this in the next release of Xstream (If you are busy, I would be happy to submit a patch)? This will really help in this field as I have tried JDK xmlEncoder/decoder, Commons Betwixt, Castor, Simple framework, but failed to serialize Java beans to XML with simple converter or persistentDelegates. Only Xstream with the above change is able to correctly handle Hibernate lazy loaded collections (i.e. CGLIB enhanced classes) properly.
Hide
Joerg Schaible added a comment -

Can't say. I'll have to analyze this first. The converter is for CGLIB enhanced proxies in general, not only for ones that are created by Hibernate.

Show
Joerg Schaible added a comment - Can't say. I'll have to analyze this first. The converter is for CGLIB enhanced proxies in general, not only for ones that are created by Hibernate.
Hide
Bryan Taylor added a comment -

This issue biting me right now. I've got a Hibernate cglib proxy with two callbacks. 0 is a org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer and 1 is null.

Why is a null callback ever a problem? Don't we just need to exclude multiple instantiated callbacks?

Callback[] callbacks = hasFactory ? ((Factory)source).getCallbacks() : getCallbacks(source);
Callback callback = getUnique(callbacks);
boolean isInterceptor = MethodInterceptor.class.isAssignableFrom(callback.getClass());

ExtendedHierarchicalStreamWriterHelper.startNode(writer, mapper.serializedClass(callback.getClass()), callback.getClass());
context.convertAnother(callback);

and

private Callback extractUniqueCallback(Callback[] callbacks) {
Callback firstCallback = null;
for (Callback callback: callbacks) {
if ((callback != null) && (firstCallback != null)) { throw new ConversionException("Cannot handle CGLIB enhanced proxies with multiple callbacks"); } else if (callback != null) { firstCallback = callback; }
}
return firstCallback;
}

Show
Bryan Taylor added a comment - This issue biting me right now. I've got a Hibernate cglib proxy with two callbacks. 0 is a org.hibernate.proxy.pojo.cglib.CGLIBLazyInitializer and 1 is null. Why is a null callback ever a problem? Don't we just need to exclude multiple instantiated callbacks? Callback[] callbacks = hasFactory ? ((Factory)source).getCallbacks() : getCallbacks(source); Callback callback = getUnique(callbacks); boolean isInterceptor = MethodInterceptor.class.isAssignableFrom(callback.getClass()); ExtendedHierarchicalStreamWriterHelper.startNode(writer, mapper.serializedClass(callback.getClass()), callback.getClass()); context.convertAnother(callback); and private Callback extractUniqueCallback(Callback[] callbacks) { Callback firstCallback = null; for (Callback callback: callbacks) { if ((callback != null) && (firstCallback != null)) { throw new ConversionException("Cannot handle CGLIB enhanced proxies with multiple callbacks"); } else if (callback != null) { firstCallback = callback; } } return firstCallback; }
Hide
Kasra Rasaee added a comment -

Any updates on this issue? my investigation brought me to the same conclusion, there are two
callbacks registered but one of them is a null, can't we simply ignore nulls?

Can't NoOp.class also be considered ignorable?

Any news on when we can expect this to be resolved?

Thanks,

Kaz-

Show
Kasra Rasaee added a comment - Any updates on this issue? my investigation brought me to the same conclusion, there are two callbacks registered but one of them is a null, can't we simply ignore nulls? Can't NoOp.class also be considered ignorable? Any news on when we can expect this to be resolved? Thanks, Kaz-
Hide
Frank Adcock added a comment -

This also affects version 1.3

Show
Frank Adcock added a comment - This also affects version 1.3
Hide
Jerry Shea added a comment -

I've just applied the change to my local version of xstream 1.2.2 which solves the problem for me. I've attached a patch in the hope of helping move this along. Cheers

Show
Jerry Shea added a comment - I've just applied the change to my local version of xstream 1.2.2 which solves the problem for me. I've attached a patch in the hope of helping move this along. Cheers
Hide
Joerg Schaible added a comment -

CGLIB enhanced proxies with multiple callbacks are now supported if the proxy uses a factory (CGLIB default).

Show
Joerg Schaible added a comment - CGLIB enhanced proxies with multiple callbacks are now supported if the proxy uses a factory (CGLIB default).
Hide
Jerry Shea added a comment -

This is still a problem in 1.3.1. The fix is really simple: in getCallbacks(), just check that the callback's value is not null before adding it to the list to return. See attached patch (valid against 1.3.1 or trunk)

Show
Jerry Shea added a comment - This is still a problem in 1.3.1. The fix is really simple: in getCallbacks(), just check that the callback's value is not null before adding it to the list to return. See attached patch (valid against 1.3.1 or trunk)

People

Vote (0)
Watch (2)

Dates

  • Created:
    Updated:
    Resolved: