From 7c3d828cc72ca6f1f58ee2e45526d5073fab33a5 Mon Sep 17 00:00:00 2001 From: Nathan Sweet Date: Fri, 27 Apr 2012 19:13:51 +0000 Subject: [PATCH] Updated ConstructorAccess. --- pom.xml | 2 +- project.yaml | 2 +- .../reflectasm/AccessClassLoader.java | 16 ++++++- .../reflectasm/ConstructorAccess.java | 15 ++++++- .../reflectasm/FieldAccess.java | 2 +- .../reflectasm/MethodAccess.java | 2 +- .../reflectasm/ConstructorAccessTest.java | 41 +++++++++++++++++ .../benchmark/ConstructorAccessBenchmark.java | 45 +++++++++++++++++++ 8 files changed, 118 insertions(+), 7 deletions(-) create mode 100644 test/com/esotericsoftware/reflectasm/ConstructorAccessTest.java create mode 100644 test/com/esotericsoftware/reflectasm/benchmark/ConstructorAccessBenchmark.java 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(); + } +}