Several GlassFish bugs have been discovered when running with Java SE 7 due to a change in the return value of the Class.getMethods and Class.getDeclaredMethods calls. This page discusses the change in the Java SE implementation, examples of GlassFish bugs that have already been found and why the bugs only showed up with Java SE 7, and examples of how to fix this issue.

Background

The Class.getMethods javadoc (and Class.getDeclaredMethods) from Java SE 6 says:

The elements in the array returned are not sorted and are not in any particular order.

Despite this statement, up through Java SE 6 and up until build 128 of Java SE 7, the methods were returned in a consistent order from run to run of the JVM and within a single run.  However, starting with build 129 of Java SE 7, according to bug 7023180, there was a change in the implementation of the JVM that causes the order of the methods in the return value to vary, both from run to run and within a single run of the JVM. So for example, given the following class:

class A {
  public void getX() { ... }
  public void getY() { ...}
}

One call to A.class.getMethods() might return [ getX, getY ] while another call might return [ getY, getX ]. The actual order depends on class loading, the JVM symbol table, and various other factors within the JVM.

GlassFish Example Issue

Several JIRA bugs (18133, 18184, 18368) have been filed against GlassFish where the root cause is due to this change. In each of these cases, there is a loop over the return value of Class.getMethods, and the logic within the loop is looking for a method with particular characteristics. However, the logic was not precise enough about the method being sought, and with earlier JVM releases, the code happened to find the method it was looking for first.  With newer Java SE 7 releases, a different (wrong) method is found.  For example, consider bug 18133.  Here, the loop looks like this:

// find now the accessor method.
        String methodName = myself.metadata().get("method-name").get(0);
        targetMethod=null;
        for (Method m : parentType.getMethods()) {
            if (m.getName().equals(methodName)) {
                targetMethod=m;
                break;
            }
        }

.The class referenced by parentType has the following two methods:

public List<Node> getNode();
public Node getNode(String name);

The string methodName in this case is "getNode".  Depending on the order of the array returned by getMethods, this loop may find either of the methods.  Later in the method, targetMethod.invoke is called, expecting to pass in no arguments.  If the second method is found by the loop, the invoke call throws an exception.

The fix for the bug depends on the what the loop is actually searching for. In this case, the method not only has to have the given name, but it must also be annotated with an annotation that extends the InhabitantAnnotation. So to correct this code, the if statement in the loop has to be changed to check not only for the name of the method, but for the desired annotation.

// find now the accessor method.
        String methodName = myself.metadata().get("method-name").get(0);
        targetMethod=null;
methodlookup:
        for (Method m : parentType.getMethods()) {
            if (m.getName().equals(methodName) && m.get) {
                // Make sure that this method is annotated with an annotation
                // that is annotated with InhabitantAnnotation (such as @Create).
                // This makes sure that we have found the method we are looking for
                // in case there is a like-named method that is not annotated.
                for (Annotation a : m.getAnnotations()) {
                    if (a.annotationType().getAnnotation(InhabitantAnnotation.class) != null) {
                        targetMethod=m;
                        break methodlookup;
                    }
                }
            }
        }

With the other bugs, the check that is made on the method is more complex, and in each case, the fix was to add a more specific check on the method, either looking for the number of parameters that the method accepts or the methods return type.

Usage in GlassFish

Using Netbeans we've attempted to search the GlassFish trunk for all uses of Class.getMethods(), Class.getDeclaredMethods(). Those results are summarized on the following wiki page:

GetMethods Usage in Source

Tasks have been created to track code inspection of the files in the above list. You can see those tasks here:

Jira tasks for get*Methods() code inspection