3

I'm facing a very mysterious java.lang.NoSuchMethodError in the code pasted below. The same method, called through reflection, works as expected:

Widget a = getTextBoxWidget();
com.google.gwt.user.client.ui.UIObject uio = a; // Widget extends UIObject
for (java.lang.reflect.Method method : uio.getClass().getMethods()) {
    if (method.getName().equals("getElement")) {
        System.err.println("Method " + method.getName() + ":" + 
                           method.getDeclaringClass().getName());
        System.err.println("Modifier " + 
                           java.lang.reflect.Modifier.toString(method.getModifiers()));
        System.err.println("Parameter count: " + method.getParameterCount());
        System.err.println("Parameter types: " + Arrays.asList(method.getParameterTypes()));
        System.err.println("Return type: " + method.getReturnType());
        try {
            Object result = method.invoke(uio, new Object[0]);
            System.err.println("Invocation successful: " + result);
            Object result2 = method.invoke(uio, new Object[0]);
            System.err.println("Invocation successful2: " + result2);
        } catch (Exception e) {
            System.err.println("Failed to invoke getElement: " + e);
            e.printStackTrace(System.err);
        }
    }
}
// until here everything is good and it seems that 
// we can call getElement and get the result, but...
Object result3 = uio.getElement(); // line 470, here I get java.lang.NoSuchMethodError

Output:

Method getElement:com.google.gwt.user.client.ui.UIObject
Modifier public
Invocation successful: <result here>
Invocation successful2: <result here>
Parameter count: 0
Parameter types: []
Return type: class com.google.gwt.dom.client.Element

Stacktrace:

java.lang.NoSuchMethodError: com.google.gwt.user.client.ui.UIObject.getElement()Lcom/google/gwt/user/client/Element;
at com.pyx4j.widgets.client.ValueBoxBase.setAriaLabel(ValueBoxBase.java:470)

What can the possible cause for this?
uio.getClass().getClassLoader() is sun.misc.Launcher$AppClassLoader, id=151 method.getDeclaringClass().getClassLoader() is the same, with the same id.

Running with -verbose:class shows the UIObject class loaded from wherever it is expected to be loaded. The major version inside UIObject.class is 52, which matches the runtime major version (1.8)

khachik
  • 28,112
  • 9
  • 59
  • 94
  • @JimGarrison good catch, thank you, I mean `NoSuchMethodError` everywhere, fixed now. – khachik Jul 12 '18 at 22:48
  • `Object result = method.invoke(uio, new Object[0]);` This invoke method on object UIO and push parameter, maybe Try to use invoke without pushing params and lets look for the result? – Thomas Banderas Jul 12 '18 at 22:50
  • 1
    @ThomasBanderas From the `invoke()` Javadoc: _If the number of formal parameters required by the underlying method is 0, the supplied args array may be of length 0 or null_ – Jim Garrison Jul 12 '18 at 22:54
  • 1
    Is there a difference between `uio.getClass().getClassLoader()` and `method.getDeclaringClass().getClassLoader()`? Trying to understand if there are multiple class loaders in play here. – Karol Dowbecki Jul 12 '18 at 22:57
  • Just out of curiosity, try also printing the values returned by `method.getParameterCount()`, `...getParameterTypes()` and `...getReturnType()`. – Jim Garrison Jul 12 '18 at 23:00
  • @KarolDowbecki good question, `method.getClass().getClassLoader()` is null, because I assume the 'Method` class is from the bootstrap. – khachik Jul 12 '18 at 23:00
  • @khachik He meant `method.getDeclaringClass().getClassLoader()` to see if the method that's actually being invoked by reflection is in the same classloading hierarchy. – Jim Garrison Jul 12 '18 at 23:03
  • 1
    Maybe run with `-verbose:class` as per [this answer](https://stackoverflow.com/a/10230391/1602555) and see what's going on with `UIObject` class. – Karol Dowbecki Jul 12 '18 at 23:04
  • @JimGarrison updated the question with parameter count, types and return type info. Everything is as expected. – khachik Jul 12 '18 at 23:05
  • Well, I'm stumped. I hope someone answers. – Jim Garrison Jul 12 '18 at 23:06
  • 1
    @JimGarrison @KarolDowbecki `method.getDeclaringClass().getClassLoader()` is the same as for `uio`, with same id. – khachik Jul 12 '18 at 23:08

1 Answers1

3

It appears that the code actually might be different during the compilation and in runtime.

Reflection output suggests that UIObject.getElement() method return type is com.google.gwt.dom.client.Element however the JVM complains that it wants com.google.gwt.user.client.Element. Notice difference in the dom and user sub-packages in the middle of the fully qualified class name.

If there is no covariant relation between these two types, as in former extends latter, there might be an error. There is no type casting since line 470 is assigning to an Object. Maybe there will be a ClassCastException if an actual return type is used to declare result3 in line 470.

Karol Dowbecki
  • 43,645
  • 9
  • 78
  • 111