Hi,

I'm in the process of migrating our Spring application from ancient Wicket 1.5 to shiny new Wicket 7.10 (along with upgrading ~100 Maven dependencies to their latest version and moving to JDK 9.0.4 ...). I did the Wicket upgrade in two separate steps (1.5->6, 6 -> 7) and while the Wicket 6.x version of our application worked without (obvious) issues, one of our pages is crashing in the Wicket 7.10 version because an internal sanity check gets tripped when the LazyInitProxyFactory tries to proxy one of our Spring beans.

The code of the Spring bean that fails to be proxied in Wicket 7.x (which uses CGLIB 3.1 while Wicket 6.0.29 used CGLIB 2.2.2) looks similar to this:

public class SomeBean {

    private static final AtomicLong INSTANCE_COUNTER = new AtomicLong(0); // <<< DEBUG CODEto track instances

    private static final Logger LOG = org.apache.logging.log4j.LogManager.getLogger(SomeClass.class);

    private final Map<stuff,stuff> registeredStuff=new HashMap<>();
    private long id;

   public SomeClass() {
     this.id = INSTANCE_COUNTER.incrementAndGet();
     registerStuff();
   }

    void registerStuff() {

        LOG.error("=== registerStuff( ID = "+id+") called ===",new Exception("dummy"));

        register(...);
        register(...);
        // more
   }

  private void register(stuff) {

     if ( registeredStuff.contains( stuff ) ) {
       throw new IllegalArgumentException("stuff already registered");<<< sanity check that gets tripped with CGLIB 3.3 since the map is already populated
     }
     registeredStuff.put(stuff);
  }
}

The difference between CGLIB 2.2.2 and CGLIB 3.1 is that the code in LazyInitProxyFactory creates an uninitialized instance of the proxy target when CGLIB 2.x is being used but CGLIB 3.x seems to copy the field values from the proxy target and just invoke the registerStuff() method without newly assigning the private fields.

At least this is what I could see through the "this.id = INSTANCE_COUNTER.incrementAndGet();" line in my constructor ; on CGLIB 2.x the proxied instance has a new 'id' value while on CGLIB 3.1 the proxied instance has the same ID value as the proxy target.

=== Wicket 6.x ===

2018-02-28 13:47:40,352 ERROR [main] com.vodecc.voipmng.boundary.wicket.alarming.conditions.ConditionFactory:80 - === registerDefaultHandlers( ID = 1) called ===
java.lang.Exception: dummy
        at com.vodecc.voipmng.boundary.wicket.alarms.conditions.ConditionFactory.registerDefaultHandlers(ConditionFactory.java:80) [classes/:5.4.0-jdk9-SNAPSHOT]         at com.vodecc.voipmng.boundary.wicket.alarms.conditions.ConditionFactory.<init>(ConditionFactory.java:69) [classes/:5.4.0-jdk9-SNAPSHOT]         at com.vodecc.voipmng.boundary.wicket.alarms.conditions.ConditionFactory.<clinit>(ConditionFactory.java:59) [classes/:5.4.0-jdk9-SNAPSHOT]         at jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[?:?]
--
2018-02-28 13:47:40,376 ERROR [main] com.vodecc.voipmng.boundary.wicket.alarming.conditions.ConditionFactory:80 - === registerDefaultHandlers( ID = 2) called ===
java.lang.Exception: dummy
        at com.vodecc.voipmng.boundary.wicket.alarms.conditions.ConditionFactory.registerDefaultHandlers(ConditionFactory.java:80) [classes/:5.4.0-jdk9-SNAPSHOT]         at com.vodecc.voipmng.boundary.wicket.alarms.conditions.ConditionFactory.<init>(ConditionFactory.java:69) [classes/:5.4.0-jdk9-SNAPSHOT]         at jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[?:?]         at jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[?:?]
--
2018-02-28 13:48:08,889 ERROR [http-nio-8080-exec-1] com.vodecc.voipmng.boundary.wicket.alarming.conditions.ConditionFactory:80 - === registerDefaultHandlers( ID = 3) called ===
java.lang.Exception: dummy
        at com.vodecc.voipmng.boundary.wicket.alarms.conditions.ConditionFactory.registerDefaultHandlers(ConditionFactory.java:80) [classes/:5.4.0-jdk9-SNAPSHOT]         at com.vodecc.voipmng.boundary.wicket.alarms.conditions.ConditionFactory.<init>(ConditionFactory.java:69) [classes/:5.4.0-jdk9-SNAPSHOT]         at WICKET_com.vodecc.voipmng.boundary.wicket.alarming.conditions.ConditionFactory$$EnhancerByCGLIB$$b957aaed.<init>(<generated>) [cglib-2.2.2.jar:?]         at jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[?:?]

=== Wicket 7.x ===

2018-02-28 13:40:22,710 ERROR [main] com.vodecc.voipmng.boundary.wicket.alarming.conditions.ConditionFactory:80 - === registerDefaultHandlers( ID = 1) called ===
java.lang.Exception: dummy
        at com.vodecc.voipmng.boundary.wicket.alarms.conditions.ConditionFactory.registerDefaultHandlers(ConditionFactory.java:80) [classes/:5.4.0-jdk9-SNAPSHOT]         at com.vodecc.voipmng.boundary.wicket.alarms.conditions.ConditionFactory.<init>(ConditionFactory.java:69) [classes/:5.4.0-jdk9-SNAPSHOT]         at com.vodecc.voipmng.boundary.wicket.alarms.conditions.ConditionFactory.<clinit>(ConditionFactory.java:59) [classes/:5.4.0-jdk9-SNAPSHOT]         at jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[?:?]
--
2018-02-28 13:40:22,734 ERROR [main] com.vodecc.voipmng.boundary.wicket.alarming.conditions.ConditionFactory:80 - === registerDefaultHandlers( ID = 2) called ===
java.lang.Exception: dummy
        at com.vodecc.voipmng.boundary.wicket.alarms.conditions.ConditionFactory.registerDefaultHandlers(ConditionFactory.java:80) [classes/:5.4.0-jdk9-SNAPSHOT]         at com.vodecc.voipmng.boundary.wicket.alarms.conditions.ConditionFactory.<init>(ConditionFactory.java:69) [classes/:5.4.0-jdk9-SNAPSHOT]         at jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method) ~[?:?]         at jdk.internal.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62) ~[?:?]
--
2018-02-28 13:40:58,994 ERROR [http-nio-8080-exec-7] com.vodecc.voipmng.boundary.wicket.alarming.conditions.ConditionFactory:80 - === registerDefaultHandlers( ID = 2) called ===
java.lang.Exception: dummy
        at com.vodecc.voipmng.boundary.wicket.alarming.conditions.ConditionFactory.registerDefaultHandlers(ConditionFactory.java:80) [classes/:5.4.0-jdk9-SNAPSHOT]         at com.vodecc.voipmng.boundary.wicket.alarming.conditions.Wicket_Proxy_ConditionFactory$$FastClassByCGLIB$$6aba25f8.invoke(<generated>) [cglib-3.1.jar:5.4.0-jdk9-SNAPSHOT]         at net.sf.cglib.proxy.MethodProxy.invoke(MethodProxy.java:204) [cglib-3.1.jar:?]         at org.apache.wicket.proxy.LazyInitProxyFactory$AbstractCGLibInterceptor.intercept(LazyInitProxyFactory.java:351) [wicket-ioc-7.10.0.jar:7.10.0]

Unfortunately it seems neither the CGLIB nor the ASM guys keep track of their changes in a changelog/migration guide so I was unable to figure out the root cause of this change in behaviour.

Any ideas ?

Thanks,
Tobias

Reply via email to