Google App Engine/Jetty: Introspection Fails for D

2019-05-30 01:40发布

问题:

Why does Introspector not correctly discover the properties of a dynamic proxy class in Jetty/GAE?

I ran into this curious problem while trying to use a dynamic proxy with Java EL/JSPs when deploying locally on GAE with Jetty. You can see the original question here.

Anyways, I have since simplified the code and narrowed down the problem. Here is the new code:

MyServlet.java:

package test;

// imports omitted

public class MyServlet extends HttpServlet {

    public interface MyInterface {
        public String getValue();
    }

    private static <T> T getProxy(Class<T> c) {
        return (T)Proxy.newProxyInstance(
                klass.getClassLoader(),
                new Class<?>[]{ klass },
                new InvocationHandler() {
                    @Override public Object invoke(Object proxy, Method m,
                            Object[] args) throws Throwable {
                        return null;
                    }
                });
    }

    public static void testIntrospection() {
        StringBuilder sb = new StringBuilder();
        try {
            MyInterface proxy = getProxy(MyInterface.class);
            BeanInfo info = Introspector.getBeanInfo(proxy.getClass());
            for (PropertyDescriptor d : info.getPropertyDescriptors())
                sb.append(d.getName()).append(", ");
        } catch (Exception e) {
            throw new AssertionError("failed", e);
        }
        throw new AssertionError("found: " + sb.toString());
    }

    @Override
    public void doGet(HttpServletRequest request, HttpServletResponse resp) {
        testIntrospection();
    }

    public static void main(String... args) {
        testIntrospection();
    }
}

When I deploy the code above and send a GET request, I get the following:

java.lang.AssertionError: found: class,

However, I expected that both class and value would be discovered, as per the documentation for Proxy. But, when I just run it in main(), I get the expected output. I also tried putting the proxied interface in a separate file/package, and it did not work. To make things weirder, I also get the expected output when I change MyInterface to be private, protected, or default.

Why have I limited the question to GAE/Jetty? Because I was able to deploy the exact same servlet on Tomcat 7 with no problem, even when MyInterface is public.

In case it's relevant, I am using the Google plugin in Eclipse Juno, and I am only deploying locally.

One last thing: I checked the output of proxy.getClass().getDeclaredMethods() and it did include getValue. However, I can't simply parse the bean properties myself, because I need it to work in EL, which relies on Introspector.

I am really stumped by this one, so any guidance is greatly appreciated.