You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@myfaces.apache.org by sk...@apache.org on 2008/06/12 15:42:36 UTC
svn commit: r667085 - in /myfaces/orchestra/trunk/sandbox: ./
src/main/java/org/apache/myfaces/orchestra/dynaForm/metadata/impl/ejb/
Author: skitching
Date: Thu Jun 12 06:42:36 2008
New Revision: 667085
URL: http://svn.apache.org/viewvc?rev=667085&view=rev
Log:
Use ASM to perform class introspection in preference to BCEL (faster, smaller).
Added:
myfaces/orchestra/trunk/sandbox/src/main/java/org/apache/myfaces/orchestra/dynaForm/metadata/impl/ejb/AsmHelper.java (with props)
myfaces/orchestra/trunk/sandbox/src/main/java/org/apache/myfaces/orchestra/dynaForm/metadata/impl/ejb/EmptyClassVisitor.java (with props)
Modified:
myfaces/orchestra/trunk/sandbox/pom.xml
myfaces/orchestra/trunk/sandbox/src/main/java/org/apache/myfaces/orchestra/dynaForm/metadata/impl/ejb/ClassHelper.java
myfaces/orchestra/trunk/sandbox/src/main/java/org/apache/myfaces/orchestra/dynaForm/metadata/impl/ejb/ClassHelperFactory.java
Modified: myfaces/orchestra/trunk/sandbox/pom.xml
URL: http://svn.apache.org/viewvc/myfaces/orchestra/trunk/sandbox/pom.xml?rev=667085&r1=667084&r2=667085&view=diff
==============================================================================
--- myfaces/orchestra/trunk/sandbox/pom.xml (original)
+++ myfaces/orchestra/trunk/sandbox/pom.xml Thu Jun 12 06:42:36 2008
@@ -62,10 +62,30 @@
</dependency>
<dependency>
+ <!--
+ - WARNING: asm versions are horribly non-compatible between major releases.
+ - We might need to use maven-shade-plugin to instead import a private version
+ - of asm into this project, so that orchestra can be used within projects
+ - that use other versions of asm.
+ -->
+ <groupId>asm</groupId>
+ <artifactId>asm</artifactId>
+ <version>2.2.3</version>
+ <scope>compile</scope>
+ </dependency>
+
+ <dependency>
+ <!--
+ - Needed only for BcelHelper class. The AsmHelper class is selected
+ - by default, and better. So this dependency is only needed if you
+ - want to exclude the ASM library for some reason, but still want
+ - the ClassHelper functionality.
+ -->
<groupId>bcel</groupId>
<artifactId>bcel</artifactId>
<version>5.1</version>
<scope>compile</scope>
+ <optional>true</optional>
</dependency>
<dependency>
Added: myfaces/orchestra/trunk/sandbox/src/main/java/org/apache/myfaces/orchestra/dynaForm/metadata/impl/ejb/AsmHelper.java
URL: http://svn.apache.org/viewvc/myfaces/orchestra/trunk/sandbox/src/main/java/org/apache/myfaces/orchestra/dynaForm/metadata/impl/ejb/AsmHelper.java?rev=667085&view=auto
==============================================================================
--- myfaces/orchestra/trunk/sandbox/src/main/java/org/apache/myfaces/orchestra/dynaForm/metadata/impl/ejb/AsmHelper.java (added)
+++ myfaces/orchestra/trunk/sandbox/src/main/java/org/apache/myfaces/orchestra/dynaForm/metadata/impl/ejb/AsmHelper.java Thu Jun 12 06:42:36 2008
@@ -0,0 +1,190 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.orchestra.dynaForm.metadata.impl.ejb;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Field;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.commons.logging.Log;
+import org.apache.commons.logging.LogFactory;
+import org.apache.myfaces.orchestra.lib.OrchestraException;
+import org.objectweb.asm.ClassReader;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.MethodVisitor;
+
+/**
+ * Reimplement the reflection facilities provided by Class.class, but preserving the order in which
+ * the properties exist within the .class file.
+ * <p>
+ * Presumably the field order in the .class file is the same as the order they are declared within
+ * the source file. And presumably the code author arranged those in some logical order.
+ * <p>
+ * This class uses the ASM library to inspect the class data.
+ */
+public class AsmHelper implements ClassHelper
+{
+ private final Log log = LogFactory.getLog(AsmHelper.class);
+ private static final Field[] FIELDS_TYPE = new Field[0];
+ private static final Method[] METHODS_TYPE = new Method[0];
+
+ private void applyVisitorToClass(Class clazz, ClassVisitor visitor)
+ {
+ // Note: Simply using the constructor ClassReader(clazz.getName())
+ // does not allow control over which classloader the class is loaded
+ // from.
+ String className = clazz.getName().replace('.', '/') + ".class";
+ ClassReader cr = null;
+ InputStream is = null;
+ try
+ {
+ is = this.getClass().getClassLoader().getResourceAsStream(className);
+ cr = new ClassReader(is);
+ cr.accept(visitor, true);
+ }
+ catch (IOException e)
+ {
+ throw new OrchestraException("Unable to read class " + className, e);
+ }
+ finally
+ {
+ if (is != null)
+ {
+ try
+ {
+ is.close();
+ }
+ catch(IOException e2)
+ {
+ // Not likely to occur, and nothing can be done about it.
+ log.error("Unable to close input stream", e2);
+ }
+ }
+ }
+ }
+
+ /**
+ * Return a list of all the static and non-static fields of the specified class, regardless of
+ * their accessability.
+ * <p>
+ * The array order matches the order in which the fields were declared within the original
+ * source file.
+ */
+ public Field[] getFields(final Class<?> clazz)
+ {
+ final List<Field> fields = new ArrayList<Field>(50);
+ ClassVisitor fv = new EmptyClassVisitor()
+ {
+ @Override
+ public FieldVisitor visitField(int access, String name, String desc, String signature,
+ Object value)
+ {
+ try
+ {
+ // Note: no two fields can have the same name, so we don't need to check
+ // whether the found field is already in the fields list.
+ Field f = clazz.getDeclaredField(name);
+ fields.add(f);
+ }
+ catch (NoSuchFieldException e)
+ {
+ log.warn("Cannot find Field object for " + name);
+ }
+ return super.visitField(access, name, desc, signature, value);
+ }
+ };
+ applyVisitorToClass(clazz, fv);
+ return fields.toArray(FIELDS_TYPE);
+ }
+
+ /**
+ * Given an ASM method descriptor, find the associated java.lang.reflect.Method object.
+ * <p>
+ * Returns null if no such method is found.
+ */
+ private Method getMethod(Class<?> clazz, String methodName, String descriptor)
+ {
+ if (!methodName.startsWith("set") && !methodName.startsWith("get")
+ && !methodName.startsWith("is"))
+ {
+ return null;
+ }
+
+ // TODO: this looping through all methods and calling getMethodDescriptor
+ // on each one is not very efficient. It might be nice to build all the
+ // descriptor->Method mappings once and cache them in a map. The question
+ // then is how long to hold onto that cached data though. And where to
+ // store it, as keeping the cache in a parent classloader will prevent unloading
+ // of any of the classes that those Method objects are on, unless weak
+ // references are used. For now, keep things simple..
+ Method[] methods = clazz.getDeclaredMethods();
+ for(Method m: methods)
+ {
+ String thisMethodDesc = org.objectweb.asm.Type.getMethodDescriptor(m);
+ if (thisMethodDesc.equals(descriptor))
+ {
+ return m;
+ }
+ }
+
+ return null;
+ }
+
+ /**
+ * Return a list of all the get*, set* and is* method on the specified class, regardless of
+ * their accessability.
+ * <p>
+ * The array order matches the order in which the methods were declared within the original
+ * source file.
+ */
+ public Method[] getMethods(final Class<?> clazz)
+ {
+ final List<Method> methods = new ArrayList<Method>(50);
+ ClassVisitor fv = new EmptyClassVisitor()
+ {
+ @Override
+ public MethodVisitor visitMethod(int access, String name, String descriptor,
+ String signature, String[] exceptions)
+ {
+ // Note that "descriptor" is like signature, except without any info about
+ // java15 generic type params. When a visited method has no generic types
+ // in its prototype, then param signature=null.
+ //
+ // As there can never be two methods with the same "descriptor", we just
+ // use that to locate the real Method object.
+ Method m = getMethod(clazz, name, descriptor);
+ if (m != null)
+ {
+ if (!methods.contains(m))
+ {
+ methods.add(m);
+ }
+ }
+ return super.visitMethod(access, name, descriptor, signature, exceptions);
+ }
+
+ };
+ applyVisitorToClass(clazz, fv);
+ return methods.toArray(METHODS_TYPE);
+ }
+}
Propchange: myfaces/orchestra/trunk/sandbox/src/main/java/org/apache/myfaces/orchestra/dynaForm/metadata/impl/ejb/AsmHelper.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified: myfaces/orchestra/trunk/sandbox/src/main/java/org/apache/myfaces/orchestra/dynaForm/metadata/impl/ejb/ClassHelper.java
URL: http://svn.apache.org/viewvc/myfaces/orchestra/trunk/sandbox/src/main/java/org/apache/myfaces/orchestra/dynaForm/metadata/impl/ejb/ClassHelper.java?rev=667085&r1=667084&r2=667085&view=diff
==============================================================================
--- myfaces/orchestra/trunk/sandbox/src/main/java/org/apache/myfaces/orchestra/dynaForm/metadata/impl/ejb/ClassHelper.java (original)
+++ myfaces/orchestra/trunk/sandbox/src/main/java/org/apache/myfaces/orchestra/dynaForm/metadata/impl/ejb/ClassHelper.java Thu Jun 12 06:42:36 2008
@@ -22,11 +22,27 @@
import java.lang.reflect.Method;
/**
- * Interface for helpers to retrieve class meta information
+ * Interface for helpers to retrieve class meta information.
+ * <p>
+ * Implementations must be threadsafe.
*/
public interface ClassHelper
{
+ /**
+ * Return a list of all the static and non-static fields of the specified
+ * class, regardless of their accessibility.
+ * <p>
+ * The array order matches the order in which the fields were declared within
+ * the original source file.
+ */
public Field[] getFields(Class<?> clazz);
+ /**
+ * Return a list of all the get*, set* and is* method on the specified class,
+ * regardless of their accessibility.
+ * <p>
+ * The array order matches the order in which the methods were declared within
+ * the original source file.
+ */
public Method[] getMethods(Class<?> clazz);
}
Modified: myfaces/orchestra/trunk/sandbox/src/main/java/org/apache/myfaces/orchestra/dynaForm/metadata/impl/ejb/ClassHelperFactory.java
URL: http://svn.apache.org/viewvc/myfaces/orchestra/trunk/sandbox/src/main/java/org/apache/myfaces/orchestra/dynaForm/metadata/impl/ejb/ClassHelperFactory.java?rev=667085&r1=667084&r2=667085&view=diff
==============================================================================
--- myfaces/orchestra/trunk/sandbox/src/main/java/org/apache/myfaces/orchestra/dynaForm/metadata/impl/ejb/ClassHelperFactory.java (original)
+++ myfaces/orchestra/trunk/sandbox/src/main/java/org/apache/myfaces/orchestra/dynaForm/metadata/impl/ejb/ClassHelperFactory.java Thu Jun 12 06:42:36 2008
@@ -20,35 +20,45 @@
public class ClassHelperFactory
{
- private static ClassHelper classHelper = null;
+ private static final String[] helperClasses = new String[] {
+ "org.apache.myfaces.orchestra.dynaForm.metadata.impl.ejb.AsmHelper",
+ "org.apache.myfaces.orchestra.dynaForm.metadata.impl.ejb.BcelHelper"
+ };
+ private static final ClassHelper classHelper = newClassHelper();
+
private ClassHelperFactory()
{
}
public static ClassHelper get()
{
- if (classHelper != null)
- {
- return classHelper;
- }
-
- classHelper = create();
-
- return classHelper;
+ return classHelper;
}
- private static ClassHelper create()
+ public static ClassHelper newClassHelper()
{
- try
- {
- Class.forName("org.apache.bcel.classfile.JavaClass");
- return new BcelHelper();
- }
- catch (ClassNotFoundException e)
- {
- // bcel not there
- }
+ ClassLoader cl = ClassHelperFactory.class.getClassLoader();
+ for(String helperClassName: helperClasses)
+ {
+ try
+ {
+ Class<ClassHelper> c = (Class<ClassHelper>) Class.forName(helperClassName, true, cl);
+ return c.newInstance();
+ }
+ catch (ClassNotFoundException e)
+ {
+ // not there
+ }
+ catch(IllegalAccessException e)
+ {
+ // not available
+ }
+ catch(InstantiationException e)
+ {
+ // not available
+ }
+ }
// last exit
return new JavaHelper();
Added: myfaces/orchestra/trunk/sandbox/src/main/java/org/apache/myfaces/orchestra/dynaForm/metadata/impl/ejb/EmptyClassVisitor.java
URL: http://svn.apache.org/viewvc/myfaces/orchestra/trunk/sandbox/src/main/java/org/apache/myfaces/orchestra/dynaForm/metadata/impl/ejb/EmptyClassVisitor.java?rev=667085&view=auto
==============================================================================
--- myfaces/orchestra/trunk/sandbox/src/main/java/org/apache/myfaces/orchestra/dynaForm/metadata/impl/ejb/EmptyClassVisitor.java (added)
+++ myfaces/orchestra/trunk/sandbox/src/main/java/org/apache/myfaces/orchestra/dynaForm/metadata/impl/ejb/EmptyClassVisitor.java Thu Jun 12 06:42:36 2008
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.myfaces.orchestra.dynaForm.metadata.impl.ejb;
+
+import org.objectweb.asm.AnnotationVisitor;
+import org.objectweb.asm.Attribute;
+import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
+import org.objectweb.asm.MethodVisitor;
+
+/**
+ * An empty implementation of the ASM ClassVisitor interface.
+ */
+public class EmptyClassVisitor implements ClassVisitor
+{
+ public void visitOuterClass(final String owner, final String name, final String desc)
+ {
+ }
+
+ public void visit(final int version, final int access, final String name,
+ final String signature, final String superName, final String[] interfaces)
+ {
+ }
+
+ public void visitAttribute(final Attribute attr)
+ {
+ }
+
+ public void visitEnd()
+ {
+ }
+
+ public void visitInnerClass(final String name, final String outerName, final String innerName,
+ final int access)
+ {
+ }
+
+ public FieldVisitor visitField(final int access, final String name, final String desc,
+ final String signature, final Object value)
+ {
+ return null;
+ }
+
+ public void visitSource(final String source, final String debug)
+ {
+ }
+
+ public AnnotationVisitor visitAnnotation(final String desc, final boolean visible)
+ {
+ return null;
+ }
+
+ public MethodVisitor visitMethod(final int access, final String name, final String desc,
+ final String signature, final String[] exceptions)
+ {
+ return null;
+ }
+}
Propchange: myfaces/orchestra/trunk/sandbox/src/main/java/org/apache/myfaces/orchestra/dynaForm/metadata/impl/ejb/EmptyClassVisitor.java
------------------------------------------------------------------------------
svn:eol-style = native