As reported earlier, I'm using WadlApplication and WadlResource in
Restlet 1.1.1 and Sun JDK 1.6.

I've found that the non-public classes extending Resource cause
WadlApplication to fail in Java reflection attempting to invoke method
"allowGet()", due to Sun bug
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4533479
<http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4533479>  which is
marked as a duplicate of a similar issue at
http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4071957
<http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4071957> 

Details:

class MyResource extends SomeWadlResource {
  public MyResource(Context context, Request request, Response
response);
  public allowGet() { return true; }
  public Representation represent() { ... }
}

Note that class MyResource is not public, but allowGet() is public.
I've made MyResource package protected to prevent direct invocation of
Resources by other packages.  

Curiously, I have not seen any problem with normal Restlet invocations,
only with WadlApplication's use.  I haven't examined why this is the
case, but it's possible there may be other bugs due to this issue.

The error I get is

org.restlet/org/java/Handler.java:
344            if (method != null) {
345                try {
346 =>                 result = method.invoke(this, args);
347                } catch (Exception e) {
348                    getLogger().log(
349                            Level.WARNING,
350                            "Couldn't invoke the handle method for
\"" + method
351                                    + "\"", e);
352                }

java.lang.IllegalAccessException: Class org.restlet.Handler can not
access a member of class MyResource with modifiers "public"
at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:65)
at java.lang.reflect.Method.invoke(Method.java:588)
at org.restlet.Handler.invoke(Handler.java:346)

 
The invocation is from getAllowedMethods(), in WadlResource:
    public void describe(String path, ResourceInfo info) {
        info.setPath(path);
 
        // Introspect the current resource to detect the allowed methods
        final List<Method> methodsList = new ArrayList<Method>();
        methodsList.addAll(getAllowedMethods());
 
 





The issue appears to be that java.lang.reflect.Method does not allow
access to public methods of package-protected classes, whereas regular
method invocation does.  In other words, doing resource.allowGet() would
be legal, but doing the same call by reflection gives the
IllegalAccessError.
 
The Sun bug report discussion centers on a possible future change in
classfile format to provide more information from the compiler for
reflection; however, there is a simple workaround listed in Bug 4533479
and I've described it below.

Recommended Fix:

In bug 4533479, user arro239 posted workaround code for obtaining the
superclass's java.lang.reflect.Method of the same name and signature and
using it instead, and walking the tree upwards to find a public class or
interface.  That fix works in this case.  

There may be other possible fixes that I haven't explored, so I'd like
to ask for anyone with experience in this area to make suggestions.

Below is a recommended change to org.restlet/org/restlet/Handler.java
using arro239's sample.  

    /**
     * Updates the set of methods with the ones allowed by this resource
     * instance.
     * 
     * @param allowedMethods
     *            The set to update.
     */
    private void updateAllowedMethods(Set<Method> allowedMethods) {
        for (final java.lang.reflect.Method orig_classMethod :
getClass()
                .getMethods()) {
            final java.lang.reflect.Method classMethod =
fixJava4071957(orig_classMethod);
            if (classMethod.getName().startsWith("allow")
                    && (classMethod.getParameterTypes().length == 0)) {
                if ((Boolean) invoke(classMethod)) {
                    final Method allowedMethod =
Method.valueOf(classMethod
                            .getName().substring(5));
                    allowedMethods.add(allowedMethod);
                }
            }
        }
    }

    // from http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4071957
<http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4071957> 
    private static java.lang.reflect.Method
fixJava4071957(java.lang.reflect.Method method) {
        while
(!java.lang.reflect.Modifier.isPublic(method.getDeclaringClass().getModi
fiers())) {
            try {
                method =
method.getDeclaringClass().getSuperclass().getMethod(method.getName(),
method.getParameterTypes());
            } catch (NoSuchMethodException e) {
                throw new IllegalStateException(e);
            }
        }
        return method;
    }


Leigh.

------------------------------------------------------
http://restlet.tigris.org/ds/viewMessage.do?dsForumId=4447&dsMessageId=1098088

Reply via email to