Permalink
Browse files

Change way the proxy factories are constucted, to allow for metadata …

…sources other than the reflection API
  • Loading branch information...
stuartwdouglas committed Aug 8, 2011
1 parent 478cc5f commit 9f1a2eabad8968dfa0ca8a57ae021b911b4a774a
View
@@ -35,7 +35,7 @@
<!-- Artifact Information -->
<groupId>org.jboss.invocation</groupId>
<artifactId>jboss-invocation</artifactId>
<version>1.0.2.Final-SNAPSHOT</version>
<version>1.1.0.Final-SNAPSHOT</version>
<name>Invocation API</name>
<description>Invocation Application Programming Interface</description>
<packaging>jar</packaging>
@@ -60,17 +60,6 @@
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.
@@ -81,19 +70,8 @@ protected AbstractProxyFactory(String className, Class<T> superClass, ClassLoade
* @param protectionDomain the protection domain
*/
protected AbstractProxyFactory(String className, Class<T> superClass, ClassLoader classLoader,
ProtectionDomain protectionDomain) {
super(className, superClass, classLoader, protectionDomain);
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);
ProtectionDomain protectionDomain, final ReflectionMetadataSource reflectionMetadataSource) {
super(className, superClass, classLoader, protectionDomain,reflectionMetadataSource);
staticConstructor = classFile.addMethod(AccessFlag.of(AccessFlag.PUBLIC, AccessFlag.STATIC), "<clinit>", "V");
}
@@ -111,7 +89,6 @@ protected void finalizeStaticConstructor() {
public void afterClassLoad(Class<?> clazz) {
super.afterClassLoad(clazz);
cachedMethods = AccessController.doPrivileged(new CachedMethodGetter());
methodIdentifiers.clear();
}
/**
@@ -131,6 +108,7 @@ public void afterClassLoad(Class<?> clazz) {
@Override
protected void cleanup() {
staticConstructor = null;
methodIdentifiers.clear();
super.cleanup();
}
@@ -22,6 +22,10 @@
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.Method;
import java.lang.reflect.Modifier;
@@ -30,54 +34,16 @@
import java.util.HashSet;
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.
* <p>
* <p/>
* This class extends {@link AbstractClassFactory} by adding convenience methods to override methods on the superclass.
*
* @author Stuart Douglas
*
* @param <T> the superclass type
* @author Stuart Douglas
*/
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
@@ -89,6 +55,11 @@ protected AbstractSubclassFactory(String className, Class<T> superClass) {
*/
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
*/
@@ -103,13 +74,27 @@ protected AbstractSubclassFactory(String className, Class<T> superClass) {
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
* 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 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
*/
protected boolean overrideMethod(Method method, MethodIdentifier identifier, MethodBodyCreator creator) {
@@ -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
* 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 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
*/
protected boolean overrideMethod(ClassMethod method, MethodIdentifier identifier, MethodBodyCreator creator) {
@@ -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.
* <p>
* <p/>
* 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)}
* {@link #overrideHashcode(MethodBodyCreator)}{@link #overrideToString(MethodBodyCreator)}
* {@link #overrideFinalize(MethodBodyCreator)}
*
*/
protected void overridePublicMethods() {
overridePublicMethods(getDefaultMethodOverride());
}
/** {@inheritDoc} */
/**
* {@inheritDoc}
*/
@Override
protected void cleanup() {
overriddenMethods.clear();
}
/**
* 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
* <code>toString()</code>, these should be overridden separately using {@link #overrideEquals(MethodBodyCreator)}
* {@link #overrideHashcode(MethodBodyCreator)},{@link #overrideToString(MethodBodyCreator)} and
@@ -169,7 +155,8 @@ protected void cleanup() {
* @param override the method body creator to use
*/
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);
if (Modifier.isFinal(method.getModifiers())) {
continue;
@@ -191,7 +178,7 @@ protected void overrideAllMethods() {
* 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
* body.
* <p>
* <p/>
* 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
* can be accessed via reflection
@@ -201,7 +188,8 @@ protected void overrideAllMethods() {
protected void overrideAllMethods(MethodBodyCreator override) {
Class<?> currentClass = getSuperClass();
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
if (Modifier.isStatic(method.getModifiers()) || Modifier.isPrivate(method.getModifiers())) {
continue;
@@ -236,8 +224,9 @@ protected boolean overrideEquals() {
*/
protected boolean overrideEquals(MethodBodyCreator creator) {
Method equals = null;
ClassMetadataSource data = reflectionMetadataSource.getClassMetadata(getSuperClass());
try {
equals = getSuperClass().getMethod("equals", Object.class);
equals = data.getMethod("equals", Boolean.TYPE, Object.class);
} catch (Exception e) {
throw new RuntimeException(e);
}
@@ -248,7 +237,6 @@ protected boolean overrideEquals(MethodBodyCreator creator) {
* Override the hashCode method using the default {@link MethodBodyCreator}.
*
* @return true if the method was not already overridden
*
*/
protected boolean overrideHashcode() {
return overrideHashcode(getDefaultMethodOverride());
@@ -263,8 +251,9 @@ protected boolean overrideHashcode() {
protected boolean overrideHashcode(MethodBodyCreator creator) {
Method hashCode = null;
ClassMetadataSource data = reflectionMetadataSource.getClassMetadata(getSuperClass());
try {
hashCode = getSuperClass().getMethod("hashCode");
hashCode = data.getMethod("hashCode", Integer.TYPE);
} catch (Exception e) {
throw new RuntimeException(e);
}
@@ -288,8 +277,9 @@ protected boolean overrideToString() {
*/
protected boolean overrideToString(MethodBodyCreator creator) {
Method toString = null;
ClassMetadataSource data = reflectionMetadataSource.getClassMetadata(getSuperClass());
try {
toString = getSuperClass().getMethod("toString");
toString = data.getMethod("toString", String.class);
} catch (Exception e) {
throw new RuntimeException(e);
}
@@ -300,7 +290,6 @@ protected boolean overrideToString(MethodBodyCreator creator) {
* Override the finalize method using the default {@link MethodBodyCreator}.
*
* @return true if the method was not already overridden
*
*/
protected boolean overrideFinalize() {
return overrideFinalize(getDefaultMethodOverride());
@@ -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
*
* @param override the method body creator to use
* @param override the method body creator to use
* @param interfaceClass the interface to add
* @return true if the interface was not already overridden
*/
@@ -343,7 +332,8 @@ protected boolean addInterface(MethodBodyCreator override, Class<?> interfaceCla
}
interfaces.add(interfaceClass);
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);
}
return true;
@@ -363,7 +353,8 @@ protected void createConstructorDelegates() {
* @param creator the constructor body creator to use
*/
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())) {
creator.overrideConstructor(classFile.addMethod(AccessFlag.PUBLIC, "<init>", "V", DescriptorUtils
.parameterDescriptors(constructor.getParameterTypes())), constructor);
@@ -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();
}
Oops, something went wrong.

0 comments on commit 9f1a2ea

Please sign in to comment.