diff --git a/pom.xml b/pom.xml
index 4a2878d..34e93fc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -5,7 +5,7 @@
4.0.0
com.esotericsoftware.reflectasm
reflectasm
- 1.01
+ 1.03
jar
ReflectASM
High performance Java reflection using code generation
diff --git a/project.yaml b/project.yaml
index 8af8b54..be8c297 100644
--- a/project.yaml
+++ b/project.yaml
@@ -1,3 +1,3 @@
-version: 1.02
+version: 1.03
---
Build.build(project);
diff --git a/src/com/esotericsoftware/reflectasm/AccessClassLoader.java b/src/com/esotericsoftware/reflectasm/AccessClassLoader.java
index d2e48a6..c4ed1a3 100644
--- a/src/com/esotericsoftware/reflectasm/AccessClassLoader.java
+++ b/src/com/esotericsoftware/reflectasm/AccessClassLoader.java
@@ -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 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);
}
diff --git a/src/com/esotericsoftware/reflectasm/ConstructorAccess.java b/src/com/esotericsoftware/reflectasm/ConstructorAccess.java
index 7abcdc5..bec4cdc 100644
--- a/src/com/esotericsoftware/reflectasm/ConstructorAccess.java
+++ b/src/com/esotericsoftware/reflectasm/ConstructorAccess.java
@@ -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 {
static public ConstructorAccess get (Class 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 {
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);
}
}
diff --git a/src/com/esotericsoftware/reflectasm/FieldAccess.java b/src/com/esotericsoftware/reflectasm/FieldAccess.java
index d5f09aa..20c4ad0 100644
--- a/src/com/esotericsoftware/reflectasm/FieldAccess.java
+++ b/src/com/esotericsoftware/reflectasm/FieldAccess.java
@@ -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 fields = new ArrayList();
Class nextClass = type;
diff --git a/src/com/esotericsoftware/reflectasm/MethodAccess.java b/src/com/esotericsoftware/reflectasm/MethodAccess.java
index eae97aa..97da146 100644
--- a/src/com/esotericsoftware/reflectasm/MethodAccess.java
+++ b/src/com/esotericsoftware/reflectasm/MethodAccess.java
@@ -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 methods = new ArrayList();
Class nextClass = type;
diff --git a/test/com/esotericsoftware/reflectasm/ConstructorAccessTest.java b/test/com/esotericsoftware/reflectasm/ConstructorAccessTest.java
new file mode 100644
index 0000000..9456c17
--- /dev/null
+++ b/test/com/esotericsoftware/reflectasm/ConstructorAccessTest.java
@@ -0,0 +1,41 @@
+
+package com.esotericsoftware.reflectasm;
+
+import junit.framework.TestCase;
+
+public class ConstructorAccessTest extends TestCase {
+ public void testNewInstance () {
+ ConstructorAccess 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;
+ }
+ }
+}
diff --git a/test/com/esotericsoftware/reflectasm/benchmark/ConstructorAccessBenchmark.java b/test/com/esotericsoftware/reflectasm/benchmark/ConstructorAccessBenchmark.java
new file mode 100644
index 0000000..076fc15
--- /dev/null
+++ b/test/com/esotericsoftware/reflectasm/benchmark/ConstructorAccessBenchmark.java
@@ -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 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();
+ }
+}