The Source for Java Technology Collaboration
User: Password:



Tom Ball

Tom Ball's Blog

Java 5's Varags Clean Up Reflection Code

Posted by tball on September 24, 2005 at 11:09 AM | Comments (4)

Java 5 has a lot of major improvements to the platform, to the point where some of the smaller features can get overlooked. Like many developers (including Calvin Austin his J2SE in a Nutshell article), I thought it great that varargs methods were added so printf() could be implemented, but didn't see much other use for the feature.

Yesterday I was updating a Factory class which uses a ClassLoader and Java's reflection facility to separate a public interface (JackpotEngine) from its implementation (Engine), and got an unexpected compiler warning about vararg misuse calling Class.getConstructor(). Say what? I wasn't anywhere near a printf()! Here was the code:

    public static JackpotEngine createEngine(String jarPath, AppContext appContext) throws Exception {
        ClassLoader loader = new JackpotClassLoader(jarPath);
        Class c = Class.forName("org.netbeans.jackpot.Engine", true, loader); // NOI18N
        Class[] argTypes = new Class[] { AppContext.class };
        Constructor con = c.getConstructor(argTypes);
        Object[] args = new Object[] { appContext };
        return (JackpotEngine)con.newInstance(args);
    }
Normal, ugly reflection code with a one-use array definition for each call, right? Bringing up the source for getConstructor() showed the issue: this method, along with all the other reflection methods that used to take arrays, are now varargs methods. That made sense, so I converted my code:

    public static JackpotEngine createEngine(String jarPath, AppContext appContext) throws Exception {
        ClassLoader loader = new JackpotClassLoader(jarPath);
        Class c = Class.forName("org.netbeans.jackpot.Engine", true, loader); // NOI18N
        Constructor con = c.getConstructor(AppContext.class);
        return instance = (JackpotEngine)con.newInstance(appContext);
    }
That is easier to read, and made the compiler happy. Later, when I needed to also pass the Engine constructor the jarPath; varargs again made this edit easier than dealing with array declarations:

    public static JackpotEngine createEngine(String jarPath, AppContext appContext) throws Exception {
        ClassLoader loader = new JackpotClassLoader(jarPath);
        Class c = Class.forName("org.netbeans.jackpot.Engine", true, loader); // NOI18N
        Constructor con = c.getConstructor(AppContext.class, String.class);
        return instance = (JackpotEngine)con.newInstance(appContext, jarPath);
    }
Think how much easier learning Java reflection would have been if varargs support had been in Java 1.1!

Bookmark blog post: del.icio.us del.icio.us Digg Digg DZone DZone Furl Furl Reddit Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment

  • To be fair, you could have ditched the args and argTypes variables without varargs.

    If the syntax for array initialisation had been allowed more widely instead of introducing varargs, then the language rules would have been far less surprising.

    Posted by: tackline on September 24, 2005 at 12:15 PM

  • I am not sure I follow you, since as of 1.1 it has been legal to use something like this:


    Constructor con = c.getConstructor(new Class[] { AppContext.class, String.class });

    I just find cramming too much into a single statement makes it harder to read (at least for me).

    Posted by: tball on September 24, 2005 at 12:45 PM

  • Sensible line breaks help. Whenever I break a statement, I try to make the breaks follow the structure. So, for the 1.1 syntax, preserving variable names, it would be:

    Constructor con = c.getConstructor(new Class[] {
    AppContext.class, String.class
    });

    If the array initialiser syntax was supported wherever an array was expected:

    Constructor con = c.getConstructor({AppContext.class, String.class});

    Only two extra characters. There is no confusion over overloading, nulls or passing a single array. For method calls with other arguments, the array section is nicely marked. The syntax is not limited to just the last parameter.

    Posted by: tackline on September 24, 2005 at 03:16 PM

  • tackline, there's something to be said for that, but a question that immediately arises is what is the type? For example, what is the type of

    {new Integer(5), "something"}

    ? Is it Serializable[], or Object[], or maybe something like Comparable<?>? Does it depend on the context where it appears? These questions don't arise with array initialization or the existing new X[]{...} syntax.

    Additionally, there's a problem with the grammar. With this syntax, I could write this statement:

    {someMethod(param1,param2)}.toString();

    which is presumably legal, but I can only tell that I'm seeing an array literal and not a statement block when I see the closing }. The existing grammar doesn't require arbitrary lookahead in this way, which is generally considered to be an important property.

    Posted by: emcmanus on September 29, 2005 at 09:47 AM





Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds