Skip to content

Commit

Permalink
Change way the proxy factories are constucted, to allow for metadata …
Browse files Browse the repository at this point in the history
…sources other than the reflection API
  • Loading branch information
stuartwdouglas committed Aug 8, 2011
1 parent 478cc5f commit 9f1a2ea
Show file tree
Hide file tree
Showing 15 changed files with 488 additions and 172 deletions.
2 changes: 1 addition & 1 deletion pom.xml
Expand Up @@ -35,7 +35,7 @@
<!-- Artifact Information --> <!-- Artifact Information -->
<groupId>org.jboss.invocation</groupId> <groupId>org.jboss.invocation</groupId>
<artifactId>jboss-invocation</artifactId> <artifactId>jboss-invocation</artifactId>
<version>1.0.2.Final-SNAPSHOT</version> <version>1.1.0.Final-SNAPSHOT</version>
<name>Invocation API</name> <name>Invocation API</name>
<description>Invocation Application Programming Interface</description> <description>Invocation Application Programming Interface</description>
<packaging>jar</packaging> <packaging>jar</packaging>
Expand Down
28 changes: 3 additions & 25 deletions src/main/java/org/jboss/invocation/proxy/AbstractProxyFactory.java
Expand Up @@ -60,17 +60,6 @@ public abstract class AbstractProxyFactory<T> extends AbstractSubclassFactory<T>


private static final AtomicInteger count = new AtomicInteger(); private static final AtomicInteger count = new AtomicInteger();


/**
* Construct a new instance.
*
* @param className the class name
* @param superClass the superclass
* @param classLoader the defining class loader
*/
protected AbstractProxyFactory(String className, Class<T> superClass, ClassLoader classLoader) {
super(className, superClass, classLoader);
staticConstructor = classFile.addMethod(AccessFlag.of(AccessFlag.PUBLIC, AccessFlag.STATIC), "<clinit>", "V");
}


/** /**
* Construct a new instance. * Construct a new instance.
Expand All @@ -81,19 +70,8 @@ protected AbstractProxyFactory(String className, Class<T> superClass, ClassLoade
* @param protectionDomain the protection domain * @param protectionDomain the protection domain
*/ */
protected AbstractProxyFactory(String className, Class<T> superClass, ClassLoader classLoader, protected AbstractProxyFactory(String className, Class<T> superClass, ClassLoader classLoader,
ProtectionDomain protectionDomain) { ProtectionDomain protectionDomain, final ReflectionMetadataSource reflectionMetadataSource) {
super(className, superClass, classLoader, protectionDomain); super(className, superClass, classLoader, protectionDomain,reflectionMetadataSource);
staticConstructor = classFile.addMethod(AccessFlag.of(AccessFlag.PUBLIC, AccessFlag.STATIC), "<clinit>", "V");
}

/**
* Construct a new instance.
*
* @param className the class name
* @param superClass the superclass
*/
protected AbstractProxyFactory(String className, Class<T> superClass) {
super(className, superClass);
staticConstructor = classFile.addMethod(AccessFlag.of(AccessFlag.PUBLIC, AccessFlag.STATIC), "<clinit>", "V"); staticConstructor = classFile.addMethod(AccessFlag.of(AccessFlag.PUBLIC, AccessFlag.STATIC), "<clinit>", "V");
} }


Expand All @@ -111,7 +89,6 @@ protected void finalizeStaticConstructor() {
public void afterClassLoad(Class<?> clazz) { public void afterClassLoad(Class<?> clazz) {
super.afterClassLoad(clazz); super.afterClassLoad(clazz);
cachedMethods = AccessController.doPrivileged(new CachedMethodGetter()); cachedMethods = AccessController.doPrivileged(new CachedMethodGetter());
methodIdentifiers.clear();
} }


/** /**
Expand All @@ -131,6 +108,7 @@ public Method[] getCachedMethods() {
@Override @Override
protected void cleanup() { protected void cleanup() {
staticConstructor = null; staticConstructor = null;
methodIdentifiers.clear();
super.cleanup(); super.cleanup();
} }


Expand Down
109 changes: 50 additions & 59 deletions src/main/java/org/jboss/invocation/proxy/AbstractSubclassFactory.java
Expand Up @@ -22,6 +22,10 @@


package org.jboss.invocation.proxy; package org.jboss.invocation.proxy;


import org.jboss.classfilewriter.AccessFlag;
import org.jboss.classfilewriter.ClassMethod;
import org.jboss.classfilewriter.util.DescriptorUtils;

import java.lang.reflect.Constructor; import java.lang.reflect.Constructor;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
Expand All @@ -30,54 +34,16 @@
import java.util.HashSet; import java.util.HashSet;
import java.util.Set; import java.util.Set;


import org.jboss.classfilewriter.AccessFlag;
import org.jboss.classfilewriter.ClassMethod;
import org.jboss.classfilewriter.util.DescriptorUtils;

/** /**
* Class factory for classes that override superclass methods. * Class factory for classes that override superclass methods.
* <p> * <p/>
* This class extends {@link AbstractClassFactory} by adding convenience methods to override methods on the superclass. * This class extends {@link AbstractClassFactory} by adding convenience methods to override methods on the superclass.
* *
* @author Stuart Douglas
*
* @param <T> the superclass type * @param <T> the superclass type
* @author Stuart Douglas
*/ */
public abstract class AbstractSubclassFactory<T> extends AbstractClassFactory<T> { public abstract class AbstractSubclassFactory<T> extends AbstractClassFactory<T> {


/**
* Construct a new instance.
*
* @param className the class name
* @param superClass the superclass
* @param classLoader the defining class loader
* @param protectionDomain the protection domain
*/
protected AbstractSubclassFactory(String className, Class<T> superClass, ClassLoader classLoader,
ProtectionDomain protectionDomain) {
super(className, superClass, classLoader, protectionDomain);
}

/**
* Construct a new instance.
*
* @param className the class name
* @param superClass the superclass
* @param classLoader the defining class loader
*/
protected AbstractSubclassFactory(String className, Class<T> superClass, ClassLoader classLoader) {
super(className, superClass, classLoader);
}

/**
* Construct a new instance.
*
* @param className the class name
* @param superClass the superclass
*/
protected AbstractSubclassFactory(String className, Class<T> superClass) {
super(className, superClass);
}


/** /**
* Tracks methods that have already been overridden * Tracks methods that have already been overridden
Expand All @@ -89,6 +55,11 @@ protected AbstractSubclassFactory(String className, Class<T> superClass) {
*/ */
private final Set<Class<?>> interfaces = new HashSet<Class<?>>(); private final Set<Class<?>> interfaces = new HashSet<Class<?>>();


/**
* The metadata source used to generate the proxy
*/
protected final ReflectionMetadataSource reflectionMetadataSource;

/** /**
* Methods that should not be overridden by default * Methods that should not be overridden by default
*/ */
Expand All @@ -103,13 +74,27 @@ protected AbstractSubclassFactory(String className, Class<T> superClass) {
SKIP_BY_DEFAULT = Collections.unmodifiableSet(skip); SKIP_BY_DEFAULT = Collections.unmodifiableSet(skip);
} }


/**
* Construct a new instance.
*
* @param className the class name
* @param superClass the superclass
* @param classLoader the defining class loader
* @param protectionDomain the protection domain
*/
protected AbstractSubclassFactory(String className, Class<T> superClass, ClassLoader classLoader,
ProtectionDomain protectionDomain, final ReflectionMetadataSource reflectionMetadataSource) {
super(className, superClass, classLoader, protectionDomain);
this.reflectionMetadataSource = reflectionMetadataSource;
}

/** /**
* Creates a new method on the generated class that overrides the given methods, unless a method with the same signature has * Creates a new method on the generated class that overrides the given methods, unless a method with the same signature has
* already been overridden. * already been overridden.
* *
* @param method The method to override * @param method The method to override
* @param identifier The identifier of the method to override * @param identifier The identifier of the method to override
* @param creator The {@link MethodBodyCreator} used to create the method body * @param creator The {@link MethodBodyCreator} used to create the method body
* @return {@code true} if the method was successfully overridden, {@code false} otherwise * @return {@code true} if the method was successfully overridden, {@code false} otherwise
*/ */
protected boolean overrideMethod(Method method, MethodIdentifier identifier, MethodBodyCreator creator) { protected boolean overrideMethod(Method method, MethodIdentifier identifier, MethodBodyCreator creator) {
Expand All @@ -125,9 +110,9 @@ protected boolean overrideMethod(Method method, MethodIdentifier identifier, Met
* Creates a new method on the generated class that overrides the given methods, unless a method with the same signature has * Creates a new method on the generated class that overrides the given methods, unless a method with the same signature has
* already been overridden. * already been overridden.
* *
* @param method The method to override * @param method The method to override
* @param identifier The identifier of the method to override * @param identifier The identifier of the method to override
* @param creator The {@link MethodBodyCreator} used to create the method body * @param creator The {@link MethodBodyCreator} used to create the method body
* @return {@code false} if the method has already been overridden * @return {@code false} if the method has already been overridden
*/ */
protected boolean overrideMethod(ClassMethod method, MethodIdentifier identifier, MethodBodyCreator creator) { protected boolean overrideMethod(ClassMethod method, MethodIdentifier identifier, MethodBodyCreator creator) {
Expand All @@ -141,26 +126,27 @@ protected boolean overrideMethod(ClassMethod method, MethodIdentifier identifier


/** /**
* Overrides all public methods on the superclass. The default {@link MethodBodyCreator} is used to generate the class body. * Overrides all public methods on the superclass. The default {@link MethodBodyCreator} is used to generate the class body.
* <p> * <p/>
* NOTE: This will not override <code>equals(Object)</code>, <code>hashCode()</code>, <code>finalize()</code> and * NOTE: This will not override <code>equals(Object)</code>, <code>hashCode()</code>, <code>finalize()</code> and
* <code>toString()</code>, these should be overridden separately using {@link #overrideEquals(MethodBodyCreator)} * <code>toString()</code>, these should be overridden separately using {@link #overrideEquals(MethodBodyCreator)}
* {@link #overrideHashcode(MethodBodyCreator)}{@link #overrideToString(MethodBodyCreator)} * {@link #overrideHashcode(MethodBodyCreator)}{@link #overrideToString(MethodBodyCreator)}
* {@link #overrideFinalize(MethodBodyCreator)} * {@link #overrideFinalize(MethodBodyCreator)}
*
*/ */
protected void overridePublicMethods() { protected void overridePublicMethods() {
overridePublicMethods(getDefaultMethodOverride()); overridePublicMethods(getDefaultMethodOverride());
} }


/** {@inheritDoc} */ /**
* {@inheritDoc}
*/
@Override @Override
protected void cleanup() { protected void cleanup() {
overriddenMethods.clear(); overriddenMethods.clear();
} }


/** /**
* Overrides all public methods on the superclass. The given {@link MethodBodyCreator} is used to generate the class body. * Overrides all public methods on the superclass. The given {@link MethodBodyCreator} is used to generate the class body.
* <p> * <p/>
* NOTE: This will not override <code>equals(Object)</code>, <code>hashCode()</code>, <code>finalize()</code> and * NOTE: This will not override <code>equals(Object)</code>, <code>hashCode()</code>, <code>finalize()</code> and
* <code>toString()</code>, these should be overridden separately using {@link #overrideEquals(MethodBodyCreator)} * <code>toString()</code>, these should be overridden separately using {@link #overrideEquals(MethodBodyCreator)}
* {@link #overrideHashcode(MethodBodyCreator)},{@link #overrideToString(MethodBodyCreator)} and * {@link #overrideHashcode(MethodBodyCreator)},{@link #overrideToString(MethodBodyCreator)} and
Expand All @@ -169,7 +155,8 @@ protected void cleanup() {
* @param override the method body creator to use * @param override the method body creator to use
*/ */
protected void overridePublicMethods(MethodBodyCreator override) { protected void overridePublicMethods(MethodBodyCreator override) {
for (Method method : getSuperClass().getMethods()) { ClassMetadataSource data = reflectionMetadataSource.getClassMetadata(getSuperClass());
for (Method method : data.getMethods()) {
MethodIdentifier identifier = MethodIdentifier.getIdentifierForMethod(method); MethodIdentifier identifier = MethodIdentifier.getIdentifierForMethod(method);
if (Modifier.isFinal(method.getModifiers())) { if (Modifier.isFinal(method.getModifiers())) {
continue; continue;
Expand All @@ -191,7 +178,7 @@ protected void overrideAllMethods() {
* Overrides all methods on the superclass with the exception of <code>equals(Object)</code>, <code>hashCode()</code>, * Overrides all methods on the superclass with the exception of <code>equals(Object)</code>, <code>hashCode()</code>,
* <code>toString()</code> and <code>finalize()</code>. The given {@link MethodBodyCreator} is used to generate the class * <code>toString()</code> and <code>finalize()</code>. The given {@link MethodBodyCreator} is used to generate the class
* body. * body.
* <p> * <p/>
* Note that private methods are not actually overridden, and if the sub-class is loaded by a different ClassLoader to the * Note that private methods are not actually overridden, and if the sub-class is loaded by a different ClassLoader to the
* parent class then neither will package-private methods. These methods will still be present on the new class however, and * parent class then neither will package-private methods. These methods will still be present on the new class however, and
* can be accessed via reflection * can be accessed via reflection
Expand All @@ -201,7 +188,8 @@ protected void overrideAllMethods() {
protected void overrideAllMethods(MethodBodyCreator override) { protected void overrideAllMethods(MethodBodyCreator override) {
Class<?> currentClass = getSuperClass(); Class<?> currentClass = getSuperClass();
while (currentClass != null && currentClass != Object.class) { while (currentClass != null && currentClass != Object.class) {
for (Method method : currentClass.getDeclaredMethods()) { ClassMetadataSource data = reflectionMetadataSource.getClassMetadata(currentClass);
for (Method method : data.getDeclaredMethods()) {
// do not override static or private methods // do not override static or private methods
if (Modifier.isStatic(method.getModifiers()) || Modifier.isPrivate(method.getModifiers())) { if (Modifier.isStatic(method.getModifiers()) || Modifier.isPrivate(method.getModifiers())) {
continue; continue;
Expand Down Expand Up @@ -236,8 +224,9 @@ protected boolean overrideEquals() {
*/ */
protected boolean overrideEquals(MethodBodyCreator creator) { protected boolean overrideEquals(MethodBodyCreator creator) {
Method equals = null; Method equals = null;
ClassMetadataSource data = reflectionMetadataSource.getClassMetadata(getSuperClass());
try { try {
equals = getSuperClass().getMethod("equals", Object.class); equals = data.getMethod("equals", Boolean.TYPE, Object.class);
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
Expand All @@ -248,7 +237,6 @@ protected boolean overrideEquals(MethodBodyCreator creator) {
* Override the hashCode method using the default {@link MethodBodyCreator}. * Override the hashCode method using the default {@link MethodBodyCreator}.
* *
* @return true if the method was not already overridden * @return true if the method was not already overridden
*
*/ */
protected boolean overrideHashcode() { protected boolean overrideHashcode() {
return overrideHashcode(getDefaultMethodOverride()); return overrideHashcode(getDefaultMethodOverride());
Expand All @@ -263,8 +251,9 @@ protected boolean overrideHashcode() {
protected boolean overrideHashcode(MethodBodyCreator creator) { protected boolean overrideHashcode(MethodBodyCreator creator) {


Method hashCode = null; Method hashCode = null;
ClassMetadataSource data = reflectionMetadataSource.getClassMetadata(getSuperClass());
try { try {
hashCode = getSuperClass().getMethod("hashCode"); hashCode = data.getMethod("hashCode", Integer.TYPE);
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
Expand All @@ -288,8 +277,9 @@ protected boolean overrideToString() {
*/ */
protected boolean overrideToString(MethodBodyCreator creator) { protected boolean overrideToString(MethodBodyCreator creator) {
Method toString = null; Method toString = null;
ClassMetadataSource data = reflectionMetadataSource.getClassMetadata(getSuperClass());
try { try {
toString = getSuperClass().getMethod("toString"); toString = data.getMethod("toString", String.class);
} catch (Exception e) { } catch (Exception e) {
throw new RuntimeException(e); throw new RuntimeException(e);
} }
Expand All @@ -300,7 +290,6 @@ protected boolean overrideToString(MethodBodyCreator creator) {
* Override the finalize method using the default {@link MethodBodyCreator}. * Override the finalize method using the default {@link MethodBodyCreator}.
* *
* @return true if the method was not already overridden * @return true if the method was not already overridden
*
*/ */
protected boolean overrideFinalize() { protected boolean overrideFinalize() {
return overrideFinalize(getDefaultMethodOverride()); return overrideFinalize(getDefaultMethodOverride());
Expand Down Expand Up @@ -333,7 +322,7 @@ protected boolean addInterface(Class<?> interfaceClass) {
/** /**
* Adds an interface to the generated subclass, using the given {@link MethodBodyCreator} to generate the method bodies * Adds an interface to the generated subclass, using the given {@link MethodBodyCreator} to generate the method bodies
* *
* @param override the method body creator to use * @param override the method body creator to use
* @param interfaceClass the interface to add * @param interfaceClass the interface to add
* @return true if the interface was not already overridden * @return true if the interface was not already overridden
*/ */
Expand All @@ -343,7 +332,8 @@ protected boolean addInterface(MethodBodyCreator override, Class<?> interfaceCla
} }
interfaces.add(interfaceClass); interfaces.add(interfaceClass);
classFile.addInterface(interfaceClass.getName()); classFile.addInterface(interfaceClass.getName());
for (Method method : interfaceClass.getMethods()) { ClassMetadataSource data = reflectionMetadataSource.getClassMetadata(interfaceClass);
for (Method method : data.getMethods()) {
overrideMethod(method, MethodIdentifier.getIdentifierForMethod(method), override); overrideMethod(method, MethodIdentifier.getIdentifierForMethod(method), override);
} }
return true; return true;
Expand All @@ -363,7 +353,8 @@ protected void createConstructorDelegates() {
* @param creator the constructor body creator to use * @param creator the constructor body creator to use
*/ */
protected void createConstructorDelegates(ConstructorBodyCreator creator) { protected void createConstructorDelegates(ConstructorBodyCreator creator) {
for (Constructor<?> constructor : getSuperClass().getDeclaredConstructors()) { ClassMetadataSource data = reflectionMetadataSource.getClassMetadata(getSuperClass());
for (Constructor<?> constructor : data.getConstructors()) {
if (!Modifier.isPrivate(constructor.getModifiers())) { if (!Modifier.isPrivate(constructor.getModifiers())) {
creator.overrideConstructor(classFile.addMethod(AccessFlag.PUBLIC, "<init>", "V", DescriptorUtils creator.overrideConstructor(classFile.addMethod(AccessFlag.PUBLIC, "<init>", "V", DescriptorUtils
.parameterDescriptors(constructor.getParameterTypes())), constructor); .parameterDescriptors(constructor.getParameterTypes())), constructor);
Expand Down
43 changes: 43 additions & 0 deletions src/main/java/org/jboss/invocation/proxy/ClassMetadataSource.java
@@ -0,0 +1,43 @@
/*
* JBoss, Home of Professional Open Source
* Copyright 2010, Red Hat Inc., and individual contributors as indicated
* by the @authors tag. See the copyright.txt in the distribution for a
* full listing of individual contributors.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.jboss.invocation.proxy;

import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.Collection;

/**
* Interface that provides reflection data for a given class
*
* @author Stuart Douglas
*/
public interface ClassMetadataSource {

Collection<Method> getDeclaredMethods();

Collection<Method> getMethods();

Method getMethod(String methodName, Class<?> returnType, Class<?> ... parameters) throws NoSuchMethodException;

Collection<Constructor<?>> getConstructors();

}

0 comments on commit 9f1a2ea

Please sign in to comment.