[Git][java-team/libreflectasm-java][upstream] New upstream version 1.11.6+dfsg

Pierre Gruet (@pgt) gitlab at salsa.debian.org
Tue May 18 13:28:04 BST 2021



Pierre Gruet pushed to branch upstream at Debian Java Maintainers / libreflectasm-java


Commits:
2f658ad2 by Pierre Gruet at 2021-05-17T10:35:59+02:00
New upstream version 1.11.6+dfsg
- - - - -


26 changed files:

- java/.classpath → .classpath
- java/.project → .project
- + .travis.yml
- + CONTRIBUTING.md
- + README.md
- − java/src/com/esotericsoftware/reflectasm/AccessClassLoader.java
- − java/src/com/esotericsoftware/reflectasm/ConstructorAccess.java
- − java/src/com/esotericsoftware/reflectasm/MethodAccess.java
- − java/test/com/esotericsoftware/reflectasm/ClassLoaderTest.java
- − java/test/com/esotericsoftware/reflectasm/ConstructorAccessTest.java
- java/license.txt → license.txt
- java/pom.xml → pom.xml
- java/project.yaml → project.yaml
- + src/com/esotericsoftware/reflectasm/AccessClassLoader.java
- + src/com/esotericsoftware/reflectasm/ConstructorAccess.java
- java/src/com/esotericsoftware/reflectasm/FieldAccess.java → src/com/esotericsoftware/reflectasm/FieldAccess.java
- + src/com/esotericsoftware/reflectasm/MethodAccess.java
- + src/com/esotericsoftware/reflectasm/PublicConstructorAccess.java
- + test/com/esotericsoftware/reflectasm/ClassLoaderTest.java
- + test/com/esotericsoftware/reflectasm/ConstructorAccessTest.java
- java/test/com/esotericsoftware/reflectasm/FieldAccessTest.java → test/com/esotericsoftware/reflectasm/FieldAccessTest.java
- java/test/com/esotericsoftware/reflectasm/MethodAccessTest.java → test/com/esotericsoftware/reflectasm/MethodAccessTest.java
- java/test/com/esotericsoftware/reflectasm/benchmark/Benchmark.java → test/com/esotericsoftware/reflectasm/benchmark/Benchmark.java
- java/test/com/esotericsoftware/reflectasm/benchmark/ConstructorAccessBenchmark.java → test/com/esotericsoftware/reflectasm/benchmark/ConstructorAccessBenchmark.java
- java/test/com/esotericsoftware/reflectasm/benchmark/FieldAccessBenchmark.java → test/com/esotericsoftware/reflectasm/benchmark/FieldAccessBenchmark.java
- java/test/com/esotericsoftware/reflectasm/benchmark/MethodAccessBenchmark.java → test/com/esotericsoftware/reflectasm/benchmark/MethodAccessBenchmark.java


Changes:

=====================================
java/.classpath → .classpath
=====================================
@@ -4,6 +4,6 @@
 	<classpathentry excluding="**/.svn/*" kind="src" path="test"/>
 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
 	<classpathentry kind="lib" path="build/junit-4.6.jar"/>
-	<classpathentry kind="lib" path="lib/asm-4.0.jar"/>
+	<classpathentry kind="lib" path="lib/asm-5.1.jar"/>
 	<classpathentry kind="output" path="bin"/>
 </classpath>


=====================================
java/.project → .project
=====================================


=====================================
.travis.yml
=====================================
@@ -0,0 +1,12 @@
+language: java
+
+jdk:
+  - openjdk7
+  - oraclejdk8
+
+cache:
+  directories:
+    - $HOME/.m2
+
+# use container
+sudo: false


=====================================
CONTRIBUTING.md
=====================================
@@ -0,0 +1,7 @@
+Project license(s): 3-Clause BSD License
+
+* You will only Submit Contributions where You have authored 100% of the content.
+
+* You will only Submit Contributions to which You have the necessary rights. This means that if You are employed You have received the necessary permissions from Your employer to make the Contributions.
+
+* Whatever content You Contribute will be provided under the Project License(s).


=====================================
README.md
=====================================
@@ -0,0 +1,128 @@
+![](https://raw.github.com/wiki/EsotericSoftware/reflectasm/images/logo.png)
+
+[![Build Status](https://travis-ci.org/EsotericSoftware/reflectasm.png?branch=master)](https://travis-ci.org/EsotericSoftware/reflectasm)
+[![Maven Central](https://maven-badges.herokuapp.com/maven-central/com.esotericsoftware/reflectasm/badge.svg)](http://search.maven.org/#search%7Cga%7C1%7Cg%3A%22com.esotericsoftware%22%20AND%20a%3Areflectasm)
+
+Please use the [ReflectASM discussion group](http://groups.google.com/group/reflectasm-users) for support.
+
+## Overview
+
+ReflectASM is a very small Java library that provides high performance reflection by using code generation. An access class is generated to set/get fields, call methods, or create a new instance. The access class uses bytecode rather than Java's reflection, so it is much faster. It can also access primitive fields via bytecode to avoid boxing.
+
+## Performance
+
+![](http://chart.apis.google.com/chart?chma=100&chtt=Field%20Set/Get&chs=700x62&chd=t:1402081,11339107&chds=0,11339107&chxl=0:|Java%20Reflection|FieldAccess&cht=bhg&chbh=10&chxt=y&chco=6600FF)
+
+![](http://chart.apis.google.com/chart?chma=100&chtt=Method%20Call&chs=700x62&chd=t:97390,208750&chds=0,208750&chxl=0:|Java%20Reflection|MethodAccess&cht=bhg&chbh=10&chxt=y&chco=6600AA)
+
+![](http://chart.apis.google.com/chart?chma=100&chtt=Constructor&chs=700x62&chd=t:2853063,5828993&chds=0,5828993&chxl=0:|Java%20Reflection|ConstructorAccess&cht=bhg&chbh=10&chxt=y&chco=660066)
+
+The source code for these benchmarks is included in the project. The above charts were generated on Oracle's Java 7u3, server VM.
+
+## Installation
+
+To use reflectasm with maven, please use the following snippet in your pom.xml
+
+```xml
+    <dependency>
+        <groupId>com.esotericsoftware</groupId>
+        <artifactId>reflectasm</artifactId>
+        <version>1.11.3</version>
+    </dependency>
+```
+
+If you already have asm in a different version (than the one pulled in by reflectasm - see pom.xml) in your classpath, you should use the shaded reflectasm (contains relocated asm classes):
+
+```xml
+<dependency>
+  <groupId>com.esotericsoftware</groupId>
+  <artifactId>reflectasm</artifactId>
+  <version>1.11.3</version>
+  <classifier>shaded</classifier>
+  <exclusions>
+    <exclusion>
+      <groupId>org.ow2.asm</groupId>
+      <artifactId>asm</artifactId>
+    </exclusion>
+  </exclusions>
+</dependency>
+```
+
+## Usage
+
+Method reflection with ReflectASM:
+
+```java
+SomeClass someObject = ...
+MethodAccess access = MethodAccess.get(SomeClass.class);
+access.invoke(someObject, "setName", "Awesome McLovin");
+String name = (String)access.invoke(someObject, "getName");
+```
+
+Field reflection with ReflectASM:
+
+```java
+SomeClass someObject = ...
+FieldAccess access = FieldAccess.get(SomeClass.class);
+access.set(someObject, "name", "Awesome McLovin");
+String name = (String)access.get(someObject, "name");
+```
+
+Constructor reflection with ReflectASM:
+
+```java
+ConstructorAccess<SomeClass> access = ConstructorAccess.get(SomeClass.class);
+SomeClass someObject = access.newInstance();
+```
+
+## Avoiding Name Lookup
+
+For maximum performance when methods or fields are accessed repeatedly, the method or field index should be used instead of the name:
+
+```java
+SomeClass someObject = ...
+MethodAccess access = MethodAccess.get(SomeClass.class);
+int addNameIndex = access.getIndex("addName");
+for (String name : names)
+    access.invoke(someObject, addNameIndex, "Awesome McLovin");
+```
+
+Iterate all fields:
+
+```java
+FieldAccess access = FieldAccess.get(SomeClass.class);
+for(int i = 0, n = access.getFieldCount(); i < n; i++) {
+    access.set(instanceObject, i, valueToPut);              
+}
+```
+
+## Visibility
+
+ReflectASM can always access public members. An attempt is made to define access classes in the same classloader (using setAccessible) and package as the accessed class. If the security manager allows setAccessible to succeed, then protected and default access (package private) members can be accessed. If setAccessible fails, no exception is thrown, but only public members can be accessed. Private members can never be accessed.
+
+## Exceptions
+
+Stack traces when using ReflectASM are a bit cleaner. Here is Java's reflection calling a method that throws a RuntimeException:
+
+```
+Exception in thread "main" java.lang.reflect.InvocationTargetException
+	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
+	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
+	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
+	at java.lang.reflect.Method.invoke(Method.java:597)
+	at com.example.SomeCallingCode.doit(SomeCallingCode.java:22)
+Caused by: java.lang.RuntimeException
+	at com.example.SomeClass.someMethod(SomeClass.java:48)
+	... 5 more
+```
+
+Here is the same but when ReflectASM is used:
+
+```
+Exception in thread "main" java.lang.RuntimeException
+	at com.example.SomeClass.someMethod(SomeClass.java:48)
+	at com.example.SomeClassMethodAccess.invoke(Unknown Source)
+	at com.example.SomeCallingCode.doit(SomeCallingCode.java:22)
+```
+
+If ReflectASM is used to invoke code that throws a checked exception, the checked exception is thrown. Because it is a compilation error to use try/catch with a checked exception around code that doesn't declare that exception as being thrown, you must catch Exception if you care about catching a checked exception in code you invoke with ReflectASM.


=====================================
java/src/com/esotericsoftware/reflectasm/AccessClassLoader.java deleted
=====================================
@@ -1,47 +0,0 @@
-
-package com.esotericsoftware.reflectasm;
-
-import java.lang.reflect.Method;
-import java.util.ArrayList;
-
-class AccessClassLoader extends ClassLoader {
-	static private final ArrayList<AccessClassLoader> accessClassLoaders = new ArrayList();
-
-	static AccessClassLoader get (Class type) {
-		ClassLoader parent = type.getClassLoader();
-		synchronized (accessClassLoaders) {
-			for (int i = 0, n = accessClassLoaders.size(); i < n; i++) {
-				AccessClassLoader accessClassLoader = accessClassLoaders.get(i);
-				if (accessClassLoader.getParent() == parent) return accessClassLoader;
-			}
-			AccessClassLoader accessClassLoader = new AccessClassLoader(parent);
-			accessClassLoaders.add(accessClassLoader);
-			return accessClassLoader;
-		}
-	}
-
-	private AccessClassLoader (ClassLoader parent) {
-		super(parent);
-	}
-
-	protected synchronized java.lang.Class<?> loadClass (String name, boolean resolve) throws ClassNotFoundException {
-		// 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);
-	}
-
-	Class<?> defineClass (String name, byte[] bytes) throws ClassFormatError {
-		try {
-			// Attempt to load the access class in the same loader, which makes protected and default access members accessible.
-			Method method = ClassLoader.class.getDeclaredMethod("defineClass", new Class[] {String.class, byte[].class, int.class,
-				int.class});
-			method.setAccessible(true);
-			return (Class)method.invoke(getParent(), new Object[] {name, bytes, Integer.valueOf(0), Integer.valueOf(bytes.length)});
-		} catch (Exception ignored) {
-		}
-		return defineClass(name, bytes, 0, bytes.length);
-	}
-}


=====================================
java/src/com/esotericsoftware/reflectasm/ConstructorAccess.java deleted
=====================================
@@ -1,71 +0,0 @@
-
-package com.esotericsoftware.reflectasm;
-
-import java.lang.reflect.Modifier;
-
-import org.objectweb.asm.ClassWriter;
-import org.objectweb.asm.MethodVisitor;
-
-import static org.objectweb.asm.Opcodes.*;
-
-public abstract class ConstructorAccess<T> {
-	static public <T> ConstructorAccess<T> get (Class<T> type) {
-		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";
-		if (accessClassName.startsWith("java.")) accessClassName = "reflectasm." + accessClassName;
-		Class accessClass = null;
-		try {
-			accessClass = loader.loadClass(accessClassName);
-		} catch (ClassNotFoundException ignored) {
-		}
-		if (accessClass == null) {
-			String accessClassNameInternal = accessClassName.replace('.', '/');
-			String classNameInternal = className.replace('.', '/');
-
-			ClassWriter cw = new ClassWriter(0);
-			cw.visit(V1_1, ACC_PUBLIC + ACC_SUPER, accessClassNameInternal, null,
-				"com/esotericsoftware/reflectasm/ConstructorAccess", null);
-			MethodVisitor mv;
-			{
-				mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
-				mv.visitCode();
-				mv.visitVarInsn(ALOAD, 0);
-				mv.visitMethodInsn(INVOKESPECIAL, "com/esotericsoftware/reflectasm/ConstructorAccess", "<init>", "()V");
-				mv.visitInsn(RETURN);
-				mv.visitMaxs(1, 1);
-				mv.visitEnd();
-			}
-			{
-				mv = cw.visitMethod(ACC_PUBLIC, "newInstance", "()Ljava/lang/Object;", null, null);
-				mv.visitCode();
-				mv.visitTypeInsn(NEW, classNameInternal);
-				mv.visitInsn(DUP);
-				mv.visitMethodInsn(INVOKESPECIAL, classNameInternal, "<init>", "()V");
-				mv.visitInsn(ARETURN);
-				mv.visitMaxs(2, 1);
-				mv.visitEnd();
-			}
-			cw.visitEnd();
-			byte[] data = cw.toByteArray();
-			accessClass = loader.defineClass(accessClassName, data);
-		}
-		try {
-			return (ConstructorAccess)accessClass.newInstance();
-		} catch (Exception ex) {
-			throw new RuntimeException("Error constructing constructor access class: " + accessClassName, ex);
-		}
-	}
-
-	abstract public T newInstance ();
-}


=====================================
java/src/com/esotericsoftware/reflectasm/MethodAccess.java deleted
=====================================
@@ -1,245 +0,0 @@
-
-package com.esotericsoftware.reflectasm;
-
-import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.ArrayList;
-import java.util.Arrays;
-
-import org.objectweb.asm.ClassWriter;
-import org.objectweb.asm.Label;
-import org.objectweb.asm.MethodVisitor;
-import org.objectweb.asm.Opcodes;
-import org.objectweb.asm.Type;
-
-import static org.objectweb.asm.Opcodes.*;
-
-public abstract class MethodAccess {
-	private String[] methodNames;
-	private Class[][] parameterTypes;
-
-	abstract public Object invoke (Object object, int methodIndex, Object... args);
-
-	/** Invokes the first method with the specified name. */
-	public Object invoke (Object object, String methodName, Object... args) {
-		return invoke(object, getIndex(methodName), args);
-	}
-
-	/** Returns the index of the first method with the specified name. */
-	public int getIndex (String methodName) {
-		for (int i = 0, n = methodNames.length; i < n; i++)
-			if (methodNames[i].equals(methodName)) return i;
-		throw new IllegalArgumentException("Unable to find public method: " + methodName);
-	}
-
-	public int getIndex (String methodName, Class... paramTypes) {
-		for (int i = 0, n = methodNames.length; i < n; i++)
-			if (methodNames[i].equals(methodName) && Arrays.equals(paramTypes, parameterTypes[i])) return i;
-		throw new IllegalArgumentException("Unable to find public method: " + methodName + " " + Arrays.toString(parameterTypes));
-	}
-
-	public String[] getMethodNames () {
-		return methodNames;
-	}
-
-	public Class[][] getParameterTypes () {
-		return parameterTypes;
-	}
-
-	static public MethodAccess get (Class type) {
-		AccessClassLoader loader = AccessClassLoader.get(type);
-
-		ArrayList<Method> methods = new ArrayList();
-		Class nextClass = type;
-		while (nextClass != Object.class) {
-			Method[] declaredMethods = nextClass.getDeclaredMethods();
-			for (int i = 0, n = declaredMethods.length; i < n; i++) {
-				Method method = declaredMethods[i];
-				int modifiers = method.getModifiers();
-				if (Modifier.isStatic(modifiers)) continue;
-				if (Modifier.isPrivate(modifiers)) continue;
-				methods.add(method);
-			}
-			nextClass = nextClass.getSuperclass();
-		}
-
-		Class[][] parameterTypes = new Class[methods.size()][];
-		String[] methodNames = new String[methods.size()];
-		for (int i = 0, n = methodNames.length; i < n; i++) {
-			Method method = methods.get(i);
-			methodNames[i] = method.getName();
-			parameterTypes[i] = method.getParameterTypes();
-		}
-
-		String className = type.getName();
-		String accessClassName = className + "MethodAccess";
-		if (accessClassName.startsWith("java.")) accessClassName = "reflectasm." + accessClassName;
-		Class accessClass = null;
-		try {
-			accessClass = loader.loadClass(accessClassName);
-		} catch (ClassNotFoundException ignored) {
-		}
-		if (accessClass == null) {
-			String accessClassNameInternal = accessClassName.replace('.', '/');
-			String classNameInternal = className.replace('.', '/');
-
-			ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
-			MethodVisitor mv;
-			cw.visit(V1_1, ACC_PUBLIC + ACC_SUPER, accessClassNameInternal, null, "com/esotericsoftware/reflectasm/MethodAccess",
-				null);
-			{
-				mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
-				mv.visitCode();
-				mv.visitVarInsn(ALOAD, 0);
-				mv.visitMethodInsn(INVOKESPECIAL, "com/esotericsoftware/reflectasm/MethodAccess", "<init>", "()V");
-				mv.visitInsn(RETURN);
-				mv.visitMaxs(0, 0);
-				mv.visitEnd();
-			}
-			{
-				mv = cw.visitMethod(ACC_PUBLIC + ACC_VARARGS, "invoke", "(Ljava/lang/Object;I[Ljava/lang/Object;)Ljava/lang/Object;",
-					null, null);
-				mv.visitCode();
-
-				if (!methods.isEmpty()) {
-					mv.visitVarInsn(ALOAD, 1);
-					mv.visitTypeInsn(CHECKCAST, classNameInternal);
-					mv.visitVarInsn(ASTORE, 4);
-
-					mv.visitVarInsn(ILOAD, 2);
-					Label[] labels = new Label[methods.size()];
-					for (int i = 0, n = labels.length; i < n; i++)
-						labels[i] = new Label();
-					Label defaultLabel = new Label();
-					mv.visitTableSwitchInsn(0, labels.length - 1, defaultLabel, labels);
-
-					StringBuilder buffer = new StringBuilder(128);
-					for (int i = 0, n = labels.length; i < n; i++) {
-						mv.visitLabel(labels[i]);
-						if (i == 0)
-							mv.visitFrame(Opcodes.F_APPEND, 1, new Object[] {classNameInternal}, 0, null);
-						else
-							mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
-						mv.visitVarInsn(ALOAD, 4);
-
-						buffer.setLength(0);
-						buffer.append('(');
-
-						Method method = methods.get(i);
-						Class[] paramTypes = method.getParameterTypes();
-						for (int paramIndex = 0; paramIndex < paramTypes.length; paramIndex++) {
-							mv.visitVarInsn(ALOAD, 3);
-							mv.visitIntInsn(BIPUSH, paramIndex);
-							mv.visitInsn(AALOAD);
-							Type paramType = Type.getType(paramTypes[paramIndex]);
-							switch (paramType.getSort()) {
-							case Type.BOOLEAN:
-								mv.visitTypeInsn(CHECKCAST, "java/lang/Boolean");
-								mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z");
-								break;
-							case Type.BYTE:
-								mv.visitTypeInsn(CHECKCAST, "java/lang/Byte");
-								mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B");
-								break;
-							case Type.CHAR:
-								mv.visitTypeInsn(CHECKCAST, "java/lang/Character");
-								mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C");
-								break;
-							case Type.SHORT:
-								mv.visitTypeInsn(CHECKCAST, "java/lang/Short");
-								mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S");
-								break;
-							case Type.INT:
-								mv.visitTypeInsn(CHECKCAST, "java/lang/Integer");
-								mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I");
-								break;
-							case Type.FLOAT:
-								mv.visitTypeInsn(CHECKCAST, "java/lang/Float");
-								mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F");
-								break;
-							case Type.LONG:
-								mv.visitTypeInsn(CHECKCAST, "java/lang/Long");
-								mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J");
-								break;
-							case Type.DOUBLE:
-								mv.visitTypeInsn(CHECKCAST, "java/lang/Double");
-								mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D");
-								break;
-							case Type.ARRAY:
-								mv.visitTypeInsn(CHECKCAST, paramType.getDescriptor());
-								break;
-							case Type.OBJECT:
-								mv.visitTypeInsn(CHECKCAST, paramType.getInternalName());
-								break;
-							}
-							buffer.append(paramType.getDescriptor());
-						}
-
-						buffer.append(')');
-						buffer.append(Type.getDescriptor(method.getReturnType()));
-						mv.visitMethodInsn(INVOKEVIRTUAL, classNameInternal, method.getName(), buffer.toString());
-
-						switch (Type.getType(method.getReturnType()).getSort()) {
-						case Type.VOID:
-							mv.visitInsn(ACONST_NULL);
-							break;
-						case Type.BOOLEAN:
-							mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;");
-							break;
-						case Type.BYTE:
-							mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;");
-							break;
-						case Type.CHAR:
-							mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;");
-							break;
-						case Type.SHORT:
-							mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;");
-							break;
-						case Type.INT:
-							mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
-							break;
-						case Type.FLOAT:
-							mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;");
-							break;
-						case Type.LONG:
-							mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;");
-							break;
-						case Type.DOUBLE:
-							mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;");
-							break;
-						}
-
-						mv.visitInsn(ARETURN);
-					}
-
-					mv.visitLabel(defaultLabel);
-					mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
-				}
-				mv.visitTypeInsn(NEW, "java/lang/IllegalArgumentException");
-				mv.visitInsn(DUP);
-				mv.visitTypeInsn(NEW, "java/lang/StringBuilder");
-				mv.visitInsn(DUP);
-				mv.visitLdcInsn("Method not found: ");
-				mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "(Ljava/lang/String;)V");
-				mv.visitVarInsn(ILOAD, 2);
-				mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(I)Ljava/lang/StringBuilder;");
-				mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;");
-				mv.visitMethodInsn(INVOKESPECIAL, "java/lang/IllegalArgumentException", "<init>", "(Ljava/lang/String;)V");
-				mv.visitInsn(ATHROW);
-				mv.visitMaxs(0, 0);
-				mv.visitEnd();
-			}
-			cw.visitEnd();
-			byte[] data = cw.toByteArray();
-			accessClass = loader.defineClass(accessClassName, data);
-		}
-		try {
-			MethodAccess access = (MethodAccess)accessClass.newInstance();
-			access.methodNames = methodNames;
-			access.parameterTypes = parameterTypes;
-			return access;
-		} catch (Exception ex) {
-			throw new RuntimeException("Error constructing method access class: " + accessClassName, ex);
-		}
-	}
-}


=====================================
java/test/com/esotericsoftware/reflectasm/ClassLoaderTest.java deleted
=====================================
@@ -1,60 +0,0 @@
-
-package com.esotericsoftware.reflectasm;
-
-import java.io.ByteArrayOutputStream;
-import java.io.IOException;
-import java.io.InputStream;
-
-import junit.framework.TestCase;
-
-public class ClassLoaderTest extends TestCase {
-	public void testDifferentClassloaders () throws Exception {
-		// This classloader can see only the Test class and core Java classes.
-		ClassLoader testClassLoader = new ClassLoader() {
-			protected synchronized Class<?> loadClass (String name, boolean resolve) throws ClassNotFoundException {
-				Class c = findLoadedClass(name);
-				if (c != null) return c;
-				if (name.startsWith("java.")) return super.loadClass(name, resolve);
-				if (!name.equals("com.esotericsoftware.reflectasm.ClassLoaderTest$Test"))
-					throw new ClassNotFoundException("Class not found on purpose: " + name);
-				ByteArrayOutputStream output = new ByteArrayOutputStream(32 * 1024);
-				InputStream input = ClassLoaderTest.class.getResourceAsStream("/" + name.replace('.', '/') + ".class");
-				if (input == null) return null;
-				try {
-					byte[] buffer = new byte[4096];
-					int total = 0;
-					while (true) {
-						int length = input.read(buffer, 0, buffer.length);
-						if (length == -1) break;
-						output.write(buffer, 0, length);
-					}
-				} catch (IOException ex) {
-					throw new ClassNotFoundException("Error reading class file.", ex);
-				} finally {
-					try {
-						input.close();
-					} catch (IOException ignored) {
-					}
-				}
-				byte[] buffer = output.toByteArray();
-				return defineClass(name, buffer, 0, buffer.length);
-			}
-		};
-		Class testClass = testClassLoader.loadClass("com.esotericsoftware.reflectasm.ClassLoaderTest$Test");
-		Object testObject = testClass.newInstance();
-
-		// Ensure AccessClassLoader can access both the Test class and FieldAccess.
-		FieldAccess access = FieldAccess.get(testObject.getClass());
-		access.set(testObject, "name", "first");
-		assertEquals("first", testObject.toString());
-		assertEquals("first", access.get(testObject, "name"));
-	}
-
-	static public class Test {
-		public String name;
-
-		public String toString () {
-			return name;
-		}
-	}
-}


=====================================
java/test/com/esotericsoftware/reflectasm/ConstructorAccessTest.java deleted
=====================================
@@ -1,41 +0,0 @@
-
-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;
-		}
-	}
-}


=====================================
java/license.txt → license.txt
=====================================


=====================================
java/pom.xml → pom.xml
=====================================
@@ -1,27 +1,30 @@
-<project xmlns="http://maven.apache.org/POM/4.0.0"
-	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
-		http://maven.apache.org/xsd/maven-4.0.0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+	<parent>
+		<groupId>org.sonatype.oss</groupId>
+		<artifactId>oss-parent</artifactId>
+		<version>7</version>
+	</parent>
 	<modelVersion>4.0.0</modelVersion>
-	<groupId>com.esotericsoftware.reflectasm</groupId>
+	<groupId>com.esotericsoftware</groupId>
 	<artifactId>reflectasm</artifactId>
-	<version>1.05</version>
-	<packaging>jar</packaging>
+	<version>1.11.6</version>
+	<packaging>bundle</packaging>
 	<name>ReflectASM</name>
 	<description>High performance Java reflection using code generation</description>
-	<url>http://code.google.com/p/reflectasm/</url>
+	<url>https://github.com/EsotericSoftware/reflectasm</url>
 
 	<licenses>
 		<license>
-			<name>New BSD License</name>
-			<url>http://www.opensource.org/licenses/bsd-license.php</url>
+			<name>3-Clause BSD License</name>
+			<url>https://opensource.org/licenses/BSD-3-Clause</url>
 			<distribution>repo</distribution>
 		</license>
 	</licenses>
 
 	<scm>
-		<url>http://reflectasm.googlecode.com/svn/</url>
-		<connection>scm:svn:http://reflectasm.googlecode.com/svn/</connection>
+		<url>https://github.com/EsotericSoftware/reflectasm</url>
+		<connection>scm:git:git at github.com:EsotericSoftware/reflectasm.git</connection>
+		<developerConnection>scm:git:git at github.com:EsotericSoftware/reflectasm.git</developerConnection>
 	</scm>
 
 	<developers>
@@ -40,7 +43,7 @@
 		<dependency>
 			<groupId>org.ow2.asm</groupId>
 			<artifactId>asm</artifactId>
-			<version>4.0</version>
+			<version>5.1</version>
 		</dependency>
 		<dependency>
 			<groupId>junit</groupId>
@@ -56,6 +59,15 @@
 		<testSourceDirectory>test</testSourceDirectory>
 
 		<plugins>
+     			 <plugin>
+        			<groupId>org.apache.maven.plugins</groupId>
+        			<artifactId>maven-compiler-plugin</artifactId>
+        			<version>3.1</version>
+        			<configuration>
+          				<source>1.5</source>
+          				<target>1.5</target>
+        			</configuration>
+      			</plugin>
 			<!-- Disable resources (project has none) -->
 			<plugin>
 				<artifactId>maven-resources-plugin</artifactId>
@@ -71,6 +83,51 @@
 					</execution>
 				</executions>
 			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-jar-plugin</artifactId>
+				<version>2.4</version>
+				<configuration>
+					<excludes>
+						<exclude>**/.svn/*</exclude>
+					</excludes>
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-shade-plugin</artifactId>
+				<version>2.3</version>
+				<executions>
+					<execution>
+						<phase>package</phase>
+						<goals>
+							<goal>shade</goal>
+						</goals>
+						<configuration>
+							<!-- remove all classes of dependencies that are not used by the project -->
+							<minimizeJar>true</minimizeJar>
+							<shadedArtifactAttached>false</shadedArtifactAttached>
+							<relocations>
+								<relocation>
+									<pattern>org.objectweb.asm</pattern>
+									<shadedPattern>com.esotericsoftware.asm</shadedPattern>
+								</relocation>
+							</relocations>
+						</configuration>
+					</execution>
+				</executions>
+			</plugin>
+			<plugin>
+				<groupId>org.apache.felix</groupId>
+				<artifactId>maven-bundle-plugin</artifactId>
+				<version>2.5.0</version>
+				<extensions>true</extensions>
+				<configuration>
+					<instructions>
+						<Export-Package>com.esotericsoftware.reflectasm*</Export-Package>
+					</instructions>
+				</configuration>
+			</plugin>
 		</plugins>
 	</build>
-</project>
\ No newline at end of file
+</project>


=====================================
java/project.yaml → project.yaml
=====================================
@@ -1,4 +1,4 @@
-version: 1.05
+version: 1.11.4
 ---
 Build.build(project);
 Build.oneJAR(project);
\ No newline at end of file


=====================================
src/com/esotericsoftware/reflectasm/AccessClassLoader.java
=====================================
@@ -0,0 +1,164 @@
+/**
+ * Copyright (c) 2008, Nathan Sweet
+ *  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of Esoteric Software nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+package com.esotericsoftware.reflectasm;
+
+import java.lang.ref.WeakReference;
+import java.lang.reflect.Method;
+import java.security.ProtectionDomain;
+import java.util.HashSet;
+import java.util.WeakHashMap;
+
+class AccessClassLoader extends ClassLoader {
+	// Weak-references to class loaders, to avoid perm gen memory leaks, for example in app servers/web containters if the
+	// reflectasm library (including this class) is loaded outside the deployed applications (WAR/EAR) using ReflectASM/Kryo (exts,
+	// user classpath, etc).
+	// The key is the parent class loader and the value is the AccessClassLoader, both are weak-referenced in the hash table.
+	static private final WeakHashMap<ClassLoader, WeakReference<AccessClassLoader>> accessClassLoaders = new WeakHashMap();
+
+	// Fast-path for classes loaded in the same ClassLoader as this class.
+	static private final ClassLoader selfContextParentClassLoader = getParentClassLoader(AccessClassLoader.class);
+	static private volatile AccessClassLoader selfContextAccessClassLoader = new AccessClassLoader(selfContextParentClassLoader);
+
+	static private volatile Method defineClassMethod;
+
+	private final HashSet<String> localClassNames = new HashSet();
+
+	private AccessClassLoader (ClassLoader parent) {
+		super(parent);
+	}
+
+	/** Returns null if the access class has not yet been defined. */
+	Class loadAccessClass (String name) {
+		// No need to check the parent class loader if the access class hasn't been defined yet.
+		if (localClassNames.contains(name)) {
+			try {
+				return loadClass(name, false);
+			} catch (ClassNotFoundException ex) {
+				throw new RuntimeException(ex); // Should not happen, since we know the class has been defined.
+			}
+		}
+		return null;
+	}
+
+	Class defineAccessClass (String name, byte[] bytes) throws ClassFormatError {
+		localClassNames.add(name);
+		return defineClass(name, bytes);
+	}
+
+	protected Class<?> loadClass (String name, boolean resolve) throws ClassNotFoundException {
+		// 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;
+		if (name.equals(PublicConstructorAccess.class.getName())) return PublicConstructorAccess.class;
+		// All other classes come from the classloader that loaded the type we are accessing.
+		return super.loadClass(name, resolve);
+	}
+
+	Class<?> defineClass (String name, byte[] bytes) throws ClassFormatError {
+		try {
+			// Attempt to load the access class in the same loader, which makes protected and default access members accessible.
+			return (Class<?>)getDefineClassMethod().invoke(getParent(),
+				new Object[] {name, bytes, Integer.valueOf(0), Integer.valueOf(bytes.length), getClass().getProtectionDomain()});
+		} catch (Exception ignored) {
+			// continue with the definition in the current loader (won't have access to protected and package-protected members)
+		}
+		return defineClass(name, bytes, 0, bytes.length, getClass().getProtectionDomain());
+	}
+
+	// As per JLS, section 5.3,
+	// "The runtime package of a class or interface is determined by the package name and defining class loader of the class or
+	// interface."
+	static boolean areInSameRuntimeClassLoader (Class type1, Class type2) {
+		if (type1.getPackage() != type2.getPackage()) {
+			return false;
+		}
+		ClassLoader loader1 = type1.getClassLoader();
+		ClassLoader loader2 = type2.getClassLoader();
+		ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader();
+		if (loader1 == null) {
+			return (loader2 == null || loader2 == systemClassLoader);
+		}
+		if (loader2 == null) return loader1 == systemClassLoader;
+		return loader1 == loader2;
+	}
+
+	static private ClassLoader getParentClassLoader (Class type) {
+		ClassLoader parent = type.getClassLoader();
+		if (parent == null) parent = ClassLoader.getSystemClassLoader();
+		return parent;
+	}
+
+	static private Method getDefineClassMethod () throws Exception {
+		// DCL on volatile
+		if (defineClassMethod == null) {
+			synchronized (accessClassLoaders) {
+				defineClassMethod = ClassLoader.class.getDeclaredMethod("defineClass",
+					new Class[] {String.class, byte[].class, int.class, int.class, ProtectionDomain.class});
+				try {
+					defineClassMethod.setAccessible(true);
+				} catch (Exception ignored) {
+				}
+			}
+		}
+		return defineClassMethod;
+	}
+
+	static AccessClassLoader get (Class type) {
+		ClassLoader parent = getParentClassLoader(type);
+		// 1. fast-path:
+		if (selfContextParentClassLoader.equals(parent)) {
+			if (selfContextAccessClassLoader == null) {
+				synchronized (accessClassLoaders) { // DCL with volatile semantics
+					if (selfContextAccessClassLoader == null)
+						selfContextAccessClassLoader = new AccessClassLoader(selfContextParentClassLoader);
+				}
+			}
+			return selfContextAccessClassLoader;
+		}
+		// 2. normal search:
+		synchronized (accessClassLoaders) {
+			WeakReference<AccessClassLoader> ref = accessClassLoaders.get(parent);
+			if (ref != null) {
+				AccessClassLoader accessClassLoader = ref.get();
+				if (accessClassLoader != null)
+					return accessClassLoader;
+				else
+					accessClassLoaders.remove(parent); // the value has been GC-reclaimed, but still not the key (defensive sanity)
+			}
+			AccessClassLoader accessClassLoader = new AccessClassLoader(parent);
+			accessClassLoaders.put(parent, new WeakReference<AccessClassLoader>(accessClassLoader));
+			return accessClassLoader;
+		}
+	}
+
+	static public void remove (ClassLoader parent) {
+		// 1. fast-path:
+		if (selfContextParentClassLoader.equals(parent)) {
+			selfContextAccessClassLoader = null;
+		} else {
+			// 2. normal search:
+			synchronized (accessClassLoaders) {
+				accessClassLoaders.remove(parent);
+			}
+		}
+	}
+
+	static public int activeAccessClassLoaders () {
+		int sz = accessClassLoaders.size();
+		if (selfContextAccessClassLoader != null) sz++;
+		return sz;
+	}
+}


=====================================
src/com/esotericsoftware/reflectasm/ConstructorAccess.java
=====================================
@@ -0,0 +1,168 @@
+/**
+ * Copyright (c) 2008, Nathan Sweet
+ *  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of Esoteric Software nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+package com.esotericsoftware.reflectasm;
+
+import static org.objectweb.asm.Opcodes.*;
+
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Modifier;
+
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.MethodVisitor;
+
+abstract public class ConstructorAccess<T> {
+	boolean isNonStaticMemberClass;
+
+	public boolean isNonStaticMemberClass () {
+		return isNonStaticMemberClass;
+	}
+
+	/** Constructor for top-level classes and static nested classes.
+	 * <p>
+	 * If the underlying class is a inner (non-static nested) class, a new instance will be created using <code>null</code> as the
+	 * this$0 synthetic reference. The instantiated object will work as long as it actually don't use any member variable or method
+	 * fron the enclosing instance. */
+	abstract public T newInstance ();
+
+	/** Constructor for inner classes (non-static nested classes).
+	 * @param enclosingInstance The instance of the enclosing type to which this inner instance is related to (assigned to its
+	 *           synthetic this$0 field). */
+	abstract public T newInstance (Object enclosingInstance);
+
+	static public <T> ConstructorAccess<T> get (Class<T> type) {
+		Class enclosingType = type.getEnclosingClass();
+		boolean isNonStaticMemberClass = enclosingType != null && type.isMemberClass() && !Modifier.isStatic(type.getModifiers());
+
+		String className = type.getName();
+		String accessClassName = className + "ConstructorAccess";
+		if (accessClassName.startsWith("java.")) accessClassName = "reflectasm." + accessClassName;
+
+		AccessClassLoader loader = AccessClassLoader.get(type);
+		Class accessClass = loader.loadAccessClass(accessClassName);
+		if (accessClass == null) {
+			synchronized (loader) {
+				accessClass = loader.loadAccessClass(accessClassName);
+				if (accessClass == null) {
+					String accessClassNameInternal = accessClassName.replace('.', '/');
+					String classNameInternal = className.replace('.', '/');
+					String enclosingClassNameInternal;
+					Constructor<T> constructor = null;
+					int modifiers = 0;
+					if (!isNonStaticMemberClass) {
+						enclosingClassNameInternal = null;
+						try {
+							constructor = type.getDeclaredConstructor((Class[])null);
+							modifiers = constructor.getModifiers();
+						} catch (Exception ex) {
+							throw new RuntimeException("Class cannot be created (missing no-arg constructor): " + type.getName(), ex);
+						}
+						if (Modifier.isPrivate(modifiers)) {
+							throw new RuntimeException("Class cannot be created (the no-arg constructor is private): " + type.getName());
+						}
+					} else {
+						enclosingClassNameInternal = enclosingType.getName().replace('.', '/');
+						try {
+							constructor = type.getDeclaredConstructor(enclosingType); // Inner classes should have this.
+							modifiers = constructor.getModifiers();
+						} catch (Exception ex) {
+							throw new RuntimeException(
+								"Non-static member class cannot be created (missing enclosing class constructor): " + type.getName(), ex);
+						}
+						if (Modifier.isPrivate(modifiers)) {
+							throw new RuntimeException(
+								"Non-static member class cannot be created (the enclosing class constructor is private): "
+									+ type.getName());
+						}
+					}
+					String superclassNameInternal = Modifier.isPublic(modifiers)
+						? "com/esotericsoftware/reflectasm/PublicConstructorAccess"
+						: "com/esotericsoftware/reflectasm/ConstructorAccess";
+
+					ClassWriter cw = new ClassWriter(0);
+					cw.visit(V1_1, ACC_PUBLIC + ACC_SUPER, accessClassNameInternal, null, superclassNameInternal, null);
+
+					insertConstructor(cw, superclassNameInternal);
+					insertNewInstance(cw, classNameInternal);
+					insertNewInstanceInner(cw, classNameInternal, enclosingClassNameInternal);
+
+					cw.visitEnd();
+					accessClass = loader.defineAccessClass(accessClassName, cw.toByteArray());
+				}
+			}
+		}
+		ConstructorAccess<T> access;
+		try {
+			access = (ConstructorAccess<T>)accessClass.newInstance();
+		} catch (Throwable t) {
+			throw new RuntimeException("Exception constructing constructor access class: " + accessClassName, t);
+		}
+		if (!(access instanceof PublicConstructorAccess) && !AccessClassLoader.areInSameRuntimeClassLoader(type, accessClass)) {
+			// Must test this after the try-catch block, whether the class has been loaded as if has been defined.
+			// Throw a Runtime exception here instead of an IllegalAccessError when invoking newInstance()
+			throw new RuntimeException((!isNonStaticMemberClass
+				? "Class cannot be created (the no-arg constructor is protected or package-protected, and its ConstructorAccess could not be defined in the same class loader): "
+				: "Non-static member class cannot be created (the enclosing class constructor is protected or package-protected, and its ConstructorAccess could not be defined in the same class loader): ")
+				+ type.getName());
+		}
+		access.isNonStaticMemberClass = isNonStaticMemberClass;
+		return access;
+	}
+
+	static private void insertConstructor (ClassWriter cw, String superclassNameInternal) {
+		MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
+		mv.visitCode();
+		mv.visitVarInsn(ALOAD, 0);
+		mv.visitMethodInsn(INVOKESPECIAL, superclassNameInternal, "<init>", "()V");
+		mv.visitInsn(RETURN);
+		mv.visitMaxs(1, 1);
+		mv.visitEnd();
+	}
+
+	static void insertNewInstance (ClassWriter cw, String classNameInternal) {
+		MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "newInstance", "()Ljava/lang/Object;", null, null);
+		mv.visitCode();
+		mv.visitTypeInsn(NEW, classNameInternal);
+		mv.visitInsn(DUP);
+		mv.visitMethodInsn(INVOKESPECIAL, classNameInternal, "<init>", "()V");
+		mv.visitInsn(ARETURN);
+		mv.visitMaxs(2, 1);
+		mv.visitEnd();
+	}
+
+	static void insertNewInstanceInner (ClassWriter cw, String classNameInternal, String enclosingClassNameInternal) {
+		MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "newInstance", "(Ljava/lang/Object;)Ljava/lang/Object;", null, null);
+		mv.visitCode();
+		if (enclosingClassNameInternal != null) {
+			mv.visitTypeInsn(NEW, classNameInternal);
+			mv.visitInsn(DUP);
+			mv.visitVarInsn(ALOAD, 1);
+			mv.visitTypeInsn(CHECKCAST, enclosingClassNameInternal);
+			mv.visitInsn(DUP);
+			mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Object", "getClass", "()Ljava/lang/Class;");
+			mv.visitInsn(POP);
+			mv.visitMethodInsn(INVOKESPECIAL, classNameInternal, "<init>", "(L" + enclosingClassNameInternal + ";)V");
+			mv.visitInsn(ARETURN);
+			mv.visitMaxs(4, 2);
+		} else {
+			mv.visitTypeInsn(NEW, "java/lang/UnsupportedOperationException");
+			mv.visitInsn(DUP);
+			mv.visitLdcInsn("Not an inner class.");
+			mv.visitMethodInsn(INVOKESPECIAL, "java/lang/UnsupportedOperationException", "<init>", "(Ljava/lang/String;)V");
+			mv.visitInsn(ATHROW);
+			mv.visitMaxs(3, 2);
+		}
+		mv.visitEnd();
+	}
+}


=====================================
java/src/com/esotericsoftware/reflectasm/FieldAccess.java → src/com/esotericsoftware/reflectasm/FieldAccess.java
=====================================
@@ -1,6 +1,21 @@
+/**
+ * Copyright (c) 2008, Nathan Sweet
+ *  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of Esoteric Software nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
 
 package com.esotericsoftware.reflectasm;
 
+import static org.objectweb.asm.Opcodes.*;
+
 import java.lang.reflect.Field;
 import java.lang.reflect.Modifier;
 import java.util.ArrayList;
@@ -10,15 +25,21 @@ import org.objectweb.asm.Label;
 import org.objectweb.asm.MethodVisitor;
 import org.objectweb.asm.Type;
 
-import static org.objectweb.asm.Opcodes.*;
-
 public abstract class FieldAccess {
 	private String[] fieldNames;
+	private Class[] fieldTypes;
+	private Field[] fields;
 
 	public int getIndex (String fieldName) {
 		for (int i = 0, n = fieldNames.length; i < n; i++)
 			if (fieldNames[i].equals(fieldName)) return i;
-		throw new IllegalArgumentException("Unable to find public field: " + fieldName);
+		throw new IllegalArgumentException("Unable to find non-private field: " + fieldName);
+	}
+
+	public int getIndex (Field field) {
+		for (int i = 0, n = fields.length; i < n; i++)
+			if (fields[i].equals(field)) return i;
+		throw new IllegalArgumentException("Unable to find non-private field: " + field);
 	}
 
 	public void set (Object instance, String fieldName, Object value) {
@@ -33,6 +54,22 @@ public abstract class FieldAccess {
 		return fieldNames;
 	}
 
+	public Class[] getFieldTypes () {
+		return fieldTypes;
+	}
+
+	public int getFieldCount () {
+		return fieldTypes.length;
+	}
+
+	public Field[] getFields () {
+		return fields;
+	}
+
+	public void setFields (Field[] fields) {
+		this.fields = fields;
+	}
+
 	abstract public void set (Object instance, int fieldIndex, Object value);
 
 	abstract public void setBoolean (Object instance, int fieldIndex, boolean value);
@@ -71,8 +108,10 @@ public abstract class FieldAccess {
 
 	abstract public float getFloat (Object instance, int fieldIndex);
 
+	/** @param type Must not be the Object class, an interface, a primitive type, or void. */
 	static public FieldAccess get (Class type) {
-		AccessClassLoader loader = AccessClassLoader.get(type);
+		if (type.getSuperclass() == null)
+			throw new IllegalArgumentException("The type must not be the Object class, an interface, a primitive type, or void.");
 
 		ArrayList<Field> fields = new ArrayList<Field>();
 		Class nextClass = type;
@@ -89,55 +128,61 @@ public abstract class FieldAccess {
 		}
 
 		String[] fieldNames = new String[fields.size()];
-		for (int i = 0, n = fieldNames.length; i < n; i++)
+		Class[] fieldTypes = new Class[fields.size()];
+		for (int i = 0, n = fieldNames.length; i < n; i++) {
 			fieldNames[i] = fields.get(i).getName();
+			fieldTypes[i] = fields.get(i).getType();
+		}
 
 		String className = type.getName();
 		String accessClassName = className + "FieldAccess";
 		if (accessClassName.startsWith("java.")) accessClassName = "reflectasm." + accessClassName;
-		Class accessClass = null;
-		try {
-			accessClass = loader.loadClass(accessClassName);
-		} catch (ClassNotFoundException ignored) {
-		}
+
+		AccessClassLoader loader = AccessClassLoader.get(type);
+		Class accessClass = loader.loadAccessClass(accessClassName);
 		if (accessClass == null) {
-			String accessClassNameInternal = accessClassName.replace('.', '/');
-			String classNameInternal = className.replace('.', '/');
-
-			ClassWriter cw = new ClassWriter(0);
-			cw.visit(V1_1, ACC_PUBLIC + ACC_SUPER, accessClassNameInternal, null, "com/esotericsoftware/reflectasm/FieldAccess",
-				null);
-
-			insertConstructor(cw);
-			insertGetObject(cw, classNameInternal, fields);
-			insertSetObject(cw, classNameInternal, fields);
-			insertGetPrimitive(cw, classNameInternal, fields, Type.BOOLEAN_TYPE);
-			insertSetPrimitive(cw, classNameInternal, fields, Type.BOOLEAN_TYPE);
-			insertGetPrimitive(cw, classNameInternal, fields, Type.BYTE_TYPE);
-			insertSetPrimitive(cw, classNameInternal, fields, Type.BYTE_TYPE);
-			insertGetPrimitive(cw, classNameInternal, fields, Type.SHORT_TYPE);
-			insertSetPrimitive(cw, classNameInternal, fields, Type.SHORT_TYPE);
-			insertGetPrimitive(cw, classNameInternal, fields, Type.INT_TYPE);
-			insertSetPrimitive(cw, classNameInternal, fields, Type.INT_TYPE);
-			insertGetPrimitive(cw, classNameInternal, fields, Type.LONG_TYPE);
-			insertSetPrimitive(cw, classNameInternal, fields, Type.LONG_TYPE);
-			insertGetPrimitive(cw, classNameInternal, fields, Type.DOUBLE_TYPE);
-			insertSetPrimitive(cw, classNameInternal, fields, Type.DOUBLE_TYPE);
-			insertGetPrimitive(cw, classNameInternal, fields, Type.FLOAT_TYPE);
-			insertSetPrimitive(cw, classNameInternal, fields, Type.FLOAT_TYPE);
-			insertGetPrimitive(cw, classNameInternal, fields, Type.CHAR_TYPE);
-			insertSetPrimitive(cw, classNameInternal, fields, Type.CHAR_TYPE);
-			insertGetString(cw, classNameInternal, fields);
-
-			cw.visitEnd();
-			accessClass = loader.defineClass(accessClassName, cw.toByteArray());
+			synchronized (loader) {
+				accessClass = loader.loadAccessClass(accessClassName);
+				if (accessClass == null) {
+					String accessClassNameInternal = accessClassName.replace('.', '/');
+					String classNameInternal = className.replace('.', '/');
+
+					ClassWriter cw = new ClassWriter(0);
+					cw.visit(V1_1, ACC_PUBLIC + ACC_SUPER, accessClassNameInternal, null,
+						"com/esotericsoftware/reflectasm/FieldAccess", null);
+					insertConstructor(cw);
+					insertGetObject(cw, classNameInternal, fields);
+					insertSetObject(cw, classNameInternal, fields);
+					insertGetPrimitive(cw, classNameInternal, fields, Type.BOOLEAN_TYPE);
+					insertSetPrimitive(cw, classNameInternal, fields, Type.BOOLEAN_TYPE);
+					insertGetPrimitive(cw, classNameInternal, fields, Type.BYTE_TYPE);
+					insertSetPrimitive(cw, classNameInternal, fields, Type.BYTE_TYPE);
+					insertGetPrimitive(cw, classNameInternal, fields, Type.SHORT_TYPE);
+					insertSetPrimitive(cw, classNameInternal, fields, Type.SHORT_TYPE);
+					insertGetPrimitive(cw, classNameInternal, fields, Type.INT_TYPE);
+					insertSetPrimitive(cw, classNameInternal, fields, Type.INT_TYPE);
+					insertGetPrimitive(cw, classNameInternal, fields, Type.LONG_TYPE);
+					insertSetPrimitive(cw, classNameInternal, fields, Type.LONG_TYPE);
+					insertGetPrimitive(cw, classNameInternal, fields, Type.DOUBLE_TYPE);
+					insertSetPrimitive(cw, classNameInternal, fields, Type.DOUBLE_TYPE);
+					insertGetPrimitive(cw, classNameInternal, fields, Type.FLOAT_TYPE);
+					insertSetPrimitive(cw, classNameInternal, fields, Type.FLOAT_TYPE);
+					insertGetPrimitive(cw, classNameInternal, fields, Type.CHAR_TYPE);
+					insertSetPrimitive(cw, classNameInternal, fields, Type.CHAR_TYPE);
+					insertGetString(cw, classNameInternal, fields);
+					cw.visitEnd();
+					accessClass = loader.defineAccessClass(accessClassName, cw.toByteArray());
+				}
+			}
 		}
 		try {
 			FieldAccess access = (FieldAccess)accessClass.newInstance();
 			access.fieldNames = fieldNames;
+			access.fieldTypes = fieldTypes;
+			access.fields = fields.toArray(new Field[fields.size()]);
 			return access;
-		} catch (Exception ex) {
-			throw new RuntimeException("Error constructing field access class: " + accessClassName, ex);
+		} catch (Throwable t) {
+			throw new RuntimeException("Error constructing field access class: " + accessClassName, t);
 		}
 	}
 
@@ -216,7 +261,8 @@ public abstract class FieldAccess {
 					break;
 				}
 
-				mv.visitFieldInsn(PUTFIELD, classNameInternal, field.getName(), fieldType.getDescriptor());
+				mv.visitFieldInsn(PUTFIELD, field.getDeclaringClass().getName().replace('.', '/'), field.getName(),
+					fieldType.getDescriptor());
 				mv.visitInsn(RETURN);
 			}
 
@@ -249,7 +295,8 @@ public abstract class FieldAccess {
 				mv.visitFrame(F_SAME, 0, null, 0, null);
 				mv.visitVarInsn(ALOAD, 1);
 				mv.visitTypeInsn(CHECKCAST, classNameInternal);
-				mv.visitFieldInsn(GETFIELD, classNameInternal, field.getName(), Type.getDescriptor(field.getType()));
+				mv.visitFieldInsn(GETFIELD, field.getDeclaringClass().getName().replace('.', '/'), field.getName(),
+					Type.getDescriptor(field.getType()));
 
 				Type fieldType = Type.getType(field.getType());
 				switch (fieldType.getSort()) {
@@ -314,11 +361,13 @@ public abstract class FieldAccess {
 
 			for (int i = 0, n = labels.length; i < n; i++) {
 				if (!labels[i].equals(labelForInvalidTypes)) {
+					Field field = fields.get(i);
 					mv.visitLabel(labels[i]);
 					mv.visitFrame(F_SAME, 0, null, 0, null);
 					mv.visitVarInsn(ALOAD, 1);
 					mv.visitTypeInsn(CHECKCAST, classNameInternal);
-					mv.visitFieldInsn(GETFIELD, classNameInternal, fields.get(i).getName(), "Ljava/lang/String;");
+					mv.visitFieldInsn(GETFIELD, field.getDeclaringClass().getName().replace('.', '/'), field.getName(),
+						"Ljava/lang/String;");
 					mv.visitInsn(ARETURN);
 				}
 			}
@@ -337,7 +386,8 @@ public abstract class FieldAccess {
 		mv.visitEnd();
 	}
 
-	static private void insertSetPrimitive (ClassWriter cw, String classNameInternal, ArrayList<Field> fields, Type primitiveType) {
+	static private void insertSetPrimitive (ClassWriter cw, String classNameInternal, ArrayList<Field> fields,
+		Type primitiveType) {
 		int maxStack = 6;
 		int maxLocals = 4; // See correction below for LLOAD and DLOAD
 		final String setterMethodName;
@@ -375,8 +425,8 @@ public abstract class FieldAccess {
 			break;
 		case Type.DOUBLE:
 			setterMethodName = "setDouble";
-			loadValueInstruction = DLOAD; // (LLOAD and DLOAD actually load two slots)
-			maxLocals++;
+			loadValueInstruction = DLOAD;
+			maxLocals++; // (LLOAD and DLOAD actually load two slots)
 			break;
 		default:
 			setterMethodName = "set";
@@ -406,12 +456,14 @@ public abstract class FieldAccess {
 
 			for (int i = 0, n = labels.length; i < n; i++) {
 				if (!labels[i].equals(labelForInvalidTypes)) {
+					Field field = fields.get(i);
 					mv.visitLabel(labels[i]);
 					mv.visitFrame(F_SAME, 0, null, 0, null);
 					mv.visitVarInsn(ALOAD, 1);
 					mv.visitTypeInsn(CHECKCAST, classNameInternal);
 					mv.visitVarInsn(loadValueInstruction, 3);
-					mv.visitFieldInsn(PUTFIELD, classNameInternal, fields.get(i).getName(), typeNameInternal);
+					mv.visitFieldInsn(PUTFIELD, field.getDeclaringClass().getName().replace('.', '/'), field.getName(),
+						typeNameInternal);
 					mv.visitInsn(RETURN);
 				}
 			}
@@ -430,7 +482,8 @@ public abstract class FieldAccess {
 		mv.visitEnd();
 	}
 
-	static private void insertGetPrimitive (ClassWriter cw, String classNameInternal, ArrayList<Field> fields, Type primitiveType) {
+	static private void insertGetPrimitive (ClassWriter cw, String classNameInternal, ArrayList<Field> fields,
+		Type primitiveType) {
 		int maxStack = 6;
 		final String getterMethodName;
 		final String typeNameInternal = primitiveType.getDescriptor();
@@ -500,7 +553,8 @@ public abstract class FieldAccess {
 					mv.visitFrame(F_SAME, 0, null, 0, null);
 					mv.visitVarInsn(ALOAD, 1);
 					mv.visitTypeInsn(CHECKCAST, classNameInternal);
-					mv.visitFieldInsn(GETFIELD, classNameInternal, field.getName(), typeNameInternal);
+					mv.visitFieldInsn(GETFIELD, field.getDeclaringClass().getName().replace('.', '/'), field.getName(),
+						typeNameInternal);
 					mv.visitInsn(returnValueInstruction);
 				}
 			}
@@ -539,7 +593,7 @@ public abstract class FieldAccess {
 		mv.visitInsn(DUP);
 		mv.visitTypeInsn(NEW, "java/lang/StringBuilder");
 		mv.visitInsn(DUP);
-		mv.visitLdcInsn("The field is not declared as " + fieldType + ": ");
+		mv.visitLdcInsn("Field not declared as " + fieldType + ": ");
 		mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "(Ljava/lang/String;)V");
 		mv.visitVarInsn(ILOAD, 2);
 		mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(I)Ljava/lang/StringBuilder;");


=====================================
src/com/esotericsoftware/reflectasm/MethodAccess.java
=====================================
@@ -0,0 +1,308 @@
+/**
+ * Copyright (c) 2008, Nathan Sweet
+ *  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of Esoteric Software nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+package com.esotericsoftware.reflectasm;
+
+import static org.objectweb.asm.Opcodes.*;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Arrays;
+
+import org.objectweb.asm.ClassWriter;
+import org.objectweb.asm.Label;
+import org.objectweb.asm.MethodVisitor;
+import org.objectweb.asm.Opcodes;
+import org.objectweb.asm.Type;
+
+public abstract class MethodAccess {
+	private String[] methodNames;
+	private Class[][] parameterTypes;
+	private Class[] returnTypes;
+
+	abstract public Object invoke (Object object, int methodIndex, Object... args);
+
+	/** Invokes the method with the specified name and the specified param types. */
+	public Object invoke (Object object, String methodName, Class[] paramTypes, Object... args) {
+		return invoke(object, getIndex(methodName, paramTypes), args);
+	}
+
+	/** Invokes the first method with the specified name and the specified number of arguments. */
+	public Object invoke (Object object, String methodName, Object... args) {
+		return invoke(object, getIndex(methodName, args == null ? 0 : args.length), args);
+	}
+
+	/** Returns the index of the first method with the specified name. */
+	public int getIndex (String methodName) {
+		for (int i = 0, n = methodNames.length; i < n; i++)
+			if (methodNames[i].equals(methodName)) return i;
+		throw new IllegalArgumentException("Unable to find non-private method: " + methodName);
+	}
+
+	/** Returns the index of the first method with the specified name and param types. */
+	public int getIndex (String methodName, Class... paramTypes) {
+		for (int i = 0, n = methodNames.length; i < n; i++)
+			if (methodNames[i].equals(methodName) && Arrays.equals(paramTypes, parameterTypes[i])) return i;
+		throw new IllegalArgumentException("Unable to find non-private method: " + methodName + " " + Arrays.toString(paramTypes));
+	}
+
+	/** Returns the index of the first method with the specified name and the specified number of arguments. */
+	public int getIndex (String methodName, int paramsCount) {
+		for (int i = 0, n = methodNames.length; i < n; i++)
+			if (methodNames[i].equals(methodName) && parameterTypes[i].length == paramsCount) return i;
+		throw new IllegalArgumentException(
+			"Unable to find non-private method: " + methodName + " with " + paramsCount + " params.");
+	}
+
+	public String[] getMethodNames () {
+		return methodNames;
+	}
+
+	public Class[][] getParameterTypes () {
+		return parameterTypes;
+	}
+
+	public Class[] getReturnTypes () {
+		return returnTypes;
+	}
+
+	/** Creates a new MethodAccess for the specified type.
+	 * @param type Must not be the Object class, a primitive type, or void. */
+	static public MethodAccess get (Class type) {
+		boolean isInterface = type.isInterface();
+		if (!isInterface && type.getSuperclass() == null)
+			throw new IllegalArgumentException("The type must not be the Object class, an interface, a primitive type, or void.");
+
+		ArrayList<Method> methods = new ArrayList<Method>();
+		if (!isInterface) {
+			Class nextClass = type;
+			while (nextClass != Object.class) {
+				addDeclaredMethodsToList(nextClass, methods);
+				nextClass = nextClass.getSuperclass();
+			}
+		} else
+			recursiveAddInterfaceMethodsToList(type, methods);
+
+		int n = methods.size();
+		String[] methodNames = new String[n];
+		Class[][] parameterTypes = new Class[n][];
+		Class[] returnTypes = new Class[n];
+		for (int i = 0; i < n; i++) {
+			Method method = methods.get(i);
+			methodNames[i] = method.getName();
+			parameterTypes[i] = method.getParameterTypes();
+			returnTypes[i] = method.getReturnType();
+		}
+
+		String className = type.getName();
+		String accessClassName = className + "MethodAccess";
+		if (accessClassName.startsWith("java.")) accessClassName = "reflectasm." + accessClassName;
+
+		AccessClassLoader loader = AccessClassLoader.get(type);
+		Class accessClass = loader.loadAccessClass(accessClassName);
+		if (accessClass == null) {
+			synchronized (loader) {
+				accessClass = loader.loadAccessClass(accessClassName);
+				if (accessClass == null) {
+					String accessClassNameInternal = accessClassName.replace('.', '/');
+					String classNameInternal = className.replace('.', '/');
+
+					ClassWriter cw = new ClassWriter(ClassWriter.COMPUTE_MAXS);
+					MethodVisitor mv;
+					cw.visit(V1_1, ACC_PUBLIC + ACC_SUPER, accessClassNameInternal, null,
+						"com/esotericsoftware/reflectasm/MethodAccess", null);
+					{
+						mv = cw.visitMethod(ACC_PUBLIC, "<init>", "()V", null, null);
+						mv.visitCode();
+						mv.visitVarInsn(ALOAD, 0);
+						mv.visitMethodInsn(INVOKESPECIAL, "com/esotericsoftware/reflectasm/MethodAccess", "<init>", "()V");
+						mv.visitInsn(RETURN);
+						mv.visitMaxs(0, 0);
+						mv.visitEnd();
+					}
+					{
+						mv = cw.visitMethod(ACC_PUBLIC + ACC_VARARGS, "invoke",
+							"(Ljava/lang/Object;I[Ljava/lang/Object;)Ljava/lang/Object;", null, null);
+						mv.visitCode();
+
+						if (!methods.isEmpty()) {
+							mv.visitVarInsn(ALOAD, 1);
+							mv.visitTypeInsn(CHECKCAST, classNameInternal);
+							mv.visitVarInsn(ASTORE, 4);
+
+							mv.visitVarInsn(ILOAD, 2);
+							Label[] labels = new Label[n];
+							for (int i = 0; i < n; i++)
+								labels[i] = new Label();
+							Label defaultLabel = new Label();
+							mv.visitTableSwitchInsn(0, labels.length - 1, defaultLabel, labels);
+
+							StringBuilder buffer = new StringBuilder(128);
+							for (int i = 0; i < n; i++) {
+								mv.visitLabel(labels[i]);
+								if (i == 0)
+									mv.visitFrame(Opcodes.F_APPEND, 1, new Object[] {classNameInternal}, 0, null);
+								else
+									mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
+								mv.visitVarInsn(ALOAD, 4);
+
+								buffer.setLength(0);
+								buffer.append('(');
+
+								Class[] paramTypes = parameterTypes[i];
+								Class returnType = returnTypes[i];
+								for (int paramIndex = 0; paramIndex < paramTypes.length; paramIndex++) {
+									mv.visitVarInsn(ALOAD, 3);
+									mv.visitIntInsn(BIPUSH, paramIndex);
+									mv.visitInsn(AALOAD);
+									Type paramType = Type.getType(paramTypes[paramIndex]);
+									switch (paramType.getSort()) {
+									case Type.BOOLEAN:
+										mv.visitTypeInsn(CHECKCAST, "java/lang/Boolean");
+										mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Boolean", "booleanValue", "()Z");
+										break;
+									case Type.BYTE:
+										mv.visitTypeInsn(CHECKCAST, "java/lang/Byte");
+										mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Byte", "byteValue", "()B");
+										break;
+									case Type.CHAR:
+										mv.visitTypeInsn(CHECKCAST, "java/lang/Character");
+										mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Character", "charValue", "()C");
+										break;
+									case Type.SHORT:
+										mv.visitTypeInsn(CHECKCAST, "java/lang/Short");
+										mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Short", "shortValue", "()S");
+										break;
+									case Type.INT:
+										mv.visitTypeInsn(CHECKCAST, "java/lang/Integer");
+										mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Integer", "intValue", "()I");
+										break;
+									case Type.FLOAT:
+										mv.visitTypeInsn(CHECKCAST, "java/lang/Float");
+										mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Float", "floatValue", "()F");
+										break;
+									case Type.LONG:
+										mv.visitTypeInsn(CHECKCAST, "java/lang/Long");
+										mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Long", "longValue", "()J");
+										break;
+									case Type.DOUBLE:
+										mv.visitTypeInsn(CHECKCAST, "java/lang/Double");
+										mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/Double", "doubleValue", "()D");
+										break;
+									case Type.ARRAY:
+										mv.visitTypeInsn(CHECKCAST, paramType.getDescriptor());
+										break;
+									case Type.OBJECT:
+										mv.visitTypeInsn(CHECKCAST, paramType.getInternalName());
+										break;
+									}
+									buffer.append(paramType.getDescriptor());
+								}
+
+								buffer.append(')');
+								buffer.append(Type.getDescriptor(returnType));
+								int invoke;
+								if (isInterface)
+									invoke = INVOKEINTERFACE;
+								else if (Modifier.isStatic(methods.get(i).getModifiers()))
+									invoke = INVOKESTATIC;
+								else
+									invoke = INVOKEVIRTUAL;
+								mv.visitMethodInsn(invoke, classNameInternal, methodNames[i], buffer.toString());
+
+								switch (Type.getType(returnType).getSort()) {
+								case Type.VOID:
+									mv.visitInsn(ACONST_NULL);
+									break;
+								case Type.BOOLEAN:
+									mv.visitMethodInsn(INVOKESTATIC, "java/lang/Boolean", "valueOf", "(Z)Ljava/lang/Boolean;");
+									break;
+								case Type.BYTE:
+									mv.visitMethodInsn(INVOKESTATIC, "java/lang/Byte", "valueOf", "(B)Ljava/lang/Byte;");
+									break;
+								case Type.CHAR:
+									mv.visitMethodInsn(INVOKESTATIC, "java/lang/Character", "valueOf", "(C)Ljava/lang/Character;");
+									break;
+								case Type.SHORT:
+									mv.visitMethodInsn(INVOKESTATIC, "java/lang/Short", "valueOf", "(S)Ljava/lang/Short;");
+									break;
+								case Type.INT:
+									mv.visitMethodInsn(INVOKESTATIC, "java/lang/Integer", "valueOf", "(I)Ljava/lang/Integer;");
+									break;
+								case Type.FLOAT:
+									mv.visitMethodInsn(INVOKESTATIC, "java/lang/Float", "valueOf", "(F)Ljava/lang/Float;");
+									break;
+								case Type.LONG:
+									mv.visitMethodInsn(INVOKESTATIC, "java/lang/Long", "valueOf", "(J)Ljava/lang/Long;");
+									break;
+								case Type.DOUBLE:
+									mv.visitMethodInsn(INVOKESTATIC, "java/lang/Double", "valueOf", "(D)Ljava/lang/Double;");
+									break;
+								}
+
+								mv.visitInsn(ARETURN);
+							}
+
+							mv.visitLabel(defaultLabel);
+							mv.visitFrame(Opcodes.F_SAME, 0, null, 0, null);
+						}
+						mv.visitTypeInsn(NEW, "java/lang/IllegalArgumentException");
+						mv.visitInsn(DUP);
+						mv.visitTypeInsn(NEW, "java/lang/StringBuilder");
+						mv.visitInsn(DUP);
+						mv.visitLdcInsn("Method not found: ");
+						mv.visitMethodInsn(INVOKESPECIAL, "java/lang/StringBuilder", "<init>", "(Ljava/lang/String;)V");
+						mv.visitVarInsn(ILOAD, 2);
+						mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "append", "(I)Ljava/lang/StringBuilder;");
+						mv.visitMethodInsn(INVOKEVIRTUAL, "java/lang/StringBuilder", "toString", "()Ljava/lang/String;");
+						mv.visitMethodInsn(INVOKESPECIAL, "java/lang/IllegalArgumentException", "<init>", "(Ljava/lang/String;)V");
+						mv.visitInsn(ATHROW);
+						mv.visitMaxs(0, 0);
+						mv.visitEnd();
+					}
+					cw.visitEnd();
+					byte[] data = cw.toByteArray();
+					accessClass = loader.defineAccessClass(accessClassName, data);
+				}
+			}
+		}
+		try {
+			MethodAccess access = (MethodAccess)accessClass.newInstance();
+			access.methodNames = methodNames;
+			access.parameterTypes = parameterTypes;
+			access.returnTypes = returnTypes;
+			return access;
+		} catch (Throwable t) {
+			throw new RuntimeException("Error constructing method access class: " + accessClassName, t);
+		}
+	}
+
+	static private void addDeclaredMethodsToList (Class type, ArrayList<Method> methods) {
+		Method[] declaredMethods = type.getDeclaredMethods();
+		for (int i = 0, n = declaredMethods.length; i < n; i++) {
+			Method method = declaredMethods[i];
+			int modifiers = method.getModifiers();
+			// if (Modifier.isStatic(modifiers)) continue;
+			if (Modifier.isPrivate(modifiers)) continue;
+			methods.add(method);
+		}
+	}
+
+	static private void recursiveAddInterfaceMethodsToList (Class interfaceType, ArrayList<Method> methods) {
+		addDeclaredMethodsToList(interfaceType, methods);
+		for (Class nextInterface : interfaceType.getInterfaces())
+			recursiveAddInterfaceMethodsToList(nextInterface, methods);
+	}
+}


=====================================
src/com/esotericsoftware/reflectasm/PublicConstructorAccess.java
=====================================
@@ -0,0 +1,19 @@
+/**
+ * Copyright (c) 2008, Nathan Sweet
+ *  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of Esoteric Software nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+package com.esotericsoftware.reflectasm;
+
+public abstract class PublicConstructorAccess extends ConstructorAccess {
+
+}
\ No newline at end of file


=====================================
test/com/esotericsoftware/reflectasm/ClassLoaderTest.java
=====================================
@@ -0,0 +1,165 @@
+/**
+ * Copyright (c) 2008, Nathan Sweet
+ *  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of Esoteric Software nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+package com.esotericsoftware.reflectasm;
+
+import java.io.ByteArrayOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertTrue;
+
+import junit.framework.TestCase;
+
+public class ClassLoaderTest extends TestCase {
+	public void testDifferentClassloaders () throws Exception {
+		// This classloader can see only the Test class and core Java classes.
+		ClassLoader testClassLoader = new TestClassLoader1();
+		Class testClass = testClassLoader.loadClass("com.esotericsoftware.reflectasm.ClassLoaderTest$Test");
+		Object testObject = testClass.newInstance();
+
+		// Ensure AccessClassLoader can access both the Test class and FieldAccess.
+		FieldAccess access = FieldAccess.get(testObject.getClass());
+		access.set(testObject, "name", "first");
+		assertEquals("first", testObject.toString());
+		assertEquals("first", access.get(testObject, "name"));
+	}
+	
+	public void testAutoUnloadClassloaders () throws Exception {
+		int initialCount = AccessClassLoader.activeAccessClassLoaders();
+
+		ClassLoader testClassLoader1 = new TestClassLoader1();
+		Class testClass1 = testClassLoader1.loadClass("com.esotericsoftware.reflectasm.ClassLoaderTest$Test");
+		Object testObject1 = testClass1.newInstance();
+		FieldAccess access1 = FieldAccess.get(testObject1.getClass());
+		access1.set(testObject1, "name", "first");
+		assertEquals("first", testObject1.toString());
+		assertEquals("first", access1.get(testObject1, "name"));
+
+		ClassLoader testClassLoader2 = new TestClassLoader2();
+		Class testClass2 = testClassLoader2.loadClass("com.esotericsoftware.reflectasm.ClassLoaderTest$Test");
+		Object testObject2 = testClass2.newInstance();
+		FieldAccess access2 = FieldAccess.get(testObject2.getClass());
+		access2.set(testObject2, "name", "second");
+		assertEquals("second", testObject2.toString());
+		assertEquals("second", access2.get(testObject2, "name"));
+		
+		assertEquals(access1.getClass().toString(), access2.getClass().toString()); // Same class names
+		assertFalse(access1.getClass().equals(access2.getClass())); // But different classes
+		
+		assertEquals(initialCount+2, AccessClassLoader.activeAccessClassLoaders());
+		
+		testClassLoader1 = null;
+		testClass1 = null;
+		testObject1 = null;
+		access1 = null;
+		testClassLoader2 = null;
+		testClass2 = null;
+		testObject2 = null;
+		access2 = null;
+		
+		// Force GC to reclaim unreachable (or only weak-reachable) objects
+		System.gc();
+		try {
+			Object[] array = new Object[(int) Runtime.getRuntime().maxMemory()];
+			System.out.println(array.length);
+		} catch (Throwable e) {
+			// Ignore OME
+		}
+		System.gc();
+		int times = 0;
+		while (AccessClassLoader.activeAccessClassLoaders()>1 && times < 50) { // max 5 seconds, should be instant
+			Thread.sleep(100); // test again
+			times++;
+		}
+
+		// Yeah, both reclaimed!
+		assertEquals(Math.min(initialCount, 1), AccessClassLoader.activeAccessClassLoaders());
+	}
+
+	public void testRemoveClassloaders () throws Exception {
+		int initialCount = AccessClassLoader.activeAccessClassLoaders();
+
+		ClassLoader testClassLoader1 = new TestClassLoader1();
+		Class testClass1 = testClassLoader1.loadClass("com.esotericsoftware.reflectasm.ClassLoaderTest$Test");
+		Object testObject1 = testClass1.newInstance();
+		FieldAccess access1 = FieldAccess.get(testObject1.getClass());
+		access1.set(testObject1, "name", "first");
+		assertEquals("first", testObject1.toString());
+		assertEquals("first", access1.get(testObject1, "name"));
+
+		ClassLoader testClassLoader2 = new TestClassLoader2();
+		Class testClass2 = testClassLoader2.loadClass("com.esotericsoftware.reflectasm.ClassLoaderTest$Test");
+		Object testObject2 = testClass2.newInstance();
+		FieldAccess access2 = FieldAccess.get(testObject2.getClass());
+		access2.set(testObject2, "name", "second");
+		assertEquals("second", testObject2.toString());
+		assertEquals("second", access2.get(testObject2, "name"));
+		
+		assertEquals(access1.getClass().toString(), access2.getClass().toString()); // Same class names
+		assertFalse(access1.getClass().equals(access2.getClass())); // But different classes
+		
+		assertEquals(initialCount+2, AccessClassLoader.activeAccessClassLoaders());
+		
+		AccessClassLoader.remove(testObject1.getClass().getClassLoader());
+		assertEquals(initialCount+1, AccessClassLoader.activeAccessClassLoaders());
+		AccessClassLoader.remove(testObject2.getClass().getClassLoader());
+		assertEquals(initialCount+0, AccessClassLoader.activeAccessClassLoaders());
+		AccessClassLoader.remove(this.getClass().getClassLoader());
+		assertEquals(initialCount-1, AccessClassLoader.activeAccessClassLoaders());
+	}
+
+	static public class Test {
+		public String name;
+
+		public String toString () {
+			return name;
+		}
+	}
+	
+	static public class TestClassLoader1 extends ClassLoader {
+		protected synchronized Class<?> loadClass (String name, boolean resolve) throws ClassNotFoundException {
+			Class c = findLoadedClass(name);
+			if (c != null) return c;
+			if (name.startsWith("java.")) return super.loadClass(name, resolve);
+			if (!name.equals("com.esotericsoftware.reflectasm.ClassLoaderTest$Test"))
+				throw new ClassNotFoundException("Class not found on purpose: " + name);
+			ByteArrayOutputStream output = new ByteArrayOutputStream(32 * 1024);
+			InputStream input = ClassLoaderTest.class.getResourceAsStream("/" + name.replace('.', '/') + ".class");
+			if (input == null) return null;
+			try {
+				byte[] buffer = new byte[4096];
+				int total = 0;
+				while (true) {
+					int length = input.read(buffer, 0, buffer.length);
+					if (length == -1) break;
+					output.write(buffer, 0, length);
+				}
+			} catch (IOException ex) {
+				throw new ClassNotFoundException("Error reading class file.", ex);
+			} finally {
+				try {
+					input.close();
+				} catch (IOException ignored) {
+				}
+			}
+			byte[] buffer = output.toByteArray();
+			return defineClass(name, buffer, 0, buffer.length);
+		}
+	}
+
+	static public class TestClassLoader2 extends TestClassLoader1 {
+	}
+}


=====================================
test/com/esotericsoftware/reflectasm/ConstructorAccessTest.java
=====================================
@@ -0,0 +1,203 @@
+/**
+ * Copyright (c) 2008, Nathan Sweet
+ *  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of Esoteric Software nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
+
+package com.esotericsoftware.reflectasm;
+
+import static junit.framework.Assert.assertEquals;
+import static junit.framework.Assert.assertTrue;
+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());
+	}
+
+	public void testPackagePrivateNewInstance () {
+		ConstructorAccess<PackagePrivateClass> access = ConstructorAccess.get(PackagePrivateClass.class);
+		PackagePrivateClass someObject = new PackagePrivateClass();
+		assertEquals(someObject, access.newInstance());
+		assertEquals(someObject, access.newInstance());
+		assertEquals(someObject, access.newInstance());
+	}
+
+	public void testHasArgumentConstructor () {
+		try {
+			ConstructorAccess.get(HasArgumentConstructor.class);
+			assertTrue(false);
+		}
+		catch (RuntimeException re) {
+			System.out.println("Expected exception happened: " + re);
+		}
+		catch (Throwable t) {
+			System.out.println("Unexpected exception happened: " + t);
+			assertTrue(false);
+		}
+	}
+
+	public void testHasPrivateConstructor () {
+		try {
+			ConstructorAccess.get(HasPrivateConstructor.class);
+			assertTrue(false);
+		}
+		catch (RuntimeException re) {
+			System.out.println("Expected exception happened: " + re);
+		}
+		catch (Throwable t) {
+			System.out.println("Unexpected exception happened: " + t);
+			assertTrue(false);
+		}
+	}
+
+	public void testHasProtectedConstructor () {
+		try {
+			ConstructorAccess<HasProtectedConstructor> access = ConstructorAccess.get(HasProtectedConstructor.class);
+			HasProtectedConstructor newInstance = access.newInstance();
+			assertEquals("cow", newInstance.getMoo());
+		}
+		catch (Throwable t) {
+			System.out.println("Unexpected exception happened: " + t);
+			assertTrue(false);
+		}
+	}
+
+	public void testHasPackageProtectedConstructor () {
+		try {
+			ConstructorAccess<HasPackageProtectedConstructor> access = ConstructorAccess.get(HasPackageProtectedConstructor.class);
+			HasPackageProtectedConstructor newInstance = access.newInstance();
+			assertEquals("cow", newInstance.getMoo());
+		}
+		catch (Throwable t) {
+			System.out.println("Unexpected exception happened: " + t);
+			assertTrue(false);
+		}
+	}
+
+	public void testHasPublicConstructor () {
+		try {
+			ConstructorAccess<HasPublicConstructor> access = ConstructorAccess.get(HasPublicConstructor.class);
+			HasPublicConstructor newInstance = access.newInstance();
+			assertEquals("cow", newInstance.getMoo());
+		}
+		catch (Throwable t) {
+			System.out.println("Unexpected exception happened: " + t);
+			assertTrue(false);
+		}
+	}
+
+	static class PackagePrivateClass {
+		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;
+			PackagePrivateClass other = (PackagePrivateClass)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;
+		}
+	}
+
+	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;
+		}
+	}
+	
+	static public class HasArgumentConstructor {
+		public String moo;
+
+		public HasArgumentConstructor (String moo) {
+			this.moo = moo;
+		}
+
+		public boolean equals (Object obj) {
+			if (this == obj) return true;
+			if (obj == null) return false;
+			if (getClass() != obj.getClass()) return false;
+			HasArgumentConstructor other = (HasArgumentConstructor)obj;
+			if (moo == null) {
+				if (other.moo != null) return false;
+			} else if (!moo.equals(other.moo)) return false;
+			return true;
+		}
+		
+		public String getMoo() {
+			return moo;
+		}
+	}
+
+	static public class HasPrivateConstructor extends HasArgumentConstructor {
+		private HasPrivateConstructor () {
+			super("cow");
+		}
+	}
+
+	static public class HasProtectedConstructor extends HasPrivateConstructor {
+		@SuppressWarnings("synthetic-access")
+		protected HasProtectedConstructor () {
+			super();
+		}
+	}
+
+	static public class HasPackageProtectedConstructor extends HasProtectedConstructor {
+		HasPackageProtectedConstructor () {
+			super();
+		}
+	}
+
+	static public class HasPublicConstructor extends HasPackageProtectedConstructor {
+		HasPublicConstructor () {
+			super();
+		}
+	}
+}


=====================================
java/test/com/esotericsoftware/reflectasm/FieldAccessTest.java → test/com/esotericsoftware/reflectasm/FieldAccessTest.java
=====================================
@@ -1,3 +1,16 @@
+/**
+ * Copyright (c) 2008, Nathan Sweet
+ *  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of Esoteric Software nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
 
 package com.esotericsoftware.reflectasm;
 


=====================================
java/test/com/esotericsoftware/reflectasm/MethodAccessTest.java → test/com/esotericsoftware/reflectasm/MethodAccessTest.java
=====================================
@@ -1,7 +1,22 @@
+/**
+ * Copyright (c) 2008, Nathan Sweet
+ *  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of Esoteric Software nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
 
 package com.esotericsoftware.reflectasm;
 
-import com.esotericsoftware.reflectasm.FieldAccessTest.EmptyClass;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentMap;
+import static junit.framework.Assert.assertEquals;
 
 import junit.framework.TestCase;
 
@@ -35,6 +50,9 @@ public class MethodAccessTest extends TestCase {
 		int index = access.getIndex("methodWithManyArguments", int.class, float.class, Integer.class, Float.class, SomeClass.class,
 			SomeClass.class, SomeClass.class);
 		assertEquals(access.getIndex("methodWithManyArguments"), index);
+
+		value = access.invoke(null, "staticMethod", "moo", 1234);
+		assertEquals("meow! moo, 1234", value);
 	}
 
 	public void testEmptyClass () {
@@ -71,6 +89,22 @@ public class MethodAccessTest extends TestCase {
 		}
 	}
 
+	public void testInvokeInterface () {
+		MethodAccess access = MethodAccess.get(ConcurrentMap.class);
+		access = MethodAccess.get(ConcurrentMap.class);
+		ConcurrentHashMap<String, String> someMap = new ConcurrentHashMap<String, String>();
+		someMap.put("first", "one");
+		someMap.put("second", "two");
+		Object value;
+
+		// invoke a method declared directly in the ConcurrentMap interface
+		value = access.invoke(someMap, "replace", "first", "foo");
+		assertEquals("one", value);
+		// invoke a method declared in the Map superinterface
+		value = access.invoke(someMap, "size");
+		assertEquals(someMap.size(), value);
+	}
+
 	static public class EmptyClass {
 	}
 
@@ -97,5 +131,9 @@ public class MethodAccessTest extends TestCase {
 		public String methodWithManyArguments (int i, float f, Integer I, Float F, SomeClass c, SomeClass c1, SomeClass c2) {
 			return "test";
 		}
+
+		static public String staticMethod (String a, int b) {
+			return "meow! " + a + ", " + b;
+		}
 	}
 }


=====================================
java/test/com/esotericsoftware/reflectasm/benchmark/Benchmark.java → test/com/esotericsoftware/reflectasm/benchmark/Benchmark.java
=====================================
@@ -1,3 +1,16 @@
+/**
+ * Copyright (c) 2008, Nathan Sweet
+ *  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of Esoteric Software nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
 
 package com.esotericsoftware.reflectasm.benchmark;
 


=====================================
java/test/com/esotericsoftware/reflectasm/benchmark/ConstructorAccessBenchmark.java → test/com/esotericsoftware/reflectasm/benchmark/ConstructorAccessBenchmark.java
=====================================
@@ -1,3 +1,16 @@
+/**
+ * Copyright (c) 2008, Nathan Sweet
+ *  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of Esoteric Software nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
 
 package com.esotericsoftware.reflectasm.benchmark;
 


=====================================
java/test/com/esotericsoftware/reflectasm/benchmark/FieldAccessBenchmark.java → test/com/esotericsoftware/reflectasm/benchmark/FieldAccessBenchmark.java
=====================================
@@ -1,3 +1,16 @@
+/**
+ * Copyright (c) 2008, Nathan Sweet
+ *  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of Esoteric Software nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
 
 package com.esotericsoftware.reflectasm.benchmark;
 


=====================================
java/test/com/esotericsoftware/reflectasm/benchmark/MethodAccessBenchmark.java → test/com/esotericsoftware/reflectasm/benchmark/MethodAccessBenchmark.java
=====================================
@@ -1,40 +1,54 @@
+/**
+ * Copyright (c) 2008, Nathan Sweet
+ *  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
+ *
+ *  1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
+ *  2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
+ *  3. Neither the name of Esoteric Software nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ */
 
 package com.esotericsoftware.reflectasm.benchmark;
 
-import java.lang.reflect.Method;
-import java.util.HashMap;
-
 import com.esotericsoftware.reflectasm.MethodAccess;
 
+import java.lang.reflect.Method;
+
 public class MethodAccessBenchmark extends Benchmark {
 	public MethodAccessBenchmark () throws Exception {
 		int count = 100000;
 		Object[] dontCompileMeAway = new Object[count];
+		Object[] args = new Object[0];
 
 		MethodAccess access = MethodAccess.get(SomeClass.class);
 		SomeClass someObject = new SomeClass();
 		int index = access.getIndex("getName");
 
 		Method method = SomeClass.class.getMethod("getName");
+		// method.setAccessible(true); // Improves reflection a bit.
 
 		for (int i = 0; i < 100; i++) {
 			for (int ii = 0; ii < count; ii++)
-				dontCompileMeAway[ii] = access.invoke(someObject, index);
+				dontCompileMeAway[ii] = access.invoke(someObject, index, args);
 			for (int ii = 0; ii < count; ii++)
-				dontCompileMeAway[ii] = method.invoke(someObject);
+				dontCompileMeAway[ii] = method.invoke(someObject, args);
 		}
 		warmup = false;
 
 		for (int i = 0; i < 100; i++) {
 			start();
 			for (int ii = 0; ii < count; ii++)
-				dontCompileMeAway[ii] = access.invoke(someObject, index);
+				dontCompileMeAway[ii] = access.invoke(someObject, index, args);
 			end("MethodAccess");
 		}
 		for (int i = 0; i < 100; i++) {
 			start();
 			for (int ii = 0; ii < count; ii++)
-				dontCompileMeAway[ii] = method.invoke(someObject);
+				dontCompileMeAway[ii] = method.invoke(someObject, args);
 			end("Reflection");
 		}
 



View it on GitLab: https://salsa.debian.org/java-team/libreflectasm-java/-/commit/2f658ad2a14113e928b36bffa21f0281a5fc2822

-- 
View it on GitLab: https://salsa.debian.org/java-team/libreflectasm-java/-/commit/2f658ad2a14113e928b36bffa21f0281a5fc2822
You're receiving this email because of your account on salsa.debian.org.


-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://alioth-lists.debian.net/pipermail/pkg-java-commits/attachments/20210518/4c2cce9c/attachment.htm>


More information about the pkg-java-commits mailing list