Details
-
Type: Bug
-
Status: Open
-
Priority: Major
-
Resolution: Unresolved
-
Affects Version/s: None
-
Fix Version/s: None
-
Component/s: None
-
Labels:None
-
Number of attachments :
Description
Long story short, my company has wrapped some connection object in a delegate, then in a decorator, then in a delegate again.
Somewhere somehow later, a Set of these objects is copied. And equals() and hashcode() to delegated is invoked too.
As a result of that, in DelegatingInvoker detects it's a ReflectionUtils equals, then extracts the delegate (of type decoratingInvoker), it's a proxy class but not instance of DelegatingInvoker.
So it will keep in the while loop forever.
(DelegatingInvoker snippet to illustrate my explanation above)
public Object invoke(final Object proxy, final Method method, final Object[] args) throws Throwable {
final Object result;
Object delegate = delegate();
// equals(...) and hashCode()
if (method.equals(ReflectionUtils.equals)) {
// Note: equals will normally compare the classes directly, so we have to dereference
// all delegates and then swap the call (in case of our argument is also a delegation proxy).
final Object arg = args[0];
while (delegate != null && proxyFactory.isProxyClass(delegate.getClass())) {
Invoker invoker = proxyFactory.getInvoker(delegate);
if (invoker instanceof DelegatingInvoker<?>)
{ delegate = DelegatingInvoker.class.cast(invoker).delegate(); }}
I can admit and argue that my company is using the library in a correct way or not, but the bad usage result shouldn't be a infinite loop.
In my humble opinion, decoratingInvoker should inherit from delegatingInvoker, at least the way we use it.
Working example to demonstrate the bug:
import com.google.common.collect.ImmutableSet;
import com.thoughtworks.proxy.factory.CglibProxyFactory;
import com.thoughtworks.proxy.toys.decorate.Decorating;
import com.thoughtworks.proxy.toys.decorate.Decorator;
import com.thoughtworks.proxy.toys.delegate.Delegating;
import com.thoughtworks.proxy.toys.delegate.DelegationMode;
import java.util.HashSet;
import java.util.Set;
/**
- Created by anavarro on 9/8/14.
*/
public class BugTest {
public static void main(String [] args)
{ Set<iBase> set = new HashSet<>(); //set.add(new Base()); set.add(build()); set.add(build()); set.add(build()); Set<iBase> bset = ImmutableSet.copyOf(set); }private static iBase build()
{ Base base = new Base(); iBase delegated = Delegating.proxy(iBase.class) .with(base) .mode(DelegationMode.SIGNATURE) .build(new CglibProxyFactory()); iBase decorated = Decorating.proxy(iBase.class) .with(delegated) .visiting(new Listener<iBase>()) .build(new CglibProxyFactory()); iBase delegated2 = Delegating.proxy(iBase.class) .with(decorated) .mode(DelegationMode.SIGNATURE) .build(new CglibProxyFactory()); return delegated2; }public interface iBase {
}
public static class Base implements iBase {
@Override
public int hashCode()
{ return 1; }}
public static class Listener<T> extends Decorator<T> {
}
}
I hope you can fix it soon
Best regards
Alberto Navarro
Senior Java Developer @ Recorsure Ltd.