[seam-commits] Seam SVN: r10009 - trunk/src/main/org/jboss/seam/util.

seam-commits at lists.jboss.org seam-commits at lists.jboss.org
Wed Feb 4 14:30:23 EST 2009


Author: norman.richards at jboss.com
Date: 2009-02-04 14:30:23 -0500 (Wed, 04 Feb 2009)
New Revision: 10009

Modified:
   trunk/src/main/org/jboss/seam/util/ProxyFactory.java
Log:
JBSEAM-3925

Modified: trunk/src/main/org/jboss/seam/util/ProxyFactory.java
===================================================================
--- trunk/src/main/org/jboss/seam/util/ProxyFactory.java	2009-02-04 17:47:45 UTC (rev 10008)
+++ trunk/src/main/org/jboss/seam/util/ProxyFactory.java	2009-02-04 19:30:23 UTC (rev 10009)
@@ -1,11 +1,13 @@
 package org.jboss.seam.util;
-/**
- * Derived from javassist MethodProxy.java to create a ProxyFactory that does not generate 
+
+/* Derived from javassist MethodProxy.java to create a ProxyFactory that does not generate 
  * FINAL methods.  It is a cut & paste due methods on the javassist version largely 
  * being static and private, and thus completely non-extensible.
- * 
+ */
+
+/*
  * Javassist, a Java-bytecode translator toolkit.
- * Copyright (C) 1999-2006 Shigeru Chiba. All Rights Reserved.
+ * Copyright (C) 1999-2007 Shigeru Chiba. All Rights Reserved.
  *
  * The contents of this file are subject to the Mozilla Public License Version
  * 1.1 (the "License"); you may not use this file except in compliance with
@@ -18,34 +20,36 @@
  * License.
  */
 
-import java.lang.reflect.Constructor;
+import java.lang.reflect.AccessibleObject;
 import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.lang.reflect.Constructor;
 import java.lang.reflect.Member;
-import java.lang.reflect.Method;
 import java.lang.reflect.Modifier;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
 import java.security.ProtectionDomain;
 import java.util.HashMap;
+import java.util.WeakHashMap;
 import java.util.Iterator;
 import java.util.Map;
 import java.util.Set;
+import java.lang.ref.WeakReference;
 
 import javassist.CannotCompileException;
-import javassist.bytecode.AccessFlag;
-import javassist.bytecode.Bytecode;
-import javassist.bytecode.ClassFile;
-import javassist.bytecode.ConstPool;
-import javassist.bytecode.Descriptor;
-import javassist.bytecode.ExceptionsAttribute;
-import javassist.bytecode.FieldInfo;
-import javassist.bytecode.MethodInfo;
-import javassist.bytecode.Opcode;
+import javassist.bytecode.*;
 import javassist.util.proxy.FactoryHelper;
 import javassist.util.proxy.MethodFilter;
 import javassist.util.proxy.MethodHandler;
 import javassist.util.proxy.ProxyObject;
 import javassist.util.proxy.RuntimeSupport;
 
+/*
+ * This class is implemented only with the lower-level API of Javassist.
+ * This design decision is for maximizing performance.
+ */
+
 /**
  * Factory of dynamic proxy classes.
  *
@@ -67,7 +71,6 @@
  *         return proceed.invoke(self, args);  // execute the original method.
  *     }
  * };
- * f.setHandler(mi);
  * f.setFilter(new MethodFilter() {
  *     public boolean isHandled(Method m) {
  *         // ignore finalize()
@@ -76,6 +79,7 @@
  * });
  * Class c = f.createClass();
  * Foo foo = (Foo)c.newInstance();
+ * ((ProxyObject)foo).setHandler(mi);
  * </pre></ul>
  *
  * <p>Then, the following method call will be forwarded to MethodHandler
@@ -86,6 +90,15 @@
  * foo.bar();
  * </pre></ul>
  *
+ * <p>The last three lines of the code shown above can be replaced with a call to
+ * the helper method <code>create</code>, which generates a proxy class, instantiates
+ * it, and sets the method handler of the instance:
+ *
+ * <ul><pre>
+ *     :
+ * Foo foo = (Foo)f.create(new Class[0], new Object[0], mi);
+ * </pre></ul>
+ *
  * <p>To change the method handler during runtime,
  * execute the following code:
  *
@@ -94,7 +107,20 @@
  * ((ProxyObject)foo).setHandler(mi2);
  * </pre></ul>
  *
- * <p>Here is an example of method handler.  It does not execute
+ * <p>You can also specify the default method handler:
+ *
+ * <ul><pre>
+ * ProxyFactory f2 = new ProxyFactory();
+ * f2.setSuperclass(Foo.class);
+ * f2.setHandler(mi);            // set the default handler
+ * Class c2 = f2.createClass();
+ * </pre></ul>
+ *
+ * <p>The default handler is implicitly attached to an instance of the generated class
+ * <code>c2</code>.   Calling <code>setHandler</code> on the instance is not necessary
+ * unless another method handler must be attached to the instance. 
+ *
+ * <p>The following code is an example of method handler.  It does not execute
  * anything except invoking the original method:
  *
  * <ul><pre>
@@ -106,6 +132,11 @@
  * }
  * </pre></ul>
  *
+ * <p>A proxy object generated by <code>ProxyFactory</code> is serializable
+ * if its super class or interfaces implement a <code>java.io.Serializable</code>.
+ * However, a serialized proxy object will not be compatible with future releases.
+ * The serialization support should be used for short-term storage or RMI.
+ *
  * @see MethodHandler
  * @since 3.1
  */
@@ -131,6 +162,7 @@
 
     private static final String HOLDER = "_methods_";
     private static final String HOLDER_TYPE = "[Ljava/lang/reflect/Method;";
+    private static final String METHOD_FILTER_FIELD = "_method_filter";
     private static final String HANDLER = "handler";
     private static final String NULL_INTERCEPTOR_HOLDER = "javassist.util.proxy.RuntimeSupport";
     private static final String DEFAULT_INTERCEPTOR = "default_interceptor";
@@ -140,6 +172,61 @@
     private static final String HANDLER_SETTER_TYPE = "(" + HANDLER_TYPE + ")V";
 
     /**
+     * If true, a generated proxy class is cached and it will be reused
+     * when generating the proxy class with the same properties is requested.
+     * The default value is true.
+     *
+     * @since 3.4
+     */
+    public static boolean useCache = true; 
+
+    private static WeakHashMap proxyCache = new WeakHashMap();
+
+    static class CacheKey {
+        String classes;
+        MethodFilter filter;
+        private int hash;
+        WeakReference proxyClass;
+        MethodHandler handler;
+
+        public CacheKey(Class superClass, Class[] interfaces,
+                        MethodFilter f, MethodHandler h)
+        {
+            classes = getKey(superClass, interfaces);
+            hash = classes.hashCode();
+            filter = f;
+            handler = h;
+            proxyClass = null;
+        }
+
+        public int hashCode() { return hash; }
+
+        public boolean equals(Object obj) {
+            if (obj instanceof CacheKey) {
+                CacheKey target = (CacheKey)obj;
+                return target.filter == filter && target.handler == handler
+                       && target.classes.equals(classes);
+            }
+            else
+                return false;
+        }
+
+        static String getKey(Class superClass, Class[] interfaces) {
+            StringBuffer sbuf = new StringBuffer();
+            if (superClass != null)
+                sbuf.append(superClass.getName());
+            sbuf.append(':');
+            if (interfaces != null) {
+                int len = interfaces.length;
+                for (int i = 0; i < len; i++)
+                    sbuf.append(interfaces[i].getName()).append(',');
+            }
+
+            return sbuf.toString();
+        }
+    }
+
+    /**
      * Constructs a factory of proxy class.
      */
     public ProxyFactory() {
@@ -159,6 +246,13 @@
     }
 
     /**
+     * Obtains the super class set by <code>setSuperclass()</code>.
+     *
+     * @since 3.4
+     */
+    public Class getSuperclass() { return superClass; }
+
+    /**
      * Sets the interfaces of a proxy class.
      */
     public void setInterfaces(Class[] ifs) {
@@ -166,6 +260,13 @@
     }
 
     /**
+     * Obtains the interfaces set by <code>setInterfaces</code>.
+     *
+     * @since 3.4
+     */
+    public Class[] getInterfaces() { return interfaces; }
+
+    /**
      * Sets a filter that selects the methods that will be controlled by a handler.
      */
     public void setFilter(MethodFilter mf) {
@@ -176,36 +277,183 @@
      * Generates a proxy class.
      */
     public Class createClass() {
-        if (thisClass == null)
-            try {
-                ClassFile cf = make();
-                ClassLoader cl = getClassLoader();
-                if (writeDirectory != null)
-                    FactoryHelper.writeFile(cf, writeDirectory);
+        if (thisClass == null) {
+            ClassLoader cl = getClassLoader();
+            synchronized (proxyCache) {
+                if (useCache)
+                    createClass2(cl);
+                else 
+                    createClass3(cl);
+            }
+        }
 
-                thisClass = FactoryHelper.toClass(cf, cl, getDomain());
-                setHandler();
+        return thisClass;
+    }
+
+    private void createClass2(ClassLoader cl) {
+        CacheKey key = new CacheKey(superClass, interfaces, methodFilter, handler);
+        /*
+         * Excessive concurrency causes a large memory footprint and slows the
+         * execution speed down (with JDK 1.5).  Thus, we use a jumbo lock for
+         * reducing concrrency.
+         */
+        // synchronized (proxyCache) {
+            HashMap cacheForTheLoader = (HashMap)proxyCache.get(cl);
+            if (cacheForTheLoader == null) {
+                cacheForTheLoader = new HashMap();
+                proxyCache.put(cl, cacheForTheLoader);
+                cacheForTheLoader.put(key, key);
             }
-            catch (CannotCompileException e) {
-                throw new RuntimeException(e.getMessage(), e);
+            else {
+                CacheKey found = (CacheKey)cacheForTheLoader.get(key);
+                if (found == null)
+                    cacheForTheLoader.put(key, key);
+                else {
+                    key = found;
+                    Class c = isValidEntry(key);    // no need to synchronize
+                    if (c != null) {
+                        thisClass = c;
+                        return;
+                    }
+                }
             }
+        // }
 
-        return thisClass;
+        // synchronized (key) {
+            Class c = isValidEntry(key);
+            if (c == null) {
+                createClass3(cl);
+                key.proxyClass = new WeakReference(thisClass);
+            }
+            else
+                thisClass = c; 
+        // }
     }
 
+    private Class isValidEntry(CacheKey key) {
+        WeakReference ref = key.proxyClass;
+        if (ref != null) {
+            Class c = (Class)ref.get();
+            if(c != null)
+                return c;
+        }
+
+        return null;
+    }
+
+    private void createClass3(ClassLoader cl) {
+        try {
+            ClassFile cf = make();
+            if (writeDirectory != null)
+                FactoryHelper.writeFile(cf, writeDirectory);
+
+            thisClass = FactoryHelper.toClass(cf, cl, getDomain());
+            setField(DEFAULT_INTERCEPTOR, handler);
+            setField(METHOD_FILTER_FIELD, methodFilter);
+        }
+        catch (CannotCompileException e) {
+            throw new RuntimeException(e.getMessage(), e);
+        }
+
+    }
+
+    private void setField(String fieldName, Object value) {
+        if (thisClass != null && value != null)
+            try {
+                Field f = thisClass.getField(fieldName);
+                // SEAM CHANGE
+                setAccessible(f, true);
+                f.set(null, value);
+                // SEAM CHANGE
+                setAccessible(f, false);
+            }
+            catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+    }
+
+    static MethodFilter getFilter(Class clazz) {
+        return (MethodFilter)getField(clazz, METHOD_FILTER_FIELD);
+    }
+
+    static MethodHandler getHandler(Class clazz) {
+        return (MethodHandler)getField(clazz, DEFAULT_INTERCEPTOR);
+    }
+
+    private static Object getField(Class clazz, String fieldName) {
+        try {
+            Field f = clazz.getField(fieldName);
+            f.setAccessible(true);
+            Object value = f.get(null);
+            f.setAccessible(false);
+            return value;
+        }
+        catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * A provider of class loaders.
+     *
+     * @see #classLoaderProvider
+     * @since 3.4
+     */
+    public static interface ClassLoaderProvider {
+        /**
+         * Returns a class loader.
+         *
+         * @param pf    a proxy factory that is going to obtain a class loader.
+         */
+        public ClassLoader get(ProxyFactory pf);
+    }
+
+    /**
+     * A provider used by <code>createClass()</code> for obtaining
+     * a class loader.
+     * <code>get()</code> on this <code>ClassLoaderProvider</code> object
+     * is called to obtain a class loader.
+     *
+     * <p>The value of this field can be updated for changing the default
+     * implementation.
+     *
+     * <p>Example:
+     * <ul><pre>
+     * ProxyFactory.classLoaderProvider = new ProxyFactory.ClassLoaderProvider() {
+     *     public ClassLoader get(ProxyFactory pf) {
+     *         return Thread.currentThread().getContextClassLoader();
+     *     }
+     * };
+     * </pre></ul>
+     *
+     * @since 3.4
+     */
+    public static ClassLoaderProvider classLoaderProvider
+        = new ClassLoaderProvider() {
+              public ClassLoader get(ProxyFactory pf) {
+                  return pf.getClassLoader0();
+              }
+          };
+
     protected ClassLoader getClassLoader() {
-        // return Thread.currentThread().getContextClassLoader();
+        return classLoaderProvider.get(this);
+    }
+
+    protected ClassLoader getClassLoader0() {
         ClassLoader loader = null;
         if (superClass != null && !superClass.getName().equals("java.lang.Object"))
             loader = superClass.getClassLoader();
         else if (interfaces != null && interfaces.length > 0)
             loader = interfaces[0].getClassLoader();
-
+ 
         if (loader == null) {
             loader = getClass().getClassLoader();
             // In case javassist is in the endorsed dir
-            if (loader == null)
-               loader = ClassLoader.getSystemClassLoader();
+            if (loader == null) {
+                loader = Thread.currentThread().getContextClassLoader();
+                if (loader == null)
+                    loader = ClassLoader.getSystemClassLoader();
+            }
         }
 
         return loader;
@@ -228,7 +476,24 @@
      *
      * @param paramTypes    parameter types for a constructor.
      * @param args          arguments passed to a constructor.
+     * @param mh            the method handler for the proxy class.
+     * @since 3.4
      */
+    public Object create(Class[] paramTypes, Object[] args, MethodHandler mh)
+        throws NoSuchMethodException, IllegalArgumentException,
+               InstantiationException, IllegalAccessException, InvocationTargetException
+    {
+        Object obj = create(paramTypes, args);
+        ((ProxyObject)obj).setHandler(mh);
+        return obj;
+    }
+
+    /**
+     * Creates a proxy class and returns an instance of that class.
+     *
+     * @param paramTypes    parameter types for a constructor.
+     * @param args          arguments passed to a constructor.
+     */
     public Object create(Class[] paramTypes, Object[] args)
         throws NoSuchMethodException, IllegalArgumentException,
                InstantiationException, IllegalAccessException, InvocationTargetException
@@ -245,24 +510,15 @@
      */
     public void setHandler(MethodHandler mi) {
         handler = mi;
-        setHandler();
+        setField(DEFAULT_INTERCEPTOR, handler);
     }
 
-    private void setHandler() {
-        if (thisClass != null && handler != null)
-            try {
-                Field f = thisClass.getField(DEFAULT_INTERCEPTOR);
-                f.setAccessible(true);
-                f.set(null, handler);
-                f.setAccessible(false);
-            }
-            catch (Exception e) {
-                throw new RuntimeException(e);
-            }
+    private static int counter = 0;
+
+    private static synchronized String makeProxyName(String classname) {
+        return classname + "_$$_javassist_" + counter++;
     }
 
-    private static int counter = 0;
-
     private ClassFile make() throws CannotCompileException {
         String superName, classname;
         if (interfaces == null)
@@ -282,8 +538,7 @@
         if (Modifier.isFinal(superClass.getModifiers()))
             throw new CannotCompileException(superName + " is final");
 
-        // generate a proxy name.
-        classname = classname + "_$$_javassist_" + counter++;
+        classname = makeProxyName(classname);
         if (classname.startsWith("java."))
             classname = "org.javassist.tmp." + classname;
 
@@ -299,12 +554,25 @@
         finfo2.setAccessFlags(AccessFlag.PRIVATE);
         cf.addField(finfo2);
 
+        FieldInfo finfo3 = new FieldInfo(pool, METHOD_FILTER_FIELD,
+                                            "Ljavassist/util/proxy/MethodFilter;");
+        finfo3.setAccessFlags(AccessFlag.PUBLIC | AccessFlag.STATIC);
+        cf.addField(finfo3);
+
         HashMap allMethods = getMethods(superClass, interfaces);
+        int size = allMethods.size();
         makeConstructors(classname, cf, pool, classname);
         int s = overrideMethods(cf, pool, classname, allMethods);
         addMethodsHolder(cf, pool, classname, s);
         addSetter(classname, cf, pool);
 
+        try {
+            cf.addMethod(makeWriteReplace(pool));
+        }
+        catch (DuplicateMemberException e) {
+            // writeReplace() is already declared in the super class/interfaces.
+        }
+
         thisClass = null;          
         return cf;
     }
@@ -333,6 +601,7 @@
         finfo.setAccessFlags(AccessFlag.PRIVATE | AccessFlag.STATIC);
         cf.addField(finfo);
         MethodInfo minfo = new MethodInfo(cp, "<clinit>", "()V");
+        minfo.setAccessFlags(AccessFlag.STATIC);
         Bytecode code = new Bytecode(cp, 0, 0);
         code.addIconst(size * 2);
         code.addAnewarray("java.lang.reflect.Method");
@@ -405,7 +674,8 @@
     private void makeConstructors(String thisClassName, ClassFile cf,
             ConstPool cp, String classname) throws CannotCompileException
     {
-        Constructor[] cons = superClass.getDeclaredConstructors();
+        // SEAM CHANGE 
+        Constructor[] cons = getDeclaredConstructors(superClass);
         for (int i = 0; i < cons.length; i++) {
             Constructor c = cons[i];
             int mod = c.getModifiers();
@@ -487,7 +757,8 @@
         if (parent != null)
             getMethods(hash, parent);
 
-        Method[] methods = clazz.getDeclaredMethods();
+        // SEAM CHANGE
+        Method[] methods = getDeclaredMethods(clazz);
         for (int i = 0; i < methods.length; i++)
             if (!Modifier.isPrivate(methods[i].getModifiers())) {
                 Method m = methods[i];
@@ -511,27 +782,34 @@
 
         code.addAload(0);
         code.addGetstatic(thisClassName, DEFAULT_INTERCEPTOR, HANDLER_TYPE);
-        code.addOpcode(Opcode.DUP);
+        code.addPutfield(thisClassName, HANDLER, HANDLER_TYPE);
+        code.addGetstatic(thisClassName, DEFAULT_INTERCEPTOR, HANDLER_TYPE);
         code.addOpcode(Opcode.IFNONNULL);
-        code.addIndex(7);
-        code.addOpcode(Opcode.POP);
+        code.addIndex(10);
+        code.addAload(0);
         code.addGetstatic(NULL_INTERCEPTOR_HOLDER, DEFAULT_INTERCEPTOR, HANDLER_TYPE);
         code.addPutfield(thisClassName, HANDLER, HANDLER_TYPE);
+        int pc = code.currentPc();
 
         code.addAload(0);
         int s = addLoadParameters(code, cons.getParameterTypes(), 1);
         code.addInvokespecial(superClass.getName(), "<init>", desc);
         code.addOpcode(Opcode.RETURN);
         code.setMaxLocals(s + 1);
-        minfo.setCodeAttribute(code.toCodeAttribute());
+        CodeAttribute ca = code.toCodeAttribute();
+        minfo.setCodeAttribute(ca);
+
+        StackMapTable.Writer writer = new StackMapTable.Writer(32);
+        writer.sameFrame(pc);
+        ca.setAttribute(writer.toStackMapTable(cp));
         return minfo;
     }
 
     private static MethodInfo makeDelegator(Method meth, String desc,
                 ConstPool cp, Class declClass, String delegatorName) {
         MethodInfo delegator = new MethodInfo(cp, delegatorName, desc);
-        // SEAM CHANGE - originally had Modifier.FINAL |
-        delegator.setAccessFlags( Modifier.PUBLIC
+        // SEAM CHANGE: remove FINAL
+        delegator.setAccessFlags(Modifier.PUBLIC
                 | (meth.getModifiers() & ~(Modifier.PRIVATE
                                            | Modifier.PROTECTED
                                            | Modifier.ABSTRACT
@@ -555,8 +833,8 @@
                     Method meth, String desc, ConstPool cp,
                     Class declClass, String delegatorName, int index) {
         MethodInfo forwarder = new MethodInfo(cp, meth.getName(), desc);
-        // SEAM CHANGE - originally had Modifier.FINAL
-        forwarder.setAccessFlags( (meth.getModifiers() & ~(Modifier.ABSTRACT
+        // SEAM CHANGE: remove FINAL
+        forwarder.setAccessFlags((meth.getModifiers() & ~(Modifier.ABSTRACT
                                                | Modifier.NATIVE
                                                | Modifier.SYNCHRONIZED)));
         setThrows(forwarder, cp, meth);
@@ -588,7 +866,8 @@
         callFindMethod(code, "findSuperMethod", arrayVar, origIndex, meth.getName(), desc);
         callFindMethod(code, "findMethod", arrayVar, delIndex, delegatorName, desc);
 
-        code.write16bit(pc, code.currentPc() - pc + 1);
+        int pc2 = code.currentPc();
+        code.write16bit(pc, pc2 - pc + 1);
         code.addAload(0);
         code.addGetfield(thisClassName, HANDLER, HANDLER_TYPE);
         code.addAload(0);
@@ -609,7 +888,12 @@
         addUnwrapper(code, retType);
         addReturn(code, retType);
 
-        forwarder.setCodeAttribute(code.toCodeAttribute());
+        CodeAttribute ca = code.toCodeAttribute();
+        forwarder.setCodeAttribute(ca);
+        StackMapTable.Writer writer = new StackMapTable.Writer(32);
+        writer.appendFrame(pc2, new int[] { StackMapTable.OBJECT },
+                           new int[] { cp.addClassInfo(HOLDER_TYPE) });
+        ca.setAttribute(writer.toStackMapTable(cp));
         return forwarder;
     }
 
@@ -758,4 +1042,64 @@
         else
             code.addCheckcast(type.getName());
     }
+
+    private static MethodInfo makeWriteReplace(ConstPool cp) {
+        MethodInfo minfo = new MethodInfo(cp, "writeReplace", "()Ljava/lang/Object;");
+        String[] list = new String[1];
+        list[0] = "java.io.ObjectStreamException";
+        ExceptionsAttribute ea = new ExceptionsAttribute(cp);
+        ea.setExceptions(list);
+        minfo.setExceptionsAttribute(ea);
+        Bytecode code = new Bytecode(cp, 0, 1);
+        code.addAload(0);
+        code.addInvokestatic("javassist.util.proxy.RuntimeSupport",
+                             "makeSerializedProxy",
+                             "(Ljava/lang/Object;)Ljavassist/util/proxy/SerializedProxy;");
+        code.addOpcode(Opcode.ARETURN);
+        minfo.setCodeAttribute(code.toCodeAttribute());
+        return minfo;
+    }
+    
+    // SEAM: from SecurityActions
+    static void setAccessible(final AccessibleObject ao,
+            final boolean accessible) {
+        if (System.getSecurityManager() == null) {
+            ao.setAccessible(accessible);
+        } else {
+            AccessController.doPrivileged(new PrivilegedAction() {
+                public Object run() {
+                    ao.setAccessible(accessible);
+                    return null;
+                }
+            });
+        }
+    }
+    
+    // SEAM: from SecurityActions
+    static Method[] getDeclaredMethods(final Class clazz) {
+        if (System.getSecurityManager() == null) {
+            return clazz.getDeclaredMethods();
+        } else {
+            return (Method[]) AccessController
+                    .doPrivileged(new PrivilegedAction() {
+                        public Object run() {
+                            return clazz.getDeclaredMethods();
+                        }
+                    });
+        }
+    }
+    
+    // SEAM: from SecurityActions
+    static Constructor[] getDeclaredConstructors(final Class clazz) {
+        if (System.getSecurityManager() == null) {
+            return clazz.getDeclaredConstructors();
+        } else {
+            return (Constructor[]) AccessController
+                    .doPrivileged(new PrivilegedAction() {
+                        public Object run() {
+                            return clazz.getDeclaredConstructors();
+                        }
+                    });
+        }
+    }
 }




More information about the seam-commits mailing list