Updated ConstructorAccess.

This commit is contained in:
Nathan Sweet 2012-04-27 19:13:51 +00:00
parent c599cc03ab
commit 7c3d828cc7
8 changed files with 118 additions and 7 deletions

View File

@ -5,7 +5,7 @@
<modelVersion>4.0.0</modelVersion>
<groupId>com.esotericsoftware.reflectasm</groupId>
<artifactId>reflectasm</artifactId>
<version>1.01</version>
<version>1.03</version>
<packaging>jar</packaging>
<name>ReflectASM</name>
<description>High performance Java reflection using code generation</description>

View File

@ -1,3 +1,3 @@
version: 1.02
version: 1.03
---
Build.build(project);

View File

@ -2,9 +2,22 @@
package com.esotericsoftware.reflectasm;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.HashMap;
class AccessClassLoader extends ClassLoader {
AccessClassLoader (ClassLoader parent) {
static private ArrayList<AccessClassLoader> accessClassLoaders = new ArrayList();
static AccessClassLoader get (Class type) {
ClassLoader parent = type.getClassLoader();
for (int i = 0, n = accessClassLoaders.size(); i < n; i++) {
AccessClassLoader accessClassLoader = accessClassLoaders.get(i);
if (accessClassLoader.getParent() == parent) return accessClassLoader;
}
return new AccessClassLoader(parent);
}
private AccessClassLoader (ClassLoader parent) {
super(parent);
}
@ -12,6 +25,7 @@ class AccessClassLoader extends ClassLoader {
// These classes come from the classloader that loaded AccessClassLoader.
if (name.equals(FieldAccess.class.getName())) return FieldAccess.class;
if (name.equals(MethodAccess.class.getName())) return MethodAccess.class;
if (name.equals(ConstructorAccess.class.getName())) return ConstructorAccess.class;
// All other classes come from the classloader that loaded the type we are accessing.
return super.loadClass(name, resolve);
}

View File

@ -1,6 +1,8 @@
package com.esotericsoftware.reflectasm;
import java.lang.reflect.Modifier;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.MethodVisitor;
@ -8,7 +10,16 @@ import static org.objectweb.asm.Opcodes.*;
public abstract class ConstructorAccess<T> {
static public <T> ConstructorAccess<T> get (Class<T> type) {
AccessClassLoader loader = new AccessClassLoader(type.getClassLoader());
try {
type.getConstructor((Class[])null);
} catch (Exception ex) {
if (type.isMemberClass() && !Modifier.isStatic(type.getModifiers()))
throw new RuntimeException("Class cannot be created (non-static member class): " + type.getName());
else
throw new RuntimeException("Class cannot be created (missing no-arg constructor): " + type.getName());
}
AccessClassLoader loader = AccessClassLoader.get(type);
String className = type.getName();
String accessClassName = className + "ConstructorAccess";
@ -52,7 +63,7 @@ public abstract class ConstructorAccess<T> {
try {
return (ConstructorAccess)accessClass.newInstance();
} catch (Exception ex) {
throw new RuntimeException("Error constructing field access class: " + accessClassName, ex);
throw new RuntimeException("Error constructing constructor access class: " + accessClassName, ex);
}
}

View File

@ -15,7 +15,7 @@ import static org.objectweb.asm.Opcodes.*;
public abstract class FieldAccess {
static public FieldAccess get (Class type) {
AccessClassLoader loader = new AccessClassLoader(type.getClassLoader());
AccessClassLoader loader = AccessClassLoader.get(type);
ArrayList<Field> fields = new ArrayList();
Class nextClass = type;

View File

@ -16,7 +16,7 @@ import static org.objectweb.asm.Opcodes.*;
public abstract class MethodAccess {
static public MethodAccess get (Class type) {
AccessClassLoader loader = new AccessClassLoader(type.getClassLoader());
AccessClassLoader loader = AccessClassLoader.get(type);
ArrayList<Method> methods = new ArrayList();
Class nextClass = type;

View File

@ -0,0 +1,41 @@
package com.esotericsoftware.reflectasm;
import junit.framework.TestCase;
public class ConstructorAccessTest extends TestCase {
public void testNewInstance () {
ConstructorAccess<SomeClass> access = ConstructorAccess.get(SomeClass.class);
SomeClass someObject = new SomeClass();
assertEquals(someObject, access.newInstance());
assertEquals(someObject, access.newInstance());
assertEquals(someObject, access.newInstance());
}
static public class SomeClass {
public String name;
public int intValue;
protected float test1;
Float test2;
private String test3;
public boolean equals (Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
SomeClass other = (SomeClass)obj;
if (intValue != other.intValue) return false;
if (name == null) {
if (other.name != null) return false;
} else if (!name.equals(other.name)) return false;
if (Float.floatToIntBits(test1) != Float.floatToIntBits(other.test1)) return false;
if (test2 == null) {
if (other.test2 != null) return false;
} else if (!test2.equals(other.test2)) return false;
if (test3 == null) {
if (other.test3 != null) return false;
} else if (!test3.equals(other.test3)) return false;
return true;
}
}
}

View File

@ -0,0 +1,45 @@
package com.esotericsoftware.reflectasm.benchmark;
import com.esotericsoftware.reflectasm.ConstructorAccess;
public class ConstructorAccessBenchmark extends Benchmark {
public ConstructorAccessBenchmark () throws Exception {
int count = 1000000;
Object[] dontCompileMeAway = new Object[count];
Class type = SomeClass.class;
ConstructorAccess<SomeClass> access = ConstructorAccess.get(type);
for (int i = 0; i < 100; i++)
for (int ii = 0; ii < count; ii++)
dontCompileMeAway[ii] = access.newInstance();
for (int i = 0; i < 100; i++)
for (int ii = 0; ii < count; ii++)
dontCompileMeAway[ii] = type.newInstance();
warmup = false;
for (int i = 0; i < 100; i++) {
start();
for (int ii = 0; ii < count; ii++)
dontCompileMeAway[ii] = access.newInstance();
end("ConstructorAccess");
}
for (int i = 0; i < 100; i++) {
start();
for (int ii = 0; ii < count; ii++)
dontCompileMeAway[ii] = type.newInstance();
end("Reflection");
}
chart("Constructor");
}
static public class SomeClass {
public String name;
}
public static void main (String[] args) throws Exception {
new ConstructorAccessBenchmark();
}
}