Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

Already on GitHub? Sign in to your account

Cannot call public methods in AbstractBootstrap via reflection #1780

Closed
stuartsierra opened this Issue Aug 23, 2013 · 10 comments

Comments

Projects
None yet
5 participants

The io.netty.bootstrap.Bootstrap and ServerBootstrap classes are
public but they extend a package-private abstract class
AbstractBootstrap. The public methods inherited from
AbstractBootstrap cannot be invoked via the Java reflection API due to
long-standing bugs such as JDK-4283544.

This is a serious problem for alternative JVM languages which use
reflection to discover Java methods. For example, Clojure uses
reflection in its compiler, and it cannot invoke these methods at all,
as reported in CLJ-1243.

I know at least AbstractBootstrap is affected. There may be other
instances of this pattern that I haven't found.

Possible Solution

For this specific case, making AbstractBootstrap public will fix the
problem. This should have no impact on other code. The class will
still not be instantiable because it is also abstract.

If there are other package-private classes extended by public API
classes, they would also need to be declared public.

Steps to Reproduce in Java

This example is adapted from the first few lines of
HttpHelloWorldServer.java in the Netty examples.

Copy the following code into a file named ReflectionFail.java.

import java.lang.reflect.Method;
import io.netty.channel.ChannelOption;

public class ReflectionFail {
    public static void main(String[] args) throws Exception {
        Class klass = Class.forName("io.netty.bootstrap.ServerBootstrap");

        // Find a particular method by name
        Method method = null;
        Method methods[] = klass.getMethods();
        for (int i = 0; i < methods.length; i++) {
            method = methods[i];
            if (method.getName().equals("option")) break;
        }

        Object instance = klass.newInstance();
        method.invoke(instance, new Object[] {ChannelOption.SO_BACKLOG, 1024});
    }
}

Copy the release file netty-all-4.0.4.Final.jar to the same directory.

Compile and run with:

javac -cp .:netty-all-4.0.4.Final.jar ReflectionFail.java
java -cp .:netty-all-4.0.4.Final.jar ReflectionFail

The output is:

Exception in thread "main" java.lang.IllegalAccessException: Class ReflectionFail can not access a member of class io.netty.bootstrap.AbstractBootstrap with modifiers "public"
        at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:105)
        at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:261)
        at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:253)
        at java.lang.reflect.Method.invoke(Method.java:599)
        at ReflectionFail.main(ReflectionFail.java:17)

Notes on My Environment

Operating System: OS X 10.8.4

JDK version (Oracle):

java version "1.7.0_25"
Java(TM) SE Runtime Environment (build 1.7.0_25-b15)
Java HotSpot(TM) 64-Bit Server VM (build 23.25-b01, mixed mode)

Netty version: 4.0.4.Final

Owner

trustin commented Aug 24, 2013

Thank you so much for the detailed report. Didn't know such a bug ever existed in JDK. Should be fixed soon.

@ghost ghost assigned trustin Aug 24, 2013

Owner

normanmaurer commented Aug 24, 2013

What a mess... Thanks for the report

Am 24.08.2013 um 03:38 schrieb Trustin Lee notifications@github.com:

Thank you so much for the detailed report. Didn't know such a bug ever existed in JDK. Should be fixed soon.


Reply to this email directly or view it on GitHub.

Owner

normanmaurer commented Aug 24, 2013

@stuartsierra @trustin couldn't we use public for the class but mark the constructor package private?

Owner

trustin commented Aug 24, 2013

I think that should be fine.

Owner

normanmaurer commented Aug 24, 2013

@trustin will you take care or should I pick up later?

Am 24.08.2013 um 10:09 schrieb Trustin Lee notifications@github.com:

I think that should be fine.


Reply to this email directly or view it on GitHub.

@trustin trustin closed this in 7aefd0c Aug 24, 2013

Owner

trustin commented Aug 24, 2013

Fixed. Please feel free to open another issue if you encounter a similar issue. Thanks!

Thank you for the rapid response!

Just wanted to let you know that you can make the method accessible through reflection as shown below:

method.setAccessible(true);

Hence no need to make the class public.

Tested with Java 1.6 update 34

vadali commented Nov 17, 2013

I just now found this,
I have been investigating a similar issue this time with DefaultChannelHandlerContext (https://groups.google.com/forum/#!topic/netty/mcGswAZ5NeQ).

Referring to "..Please feel free to open another issue if you encounter a similar issue. Thanks!" - can I take you on your word? :)

should I open a new issue for this?

Owner

trustin commented Nov 18, 2013

Yes please.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment