org.springframework.cglib.Foo$$EnhancerByCGLIB$$38272841
+ * This is composed of a prefix based on the name of the superclass, a fixed
+ * string incorporating the CGLIB class responsible for generation, and a
+ * hashcode derived from the parameters used to create the object. If the same
+ * name has been previously been used in the same
+ * This an internal class, thus it might disappear in future cglib releases.
+ *
+ * @param For interface bridges, using invokesuper will fail since the method being bridged to is in a
+ * superinterface, not a superclass. Starting in Java 8, javac emits default bridge methods in
+ * interfaces, which use invokeinterface to bridge to the target method.
+ *
+ * @author sberlin@gmail.com (Sam Berlin)
+ */
+@SuppressWarnings({"rawtypes", "unchecked"})
+class BridgeMethodResolver {
+
+ private final Map/* Note: {@link CallbackFilter} implementations are supposed to be
+ * lightweight as cglib might keep {@link CallbackFilter} objects
+ * alive to enable caching of generated classes. Prefer using {@code static}
+ * classes for implementation of {@link CallbackFilter}.
+ * @version $Id: Proxy.java,v 1.6 2004/06/24 21:15:19 herbyderby Exp $
+ */
+@SuppressWarnings({"rawtypes", "unchecked", "serial"})
+public class Proxy implements Serializable {
+ protected InvocationHandler h;
+
+ private static final CallbackFilter BAD_OBJECT_METHOD_FILTER = new CallbackFilter() {
+ public int accept(Method method) {
+ if (method.getDeclaringClass().getName().equals("java.lang.Object")) {
+ String name = method.getName();
+ if (!(name.equals("hashCode") ||
+ name.equals("equals") ||
+ name.equals("toString"))) {
+ return 1;
+ }
+ }
+ return 0;
+ }
+ };
+
+ protected Proxy(InvocationHandler h) {
+ Enhancer.registerCallbacks(getClass(), new Callback[]{ h, null });
+ this.h = h;
+ }
+
+ // private for security of isProxyClass
+ private static class ProxyImpl extends Proxy {
+ protected ProxyImpl(InvocationHandler h) {
+ super(h);
+ }
+ }
+
+ public static InvocationHandler getInvocationHandler(Object proxy) {
+ if (!(proxy instanceof ProxyImpl)) {
+ throw new IllegalArgumentException("Object is not a proxy");
+ }
+ return ((Proxy)proxy).h;
+ }
+
+ public static Class getProxyClass(ClassLoader loader, Class[] interfaces) {
+ Enhancer e = new Enhancer();
+ e.setSuperclass(ProxyImpl.class);
+ e.setInterfaces(interfaces);
+ e.setCallbackTypes(new Class[]{
+ InvocationHandler.class,
+ NoOp.class,
+ });
+ e.setCallbackFilter(BAD_OBJECT_METHOD_FILTER);
+ e.setUseFactory(false);
+ return e.createClass();
+ }
+
+ public static boolean isProxyClass(Class cl) {
+ return cl.getSuperclass().equals(ProxyImpl.class);
+ }
+
+ public static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) {
+ try {
+ Class clazz = getProxyClass(loader, interfaces);
+ return clazz.getConstructor(new Class[]{ InvocationHandler.class }).newInstance(new Object[]{ h });
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Exception e) {
+ throw new CodeGenerationException(e);
+ }
+ }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/proxy/ProxyRefDispatcher.java b/spring-core/src/main/java/org/springframework/cglib/proxy/ProxyRefDispatcher.java
new file mode 100644
index 0000000000..84867c79e2
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/proxy/ProxyRefDispatcher.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2003 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.proxy;
+
+/**
+ * Dispatching {@link Enhancer} callback. This is the same as the
+ * {@link Dispatcher} except for the addition of an argument
+ * which references the proxy object.
+ */
+public interface ProxyRefDispatcher extends Callback {
+ /**
+ * Return the object which the original method invocation should
+ * be dispatched. This method is called for every method invocation.
+ * @param proxy a reference to the proxy (generated) object
+ * @return an object that can invoke the method
+ */
+ Object loadObject(Object proxy) throws Exception;
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/proxy/UndeclaredThrowableException.java b/spring-core/src/main/java/org/springframework/cglib/proxy/UndeclaredThrowableException.java
new file mode 100644
index 0000000000..f566e560ef
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/proxy/UndeclaredThrowableException.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2002,2003 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cglib.proxy;
+
+import org.springframework.cglib.core.CodeGenerationException;
+
+/**
+ * Used by {@link Proxy} as a replacement for
+ * Delegates are a typesafe pointer to another method. Since Java does not
+ * have language support for such a construct, this utility will construct
+ * a proxy that forwards method calls to any method with the same signature.
+ * This utility is inspired in part by the C# delegate mechanism. We
+ * implemented it in a Java-centric manner.
+ *
+ * Any interface with one method can become the interface for a delegate.
+ * Consider the example below:
+ *
+ * The interface above is an example of an interface that can become a
+ * delegate. It has only one method, and the interface is public. In
+ * order to create a delegate for that method, all we have to do is
+ * call
+ * By themselves, delegates don't do much. Their true power lies in the fact that
+ * they can be treated like objects, and passed to other methods. In fact that is
+ * one of the key building blocks of building Intelligent Agents which in tern are
+ * the foundation of artificial intelligence. In the above program, we could have
+ * easily created the delegate to match the static
+ * Another key use for Delegates is to register event listeners. It is much easier
+ * to have all the code for your events separated out into methods instead of individual
+ * classes. One of the ways Java gets around that is to create anonymous classes.
+ * They are particularly troublesome because many Debuggers do not know what to do
+ * with them. Anonymous classes tend to duplicate alot of code as well. We can
+ * use any interface with one declared method to forward events to any method that
+ * matches the signature (although the method name can be different).
+ *
+ * Given two arrays of equal length and varying types, the standard
+ * technique for sorting them in parallel is to create a new temporary
+ * object for each row, store the objects in a temporary array, sort the
+ * array using a custom comparator, and the extract the original values
+ * back into their respective arrays. This is wasteful in both time and
+ * memory.
+ *
+ * This class generates bytecode customized to the particular set of
+ * arrays you need to sort, in such a way that both arrays are sorted
+ * in-place, simultaneously.
+ *
+ * Two sorting algorithms are provided.
+ * Quicksort is best when you only need to sort by a single column, as
+ * it requires very few comparisons and swaps. Mergesort is best used
+ * when sorting multiple columns, as it is a "stable" sort--that is, it
+ * does not affect the relative order of equal objects from previous sorts.
+ *
+ * The mergesort algorithm here is an "in-place" variant, which while
+ * slower, does not require a temporary array.
+ *
+ * @author Chris Nokleberg
+ */
+@SuppressWarnings({"rawtypes", "unchecked"})
+abstract public class ParallelSorter extends SorterTemplate {
+ protected Object[] a;
+ private Comparer comparer;
+
+ protected ParallelSorter() {
+ }
+
+ abstract public ParallelSorter newInstance(Object[] arrays);
+
+ /**
+ * Create a new ParallelSorter object for a set of arrays. You may
+ * sort the arrays multiple times via the same ParallelSorter object.
+ * @param arrays An array of arrays to sort. The arrays may be a mix
+ * of primitive and non-primitive types, but should all be the same
+ * length.
+ * @param loader ClassLoader for generated class, uses "current" if null
+ */
+ public static ParallelSorter create(Object[] arrays) {
+ Generator gen = new Generator();
+ gen.setArrays(arrays);
+ return gen.create();
+ }
+
+ private int len() {
+ return ((Object[])a[0]).length;
+ }
+
+ /**
+ * Sort the arrays using the quicksort algorithm.
+ * @param index array (column) to sort by
+ */
+ public void quickSort(int index) {
+ quickSort(index, 0, len(), null);
+ }
+
+ /**
+ * Sort the arrays using the quicksort algorithm.
+ * @param index array (column) to sort by
+ * @param lo starting array index (row), inclusive
+ * @param hi ending array index (row), exclusive
+ */
+ public void quickSort(int index, int lo, int hi) {
+ quickSort(index, lo, hi, null);
+ }
+
+ /**
+ * Sort the arrays using the quicksort algorithm.
+ * @param index array (column) to sort by
+ * @param cmp Comparator to use if the specified column is non-primitive
+ */
+ public void quickSort(int index, Comparator cmp) {
+ quickSort(index, 0, len(), cmp);
+ }
+
+ /**
+ * Sort the arrays using the quicksort algorithm.
+ * @param index array (column) to sort by
+ * @param lo starting array index (row), inclusive
+ * @param hi ending array index (row), exclusive
+ * @param cmp Comparator to use if the specified column is non-primitive
+ */
+ public void quickSort(int index, int lo, int hi, Comparator cmp) {
+ chooseComparer(index, cmp);
+ super.quickSort(lo, hi - 1);
+ }
+
+ /**
+ * @param index array (column) to sort by
+ */
+ public void mergeSort(int index) {
+ mergeSort(index, 0, len(), null);
+ }
+
+ /**
+ * Sort the arrays using an in-place merge sort.
+ * @param index array (column) to sort by
+ * @param lo starting array index (row), inclusive
+ * @param hi ending array index (row), exclusive
+ */
+ public void mergeSort(int index, int lo, int hi) {
+ mergeSort(index, lo, hi, null);
+ }
+
+ /**
+ * Sort the arrays using an in-place merge sort.
+ * @param index array (column) to sort by
+ * @param lo starting array index (row), inclusive
+ * @param hi ending array index (row), exclusive
+ */
+ public void mergeSort(int index, Comparator cmp) {
+ mergeSort(index, 0, len(), cmp);
+ }
+
+ /**
+ * Sort the arrays using an in-place merge sort.
+ * @param index array (column) to sort by
+ * @param lo starting array index (row), inclusive
+ * @param hi ending array index (row), exclusive
+ * @param cmp Comparator to use if the specified column is non-primitive
+ */
+ public void mergeSort(int index, int lo, int hi, Comparator cmp) {
+ chooseComparer(index, cmp);
+ super.mergeSort(lo, hi - 1);
+ }
+
+ private void chooseComparer(int index, Comparator cmp) {
+ Object array = a[index];
+ Class type = array.getClass().getComponentType();
+ if (type.equals(Integer.TYPE)) {
+ comparer = new IntComparer((int[])array);
+ } else if (type.equals(Long.TYPE)) {
+ comparer = new LongComparer((long[])array);
+ } else if (type.equals(Double.TYPE)) {
+ comparer = new DoubleComparer((double[])array);
+ } else if (type.equals(Float.TYPE)) {
+ comparer = new FloatComparer((float[])array);
+ } else if (type.equals(Short.TYPE)) {
+ comparer = new ShortComparer((short[])array);
+ } else if (type.equals(Byte.TYPE)) {
+ comparer = new ByteComparer((byte[])array);
+ } else if (cmp != null) {
+ comparer = new ComparatorComparer((Object[])array, cmp);
+ } else {
+ comparer = new ObjectComparer((Object[])array);
+ }
+ }
+
+ protected int compare(int i, int j) {
+ return comparer.compare(i, j);
+ }
+
+ interface Comparer {
+ int compare(int i, int j);
+ }
+
+ static class ComparatorComparer implements Comparer {
+ private Object[] a;
+ private Comparator cmp;
+
+ public ComparatorComparer(Object[] a, Comparator cmp) {
+ this.a = a;
+ this.cmp = cmp;
+ }
+
+ public int compare(int i, int j) {
+ return cmp.compare(a[i], a[j]);
+ }
+ }
+
+ static class ObjectComparer implements Comparer {
+ private Object[] a;
+ public ObjectComparer(Object[] a) { this.a = a; }
+ public int compare(int i, int j) {
+ return ((Comparable)a[i]).compareTo(a[j]);
+ }
+ }
+
+ static class IntComparer implements Comparer {
+ private int[] a;
+ public IntComparer(int[] a) { this.a = a; }
+ public int compare(int i, int j) { return a[i] - a[j]; }
+ }
+
+ static class LongComparer implements Comparer {
+ private long[] a;
+ public LongComparer(long[] a) { this.a = a; }
+ public int compare(int i, int j) {
+ long vi = a[i];
+ long vj = a[j];
+ return (vi == vj) ? 0 : (vi > vj) ? 1 : -1;
+ }
+ }
+
+ static class FloatComparer implements Comparer {
+ private float[] a;
+ public FloatComparer(float[] a) { this.a = a; }
+ public int compare(int i, int j) {
+ float vi = a[i];
+ float vj = a[j];
+ return (vi == vj) ? 0 : (vi > vj) ? 1 : -1;
+ }
+ }
+
+ static class DoubleComparer implements Comparer {
+ private double[] a;
+ public DoubleComparer(double[] a) { this.a = a; }
+ public int compare(int i, int j) {
+ double vi = a[i];
+ double vj = a[j];
+ return (vi == vj) ? 0 : (vi > vj) ? 1 : -1;
+ }
+ }
+
+ static class ShortComparer implements Comparer {
+ private short[] a;
+ public ShortComparer(short[] a) { this.a = a; }
+ public int compare(int i, int j) { return a[i] - a[j]; }
+ }
+
+ static class ByteComparer implements Comparer {
+ private byte[] a;
+ public ByteComparer(byte[] a) { this.a = a; }
+ public int compare(int i, int j) { return a[i] - a[j]; }
+ }
+
+ public static class Generator extends AbstractClassGenerator {
+ private static final Source SOURCE = new Source(ParallelSorter.class.getName());
+
+ private Object[] arrays;
+
+ public Generator() {
+ super(SOURCE);
+ }
+
+ protected ClassLoader getDefaultClassLoader() {
+ return null; // TODO
+ }
+
+ public void setArrays(Object[] arrays) {
+ this.arrays = arrays;
+ }
+
+ public ParallelSorter create() {
+ return (ParallelSorter)super.create(ClassesKey.create(arrays));
+ }
+
+ public void generateClass(ClassVisitor v) throws Exception {
+ if (arrays.length == 0) {
+ throw new IllegalArgumentException("No arrays specified to sort");
+ }
+ for (int i = 0; i < arrays.length; i++) {
+ if (!arrays[i].getClass().isArray()) {
+ throw new IllegalArgumentException(arrays[i].getClass() + " is not an array");
+ }
+ }
+ new ParallelSorterEmitter(v, getClassName(), arrays);
+ }
+
+ protected Object firstInstance(Class type) {
+ return ((ParallelSorter)ReflectUtils.newInstance(type)).newInstance(arrays);
+ }
+
+ protected Object nextInstance(Object instance) {
+ return ((ParallelSorter)instance).newInstance(arrays);
+ }
+ }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/util/ParallelSorterEmitter.java b/spring-core/src/main/java/org/springframework/cglib/util/ParallelSorterEmitter.java
new file mode 100644
index 0000000000..298c0f234f
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/util/ParallelSorterEmitter.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2003 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.util;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import org.springframework.cglib.core.*;
+import org.springframework.asm.ClassVisitor;
+import org.springframework.asm.Type;
+
+class ParallelSorterEmitter extends ClassEmitter {
+ private static final Type PARALLEL_SORTER =
+ TypeUtils.parseType("org.springframework.cglib.util.ParallelSorter");
+ private static final Signature CSTRUCT_OBJECT_ARRAY =
+ TypeUtils.parseConstructor("Object[]");
+ private static final Signature NEW_INSTANCE =
+ new Signature("newInstance", PARALLEL_SORTER, new Type[]{ Constants.TYPE_OBJECT_ARRAY });
+ private static final Signature SWAP =
+ TypeUtils.parseSignature("void swap(int, int)");
+
+ public ParallelSorterEmitter(ClassVisitor v, String className, Object[] arrays) {
+ super(v);
+ begin_class(Constants.V1_8, Constants.ACC_PUBLIC, className, PARALLEL_SORTER, null, Constants.SOURCE_FILE);
+ EmitUtils.null_constructor(this);
+ EmitUtils.factory_method(this, NEW_INSTANCE);
+ generateConstructor(arrays);
+ generateSwap(arrays);
+ end_class();
+ }
+
+ private String getFieldName(int index) {
+ return "FIELD_" + index;
+ }
+
+ private void generateConstructor(Object[] arrays) {
+ CodeEmitter e = begin_method(Constants.ACC_PUBLIC, CSTRUCT_OBJECT_ARRAY, null);
+ e.load_this();
+ e.super_invoke_constructor();
+ e.load_this();
+ e.load_arg(0);
+ e.super_putfield("a", Constants.TYPE_OBJECT_ARRAY);
+ for (int i = 0; i < arrays.length; i++) {
+ Type type = Type.getType(arrays[i].getClass());
+ declare_field(Constants.ACC_PRIVATE, getFieldName(i), type, null);
+ e.load_this();
+ e.load_arg(0);
+ e.push(i);
+ e.aaload();
+ e.checkcast(type);
+ e.putfield(getFieldName(i));
+ }
+ e.return_value();
+ e.end_method();
+ }
+
+ private void generateSwap(final Object[] arrays) {
+ CodeEmitter e = begin_method(Constants.ACC_PUBLIC, SWAP, null);
+ for (int i = 0; i < arrays.length; i++) {
+ Type type = Type.getType(arrays[i].getClass());
+ Type component = TypeUtils.getComponentType(type);
+ Local T = e.make_local(type);
+
+ e.load_this();
+ e.getfield(getFieldName(i));
+ e.store_local(T);
+
+ e.load_local(T);
+ e.load_arg(0);
+
+ e.load_local(T);
+ e.load_arg(1);
+ e.array_load(component);
+
+ e.load_local(T);
+ e.load_arg(1);
+
+ e.load_local(T);
+ e.load_arg(0);
+ e.array_load(component);
+
+ e.array_store(component);
+ e.array_store(component);
+ }
+ e.return_value();
+ e.end_method();
+ }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/util/SorterTemplate.java b/spring-core/src/main/java/org/springframework/cglib/util/SorterTemplate.java
new file mode 100644
index 0000000000..10f33495ad
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/util/SorterTemplate.java
@@ -0,0 +1,173 @@
+/*
+ * Copyright 2003 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.util;
+
+import java.util.*;
+
+abstract class SorterTemplate {
+ private static final int MERGESORT_THRESHOLD = 12;
+ private static final int QUICKSORT_THRESHOLD = 7;
+
+ abstract protected void swap(int i, int j);
+ abstract protected int compare(int i, int j);
+
+ protected void quickSort(int lo, int hi) {
+ quickSortHelper(lo, hi);
+ insertionSort(lo, hi);
+ }
+
+ private void quickSortHelper(int lo, int hi) {
+ for (;;) {
+ int diff = hi - lo;
+ if (diff <= QUICKSORT_THRESHOLD) {
+ break;
+ }
+ int i = (hi + lo) / 2;
+ if (compare(lo, i) > 0) {
+ swap(lo, i);
+ }
+ if (compare(lo, hi) > 0) {
+ swap(lo, hi);
+ }
+ if (compare(i, hi) > 0) {
+ swap(i, hi);
+ }
+ int j = hi - 1;
+ swap(i, j);
+ i = lo;
+ int v = j;
+ for (;;) {
+ while (compare(++i, v) < 0) {
+ /* nothing */;
+ }
+ while (compare(--j, v) > 0) {
+ /* nothing */;
+ }
+ if (j < i) {
+ break;
+ }
+ swap(i, j);
+ }
+ swap(i, hi - 1);
+ if (j - lo <= hi - i + 1) {
+ quickSortHelper(lo, j);
+ lo = i + 1;
+ } else {
+ quickSortHelper(i + 1, hi);
+ hi = j;
+ }
+ }
+ }
+
+ private void insertionSort(int lo, int hi) {
+ for (int i = lo + 1 ; i <= hi; i++) {
+ for (int j = i; j > lo; j--) {
+ if (compare(j - 1, j) > 0) {
+ swap(j - 1, j);
+ } else {
+ break;
+ }
+ }
+ }
+ }
+
+ protected void mergeSort(int lo, int hi) {
+ int diff = hi - lo;
+ if (diff <= MERGESORT_THRESHOLD) {
+ insertionSort(lo, hi);
+ return;
+ }
+ int mid = lo + diff / 2;
+ mergeSort(lo, mid);
+ mergeSort(mid, hi);
+ merge(lo, mid, hi, mid - lo, hi - mid);
+ }
+
+ private void merge(int lo, int pivot, int hi, int len1, int len2) {
+ if (len1 == 0 || len2 == 0) {
+ return;
+ }
+ if (len1 + len2 == 2) {
+ if (compare(pivot, lo) < 0) {
+ swap(pivot, lo);
+ }
+ return;
+ }
+ int first_cut, second_cut;
+ int len11, len22;
+ if (len1 > len2) {
+ len11 = len1 / 2;
+ first_cut = lo + len11;
+ second_cut = lower(pivot, hi, first_cut);
+ len22 = second_cut - pivot;
+ } else {
+ len22 = len2 / 2;
+ second_cut = pivot + len22;
+ first_cut = upper(lo, pivot, second_cut);
+ len11 = first_cut - lo;
+ }
+ rotate(first_cut, pivot, second_cut);
+ int new_mid = first_cut + len22;
+ merge(lo, first_cut, new_mid, len11, len22);
+ merge(new_mid, second_cut, hi, len1 - len11, len2 - len22);
+ }
+
+ private void rotate(int lo, int mid, int hi) {
+ int lot = lo;
+ int hit = mid - 1;
+ while (lot < hit) {
+ swap(lot++, hit--);
+ }
+ lot = mid; hit = hi - 1;
+ while (lot < hit) {
+ swap(lot++, hit--);
+ }
+ lot = lo; hit = hi - 1;
+ while (lot < hit) {
+ swap(lot++, hit--);
+ }
+ }
+
+ private int lower(int lo, int hi, int val) {
+ int len = hi - lo;
+ while (len > 0) {
+ int half = len / 2;
+ int mid= lo + half;
+ if (compare(mid, val) < 0) {
+ lo = mid + 1;
+ len = len - half -1;
+ } else {
+ len = half;
+ }
+ }
+ return lo;
+ }
+
+ private int upper(int lo, int hi, int val) {
+ int len = hi - lo;
+ while (len > 0) {
+ int half = len / 2;
+ int mid = lo + half;
+ if (compare(val, mid) < 0) {
+ len = half;
+ } else {
+ lo = mid + 1;
+ len = len - half -1;
+ }
+ }
+ return lo;
+ }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/util/StringSwitcher.java b/spring-core/src/main/java/org/springframework/cglib/util/StringSwitcher.java
new file mode 100644
index 0000000000..3a35ead05f
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/util/StringSwitcher.java
@@ -0,0 +1,155 @@
+/*
+ * Copyright 2003 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.util;
+
+import java.util.*;
+import org.springframework.cglib.core.*;
+import org.springframework.asm.ClassVisitor;
+import org.springframework.asm.Label;
+import org.springframework.asm.Type;
+
+/**
+ * This class implements a simple String->int mapping for a fixed set of keys.
+ */
+@SuppressWarnings({"rawtypes", "unchecked"})
+abstract public class StringSwitcher {
+ private static final Type STRING_SWITCHER =
+ TypeUtils.parseType("org.springframework.cglib.util.StringSwitcher");
+ private static final Signature INT_VALUE =
+ TypeUtils.parseSignature("int intValue(String)");
+ private static final StringSwitcherKey KEY_FACTORY =
+ (StringSwitcherKey)KeyFactory.create(StringSwitcherKey.class);
+
+ interface StringSwitcherKey {
+ public Object newInstance(String[] strings, int[] ints, boolean fixedInput);
+ }
+
+ /**
+ * Helper method to create a StringSwitcher.
+ * For finer control over the generated instance, use a new instance of StringSwitcher.Generator
+ * instead of this static method.
+ * @param strings the array of String keys; must be the same length as the value array
+ * @param ints the array of integer results; must be the same length as the key array
+ * @param fixedInput if false, an unknown key will be returned from {@link #intValue} as ClassLoader, a
+ * suffix is added to ensure uniqueness.
+ */
+public class DefaultNamingPolicy implements NamingPolicy {
+ public static final DefaultNamingPolicy INSTANCE = new DefaultNamingPolicy();
+
+ /**
+ * This allows to test collisions of {@code key.hashCode()}.
+ */
+ private final static boolean STRESS_HASH_CODE = Boolean.getBoolean("org.springframework.cglib.test.stressHashCodes");
+
+ public String getClassName(String prefix, String source, Object key, Predicate names) {
+ if (prefix == null) {
+ prefix = "org.springframework.cglib.empty.Object";
+ } else if (prefix.startsWith("java")) {
+ prefix = "$" + prefix;
+ }
+ String base =
+ prefix + "$$" +
+ source.substring(source.lastIndexOf('.') + 1) +
+ getTag() + "$$" +
+ Integer.toHexString(STRESS_HASH_CODE ? 0 : key.hashCode());
+ String attempt = base;
+ int index = 2;
+ while (names.evaluate(attempt))
+ attempt = base + "_" + index++;
+ return attempt;
+ }
+
+ /**
+ * Returns a string which is incorporated into every generated class name.
+ * By default returns "ByCGLIB"
+ */
+ protected String getTag() {
+ return "ByCGLIB";
+ }
+
+ public int hashCode() {
+ return getTag().hashCode();
+ }
+
+ public boolean equals(Object o) {
+ return (o instanceof DefaultNamingPolicy) && ((DefaultNamingPolicy) o).getTag().equals(getTag());
+ }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/core/DuplicatesPredicate.java b/spring-core/src/main/java/org/springframework/cglib/core/DuplicatesPredicate.java
new file mode 100644
index 0000000000..a12cf1ce62
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/core/DuplicatesPredicate.java
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2003 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.core;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Method;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import org.springframework.asm.ClassReader;
+import org.springframework.asm.ClassVisitor;
+import org.springframework.asm.MethodVisitor;
+import org.springframework.asm.Opcodes;
+
+@SuppressWarnings({"rawtypes", "unchecked"})
+public class DuplicatesPredicate implements Predicate {
+ private final Set unique;
+ private final Set rejected;
+
+ /**
+ * Constructs a DuplicatesPredicate that will allow subclass bridge methods to be preferred over
+ * superclass non-bridge methods.
+ */
+ public DuplicatesPredicate() {
+ unique = new HashSet();
+ rejected = Collections.emptySet();
+ }
+
+ /**
+ * Constructs a DuplicatesPredicate that prefers using superclass non-bridge methods despite a
+ * subclass method with the same signtaure existing (if the subclass is a bridge method).
+ */
+ public DuplicatesPredicate(List allMethods) {
+ rejected = new HashSet();
+ unique = new HashSet();
+
+ // Traverse through the methods and capture ones that are bridge
+ // methods when a subsequent method (from a non-interface superclass)
+ // has the same signature but isn't a bridge. Record these so that
+ // we avoid using them when filtering duplicates.
+ Map scanned = new HashMap();
+ Map suspects = new HashMap();
+ for (Object o : allMethods) {
+ Method method = (Method) o;
+ Object sig = MethodWrapper.create(method);
+ Method existing = (Method) scanned.get(sig);
+ if (existing == null) {
+ scanned.put(sig, method);
+ } else if (!suspects.containsKey(sig) && existing.isBridge() && !method.isBridge()) {
+ // TODO: this currently only will capture a single bridge. it will not work
+ // if there's Child.bridge1 Middle.bridge2 Parent.concrete. (we'd offer the 2nd bridge).
+ // no idea if that's even possible tho...
+ suspects.put(sig, existing);
+ }
+ }
+
+ if (!suspects.isEmpty()) {
+ Set classes = new HashSet();
+ UnnecessaryBridgeFinder finder = new UnnecessaryBridgeFinder(rejected);
+ for (Object o : suspects.values()) {
+ Method m = (Method) o;
+ classes.add(m.getDeclaringClass());
+ finder.addSuspectMethod(m);
+ }
+ for (Object o : classes) {
+ Class c = (Class) o;
+ try {
+ ClassLoader cl = getClassLoader(c);
+ if (cl == null) {
+ continue;
+ }
+ InputStream is = cl.getResourceAsStream(c.getName().replace('.', '/') + ".class");
+ if (is == null) {
+ continue;
+ }
+ try {
+ new ClassReader(is).accept(finder, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG);
+ } finally {
+ is.close();
+ }
+ } catch (IOException ignored) {
+ }
+ }
+ }
+ }
+
+ public boolean evaluate(Object arg) {
+ return !rejected.contains(arg) && unique.add(MethodWrapper.create((Method) arg));
+ }
+
+ private static ClassLoader getClassLoader(Class c) {
+ ClassLoader cl = c.getClassLoader();
+ if (cl == null) {
+ cl = DuplicatesPredicate.class.getClassLoader();
+ }
+ if (cl == null) {
+ cl = Thread.currentThread().getContextClassLoader();
+ }
+ return cl;
+ }
+
+ private static class UnnecessaryBridgeFinder extends ClassVisitor {
+ private final Set rejected;
+
+ private Signature currentMethodSig = null;
+ private Map methods = new HashMap();
+
+ UnnecessaryBridgeFinder(Set rejected) {
+ super(Constants.ASM_API);
+ this.rejected = rejected;
+ }
+
+ void addSuspectMethod(Method m) {
+ methods.put(ReflectUtils.getSignature(m), m);
+ }
+
+ public void visit(
+ int version,
+ int access,
+ String name,
+ String signature,
+ String superName,
+ String[] interfaces) {}
+
+ public MethodVisitor visitMethod(
+ int access, String name, String desc, String signature, String[] exceptions) {
+ Signature sig = new Signature(name, desc);
+ final Method currentMethod = (Method) methods.remove(sig);
+ if (currentMethod != null) {
+ currentMethodSig = sig;
+ return new MethodVisitor(Constants.ASM_API) {
+ public void visitMethodInsn(
+ int opcode, String owner, String name, String desc, boolean itf) {
+ if (opcode == Opcodes.INVOKESPECIAL && currentMethodSig != null) {
+ Signature target = new Signature(name, desc);
+ if (target.equals(currentMethodSig)) {
+ rejected.add(currentMethod);
+ }
+ currentMethodSig = null;
+ }
+ }
+ };
+ } else {
+ return null;
+ }
+ }
+ }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/core/EmitUtils.java b/spring-core/src/main/java/org/springframework/cglib/core/EmitUtils.java
new file mode 100644
index 0000000000..e5b59497df
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/core/EmitUtils.java
@@ -0,0 +1,961 @@
+/*
+ * Copyright 2003,2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.core;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.util.*;
+
+import org.springframework.cglib.core.internal.CustomizerRegistry;
+import org.springframework.asm.Label;
+import org.springframework.asm.Type;
+
+@SuppressWarnings({"rawtypes", "unchecked", "static", "fallthrough", "deprecation"})
+public class EmitUtils {
+ private static final Signature CSTRUCT_NULL =
+ TypeUtils.parseConstructor("");
+ private static final Signature CSTRUCT_THROWABLE =
+ TypeUtils.parseConstructor("Throwable");
+
+ private static final Signature GET_NAME =
+ TypeUtils.parseSignature("String getName()");
+ private static final Signature HASH_CODE =
+ TypeUtils.parseSignature("int hashCode()");
+ private static final Signature EQUALS =
+ TypeUtils.parseSignature("boolean equals(Object)");
+ private static final Signature STRING_LENGTH =
+ TypeUtils.parseSignature("int length()");
+ private static final Signature STRING_CHAR_AT =
+ TypeUtils.parseSignature("char charAt(int)");
+ private static final Signature FOR_NAME =
+ TypeUtils.parseSignature("Class forName(String)");
+ private static final Signature DOUBLE_TO_LONG_BITS =
+ TypeUtils.parseSignature("long doubleToLongBits(double)");
+ private static final Signature FLOAT_TO_INT_BITS =
+ TypeUtils.parseSignature("int floatToIntBits(float)");
+ private static final Signature TO_STRING =
+ TypeUtils.parseSignature("String toString()");
+ private static final Signature APPEND_STRING =
+ TypeUtils.parseSignature("StringBuffer append(String)");
+ private static final Signature APPEND_INT =
+ TypeUtils.parseSignature("StringBuffer append(int)");
+ private static final Signature APPEND_DOUBLE =
+ TypeUtils.parseSignature("StringBuffer append(double)");
+ private static final Signature APPEND_FLOAT =
+ TypeUtils.parseSignature("StringBuffer append(float)");
+ private static final Signature APPEND_CHAR =
+ TypeUtils.parseSignature("StringBuffer append(char)");
+ private static final Signature APPEND_LONG =
+ TypeUtils.parseSignature("StringBuffer append(long)");
+ private static final Signature APPEND_BOOLEAN =
+ TypeUtils.parseSignature("StringBuffer append(boolean)");
+ private static final Signature LENGTH =
+ TypeUtils.parseSignature("int length()");
+ private static final Signature SET_LENGTH =
+ TypeUtils.parseSignature("void setLength(int)");
+ private static final Signature GET_DECLARED_METHOD =
+ TypeUtils.parseSignature("java.lang.reflect.Method getDeclaredMethod(String, Class[])");
+
+
+
+ public static final ArrayDelimiters DEFAULT_DELIMITERS = new ArrayDelimiters("{", ", ", "}");
+
+ private EmitUtils() {
+ }
+
+ public static void factory_method(ClassEmitter ce, Signature sig) {
+ CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, sig, null);
+ e.new_instance_this();
+ e.dup();
+ e.load_args();
+ e.invoke_constructor_this(TypeUtils.parseConstructor(sig.getArgumentTypes()));
+ e.return_value();
+ e.end_method();
+ }
+
+ public static void null_constructor(ClassEmitter ce) {
+ CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, CSTRUCT_NULL, null);
+ e.load_this();
+ e.super_invoke_constructor();
+ e.return_value();
+ e.end_method();
+ }
+
+ /**
+ * Process an array on the stack. Assumes the top item on the stack
+ * is an array of the specified type. For each element in the array,
+ * puts the element on the stack and triggers the callback.
+ * @param type the type of the array (type.isArray() must be true)
+ * @param callback the callback triggered for each element
+ */
+ public static void process_array(CodeEmitter e, Type type, ProcessArrayCallback callback) {
+ Type componentType = TypeUtils.getComponentType(type);
+ Local array = e.make_local();
+ Local loopvar = e.make_local(Type.INT_TYPE);
+ Label loopbody = e.make_label();
+ Label checkloop = e.make_label();
+ e.store_local(array);
+ e.push(0);
+ e.store_local(loopvar);
+ e.goTo(checkloop);
+
+ e.mark(loopbody);
+ e.load_local(array);
+ e.load_local(loopvar);
+ e.array_load(componentType);
+ callback.processElement(componentType);
+ e.iinc(loopvar, 1);
+
+ e.mark(checkloop);
+ e.load_local(loopvar);
+ e.load_local(array);
+ e.arraylength();
+ e.if_icmp(e.LT, loopbody);
+ }
+
+ /**
+ * Process two arrays on the stack in parallel. Assumes the top two items on the stack
+ * are arrays of the specified class. The arrays must be the same length. For each pair
+ * of elements in the arrays, puts the pair on the stack and triggers the callback.
+ * @param type the type of the arrays (type.isArray() must be true)
+ * @param callback the callback triggered for each pair of elements
+ */
+ public static void process_arrays(CodeEmitter e, Type type, ProcessArrayCallback callback) {
+ Type componentType = TypeUtils.getComponentType(type);
+ Local array1 = e.make_local();
+ Local array2 = e.make_local();
+ Local loopvar = e.make_local(Type.INT_TYPE);
+ Label loopbody = e.make_label();
+ Label checkloop = e.make_label();
+ e.store_local(array1);
+ e.store_local(array2);
+ e.push(0);
+ e.store_local(loopvar);
+ e.goTo(checkloop);
+
+ e.mark(loopbody);
+ e.load_local(array1);
+ e.load_local(loopvar);
+ e.array_load(componentType);
+ e.load_local(array2);
+ e.load_local(loopvar);
+ e.array_load(componentType);
+ callback.processElement(componentType);
+ e.iinc(loopvar, 1);
+
+ e.mark(checkloop);
+ e.load_local(loopvar);
+ e.load_local(array1);
+ e.arraylength();
+ e.if_icmp(e.LT, loopbody);
+ }
+
+ public static void string_switch(CodeEmitter e, String[] strings, int switchStyle, ObjectSwitchCallback callback) {
+ try {
+ switch (switchStyle) {
+ case Constants.SWITCH_STYLE_TRIE:
+ string_switch_trie(e, strings, callback);
+ break;
+ case Constants.SWITCH_STYLE_HASH:
+ string_switch_hash(e, strings, callback, false);
+ break;
+ case Constants.SWITCH_STYLE_HASHONLY:
+ string_switch_hash(e, strings, callback, true);
+ break;
+ default:
+ throw new IllegalArgumentException("unknown switch style " + switchStyle);
+ }
+ } catch (RuntimeException ex) {
+ throw ex;
+ } catch (Error ex) {
+ throw ex;
+ } catch (Exception ex) {
+ throw new CodeGenerationException(ex);
+ }
+ }
+
+ private static void string_switch_trie(final CodeEmitter e,
+ String[] strings,
+ final ObjectSwitchCallback callback) throws Exception {
+ final Label def = e.make_label();
+ final Label end = e.make_label();
+ final Map buckets = CollectionUtils.bucket(Arrays.asList(strings), new Transformer() {
+ public Object transform(Object value) {
+ return ((String)value).length();
+ }
+ });
+ e.dup();
+ e.invoke_virtual(Constants.TYPE_STRING, STRING_LENGTH);
+ e.process_switch(getSwitchKeys(buckets), new ProcessSwitchCallback() {
+ public void processCase(int key, Label ignore_end) throws Exception {
+ List bucket = (List)buckets.get(key);
+ stringSwitchHelper(e, bucket, callback, def, end, 0);
+ }
+ public void processDefault() {
+ e.goTo(def);
+ }
+ });
+ e.mark(def);
+ e.pop();
+ callback.processDefault();
+ e.mark(end);
+ }
+
+ private static void stringSwitchHelper(final CodeEmitter e,
+ List strings,
+ final ObjectSwitchCallback callback,
+ final Label def,
+ final Label end,
+ final int index) throws Exception {
+ final int len = ((String)strings.get(0)).length();
+ final Map buckets = CollectionUtils.bucket(strings, new Transformer() {
+ public Object transform(Object value) {
+ return ((String)value).charAt(index);
+ }
+ });
+ e.dup();
+ e.push(index);
+ e.invoke_virtual(Constants.TYPE_STRING, STRING_CHAR_AT);
+ e.process_switch(getSwitchKeys(buckets), new ProcessSwitchCallback() {
+ public void processCase(int key, Label ignore_end) throws Exception {
+ List bucket = (List)buckets.get(key);
+ if (index + 1 == len) {
+ e.pop();
+ callback.processCase(bucket.get(0), end);
+ } else {
+ stringSwitchHelper(e, bucket, callback, def, end, index + 1);
+ }
+ }
+ public void processDefault() {
+ e.goTo(def);
+ }
+ });
+ }
+
+ static int[] getSwitchKeys(Map buckets) {
+ int[] keys = new int[buckets.size()];
+ int index = 0;
+ for (Iterator it = buckets.keySet().iterator(); it.hasNext();) {
+ keys[index++] = ((Integer)it.next());
+ }
+ Arrays.sort(keys);
+ return keys;
+ }
+
+ private static void string_switch_hash(final CodeEmitter e,
+ final String[] strings,
+ final ObjectSwitchCallback callback,
+ final boolean skipEquals) throws Exception {
+ final Map buckets = CollectionUtils.bucket(Arrays.asList(strings), new Transformer() {
+ public Object transform(Object value) {
+ return value.hashCode();
+ }
+ });
+ final Label def = e.make_label();
+ final Label end = e.make_label();
+ e.dup();
+ e.invoke_virtual(Constants.TYPE_OBJECT, HASH_CODE);
+ e.process_switch(getSwitchKeys(buckets), new ProcessSwitchCallback() {
+ public void processCase(int key, Label ignore_end) throws Exception {
+ List bucket = (List)buckets.get(key);
+ Label next = null;
+ if (skipEquals && bucket.size() == 1) {
+ if (skipEquals)
+ e.pop();
+ callback.processCase((String)bucket.get(0), end);
+ } else {
+ for (Iterator it = bucket.iterator(); it.hasNext();) {
+ String string = (String)it.next();
+ if (next != null) {
+ e.mark(next);
+ }
+ if (it.hasNext()) {
+ e.dup();
+ }
+ e.push(string);
+ e.invoke_virtual(Constants.TYPE_OBJECT, EQUALS);
+ if (it.hasNext()) {
+ e.if_jump(e.EQ, next = e.make_label());
+ e.pop();
+ } else {
+ e.if_jump(e.EQ, def);
+ }
+ callback.processCase(string, end);
+ }
+ }
+ }
+ public void processDefault() {
+ e.pop();
+ }
+ });
+ e.mark(def);
+ callback.processDefault();
+ e.mark(end);
+ }
+
+ public static void load_class_this(CodeEmitter e) {
+ load_class_helper(e, e.getClassEmitter().getClassType());
+ }
+
+ public static void load_class(CodeEmitter e, Type type) {
+ if (TypeUtils.isPrimitive(type)) {
+ if (type == Type.VOID_TYPE) {
+ throw new IllegalArgumentException("cannot load void type");
+ }
+ e.getstatic(TypeUtils.getBoxedType(type), "TYPE", Constants.TYPE_CLASS);
+ } else {
+ load_class_helper(e, type);
+ }
+ }
+
+ private static void load_class_helper(CodeEmitter e, final Type type) {
+ if (e.isStaticHook()) {
+ // have to fall back on non-optimized load
+ e.push(TypeUtils.emulateClassGetName(type));
+ e.invoke_static(Constants.TYPE_CLASS, FOR_NAME);
+ } else {
+ ClassEmitter ce = e.getClassEmitter();
+ String typeName = TypeUtils.emulateClassGetName(type);
+
+ // TODO: can end up with duplicated field names when using chained transformers; incorporate static hook # somehow
+ String fieldName = "CGLIB$load_class$" + TypeUtils.escapeType(typeName);
+ if (!ce.isFieldDeclared(fieldName)) {
+ ce.declare_field(Constants.PRIVATE_FINAL_STATIC, fieldName, Constants.TYPE_CLASS, null);
+ CodeEmitter hook = ce.getStaticHook();
+ hook.push(typeName);
+ hook.invoke_static(Constants.TYPE_CLASS, FOR_NAME);
+ hook.putstatic(ce.getClassType(), fieldName, Constants.TYPE_CLASS);
+ }
+ e.getfield(fieldName);
+ }
+ }
+
+ public static void push_array(CodeEmitter e, Object[] array) {
+ e.push(array.length);
+ e.newarray(Type.getType(remapComponentType(array.getClass().getComponentType())));
+ for (int i = 0; i < array.length; i++) {
+ e.dup();
+ e.push(i);
+ push_object(e, array[i]);
+ e.aastore();
+ }
+ }
+
+ private static Class remapComponentType(Class componentType) {
+ if (componentType.equals(Type.class))
+ return Class.class;
+ return componentType;
+ }
+
+ public static void push_object(CodeEmitter e, Object obj) {
+ if (obj == null) {
+ e.aconst_null();
+ } else {
+ Class type = obj.getClass();
+ if (type.isArray()) {
+ push_array(e, (Object[])obj);
+ } else if (obj instanceof String) {
+ e.push((String)obj);
+ } else if (obj instanceof Type) {
+ load_class(e, (Type)obj);
+ } else if (obj instanceof Class) {
+ load_class(e, Type.getType((Class)obj));
+ } else if (obj instanceof BigInteger) {
+ e.new_instance(Constants.TYPE_BIG_INTEGER);
+ e.dup();
+ e.push(obj.toString());
+ e.invoke_constructor(Constants.TYPE_BIG_INTEGER);
+ } else if (obj instanceof BigDecimal) {
+ e.new_instance(Constants.TYPE_BIG_DECIMAL);
+ e.dup();
+ e.push(obj.toString());
+ e.invoke_constructor(Constants.TYPE_BIG_DECIMAL);
+ } else {
+ throw new IllegalArgumentException("unknown type: " + obj.getClass());
+ }
+ }
+ }
+
+ /**
+ * @deprecated use {@link #hash_code(CodeEmitter, Type, int, CustomizerRegistry)} instead
+ */
+ @Deprecated
+ public static void hash_code(CodeEmitter e, Type type, int multiplier, final Customizer customizer) {
+ hash_code(e, type, multiplier, CustomizerRegistry.singleton(customizer));
+ }
+
+ public static void hash_code(CodeEmitter e, Type type, int multiplier, final CustomizerRegistry registry) {
+ if (TypeUtils.isArray(type)) {
+ hash_array(e, type, multiplier, registry);
+ } else {
+ e.swap(Type.INT_TYPE, type);
+ e.push(multiplier);
+ e.math(e.MUL, Type.INT_TYPE);
+ e.swap(type, Type.INT_TYPE);
+ if (TypeUtils.isPrimitive(type)) {
+ hash_primitive(e, type);
+ } else {
+ hash_object(e, type, registry);
+ }
+ e.math(e.ADD, Type.INT_TYPE);
+ }
+ }
+
+ private static void hash_array(final CodeEmitter e, Type type, final int multiplier, final CustomizerRegistry registry) {
+ Label skip = e.make_label();
+ Label end = e.make_label();
+ e.dup();
+ e.ifnull(skip);
+ EmitUtils.process_array(e, type, new ProcessArrayCallback() {
+ public void processElement(Type type) {
+ hash_code(e, type, multiplier, registry);
+ }
+ });
+ e.goTo(end);
+ e.mark(skip);
+ e.pop();
+ e.mark(end);
+ }
+
+ private static void hash_object(CodeEmitter e, Type type, CustomizerRegistry registry) {
+ // (f == null) ? 0 : f.hashCode();
+ Label skip = e.make_label();
+ Label end = e.make_label();
+ e.dup();
+ e.ifnull(skip);
+ boolean customHashCode = false;
+ for (HashCodeCustomizer customizer : registry.get(HashCodeCustomizer.class)) {
+ if (customizer.customize(e, type)) {
+ customHashCode = true;
+ break;
+ }
+ }
+ if (!customHashCode) {
+ for (Customizer customizer : registry.get(Customizer.class)) {
+ customizer.customize(e, type);
+ }
+ e.invoke_virtual(Constants.TYPE_OBJECT, HASH_CODE);
+ }
+ e.goTo(end);
+ e.mark(skip);
+ e.pop();
+ e.push(0);
+ e.mark(end);
+ }
+
+ private static void hash_primitive(CodeEmitter e, Type type) {
+ switch (type.getSort()) {
+ case Type.BOOLEAN:
+ // f ? 0 : 1
+ e.push(1);
+ e.math(e.XOR, Type.INT_TYPE);
+ break;
+ case Type.FLOAT:
+ // Float.floatToIntBits(f)
+ e.invoke_static(Constants.TYPE_FLOAT, FLOAT_TO_INT_BITS);
+ break;
+ case Type.DOUBLE:
+ // Double.doubleToLongBits(f), hash_code(Long.TYPE)
+ e.invoke_static(Constants.TYPE_DOUBLE, DOUBLE_TO_LONG_BITS);
+ // fall through
+ case Type.LONG:
+ hash_long(e);
+ }
+ }
+
+ private static void hash_long(CodeEmitter e) {
+ // (int)(f ^ (f >>> 32))
+ e.dup2();
+ e.push(32);
+ e.math(e.USHR, Type.LONG_TYPE);
+ e.math(e.XOR, Type.LONG_TYPE);
+ e.cast_numeric(Type.LONG_TYPE, Type.INT_TYPE);
+ }
+
+// public static void not_equals(CodeEmitter e, Type type, Label notEquals) {
+// not_equals(e, type, notEquals, null);
+// }
+
+ /**
+ * @deprecated use {@link #not_equals(CodeEmitter, Type, Label, CustomizerRegistry)} instead
+ */
+ @Deprecated
+ public static void not_equals(CodeEmitter e, Type type, final Label notEquals, final Customizer customizer) {
+ not_equals(e, type, notEquals, CustomizerRegistry.singleton(customizer));
+ }
+
+ /**
+ * Branches to the specified label if the top two items on the stack
+ * are not equal. The items must both be of the specified
+ * class. Equality is determined by comparing primitive values
+ * directly and by invoking the equals method for
+ * Objects. Arrays are recursively processed in the same manner.
+ */
+ public static void not_equals(final CodeEmitter e, Type type, final Label notEquals, final CustomizerRegistry registry) {
+ (new ProcessArrayCallback() {
+ public void processElement(Type type) {
+ not_equals_helper(e, type, notEquals, registry, this);
+ }
+ }).processElement(type);
+ }
+
+ private static void not_equals_helper(CodeEmitter e,
+ Type type,
+ Label notEquals,
+ CustomizerRegistry registry,
+ ProcessArrayCallback callback) {
+ if (TypeUtils.isPrimitive(type)) {
+ e.if_cmp(type, e.NE, notEquals);
+ } else {
+ Label end = e.make_label();
+ nullcmp(e, notEquals, end);
+ if (TypeUtils.isArray(type)) {
+ Label checkContents = e.make_label();
+ e.dup2();
+ e.arraylength();
+ e.swap();
+ e.arraylength();
+ e.if_icmp(e.EQ, checkContents);
+ e.pop2();
+ e.goTo(notEquals);
+ e.mark(checkContents);
+ EmitUtils.process_arrays(e, type, callback);
+ } else {
+ ListGeneratorStrategyClass. By providing your
+ * own strategy you may examine or modify the generated class before
+ * it is loaded. Typically this will be accomplished by subclassing
+ * {@link DefaultGeneratorStrategy} and overriding the appropriate
+ * protected method.
+ * @see AbstractClassGenerator#setStrategy
+ */
+public interface GeneratorStrategy {
+ /**
+ * Generate the class.
+ * @param cg a class generator on which you can call {@link ClassGenerator#generateClass}
+ * @return a byte array containing the bits of a valid Class
+ */
+ byte[] generate(ClassGenerator cg) throws Exception;
+
+ /**
+ * The GeneratorStrategy in use does not currently, but may
+ * in the future, affect the caching of classes generated by {@link
+ * AbstractClassGenerator}, so this is a reminder that you should
+ * correctly implement equals and hashCode
+ * to avoid generating too many classes.
+ */
+ boolean equals(Object o);
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/core/HashCodeCustomizer.java b/spring-core/src/main/java/org/springframework/cglib/core/HashCodeCustomizer.java
new file mode 100644
index 0000000000..21899023d4
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/core/HashCodeCustomizer.java
@@ -0,0 +1,12 @@
+package org.springframework.cglib.core;
+
+import org.springframework.asm.Type;
+
+public interface HashCodeCustomizer extends KeyFactoryCustomizer {
+ /**
+ * Customizes calculation of hashcode
+ * @param e code emitter
+ * @param type parameter type
+ */
+ boolean customize(CodeEmitter e, Type type);
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/core/KeyFactoryCustomizer.java b/spring-core/src/main/java/org/springframework/cglib/core/KeyFactoryCustomizer.java
new file mode 100644
index 0000000000..54f23bf679
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/core/KeyFactoryCustomizer.java
@@ -0,0 +1,7 @@
+package org.springframework.cglib.core;
+
+/**
+ * Marker interface for customizers of {@link KeyFactory}
+ */
+public interface KeyFactoryCustomizer {
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/core/Local.java b/spring-core/src/main/java/org/springframework/cglib/core/Local.java
new file mode 100644
index 0000000000..93c2d22f35
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/core/Local.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2003 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.core;
+
+import org.springframework.asm.Type;
+
+public class Local
+{
+ private Type type;
+ private int index;
+
+ public Local(int index, Type type) {
+ this.type = type;
+ this.index = index;
+ }
+
+ public int getIndex() {
+ return index;
+ }
+
+ public Type getType() {
+ return type;
+ }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/core/LocalVariablesSorter.java b/spring-core/src/main/java/org/springframework/cglib/core/LocalVariablesSorter.java
new file mode 100644
index 0000000000..d3cdd9d548
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/core/LocalVariablesSorter.java
@@ -0,0 +1,158 @@
+/***
+ * ASM: a very small and fast Java bytecode manipulation framework
+ * Copyright (c) 2000-2005 INRIA, France Telecom
+ * 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 the copyright holders 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 OWNER 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 org.springframework.cglib.core;
+
+import org.springframework.asm.Label;
+import org.springframework.asm.MethodVisitor;
+import org.springframework.asm.Opcodes;
+import org.springframework.asm.Type;
+
+/**
+ * A {@link MethodVisitor} that renumbers local variables in their order of
+ * appearance. This adapter allows one to easily add new local variables to a
+ * method.
+ *
+ * @author Chris Nokleberg
+ * @author Eric Bruneton
+ */
+public class LocalVariablesSorter extends MethodVisitor {
+
+ /**
+ * Mapping from old to new local variable indexes. A local variable at index
+ * i of size 1 is remapped to 'mapping[2*i]', while a local variable at
+ * index i of size 2 is remapped to 'mapping[2*i+1]'.
+ */
+ private static class State
+ {
+ int[] mapping = new int[40];
+ int nextLocal;
+ }
+
+ protected final int firstLocal;
+ private final State state;
+
+ public LocalVariablesSorter(
+ final int access,
+ final String desc,
+ final MethodVisitor mv)
+ {
+ super(Constants.ASM_API, mv);
+ state = new State();
+ Type[] args = Type.getArgumentTypes(desc);
+ state.nextLocal = ((Opcodes.ACC_STATIC & access) != 0) ? 0 : 1;
+ for (int i = 0; i < args.length; i++) {
+ state.nextLocal += args[i].getSize();
+ }
+ firstLocal = state.nextLocal;
+ }
+
+ public LocalVariablesSorter(LocalVariablesSorter lvs) {
+ super(Constants.ASM_API, lvs.mv);
+ state = lvs.state;
+ firstLocal = lvs.firstLocal;
+ }
+
+ public void visitVarInsn(final int opcode, final int var) {
+ int size;
+ switch (opcode) {
+ case Opcodes.LLOAD:
+ case Opcodes.LSTORE:
+ case Opcodes.DLOAD:
+ case Opcodes.DSTORE:
+ size = 2;
+ break;
+ default:
+ size = 1;
+ }
+ mv.visitVarInsn(opcode, remap(var, size));
+ }
+
+ public void visitIincInsn(final int var, final int increment) {
+ mv.visitIincInsn(remap(var, 1), increment);
+ }
+
+ public void visitMaxs(final int maxStack, final int maxLocals) {
+ mv.visitMaxs(maxStack, state.nextLocal);
+ }
+
+ public void visitLocalVariable(
+ final String name,
+ final String desc,
+ final String signature,
+ final Label start,
+ final Label end,
+ final int index)
+ {
+ mv.visitLocalVariable(name, desc, signature, start, end, remap(index));
+ }
+
+ // -------------
+
+ protected int newLocal(final int size) {
+ int var = state.nextLocal;
+ state.nextLocal += size;
+ return var;
+ }
+
+ private int remap(final int var, final int size) {
+ if (var < firstLocal) {
+ return var;
+ }
+ int key = 2 * var + size - 1;
+ int length = state.mapping.length;
+ if (key >= length) {
+ int[] newMapping = new int[Math.max(2 * length, key + 1)];
+ System.arraycopy(state.mapping, 0, newMapping, 0, length);
+ state.mapping = newMapping;
+ }
+ int value = state.mapping[key];
+ if (value == 0) {
+ value = state.nextLocal + 1;
+ state.mapping[key] = value;
+ state.nextLocal += size;
+ }
+ return value - 1;
+ }
+
+ private int remap(final int var) {
+ if (var < firstLocal) {
+ return var;
+ }
+ int key = 2 * var;
+ int value = key < state.mapping.length ? state.mapping[key] : 0;
+ if (value == 0) {
+ value = key + 1 < state.mapping.length ? state.mapping[key + 1] : 0;
+ }
+ if (value == 0) {
+ throw new IllegalStateException("Unknown local variable " + var);
+ }
+ return value - 1;
+ }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/core/MethodInfo.java b/spring-core/src/main/java/org/springframework/cglib/core/MethodInfo.java
new file mode 100644
index 0000000000..2f54aea276
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/core/MethodInfo.java
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.core;
+
+import org.springframework.asm.Attribute;
+import org.springframework.asm.Type;
+
+abstract public class MethodInfo {
+
+ protected MethodInfo() {
+ }
+
+ abstract public ClassInfo getClassInfo();
+ abstract public int getModifiers();
+ abstract public Signature getSignature();
+ abstract public Type[] getExceptionTypes();
+
+ public boolean equals(Object o) {
+ if (o == null)
+ return false;
+ if (!(o instanceof MethodInfo))
+ return false;
+ return getSignature().equals(((MethodInfo)o).getSignature());
+ }
+
+ public int hashCode() {
+ return getSignature().hashCode();
+ }
+
+ public String toString() {
+ // TODO: include modifiers, exceptions
+ return getSignature().toString();
+ }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/core/MethodInfoTransformer.java b/spring-core/src/main/java/org/springframework/cglib/core/MethodInfoTransformer.java
new file mode 100644
index 0000000000..2ddad07de8
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/core/MethodInfoTransformer.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.core;
+
+import java.lang.reflect.*;
+
+public class MethodInfoTransformer implements Transformer
+{
+ private static final MethodInfoTransformer INSTANCE = new MethodInfoTransformer();
+
+ public static MethodInfoTransformer getInstance() {
+ return INSTANCE;
+ }
+
+ public Object transform(Object value) {
+ if (value instanceof Method) {
+ return ReflectUtils.getMethodInfo((Method)value);
+ } else if (value instanceof Constructor) {
+ return ReflectUtils.getMethodInfo((Constructor)value);
+ } else {
+ throw new IllegalArgumentException("cannot get method info for " + value);
+ }
+ }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/core/NamingPolicy.java b/spring-core/src/main/java/org/springframework/cglib/core/NamingPolicy.java
new file mode 100644
index 0000000000..152e891641
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/core/NamingPolicy.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2003 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.core;
+
+import java.util.Set;
+
+/**
+ * Customize the generated class name for {@link AbstractClassGenerator}-based utilities.
+ */
+public interface NamingPolicy {
+ /**
+ * Choose a name for a generated class.
+ * @param prefix a dotted-name chosen by the generating class (possibly to put the generated class in a particular package)
+ * @param source the fully-qualified class name of the generating class (for example "org.springframework.cglib.Enhancer")
+ * @param key A key object representing the state of the parameters; for caching to work properly, equal keys should result
+ * in the same generated class name. The default policy incorporates key.hashCode() into the class name.
+ * @param names a predicate that returns true if the given classname has already been used in the same ClassLoader.
+ * @return the fully-qualified class name
+ */
+ String getClassName(String prefix, String source, Object key, Predicate names);
+
+ /**
+ * The NamingPolicy in use does not currently, but may
+ * in the future, affect the caching of classes generated by {@link
+ * AbstractClassGenerator}, so this is a reminder that you should
+ * correctly implement equals and hashCode
+ * to avoid generating too many classes.
+ */
+ boolean equals(Object o);
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/core/ObjectSwitchCallback.java b/spring-core/src/main/java/org/springframework/cglib/core/ObjectSwitchCallback.java
new file mode 100644
index 0000000000..0fc3496913
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/core/ObjectSwitchCallback.java
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2003 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.core;
+
+import org.springframework.asm.Label;
+
+public interface ObjectSwitchCallback {
+ void processCase(Object key, Label end) throws Exception;
+ void processDefault() throws Exception;
+}
+
diff --git a/spring-core/src/main/java/org/springframework/cglib/core/Predicate.java b/spring-core/src/main/java/org/springframework/cglib/core/Predicate.java
new file mode 100644
index 0000000000..dad9ae37b9
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/core/Predicate.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2003 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.core;
+
+public interface Predicate {
+ boolean evaluate(Object arg);
+}
+
diff --git a/spring-core/src/main/java/org/springframework/cglib/core/ProcessArrayCallback.java b/spring-core/src/main/java/org/springframework/cglib/core/ProcessArrayCallback.java
new file mode 100644
index 0000000000..da8eadbdfb
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/core/ProcessArrayCallback.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2003 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.core;
+
+import org.springframework.asm.Type;
+
+public interface ProcessArrayCallback {
+ void processElement(Type type);
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/core/ProcessSwitchCallback.java b/spring-core/src/main/java/org/springframework/cglib/core/ProcessSwitchCallback.java
new file mode 100644
index 0000000000..1178dcb98e
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/core/ProcessSwitchCallback.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2003 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.core;
+
+import org.springframework.asm.Label;
+
+public interface ProcessSwitchCallback {
+ void processCase(int key, Label end) throws Exception;
+ void processDefault() throws Exception;
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/core/RejectModifierPredicate.java b/spring-core/src/main/java/org/springframework/cglib/core/RejectModifierPredicate.java
new file mode 100644
index 0000000000..5bcdb3ae00
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/core/RejectModifierPredicate.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.core;
+
+import java.lang.reflect.*;
+
+public class RejectModifierPredicate implements Predicate {
+ private int rejectMask;
+
+ public RejectModifierPredicate(int rejectMask) {
+ this.rejectMask = rejectMask;
+ }
+
+ public boolean evaluate(Object arg) {
+ return (((Member)arg).getModifiers() & rejectMask) == 0;
+ }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/core/Signature.java b/spring-core/src/main/java/org/springframework/cglib/core/Signature.java
new file mode 100644
index 0000000000..ab040ad69c
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/core/Signature.java
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2003 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.core;
+
+import org.springframework.asm.Type;
+
+/**
+ * A representation of a method signature, containing the method name,
+ * return type, and parameter types.
+ */
+public class Signature {
+ private String name;
+ private String desc;
+
+ public Signature(String name, String desc) {
+ // TODO: better error checking
+ if (name.indexOf('(') >= 0) {
+ throw new IllegalArgumentException("Name '" + name + "' is invalid");
+ }
+ this.name = name;
+ this.desc = desc;
+ }
+
+ public Signature(String name, Type returnType, Type[] argumentTypes) {
+ this(name, Type.getMethodDescriptor(returnType, argumentTypes));
+ }
+
+ public String getName() {
+ return name;
+ }
+
+ public String getDescriptor() {
+ return desc;
+ }
+
+ public Type getReturnType() {
+ return Type.getReturnType(desc);
+ }
+
+ public Type[] getArgumentTypes() {
+ return Type.getArgumentTypes(desc);
+ }
+
+ public String toString() {
+ return name + desc;
+ }
+
+ public boolean equals(Object o) {
+ if (o == null)
+ return false;
+ if (!(o instanceof Signature))
+ return false;
+ Signature other = (Signature)o;
+ return name.equals(other.name) && desc.equals(other.desc);
+ }
+
+ public int hashCode() {
+ return name.hashCode() ^ desc.hashCode();
+ }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/core/TinyBitSet.java b/spring-core/src/main/java/org/springframework/cglib/core/TinyBitSet.java
new file mode 100644
index 0000000000..52a273fd34
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/core/TinyBitSet.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2003 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.core;
+
+@Deprecated
+public class TinyBitSet {
+ private static int[] T = new int[256];
+ private int value = 0;
+
+ private static int gcount(int x) {
+ int c = 0;
+ while (x != 0) {
+ c++;
+ x &= (x - 1);
+ }
+ return c;
+ }
+
+ static {
+ for (int j = 0; j < 256; j++) {
+ T[j] = gcount(j);
+ }
+ }
+
+ private static int topbit(int i) {
+ int j;
+ for (j = 0; i != 0; i ^= j) {
+ j = i & -i;
+ }
+ return j;
+ }
+
+ private static int log2(int i) {
+ int j = 0;
+ for (j = 0; i != 0; i >>= 1) {
+ j++;
+ }
+ return j;
+ }
+
+ public int length() {
+ return log2(topbit(value));
+ }
+
+ /**
+ * If bit 31 is set then this method results in an infinite loop.
+ *
+ * @return the number of bits set to true in this TinyBitSet.
+ */
+ public int cardinality() {
+ int w = value;
+ int c = 0;
+ while (w != 0) {
+ c += T[w & 255];
+ w >>= 8;
+ }
+ return c;
+ }
+
+ public boolean get(int index) {
+ return (value & (1 << index)) != 0;
+ }
+
+ public void set(int index) {
+ value |= (1 << index);
+ }
+
+ public void clear(int index) {
+ value &= ~(1 << index);
+ }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/core/Transformer.java b/spring-core/src/main/java/org/springframework/cglib/core/Transformer.java
new file mode 100644
index 0000000000..cdbfef8473
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/core/Transformer.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2003 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.core;
+
+public interface Transformer {
+ Object transform(Object value);
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/core/TypeUtils.java b/spring-core/src/main/java/org/springframework/cglib/core/TypeUtils.java
new file mode 100644
index 0000000000..1a34e246cf
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/core/TypeUtils.java
@@ -0,0 +1,422 @@
+/*
+ * Copyright 2003,2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.core;
+
+import java.util.*;
+import org.springframework.asm.Type;
+
+@SuppressWarnings({"rawtypes", "unchecked"})
+public class TypeUtils {
+ private static final Map transforms = new HashMap();
+ private static final Map rtransforms = new HashMap();
+
+ private TypeUtils() {
+ }
+
+ static {
+ transforms.put("void", "V");
+ transforms.put("byte", "B");
+ transforms.put("char", "C");
+ transforms.put("double", "D");
+ transforms.put("float", "F");
+ transforms.put("int", "I");
+ transforms.put("long", "J");
+ transforms.put("short", "S");
+ transforms.put("boolean", "Z");
+
+ CollectionUtils.reverse(transforms, rtransforms);
+ }
+
+ public static Type getType(String className) {
+ return Type.getType("L" + className.replace('.', '/') + ";");
+ }
+
+ public static boolean isFinal(int access) {
+ return (Constants.ACC_FINAL & access) != 0;
+ }
+
+ public static boolean isStatic(int access) {
+ return (Constants.ACC_STATIC & access) != 0;
+ }
+
+ public static boolean isProtected(int access) {
+ return (Constants.ACC_PROTECTED & access) != 0;
+ }
+
+ public static boolean isPublic(int access) {
+ return (Constants.ACC_PUBLIC & access) != 0;
+ }
+
+ public static boolean isAbstract(int access) {
+ return (Constants.ACC_ABSTRACT & access) != 0;
+ }
+
+ public static boolean isInterface(int access) {
+ return (Constants.ACC_INTERFACE & access) != 0;
+ }
+
+ public static boolean isPrivate(int access) {
+ return (Constants.ACC_PRIVATE & access) != 0;
+ }
+
+ public static boolean isSynthetic(int access) {
+ return (Constants.ACC_SYNTHETIC & access) != 0;
+ }
+
+ public static boolean isBridge(int access) {
+ return (Constants.ACC_BRIDGE & access) != 0;
+ }
+
+ // getPackage returns null on JDK 1.2
+ public static String getPackageName(Type type) {
+ return getPackageName(getClassName(type));
+ }
+
+ public static String getPackageName(String className) {
+ int idx = className.lastIndexOf('.');
+ return (idx < 0) ? "" : className.substring(0, idx);
+ }
+
+ public static String upperFirst(String s) {
+ if (s == null || s.length() == 0) {
+ return s;
+ }
+ return Character.toUpperCase(s.charAt(0)) + s.substring(1);
+ }
+
+ public static String getClassName(Type type) {
+ if (isPrimitive(type)) {
+ return (String)rtransforms.get(type.getDescriptor());
+ } else if (isArray(type)) {
+ return getClassName(getComponentType(type)) + "[]";
+ } else {
+ return type.getClassName();
+ }
+ }
+
+ public static Type[] add(Type[] types, Type extra) {
+ if (types == null) {
+ return new Type[]{ extra };
+ } else {
+ List list = Arrays.asList(types);
+ if (list.contains(extra)) {
+ return types;
+ }
+ Type[] copy = new Type[types.length + 1];
+ System.arraycopy(types, 0, copy, 0, types.length);
+ copy[types.length] = extra;
+ return copy;
+ }
+ }
+
+ public static Type[] add(Type[] t1, Type[] t2) {
+ // TODO: set semantics?
+ Type[] all = new Type[t1.length + t2.length];
+ System.arraycopy(t1, 0, all, 0, t1.length);
+ System.arraycopy(t2, 0, all, t1.length, t2.length);
+ return all;
+ }
+
+ public static Type fromInternalName(String name) {
+ // TODO; primitives?
+ return Type.getType("L" + name + ";");
+ }
+
+ public static Type[] fromInternalNames(String[] names) {
+ if (names == null) {
+ return null;
+ }
+ Type[] types = new Type[names.length];
+ for (int i = 0; i < names.length; i++) {
+ types[i] = fromInternalName(names[i]);
+ }
+ return types;
+ }
+
+ public static int getStackSize(Type[] types) {
+ int size = 0;
+ for (int i = 0; i < types.length; i++) {
+ size += types[i].getSize();
+ }
+ return size;
+ }
+
+ public static String[] toInternalNames(Type[] types) {
+ if (types == null) {
+ return null;
+ }
+ String[] names = new String[types.length];
+ for (int i = 0; i < types.length; i++) {
+ names[i] = types[i].getInternalName();
+ }
+ return names;
+ }
+
+ public static Signature parseSignature(String s) {
+ int space = s.indexOf(' ');
+ int lparen = s.indexOf('(', space);
+ int rparen = s.indexOf(')', lparen);
+ String returnType = s.substring(0, space);
+ String methodName = s.substring(space + 1, lparen);
+ StringBuffer sb = new StringBuffer();
+ sb.append('(');
+ for (Iterator it = parseTypes(s, lparen + 1, rparen).iterator(); it.hasNext();) {
+ sb.append(it.next());
+ }
+ sb.append(')');
+ sb.append(map(returnType));
+ return new Signature(methodName, sb.toString());
+ }
+
+ public static Type parseType(String s) {
+ return Type.getType(map(s));
+ }
+
+ public static Type[] parseTypes(String s) {
+ List names = parseTypes(s, 0, s.length());
+ Type[] types = new Type[names.size()];
+ for (int i = 0; i < types.length; i++) {
+ types[i] = Type.getType((String)names.get(i));
+ }
+ return types;
+ }
+
+ public static Signature parseConstructor(Type[] types) {
+ StringBuffer sb = new StringBuffer();
+ sb.append("(");
+ for (int i = 0; i < types.length; i++) {
+ sb.append(types[i].getDescriptor());
+ }
+ sb.append(")");
+ sb.append("V");
+ return new Signature(Constants.CONSTRUCTOR_NAME, sb.toString());
+ }
+
+ public static Signature parseConstructor(String sig) {
+ return parseSignature("void CallbackFilter in use affects which cached class
+ * the Enhancer will use, so this is a reminder that
+ * you should correctly implement equals and
+ * hashCode for custom CallbackFilter
+ * implementations in order to improve performance.
+ */
+ boolean equals(Object o);
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/proxy/CallbackGenerator.java b/spring-core/src/main/java/org/springframework/cglib/proxy/CallbackGenerator.java
new file mode 100644
index 0000000000..168dab3b11
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/proxy/CallbackGenerator.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2003,2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.proxy;
+
+import java.util.List;
+import org.springframework.cglib.core.*;
+
+@SuppressWarnings({"rawtypes", "unchecked"})
+interface CallbackGenerator
+{
+ void generate(ClassEmitter ce, Context context, List methods) throws Exception;
+ void generateStatic(CodeEmitter e, Context context, List methods) throws Exception;
+
+ interface Context
+ {
+ ClassLoader getClassLoader();
+ CodeEmitter beginMethod(ClassEmitter ce, MethodInfo method);
+ int getOriginalModifiers(MethodInfo method);
+ int getIndex(MethodInfo method);
+ void emitCallback(CodeEmitter ce, int index);
+ Signature getImplSignature(MethodInfo method);
+ void emitLoadArgsAndInvoke(CodeEmitter e, MethodInfo method);
+ }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/proxy/CallbackHelper.java b/spring-core/src/main/java/org/springframework/cglib/proxy/CallbackHelper.java
new file mode 100644
index 0000000000..9aa54f0728
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/proxy/CallbackHelper.java
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.proxy;
+
+import org.springframework.cglib.core.ReflectUtils;
+import java.lang.reflect.Method;
+import java.util.*;
+
+/**
+ * @version $Id: CallbackHelper.java,v 1.2 2004/06/24 21:15:20 herbyderby Exp $
+ */
+@SuppressWarnings({"rawtypes", "unchecked"})
+abstract public class CallbackHelper
+implements CallbackFilter
+{
+ private Map methodMap = new HashMap();
+ private List callbacks = new ArrayList();
+
+ public CallbackHelper(Class superclass, Class[] interfaces)
+ {
+ List methods = new ArrayList();
+ Enhancer.getMethods(superclass, interfaces, methods);
+ Map indexes = new HashMap();
+ for (int i = 0, size = methods.size(); i < size; i++) {
+ Method method = (Method)methods.get(i);
+ Object callback = getCallback(method);
+ if (callback == null)
+ throw new IllegalStateException("getCallback cannot return null");
+ boolean isCallback = callback instanceof Callback;
+ if (!(isCallback || (callback instanceof Class)))
+ throw new IllegalStateException("getCallback must return a Callback or a Class");
+ if (i > 0 && ((callbacks.get(i - 1) instanceof Callback) ^ isCallback))
+ throw new IllegalStateException("getCallback must return a Callback or a Class consistently for every Method");
+ Integer index = (Integer)indexes.get(callback);
+ if (index == null) {
+ index = callbacks.size();
+ indexes.put(callback, index);
+ }
+ methodMap.put(method, index);
+ callbacks.add(callback);
+ }
+ }
+
+ abstract protected Object getCallback(Method method);
+
+ public Callback[] getCallbacks()
+ {
+ if (callbacks.size() == 0)
+ return new Callback[0];
+ if (callbacks.get(0) instanceof Callback) {
+ return (Callback[])callbacks.toArray(new Callback[callbacks.size()]);
+ } else {
+ throw new IllegalStateException("getCallback returned classes, not callbacks; call getCallbackTypes instead");
+ }
+ }
+
+ public Class[] getCallbackTypes()
+ {
+ if (callbacks.size() == 0)
+ return new Class[0];
+ if (callbacks.get(0) instanceof Callback) {
+ return ReflectUtils.getClasses(getCallbacks());
+ } else {
+ return (Class[])callbacks.toArray(new Class[callbacks.size()]);
+ }
+ }
+
+ public int accept(Method method)
+ {
+ return ((Integer)methodMap.get(method)).intValue();
+ }
+
+ public int hashCode()
+ {
+ return methodMap.hashCode();
+ }
+
+ public boolean equals(Object o)
+ {
+ if (o == null)
+ return false;
+ if (!(o instanceof CallbackHelper))
+ return false;
+ return methodMap.equals(((CallbackHelper)o).methodMap);
+ }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/proxy/CallbackInfo.java b/spring-core/src/main/java/org/springframework/cglib/proxy/CallbackInfo.java
new file mode 100644
index 0000000000..e1a5cbc5bb
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/proxy/CallbackInfo.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.proxy;
+
+import org.springframework.asm.Type;
+
+@SuppressWarnings({"rawtypes", "unchecked"})
+class CallbackInfo
+{
+ public static Type[] determineTypes(Class[] callbackTypes) {
+ return determineTypes(callbackTypes, true);
+ }
+
+ public static Type[] determineTypes(Class[] callbackTypes, boolean checkAll) {
+ Type[] types = new Type[callbackTypes.length];
+ for (int i = 0; i < types.length; i++) {
+ types[i] = determineType(callbackTypes[i], checkAll);
+ }
+ return types;
+ }
+
+ public static Type[] determineTypes(Callback[] callbacks) {
+ return determineTypes(callbacks, true);
+ }
+
+ public static Type[] determineTypes(Callback[] callbacks, boolean checkAll) {
+ Type[] types = new Type[callbacks.length];
+ for (int i = 0; i < types.length; i++) {
+ types[i] = determineType(callbacks[i], checkAll);
+ }
+ return types;
+ }
+
+ public static CallbackGenerator[] getGenerators(Type[] callbackTypes) {
+ CallbackGenerator[] generators = new CallbackGenerator[callbackTypes.length];
+ for (int i = 0; i < generators.length; i++) {
+ generators[i] = getGenerator(callbackTypes[i]);
+ }
+ return generators;
+ }
+
+ //////////////////// PRIVATE ////////////////////
+
+ private Class cls;
+ private CallbackGenerator generator;
+ private Type type;
+
+ private static final CallbackInfo[] CALLBACKS = {
+ new CallbackInfo(NoOp.class, NoOpGenerator.INSTANCE),
+ new CallbackInfo(MethodInterceptor.class, MethodInterceptorGenerator.INSTANCE),
+ new CallbackInfo(InvocationHandler.class, InvocationHandlerGenerator.INSTANCE),
+ new CallbackInfo(LazyLoader.class, LazyLoaderGenerator.INSTANCE),
+ new CallbackInfo(Dispatcher.class, DispatcherGenerator.INSTANCE),
+ new CallbackInfo(FixedValue.class, FixedValueGenerator.INSTANCE),
+ new CallbackInfo(ProxyRefDispatcher.class, DispatcherGenerator.PROXY_REF_INSTANCE),
+ };
+
+ private CallbackInfo(Class cls, CallbackGenerator generator) {
+ this.cls = cls;
+ this.generator = generator;
+ type = Type.getType(cls);
+ }
+
+ private static Type determineType(Callback callback, boolean checkAll) {
+ if (callback == null) {
+ throw new IllegalStateException("Callback is null");
+ }
+ return determineType(callback.getClass(), checkAll);
+ }
+
+ private static Type determineType(Class callbackType, boolean checkAll) {
+ Class cur = null;
+ Type type = null;
+ for (int i = 0; i < CALLBACKS.length; i++) {
+ CallbackInfo info = CALLBACKS[i];
+ if (info.cls.isAssignableFrom(callbackType)) {
+ if (cur != null) {
+ throw new IllegalStateException("Callback implements both " + cur + " and " + info.cls);
+ }
+ cur = info.cls;
+ type = info.type;
+ if (!checkAll) {
+ break;
+ }
+ }
+ }
+ if (cur == null) {
+ throw new IllegalStateException("Unknown callback type " + callbackType);
+ }
+ return type;
+ }
+
+ private static CallbackGenerator getGenerator(Type callbackType) {
+ for (int i = 0; i < CALLBACKS.length; i++) {
+ CallbackInfo info = CALLBACKS[i];
+ if (info.type.equals(callbackType)) {
+ return info.generator;
+ }
+ }
+ throw new IllegalStateException("Unknown callback type " + callbackType);
+ }
+}
+
+
diff --git a/spring-core/src/main/java/org/springframework/cglib/proxy/Dispatcher.java b/spring-core/src/main/java/org/springframework/cglib/proxy/Dispatcher.java
new file mode 100644
index 0000000000..c090f0cc44
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/proxy/Dispatcher.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2003 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.proxy;
+
+/**
+ * Dispatching {@link Enhancer} callback. This is identical to the
+ * {@link LazyLoader} interface but needs to be separate so that Enhancer
+ * knows which type of code to generate.
+ */
+public interface Dispatcher extends Callback {
+ /**
+ * Return the object which the original method invocation should
+ * be dispatched. This method is called for every method invocation.
+ * @return an object that can invoke the method
+ */
+ Object loadObject() throws Exception;
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/proxy/DispatcherGenerator.java b/spring-core/src/main/java/org/springframework/cglib/proxy/DispatcherGenerator.java
new file mode 100644
index 0000000000..154f7d7363
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/proxy/DispatcherGenerator.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2003,2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.proxy;
+
+import java.util.*;
+import org.springframework.cglib.core.*;
+import org.springframework.asm.Type;
+
+@SuppressWarnings({"rawtypes", "unchecked"})
+class DispatcherGenerator implements CallbackGenerator {
+ public static final DispatcherGenerator INSTANCE =
+ new DispatcherGenerator(false);
+ public static final DispatcherGenerator PROXY_REF_INSTANCE =
+ new DispatcherGenerator(true);
+
+ private static final Type DISPATCHER =
+ TypeUtils.parseType("org.springframework.cglib.proxy.Dispatcher");
+ private static final Type PROXY_REF_DISPATCHER =
+ TypeUtils.parseType("org.springframework.cglib.proxy.ProxyRefDispatcher");
+ private static final Signature LOAD_OBJECT =
+ TypeUtils.parseSignature("Object loadObject()");
+ private static final Signature PROXY_REF_LOAD_OBJECT =
+ TypeUtils.parseSignature("Object loadObject(Object)");
+
+ private boolean proxyRef;
+
+ private DispatcherGenerator(boolean proxyRef) {
+ this.proxyRef = proxyRef;
+ }
+
+ public void generate(ClassEmitter ce, Context context, List methods) {
+ for (Iterator it = methods.iterator(); it.hasNext();) {
+ MethodInfo method = (MethodInfo)it.next();
+ if (!TypeUtils.isProtected(method.getModifiers())) {
+ CodeEmitter e = context.beginMethod(ce, method);
+ context.emitCallback(e, context.getIndex(method));
+ if (proxyRef) {
+ e.load_this();
+ e.invoke_interface(PROXY_REF_DISPATCHER, PROXY_REF_LOAD_OBJECT);
+ } else {
+ e.invoke_interface(DISPATCHER, LOAD_OBJECT);
+ }
+ e.checkcast(method.getClassInfo().getType());
+ e.load_args();
+ e.invoke(method);
+ e.return_value();
+ e.end_method();
+ }
+ }
+ }
+
+ public void generateStatic(CodeEmitter e, Context context, List methods) { }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/proxy/Factory.java b/spring-core/src/main/java/org/springframework/cglib/proxy/Factory.java
new file mode 100644
index 0000000000..c924bb1048
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/proxy/Factory.java
@@ -0,0 +1,80 @@
+/*
+ * Copyright 2002,2003 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cglib.proxy;
+
+/**
+ * All enhanced instances returned by the {@link Enhancer} class implement this interface.
+ * Using this interface for new instances is faster than going through the Enhancer
+ * interface or using reflection. In addition, to intercept methods called during
+ * object construction you must use these methods instead of reflection.
+ * @author Juozas Baliuka baliuka@mwm.lt
+ * @version $Id: Factory.java,v 1.13 2004/06/24 21:15:20 herbyderby Exp $
+ */
+@SuppressWarnings({"rawtypes", "unchecked"})
+public interface Factory {
+ /**
+ * Creates new instance of the same type, using the no-arg constructor.
+ * The class of this object must have been created using a single Callback type.
+ * If multiple callbacks are required an exception will be thrown.
+ * @param callback the new interceptor to use
+ * @return new instance of the same type
+ */
+ Object newInstance(Callback callback);
+
+ /**
+ * Creates new instance of the same type, using the no-arg constructor.
+ * @param callbacks the new callbacks(s) to use
+ * @return new instance of the same type
+ */
+ Object newInstance(Callback[] callbacks);
+
+ /**
+ * Creates a new instance of the same type, using the constructor
+ * matching the given signature.
+ * @param types the constructor argument types
+ * @param args the constructor arguments
+ * @param callbacks the new interceptor(s) to use
+ * @return new instance of the same type
+ */
+ Object newInstance(Class[] types, Object[] args, Callback[] callbacks);
+
+ /**
+ * Return the Callback implementation at the specified index.
+ * @param index the callback index
+ * @return the callback implementation
+ */
+ Callback getCallback(int index);
+
+ /**
+ * Set the callback for this object for the given type.
+ * @param index the callback index to replace
+ * @param callback the new callback
+ */
+ void setCallback(int index, Callback callback);
+
+ /**
+ * Replace all of the callbacks for this object at once.
+ * @param callbacks the new callbacks(s) to use
+ */
+ void setCallbacks(Callback[] callbacks);
+
+ /**
+ * Get the current set of callbacks for ths object.
+ * @return a new array instance
+ */
+ Callback[] getCallbacks();
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/proxy/FixedValue.java b/spring-core/src/main/java/org/springframework/cglib/proxy/FixedValue.java
new file mode 100644
index 0000000000..6e13a1f79f
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/proxy/FixedValue.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2003 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.proxy;
+
+/**
+ * {@link Enhancer} callback that simply returns the value to return
+ * from the proxied method. No information about what method
+ * is being called is available to the callback, and the type of
+ * the returned object must be compatible with the return type of
+ * the proxied method. This makes this callback primarily useful
+ * for forcing a particular method (through the use of a {@link CallbackFilter}
+ * to return a fixed value with little overhead.
+ */
+public interface FixedValue extends Callback {
+ /**
+ * Return the object which the original method invocation should
+ * return. This method is called for every method invocation.
+ * @return an object matching the type of the return value for every
+ * method this callback is mapped to
+ */
+ Object loadObject() throws Exception;
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/proxy/FixedValueGenerator.java b/spring-core/src/main/java/org/springframework/cglib/proxy/FixedValueGenerator.java
new file mode 100644
index 0000000000..f34e2b4689
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/proxy/FixedValueGenerator.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2003,2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.proxy;
+
+import java.util.*;
+import org.springframework.cglib.core.*;
+import org.springframework.asm.Type;
+
+@SuppressWarnings({"rawtypes", "unchecked"})
+class FixedValueGenerator implements CallbackGenerator {
+ public static final FixedValueGenerator INSTANCE = new FixedValueGenerator();
+ private static final Type FIXED_VALUE =
+ TypeUtils.parseType("org.springframework.cglib.proxy.FixedValue");
+ private static final Signature LOAD_OBJECT =
+ TypeUtils.parseSignature("Object loadObject()");
+
+ public void generate(ClassEmitter ce, Context context, List methods) {
+ for (Iterator it = methods.iterator(); it.hasNext();) {
+ MethodInfo method = (MethodInfo)it.next();
+ CodeEmitter e = context.beginMethod(ce, method);
+ context.emitCallback(e, context.getIndex(method));
+ e.invoke_interface(FIXED_VALUE, LOAD_OBJECT);
+ e.unbox_or_zero(e.getReturnType());
+ e.return_value();
+ e.end_method();
+ }
+ }
+
+ public void generateStatic(CodeEmitter e, Context context, List methods) { }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/proxy/InterfaceMaker.java b/spring-core/src/main/java/org/springframework/cglib/proxy/InterfaceMaker.java
new file mode 100644
index 0000000000..258412c592
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/proxy/InterfaceMaker.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.proxy;
+
+import java.lang.reflect.*;
+import java.util.*;
+import org.springframework.cglib.core.*;
+import org.springframework.asm.ClassVisitor;
+import org.springframework.asm.Type;
+
+/**
+ * Generates new interfaces at runtime.
+ * By passing a generated interface to the Enhancer's list of interfaces to
+ * implement, you can make your enhanced classes handle an arbitrary set
+ * of method signatures.
+ * @author Chris Nokleberg
+ * @version $Id: InterfaceMaker.java,v 1.4 2006/03/05 02:43:19 herbyderby Exp $
+ */
+@SuppressWarnings({"rawtypes", "unchecked"})
+public class InterfaceMaker extends AbstractClassGenerator
+{
+ private static final Source SOURCE = new Source(InterfaceMaker.class.getName());
+ private Map signatures = new HashMap();
+
+ /**
+ * Create a new InterfaceMaker. A new InterfaceMaker
+ * object should be used for each generated interface, and should not
+ * be shared across threads.
+ */
+ public InterfaceMaker() {
+ super(SOURCE);
+ }
+
+ /**
+ * Add a method signature to the interface.
+ * @param sig the method signature to add to the interface
+ * @param exceptions an array of exception types to declare for the method
+ */
+ public void add(Signature sig, Type[] exceptions) {
+ signatures.put(sig, exceptions);
+ }
+
+ /**
+ * Add a method signature to the interface. The method modifiers are ignored,
+ * since interface methods are by definition abstract and public.
+ * @param method the method to add to the interface
+ */
+ public void add(Method method) {
+ add(ReflectUtils.getSignature(method),
+ ReflectUtils.getExceptionTypes(method));
+ }
+
+ /**
+ * Add all the public methods in the specified class.
+ * Methods from superclasses are included, except for methods declared in the base
+ * Object class (e.g. getClass, equals, hashCode).
+ * @param class the class containing the methods to add to the interface
+ */
+ public void add(Class clazz) {
+ Method[] methods = clazz.getMethods();
+ for (int i = 0; i < methods.length; i++) {
+ Method m = methods[i];
+ if (!m.getDeclaringClass().getName().equals("java.lang.Object")) {
+ add(m);
+ }
+ }
+ }
+
+ /**
+ * Create an interface using the current set of method signatures.
+ */
+ public Class create() {
+ setUseCache(false);
+ return (Class)super.create(this);
+ }
+
+ protected ClassLoader getDefaultClassLoader() {
+ return null;
+ }
+
+ protected Object firstInstance(Class type) {
+ return type;
+ }
+
+ protected Object nextInstance(Object instance) {
+ throw new IllegalStateException("InterfaceMaker does not cache");
+ }
+
+ public void generateClass(ClassVisitor v) throws Exception {
+ ClassEmitter ce = new ClassEmitter(v);
+ ce.begin_class(Constants.V1_8,
+ Constants.ACC_PUBLIC | Constants.ACC_INTERFACE | Constants.ACC_ABSTRACT,
+ getClassName(),
+ null,
+ null,
+ Constants.SOURCE_FILE);
+ for (Iterator it = signatures.keySet().iterator(); it.hasNext();) {
+ Signature sig = (Signature)it.next();
+ Type[] exceptions = (Type[])signatures.get(sig);
+ ce.begin_method(Constants.ACC_PUBLIC | Constants.ACC_ABSTRACT,
+ sig,
+ exceptions).end_method();
+ }
+ ce.end_class();
+ }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/proxy/InvocationHandler.java b/spring-core/src/main/java/org/springframework/cglib/proxy/InvocationHandler.java
new file mode 100644
index 0000000000..cf0a35477f
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/proxy/InvocationHandler.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2003 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.proxy;
+
+import java.lang.reflect.Method;
+
+/**
+ * {@link java.lang.reflect.InvocationHandler} replacement (unavailable under JDK 1.2).
+ * This callback type is primarily for use by the {@link Proxy} class but
+ * may be used with {@link Enhancer} as well.
+ * @author Neeme Praks neeme@apache.org
+ * @version $Id: InvocationHandler.java,v 1.3 2004/06/24 21:15:20 herbyderby Exp $
+ */
+public interface InvocationHandler
+extends Callback
+{
+ /**
+ * @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object)
+ */
+ public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
+
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/proxy/InvocationHandlerGenerator.java b/spring-core/src/main/java/org/springframework/cglib/proxy/InvocationHandlerGenerator.java
new file mode 100644
index 0000000000..d788729a56
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/proxy/InvocationHandlerGenerator.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright 2003,2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.proxy;
+
+import org.springframework.cglib.core.*;
+import java.util.*;
+import org.springframework.asm.Type;
+
+@SuppressWarnings({"rawtypes", "unchecked"})
+class InvocationHandlerGenerator
+implements CallbackGenerator
+{
+ public static final InvocationHandlerGenerator INSTANCE = new InvocationHandlerGenerator();
+
+ private static final Type INVOCATION_HANDLER =
+ TypeUtils.parseType("org.springframework.cglib.proxy.InvocationHandler");
+ private static final Type UNDECLARED_THROWABLE_EXCEPTION =
+ TypeUtils.parseType("org.springframework.cglib.proxy.UndeclaredThrowableException");
+ private static final Type METHOD =
+ TypeUtils.parseType("java.lang.reflect.Method");
+ private static final Signature INVOKE =
+ TypeUtils.parseSignature("Object invoke(Object, java.lang.reflect.Method, Object[])");
+
+ public void generate(ClassEmitter ce, Context context, List methods) {
+ for (Iterator it = methods.iterator(); it.hasNext();) {
+ MethodInfo method = (MethodInfo)it.next();
+ Signature impl = context.getImplSignature(method);
+ ce.declare_field(Constants.PRIVATE_FINAL_STATIC, impl.getName(), METHOD, null);
+
+ CodeEmitter e = context.beginMethod(ce, method);
+ Block handler = e.begin_block();
+ context.emitCallback(e, context.getIndex(method));
+ e.load_this();
+ e.getfield(impl.getName());
+ e.create_arg_array();
+ e.invoke_interface(INVOCATION_HANDLER, INVOKE);
+ e.unbox(method.getSignature().getReturnType());
+ e.return_value();
+ handler.end();
+ EmitUtils.wrap_undeclared_throwable(e, handler, method.getExceptionTypes(), UNDECLARED_THROWABLE_EXCEPTION);
+ e.end_method();
+ }
+ }
+
+ public void generateStatic(CodeEmitter e, Context context, List methods) {
+ for (Iterator it = methods.iterator(); it.hasNext();) {
+ MethodInfo method = (MethodInfo)it.next();
+ EmitUtils.load_method(e, method);
+ e.putfield(context.getImplSignature(method).getName());
+ }
+ }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/proxy/LazyLoader.java b/spring-core/src/main/java/org/springframework/cglib/proxy/LazyLoader.java
new file mode 100644
index 0000000000..2d1f35ca7c
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/proxy/LazyLoader.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright 2003 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.proxy;
+
+/**
+ * Lazy-loading {@link Enhancer} callback.
+ */
+public interface LazyLoader extends Callback {
+ /**
+ * Return the object which the original method invocation should be
+ * dispatched. Called as soon as the first lazily-loaded method in
+ * the enhanced instance is invoked. The same object is then used
+ * for every future method call to the proxy instance.
+ * @return an object that can invoke the method
+ */
+ Object loadObject() throws Exception;
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/proxy/LazyLoaderGenerator.java b/spring-core/src/main/java/org/springframework/cglib/proxy/LazyLoaderGenerator.java
new file mode 100644
index 0000000000..49261578b4
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/proxy/LazyLoaderGenerator.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright 2003,2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.proxy;
+
+import java.util.*;
+import org.springframework.cglib.core.*;
+import org.springframework.asm.Label;
+import org.springframework.asm.Type;
+
+@SuppressWarnings({"rawtypes", "unchecked"})
+class LazyLoaderGenerator implements CallbackGenerator {
+ public static final LazyLoaderGenerator INSTANCE = new LazyLoaderGenerator();
+
+ private static final Signature LOAD_OBJECT =
+ TypeUtils.parseSignature("Object loadObject()");
+ private static final Type LAZY_LOADER =
+ TypeUtils.parseType("org.springframework.cglib.proxy.LazyLoader");
+
+ public void generate(ClassEmitter ce, Context context, List methods) {
+ Set indexes = new HashSet();
+ for (Iterator it = methods.iterator(); it.hasNext();) {
+ MethodInfo method = (MethodInfo)it.next();
+ if (TypeUtils.isProtected(method.getModifiers())) {
+ // ignore protected methods
+ } else {
+ int index = context.getIndex(method);
+ indexes.add(index);
+ CodeEmitter e = context.beginMethod(ce, method);
+ e.load_this();
+ e.dup();
+ e.invoke_virtual_this(loadMethod(index));
+ e.checkcast(method.getClassInfo().getType());
+ e.load_args();
+ e.invoke(method);
+ e.return_value();
+ e.end_method();
+ }
+ }
+
+ for (Iterator it = indexes.iterator(); it.hasNext();) {
+ int index = ((Integer)it.next());
+
+ String delegate = "CGLIB$LAZY_LOADER_" + index;
+ ce.declare_field(Constants.ACC_PRIVATE, delegate, Constants.TYPE_OBJECT, null);
+
+ CodeEmitter e = ce.begin_method(Constants.ACC_PRIVATE |
+ Constants.ACC_SYNCHRONIZED |
+ Constants.ACC_FINAL,
+ loadMethod(index),
+ null);
+ e.load_this();
+ e.getfield(delegate);
+ e.dup();
+ Label end = e.make_label();
+ e.ifnonnull(end);
+ e.pop();
+ e.load_this();
+ context.emitCallback(e, index);
+ e.invoke_interface(LAZY_LOADER, LOAD_OBJECT);
+ e.dup_x1();
+ e.putfield(delegate);
+ e.mark(end);
+ e.return_value();
+ e.end_method();
+
+ }
+ }
+
+ private Signature loadMethod(int index) {
+ return new Signature("CGLIB$LOAD_PRIVATE_" + index,
+ Constants.TYPE_OBJECT,
+ Constants.TYPES_EMPTY);
+ }
+
+ public void generateStatic(CodeEmitter e, Context context, List methods) { }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/proxy/MethodInterceptor.java b/spring-core/src/main/java/org/springframework/cglib/proxy/MethodInterceptor.java
new file mode 100644
index 0000000000..741ef943b1
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/proxy/MethodInterceptor.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2002,2003 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.proxy;
+
+/**
+ * General-purpose {@link Enhancer} callback which provides for "around advice".
+ * @author Juozas Baliuka baliuka@mwm.lt
+ * @version $Id: MethodInterceptor.java,v 1.8 2004/06/24 21:15:20 herbyderby Exp $
+ */
+public interface MethodInterceptor
+extends Callback
+{
+ /**
+ * All generated proxied methods call this method instead of the original method.
+ * The original method may either be invoked by normal reflection using the Method object,
+ * or by using the MethodProxy (faster).
+ * @param obj "this", the enhanced object
+ * @param method intercepted Method
+ * @param args argument array; primitive types are wrapped
+ * @param proxy used to invoke super (non-intercepted method); may be called
+ * as many times as needed
+ * @throws Throwable any exception may be thrown; if so, super method will not be invoked
+ * @return any value compatible with the signature of the proxied method. Method returning void will ignore this value.
+ * @see MethodProxy
+ */
+ public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,
+ MethodProxy proxy) throws Throwable;
+
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/proxy/MethodInterceptorGenerator.java b/spring-core/src/main/java/org/springframework/cglib/proxy/MethodInterceptorGenerator.java
new file mode 100644
index 0000000000..d944e96dce
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/proxy/MethodInterceptorGenerator.java
@@ -0,0 +1,238 @@
+/*
+ * Copyright 2003,2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.proxy;
+
+import java.util.*;
+import org.springframework.cglib.core.*;
+import org.springframework.asm.Label;
+import org.springframework.asm.Type;
+
+@SuppressWarnings({"rawtypes", "unchecked", "deprecation"})
+class MethodInterceptorGenerator
+implements CallbackGenerator
+{
+ public static final MethodInterceptorGenerator INSTANCE = new MethodInterceptorGenerator();
+
+ static final String EMPTY_ARGS_NAME = "CGLIB$emptyArgs";
+ static final String FIND_PROXY_NAME = "CGLIB$findMethodProxy";
+ static final Class[] FIND_PROXY_TYPES = { Signature.class };
+
+ private static final Type ABSTRACT_METHOD_ERROR =
+ TypeUtils.parseType("AbstractMethodError");
+ private static final Type METHOD =
+ TypeUtils.parseType("java.lang.reflect.Method");
+ private static final Type REFLECT_UTILS =
+ TypeUtils.parseType("org.springframework.cglib.core.ReflectUtils");
+ private static final Type METHOD_PROXY =
+ TypeUtils.parseType("org.springframework.cglib.proxy.MethodProxy");
+ private static final Type METHOD_INTERCEPTOR =
+ TypeUtils.parseType("org.springframework.cglib.proxy.MethodInterceptor");
+ private static final Signature GET_DECLARED_METHODS =
+ TypeUtils.parseSignature("java.lang.reflect.Method[] getDeclaredMethods()");
+ private static final Signature GET_DECLARING_CLASS =
+ TypeUtils.parseSignature("Class getDeclaringClass()");
+ private static final Signature FIND_METHODS =
+ TypeUtils.parseSignature("java.lang.reflect.Method[] findMethods(String[], java.lang.reflect.Method[])");
+ private static final Signature MAKE_PROXY =
+ new Signature("create", METHOD_PROXY, new Type[]{
+ Constants.TYPE_CLASS,
+ Constants.TYPE_CLASS,
+ Constants.TYPE_STRING,
+ Constants.TYPE_STRING,
+ Constants.TYPE_STRING
+ });
+ private static final Signature INTERCEPT =
+ new Signature("intercept", Constants.TYPE_OBJECT, new Type[]{
+ Constants.TYPE_OBJECT,
+ METHOD,
+ Constants.TYPE_OBJECT_ARRAY,
+ METHOD_PROXY
+ });
+ private static final Signature FIND_PROXY =
+ new Signature(FIND_PROXY_NAME, METHOD_PROXY, new Type[]{ Constants.TYPE_SIGNATURE });
+ private static final Signature TO_STRING =
+ TypeUtils.parseSignature("String toString()");
+ private static final Transformer METHOD_TO_CLASS = new Transformer(){
+ public Object transform(Object value) {
+ return ((MethodInfo)value).getClassInfo();
+ }
+ };
+ private static final Signature CSTRUCT_SIGNATURE =
+ TypeUtils.parseConstructor("String, String");
+
+ private String getMethodField(Signature impl) {
+ return impl.getName() + "$Method";
+ }
+ private String getMethodProxyField(Signature impl) {
+ return impl.getName() + "$Proxy";
+ }
+
+ public void generate(ClassEmitter ce, Context context, List methods) {
+ Map sigMap = new HashMap();
+ for (Iterator it = methods.iterator(); it.hasNext();) {
+ MethodInfo method = (MethodInfo)it.next();
+ Signature sig = method.getSignature();
+ Signature impl = context.getImplSignature(method);
+
+ String methodField = getMethodField(impl);
+ String methodProxyField = getMethodProxyField(impl);
+
+ sigMap.put(sig.toString(), methodProxyField);
+ ce.declare_field(Constants.PRIVATE_FINAL_STATIC, methodField, METHOD, null);
+ ce.declare_field(Constants.PRIVATE_FINAL_STATIC, methodProxyField, METHOD_PROXY, null);
+ ce.declare_field(Constants.PRIVATE_FINAL_STATIC, EMPTY_ARGS_NAME, Constants.TYPE_OBJECT_ARRAY, null);
+ CodeEmitter e;
+
+ // access method
+ e = ce.begin_method(Constants.ACC_FINAL,
+ impl,
+ method.getExceptionTypes());
+ superHelper(e, method, context);
+ e.return_value();
+ e.end_method();
+
+ // around method
+ e = context.beginMethod(ce, method);
+ Label nullInterceptor = e.make_label();
+ context.emitCallback(e, context.getIndex(method));
+ e.dup();
+ e.ifnull(nullInterceptor);
+
+ e.load_this();
+ e.getfield(methodField);
+
+ if (sig.getArgumentTypes().length == 0) {
+ e.getfield(EMPTY_ARGS_NAME);
+ } else {
+ e.create_arg_array();
+ }
+
+ e.getfield(methodProxyField);
+ e.invoke_interface(METHOD_INTERCEPTOR, INTERCEPT);
+ e.unbox_or_zero(sig.getReturnType());
+ e.return_value();
+
+ e.mark(nullInterceptor);
+ superHelper(e, method, context);
+ e.return_value();
+ e.end_method();
+ }
+ generateFindProxy(ce, sigMap);
+ }
+
+ private static void superHelper(CodeEmitter e, MethodInfo method, Context context)
+ {
+ if (TypeUtils.isAbstract(method.getModifiers())) {
+ e.throw_exception(ABSTRACT_METHOD_ERROR, method.toString() + " is abstract" );
+ } else {
+ e.load_this();
+ context.emitLoadArgsAndInvoke(e, method);
+ }
+ }
+
+ public void generateStatic(CodeEmitter e, Context context, List methods) throws Exception {
+ /* generates:
+ static {
+ Class thisClass = Class.forName("NameOfThisClass");
+ Class cls = Class.forName("java.lang.Object");
+ String[] sigs = new String[]{ "toString", "()Ljava/lang/String;", ... };
+ Method[] methods = cls.getDeclaredMethods();
+ methods = ReflectUtils.findMethods(sigs, methods);
+ METHOD_0 = methods[0];
+ CGLIB$ACCESS_0 = MethodProxy.create(cls, thisClass, "()Ljava/lang/String;", "toString", "CGLIB$ACCESS_0");
+ ...
+ }
+ */
+
+ e.push(0);
+ e.newarray();
+ e.putfield(EMPTY_ARGS_NAME);
+
+ Local thisclass = e.make_local();
+ Local declaringclass = e.make_local();
+ EmitUtils.load_class_this(e);
+ e.store_local(thisclass);
+
+ Map methodsByClass = CollectionUtils.bucket(methods, METHOD_TO_CLASS);
+ for (Iterator i = methodsByClass.keySet().iterator(); i.hasNext();) {
+ ClassInfo classInfo = (ClassInfo)i.next();
+
+ List classMethods = (List)methodsByClass.get(classInfo);
+ e.push(2 * classMethods.size());
+ e.newarray(Constants.TYPE_STRING);
+ for (int index = 0; index < classMethods.size(); index++) {
+ MethodInfo method = (MethodInfo)classMethods.get(index);
+ Signature sig = method.getSignature();
+ e.dup();
+ e.push(2 * index);
+ e.push(sig.getName());
+ e.aastore();
+ e.dup();
+ e.push(2 * index + 1);
+ e.push(sig.getDescriptor());
+ e.aastore();
+ }
+
+ EmitUtils.load_class(e, classInfo.getType());
+ e.dup();
+ e.store_local(declaringclass);
+ e.invoke_virtual(Constants.TYPE_CLASS, GET_DECLARED_METHODS);
+ e.invoke_static(REFLECT_UTILS, FIND_METHODS);
+
+ for (int index = 0; index < classMethods.size(); index++) {
+ MethodInfo method = (MethodInfo)classMethods.get(index);
+ Signature sig = method.getSignature();
+ Signature impl = context.getImplSignature(method);
+ e.dup();
+ e.push(index);
+ e.array_load(METHOD);
+ e.putfield(getMethodField(impl));
+
+ e.load_local(declaringclass);
+ e.load_local(thisclass);
+ e.push(sig.getDescriptor());
+ e.push(sig.getName());
+ e.push(impl.getName());
+ e.invoke_static(METHOD_PROXY, MAKE_PROXY);
+ e.putfield(getMethodProxyField(impl));
+ }
+ e.pop();
+ }
+ }
+
+ public void generateFindProxy(ClassEmitter ce, final Map sigMap) {
+ final CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC | Constants.ACC_STATIC,
+ FIND_PROXY,
+ null);
+ e.load_arg(0);
+ e.invoke_virtual(Constants.TYPE_OBJECT, TO_STRING);
+ ObjectSwitchCallback callback = new ObjectSwitchCallback() {
+ public void processCase(Object key, Label end) {
+ e.getfield((String)sigMap.get(key));
+ e.return_value();
+ }
+ public void processDefault() {
+ e.aconst_null();
+ e.return_value();
+ }
+ };
+ EmitUtils.string_switch(e,
+ (String[])sigMap.keySet().toArray(new String[0]),
+ Constants.SWITCH_STYLE_HASH,
+ callback);
+ e.end_method();
+ }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/proxy/Mixin.java b/spring-core/src/main/java/org/springframework/cglib/proxy/Mixin.java
new file mode 100644
index 0000000000..1e06c8ccf2
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/proxy/Mixin.java
@@ -0,0 +1,243 @@
+/*
+ * Copyright 2003,2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.proxy;
+
+import java.security.ProtectionDomain;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Modifier;
+import java.util.*;
+import org.springframework.cglib.core.*;
+import org.springframework.asm.ClassVisitor;
+
+
+
+/**
+ * Mixin allows
+ * multiple objects to be combined into a single larger object. The
+ * methods in the generated object simply call the original methods in the
+ * underlying "delegate" objects.
+ * @author Chris Nokleberg
+ * @version $Id: Mixin.java,v 1.7 2005/09/27 11:42:27 baliuka Exp $
+ */
+@SuppressWarnings({"rawtypes", "unchecked"})
+abstract public class Mixin {
+ private static final MixinKey KEY_FACTORY =
+ (MixinKey)KeyFactory.create(MixinKey.class, KeyFactory.CLASS_BY_NAME);
+ private static final Map ROUTE_CACHE = Collections.synchronizedMap(new HashMap());
+
+ public static final int STYLE_INTERFACES = 0;
+ public static final int STYLE_BEANS = 1;
+ public static final int STYLE_EVERYTHING = 2;
+
+ interface MixinKey {
+ public Object newInstance(int style, String[] classes, int[] route);
+ }
+
+ abstract public Mixin newInstance(Object[] delegates);
+
+ /**
+ * Helper method to create an interface mixin. For finer control over the
+ * generated instance, use a new instance of Mixin
+ * instead of this static method.
+ * TODO
+ */
+ public static Mixin create(Object[] delegates) {
+ Generator gen = new Generator();
+ gen.setDelegates(delegates);
+ return gen.create();
+ }
+
+ /**
+ * Helper method to create an interface mixin. For finer control over the
+ * generated instance, use a new instance of Mixin
+ * instead of this static method.
+ * TODO
+ */
+ public static Mixin create(Class[] interfaces, Object[] delegates) {
+ Generator gen = new Generator();
+ gen.setClasses(interfaces);
+ gen.setDelegates(delegates);
+ return gen.create();
+ }
+
+
+ public static Mixin createBean(Object[] beans) {
+
+ return createBean(null, beans);
+
+ }
+ /**
+ * Helper method to create a bean mixin. For finer control over the
+ * generated instance, use a new instance of Mixin
+ * instead of this static method.
+ * TODO
+ */
+ public static Mixin createBean(ClassLoader loader,Object[] beans) {
+ Generator gen = new Generator();
+ gen.setStyle(STYLE_BEANS);
+ gen.setDelegates(beans);
+ gen.setClassLoader(loader);
+ return gen.create();
+ }
+
+ public static class Generator extends AbstractClassGenerator {
+ private static final Source SOURCE = new Source(Mixin.class.getName());
+
+ private Class[] classes;
+ private Object[] delegates;
+ private int style = STYLE_INTERFACES;
+
+ private int[] route;
+
+ public Generator() {
+ super(SOURCE);
+ }
+
+ protected ClassLoader getDefaultClassLoader() {
+ return classes[0].getClassLoader(); // is this right?
+ }
+
+ protected ProtectionDomain getProtectionDomain() {
+ return ReflectUtils.getProtectionDomain(classes[0]);
+ }
+
+ public void setStyle(int style) {
+ switch (style) {
+ case STYLE_INTERFACES:
+ case STYLE_BEANS:
+ case STYLE_EVERYTHING:
+ this.style = style;
+ break;
+ default:
+ throw new IllegalArgumentException("Unknown mixin style: " + style);
+ }
+ }
+
+ public void setClasses(Class[] classes) {
+ this.classes = classes;
+ }
+
+ public void setDelegates(Object[] delegates) {
+ this.delegates = delegates;
+ }
+
+ public Mixin create() {
+ if (classes == null && delegates == null) {
+ throw new IllegalStateException("Either classes or delegates must be set");
+ }
+ switch (style) {
+ case STYLE_INTERFACES:
+ if (classes == null) {
+ Route r = route(delegates);
+ classes = r.classes;
+ route = r.route;
+ }
+ break;
+ case STYLE_BEANS:
+ // fall-through
+ case STYLE_EVERYTHING:
+ if (classes == null) {
+ classes = ReflectUtils.getClasses(delegates);
+ } else {
+ if (delegates != null) {
+ Class[] temp = ReflectUtils.getClasses(delegates);
+ if (classes.length != temp.length) {
+ throw new IllegalStateException("Specified classes are incompatible with delegates");
+ }
+ for (int i = 0; i < classes.length; i++) {
+ if (!classes[i].isAssignableFrom(temp[i])) {
+ throw new IllegalStateException("Specified class " + classes[i] + " is incompatible with delegate class " + temp[i] + " (index " + i + ")");
+ }
+ }
+ }
+ }
+ }
+ setNamePrefix(classes[ReflectUtils.findPackageProtected(classes)].getName());
+
+ return (Mixin)super.create(KEY_FACTORY.newInstance(style, ReflectUtils.getNames( classes ), route));
+ }
+
+ public void generateClass(ClassVisitor v) {
+ switch (style) {
+ case STYLE_INTERFACES:
+ new MixinEmitter(v, getClassName(), classes, route);
+ break;
+ case STYLE_BEANS:
+ new MixinBeanEmitter(v, getClassName(), classes);
+ break;
+ case STYLE_EVERYTHING:
+ new MixinEverythingEmitter(v, getClassName(), classes);
+ break;
+ }
+ }
+
+ protected Object firstInstance(Class type) {
+ return ((Mixin)ReflectUtils.newInstance(type)).newInstance(delegates);
+ }
+
+ protected Object nextInstance(Object instance) {
+ return ((Mixin)instance).newInstance(delegates);
+ }
+ }
+
+ public static Class[] getClasses(Object[] delegates) {
+ return route(delegates).classes.clone();
+ }
+
+// public static int[] getRoute(Object[] delegates) {
+// return (int[])route(delegates).route.clone();
+// }
+
+ private static Route route(Object[] delegates) {
+ Object key = ClassesKey.create(delegates);
+ Route route = (Route)ROUTE_CACHE.get(key);
+ if (route == null) {
+ ROUTE_CACHE.put(key, route = new Route(delegates));
+ }
+ return route;
+ }
+
+ private static class Route
+ {
+ private Class[] classes;
+ private int[] route;
+
+ Route(Object[] delegates) {
+ Map map = new HashMap();
+ ArrayList collect = new ArrayList();
+ for (int i = 0; i < delegates.length; i++) {
+ Class delegate = delegates[i].getClass();
+ collect.clear();
+ ReflectUtils.addAllInterfaces(delegate, collect);
+ for (Iterator it = collect.iterator(); it.hasNext();) {
+ Class iface = (Class)it.next();
+ if (!map.containsKey(iface)) {
+ map.put(iface, i);
+ }
+ }
+ }
+ classes = new Class[map.size()];
+ route = new int[map.size()];
+ int index = 0;
+ for (Iterator it = map.keySet().iterator(); it.hasNext();) {
+ Class key = (Class)it.next();
+ classes[index] = key;
+ route[index] = ((Integer)map.get(key));
+ index++;
+ }
+ }
+ }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/proxy/MixinBeanEmitter.java b/spring-core/src/main/java/org/springframework/cglib/proxy/MixinBeanEmitter.java
new file mode 100644
index 0000000000..865a67e518
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/proxy/MixinBeanEmitter.java
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2003 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.proxy;
+
+import java.lang.reflect.Method;
+import org.springframework.cglib.core.ReflectUtils;
+import org.springframework.asm.ClassVisitor;
+
+/**
+ * @author Chris Nokleberg
+ * @version $Id: MixinBeanEmitter.java,v 1.2 2004/06/24 21:15:20 herbyderby Exp $
+ */
+@SuppressWarnings({"rawtypes", "unchecked"})
+class MixinBeanEmitter extends MixinEmitter {
+ public MixinBeanEmitter(ClassVisitor v, String className, Class[] classes) {
+ super(v, className, classes, null);
+ }
+
+ protected Class[] getInterfaces(Class[] classes) {
+ return null;
+ }
+
+ protected Method[] getMethods(Class type) {
+ return ReflectUtils.getPropertyMethods(ReflectUtils.getBeanProperties(type), true, true);
+ }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/proxy/MixinEmitter.java b/spring-core/src/main/java/org/springframework/cglib/proxy/MixinEmitter.java
new file mode 100644
index 0000000000..9fda5dac12
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/proxy/MixinEmitter.java
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2003,2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.proxy;
+
+import java.lang.reflect.Method;
+import java.util.*;
+import org.springframework.cglib.core.*;
+import org.springframework.asm.ClassVisitor;
+import org.springframework.asm.Type;
+
+/**
+ * @author Chris Nokleberg
+ * @version $Id: MixinEmitter.java,v 1.9 2006/08/27 21:04:37 herbyderby Exp $
+ */
+@SuppressWarnings({"rawtypes", "unchecked"})
+class MixinEmitter extends ClassEmitter {
+ private static final String FIELD_NAME = "CGLIB$DELEGATES";
+ private static final Signature CSTRUCT_OBJECT_ARRAY =
+ TypeUtils.parseConstructor("Object[]");
+ private static final Type MIXIN =
+ TypeUtils.parseType("org.springframework.cglib.proxy.Mixin");
+ private static final Signature NEW_INSTANCE =
+ new Signature("newInstance", MIXIN, new Type[]{ Constants.TYPE_OBJECT_ARRAY });
+
+ public MixinEmitter(ClassVisitor v, String className, Class[] classes, int[] route) {
+ super(v);
+
+ begin_class(Constants.V1_8,
+ Constants.ACC_PUBLIC,
+ className,
+ MIXIN,
+ TypeUtils.getTypes(getInterfaces(classes)),
+ Constants.SOURCE_FILE);
+ EmitUtils.null_constructor(this);
+ EmitUtils.factory_method(this, NEW_INSTANCE);
+
+ declare_field(Constants.ACC_PRIVATE, FIELD_NAME, Constants.TYPE_OBJECT_ARRAY, null);
+
+ CodeEmitter e = begin_method(Constants.ACC_PUBLIC, CSTRUCT_OBJECT_ARRAY, null);
+ e.load_this();
+ e.super_invoke_constructor();
+ e.load_this();
+ e.load_arg(0);
+ e.putfield(FIELD_NAME);
+ e.return_value();
+ e.end_method();
+
+ Set unique = new HashSet();
+ for (int i = 0; i < classes.length; i++) {
+ Method[] methods = getMethods(classes[i]);
+ for (int j = 0; j < methods.length; j++) {
+ if (unique.add(MethodWrapper.create(methods[j]))) {
+ MethodInfo method = ReflectUtils.getMethodInfo(methods[j]);
+ int modifiers = Constants.ACC_PUBLIC;
+ if ((method.getModifiers() & Constants.ACC_VARARGS) == Constants.ACC_VARARGS) {
+ modifiers |= Constants.ACC_VARARGS;
+ }
+ e = EmitUtils.begin_method(this, method, modifiers);
+ e.load_this();
+ e.getfield(FIELD_NAME);
+ e.aaload((route != null) ? route[i] : i);
+ e.checkcast(method.getClassInfo().getType());
+ e.load_args();
+ e.invoke(method);
+ e.return_value();
+ e.end_method();
+ }
+ }
+ }
+
+ end_class();
+ }
+
+ protected Class[] getInterfaces(Class[] classes) {
+ return classes;
+ }
+
+ protected Method[] getMethods(Class type) {
+ return type.getMethods();
+ }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/proxy/MixinEverythingEmitter.java b/spring-core/src/main/java/org/springframework/cglib/proxy/MixinEverythingEmitter.java
new file mode 100644
index 0000000000..e335e218c1
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/proxy/MixinEverythingEmitter.java
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.proxy;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Modifier;
+import java.util.*;
+import org.springframework.cglib.core.CollectionUtils;
+import org.springframework.cglib.core.ReflectUtils;
+import org.springframework.cglib.core.RejectModifierPredicate;
+import org.springframework.asm.ClassVisitor;
+
+/**
+ * @author Chris Nokleberg
+ * @version $Id: MixinEverythingEmitter.java,v 1.3 2004/06/24 21:15:19 herbyderby Exp $
+ */
+@SuppressWarnings({"rawtypes", "unchecked"})
+class MixinEverythingEmitter extends MixinEmitter {
+
+ public MixinEverythingEmitter(ClassVisitor v, String className, Class[] classes) {
+ super(v, className, classes, null);
+ }
+
+ protected Class[] getInterfaces(Class[] classes) {
+ List list = new ArrayList();
+ for (int i = 0; i < classes.length; i++) {
+ ReflectUtils.addAllInterfaces(classes[i], list);
+ }
+ return (Class[])list.toArray(new Class[list.size()]);
+ }
+
+ protected Method[] getMethods(Class type) {
+ List methods = new ArrayList(Arrays.asList(type.getMethods()));
+ CollectionUtils.filter(methods, new RejectModifierPredicate(Modifier.FINAL | Modifier.STATIC));
+ return (Method[])methods.toArray(new Method[methods.size()]);
+ }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/proxy/NoOp.java b/spring-core/src/main/java/org/springframework/cglib/proxy/NoOp.java
new file mode 100644
index 0000000000..016d6bad37
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/proxy/NoOp.java
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2003 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.proxy;
+
+/**
+ * Methods using this {@link Enhancer} callback will delegate directly to the
+ * default (super) implementation in the base class.
+ */
+public interface NoOp extends Callback
+{
+ /**
+ * A thread-safe singleton instance of the NoOp callback.
+ */
+ public static final NoOp INSTANCE = new NoOp() { };
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/proxy/NoOpGenerator.java b/spring-core/src/main/java/org/springframework/cglib/proxy/NoOpGenerator.java
new file mode 100644
index 0000000000..c2b6bd3bb1
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/proxy/NoOpGenerator.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright 2003,2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.proxy;
+
+import java.util.Iterator;
+import java.util.List;
+import org.springframework.cglib.core.*;
+
+@SuppressWarnings({"rawtypes", "unchecked"})
+class NoOpGenerator
+implements CallbackGenerator
+{
+ public static final NoOpGenerator INSTANCE = new NoOpGenerator();
+
+ public void generate(ClassEmitter ce, Context context, List methods) {
+ for (Iterator it = methods.iterator(); it.hasNext();) {
+ MethodInfo method = (MethodInfo)it.next();
+ if (TypeUtils.isBridge(method.getModifiers()) || (
+ TypeUtils.isProtected(context.getOriginalModifiers(method)) &&
+ TypeUtils.isPublic(method.getModifiers()))) {
+ CodeEmitter e = EmitUtils.begin_method(ce, method);
+ e.load_this();
+ context.emitLoadArgsAndInvoke(e, method);
+ e.return_value();
+ e.end_method();
+ }
+ }
+ }
+
+ public void generateStatic(CodeEmitter e, Context context, List methods) { }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/proxy/Proxy.java b/spring-core/src/main/java/org/springframework/cglib/proxy/Proxy.java
new file mode 100644
index 0000000000..359c6483e2
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/proxy/Proxy.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright 2003,2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.proxy;
+
+import java.io.Serializable;
+import java.lang.reflect.Method;
+import java.lang.reflect.Member;
+import org.springframework.cglib.core.CodeGenerationException;
+
+/**
+ * This class is meant to be used as replacement for
+ * java.lang.reflect.Proxy under JDK 1.2. There are some known
+ * subtle differences:
+ *
+ *
+ * getExceptionTypes
+ * on the Method passed to the invoke method
+ * are the exact set that can be thrown without resulting in an
+ * UndeclaredThrowableException being thrown.
+ * java.lang.reflect.UndeclaredThrowableException.
+ * java.lang.reflect.UndeclaredThrowableException.
+ * @author Juozas Baliuka
+ */
+@SuppressWarnings("serial")
+public class UndeclaredThrowableException extends CodeGenerationException {
+ /**
+ * Creates a new instance of UndeclaredThrowableException without detail message.
+ */
+ public UndeclaredThrowableException(Throwable t) {
+ super(t);
+ }
+
+ public Throwable getUndeclaredThrowable() {
+ return getCause();
+ }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/reflect/ConstructorDelegate.java b/spring-core/src/main/java/org/springframework/cglib/reflect/ConstructorDelegate.java
new file mode 100644
index 0000000000..331b78a093
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/reflect/ConstructorDelegate.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright 2003 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.reflect;
+
+import java.lang.reflect.*;
+import java.security.ProtectionDomain;
+import org.springframework.cglib.core.*;
+import org.springframework.asm.ClassVisitor;
+import org.springframework.asm.Type;
+
+/**
+ * @author Chris Nokleberg
+ * @version $Id: ConstructorDelegate.java,v 1.20 2006/03/05 02:43:19 herbyderby Exp $
+ */
+@SuppressWarnings({"rawtypes", "unchecked"})
+abstract public class ConstructorDelegate {
+ private static final ConstructorKey KEY_FACTORY =
+ (ConstructorKey)KeyFactory.create(ConstructorKey.class, KeyFactory.CLASS_BY_NAME);
+
+ interface ConstructorKey {
+ public Object newInstance(String declaring, String iface);
+ }
+
+ protected ConstructorDelegate() {
+ }
+
+ public static ConstructorDelegate create(Class targetClass, Class iface) {
+ Generator gen = new Generator();
+ gen.setTargetClass(targetClass);
+ gen.setInterface(iface);
+ return gen.create();
+ }
+
+ public static class Generator extends AbstractClassGenerator {
+ private static final Source SOURCE = new Source(ConstructorDelegate.class.getName());
+ private static final Type CONSTRUCTOR_DELEGATE =
+ TypeUtils.parseType("org.springframework.cglib.reflect.ConstructorDelegate");
+
+ private Class iface;
+ private Class targetClass;
+
+ public Generator() {
+ super(SOURCE);
+ }
+
+ public void setInterface(Class iface) {
+ this.iface = iface;
+ }
+
+ public void setTargetClass(Class targetClass) {
+ this.targetClass = targetClass;
+ }
+
+ public ConstructorDelegate create() {
+ setNamePrefix(targetClass.getName());
+ Object key = KEY_FACTORY.newInstance(iface.getName(), targetClass.getName());
+ return (ConstructorDelegate)super.create(key);
+ }
+
+ protected ClassLoader getDefaultClassLoader() {
+ return targetClass.getClassLoader();
+ }
+
+ protected ProtectionDomain getProtectionDomain() {
+ return ReflectUtils.getProtectionDomain(targetClass);
+ }
+
+ public void generateClass(ClassVisitor v) {
+ setNamePrefix(targetClass.getName());
+
+ final Method newInstance = ReflectUtils.findNewInstance(iface);
+ if (!newInstance.getReturnType().isAssignableFrom(targetClass)) {
+ throw new IllegalArgumentException("incompatible return type");
+ }
+ final Constructor constructor;
+ try {
+ constructor = targetClass.getDeclaredConstructor(newInstance.getParameterTypes());
+ } catch (NoSuchMethodException e) {
+ throw new IllegalArgumentException("interface does not match any known constructor");
+ }
+
+ ClassEmitter ce = new ClassEmitter(v);
+ ce.begin_class(Constants.V1_8,
+ Constants.ACC_PUBLIC,
+ getClassName(),
+ CONSTRUCTOR_DELEGATE,
+ new Type[]{ Type.getType(iface) },
+ Constants.SOURCE_FILE);
+ Type declaring = Type.getType(constructor.getDeclaringClass());
+ EmitUtils.null_constructor(ce);
+ CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC,
+ ReflectUtils.getSignature(newInstance),
+ ReflectUtils.getExceptionTypes(newInstance));
+ e.new_instance(declaring);
+ e.dup();
+ e.load_args();
+ e.invoke_constructor(declaring, ReflectUtils.getSignature(constructor));
+ e.return_value();
+ e.end_method();
+ ce.end_class();
+ }
+
+ protected Object firstInstance(Class type) {
+ return ReflectUtils.newInstance(type);
+ }
+
+ protected Object nextInstance(Object instance) {
+ return instance;
+ }
+ }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/reflect/FastClass.java b/spring-core/src/main/java/org/springframework/cglib/reflect/FastClass.java
new file mode 100644
index 0000000000..0bc911b243
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/reflect/FastClass.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright 2003,2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.reflect;
+
+import org.springframework.cglib.core.*;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.security.ProtectionDomain;
+import org.springframework.asm.ClassVisitor;
+import org.springframework.asm.Type;
+
+@SuppressWarnings({"rawtypes", "unchecked"})
+abstract public class FastClass
+{
+ private Class type;
+
+ protected FastClass() {
+ throw new Error("Using the FastClass empty constructor--please report to the cglib-devel mailing list");
+ }
+
+ protected FastClass(Class type) {
+ this.type = type;
+ }
+
+ public static FastClass create(Class type) {
+
+ return create(type.getClassLoader(),type);
+
+ }
+ public static FastClass create(ClassLoader loader, Class type) {
+ Generator gen = new Generator();
+ gen.setType(type);
+ gen.setClassLoader(loader);
+ return gen.create();
+ }
+
+ public static class Generator extends AbstractClassGenerator
+ {
+ private static final Source SOURCE = new Source(FastClass.class.getName());
+ private Class type;
+
+ public Generator() {
+ super(SOURCE);
+ }
+
+ public void setType(Class type) {
+ this.type = type;
+ }
+
+ public FastClass create() {
+ setNamePrefix(type.getName());
+ return (FastClass)super.create(type.getName());
+ }
+
+ protected ClassLoader getDefaultClassLoader() {
+ return type.getClassLoader();
+ }
+
+ protected ProtectionDomain getProtectionDomain() {
+ return ReflectUtils.getProtectionDomain(type);
+ }
+
+ public void generateClass(ClassVisitor v) throws Exception {
+ new FastClassEmitter(v, getClassName(), type);
+ }
+
+ protected Object firstInstance(Class type) {
+ return ReflectUtils.newInstance(type,
+ new Class[]{ Class.class },
+ new Object[]{ this.type });
+ }
+
+ protected Object nextInstance(Object instance) {
+ return instance;
+ }
+ }
+
+ public Object invoke(String name, Class[] parameterTypes, Object obj, Object[] args) throws InvocationTargetException {
+ return invoke(getIndex(name, parameterTypes), obj, args);
+ }
+
+ public Object newInstance() throws InvocationTargetException {
+ return newInstance(getIndex(Constants.EMPTY_CLASS_ARRAY), null);
+ }
+
+ public Object newInstance(Class[] parameterTypes, Object[] args) throws InvocationTargetException {
+ return newInstance(getIndex(parameterTypes), args);
+ }
+
+ public FastMethod getMethod(Method method) {
+ return new FastMethod(this, method);
+ }
+
+ public FastConstructor getConstructor(Constructor constructor) {
+ return new FastConstructor(this, constructor);
+ }
+
+ public FastMethod getMethod(String name, Class[] parameterTypes) {
+ try {
+ return getMethod(type.getMethod(name, parameterTypes));
+ } catch (NoSuchMethodException e) {
+ throw new NoSuchMethodError(e.getMessage());
+ }
+ }
+
+ public FastConstructor getConstructor(Class[] parameterTypes) {
+ try {
+ return getConstructor(type.getConstructor(parameterTypes));
+ } catch (NoSuchMethodException e) {
+ throw new NoSuchMethodError(e.getMessage());
+ }
+ }
+
+ public String getName() {
+ return type.getName();
+ }
+
+ public Class getJavaClass() {
+ return type;
+ }
+
+ public String toString() {
+ return type.toString();
+ }
+
+ public int hashCode() {
+ return type.hashCode();
+ }
+
+ public boolean equals(Object o) {
+ if (o == null || !(o instanceof FastClass)) {
+ return false;
+ }
+ return type.equals(((FastClass)o).type);
+ }
+
+ /**
+ * Return the index of the matching method. The index may be used
+ * later to invoke the method with less overhead. If more than one
+ * method matches (i.e. they differ by return type only), one is
+ * chosen arbitrarily.
+ * @see #invoke(int, Object, Object[])
+ * @param name the method name
+ * @param parameterTypes the parameter array
+ * @return the index, or -1 if none is found.
+ */
+ abstract public int getIndex(String name, Class[] parameterTypes);
+
+ /**
+ * Return the index of the matching constructor. The index may be used
+ * later to create a new instance with less overhead.
+ * @see #newInstance(int, Object[])
+ * @param parameterTypes the parameter array
+ * @return the constructor index, or -1 if none is found.
+ */
+ abstract public int getIndex(Class[] parameterTypes);
+
+ /**
+ * Invoke the method with the specified index.
+ * @see getIndex(name, Class[])
+ * @param index the method index
+ * @param obj the object the underlying method is invoked from
+ * @param args the arguments used for the method call
+ * @throws java.lang.reflect.InvocationTargetException if the underlying method throws an exception
+ */
+ abstract public Object invoke(int index, Object obj, Object[] args) throws InvocationTargetException;
+
+ /**
+ * Create a new instance using the specified constructor index and arguments.
+ * @see getIndex(Class[])
+ * @param index the constructor index
+ * @param args the arguments passed to the constructor
+ * @throws java.lang.reflect.InvocationTargetException if the constructor throws an exception
+ */
+ abstract public Object newInstance(int index, Object[] args) throws InvocationTargetException;
+
+ abstract public int getIndex(Signature sig);
+
+ /**
+ * Returns the maximum method index for this class.
+ */
+ abstract public int getMaxIndex();
+
+ protected static String getSignatureWithoutReturnType(String name, Class[] parameterTypes) {
+ StringBuffer sb = new StringBuffer();
+ sb.append(name);
+ sb.append('(');
+ for (int i = 0; i < parameterTypes.length; i++) {
+ sb.append(Type.getDescriptor(parameterTypes[i]));
+ }
+ sb.append(')');
+ return sb.toString();
+ }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/reflect/FastClassEmitter.java b/spring-core/src/main/java/org/springframework/cglib/reflect/FastClassEmitter.java
new file mode 100644
index 0000000000..11b45ea19d
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/reflect/FastClassEmitter.java
@@ -0,0 +1,227 @@
+/*
+ * Copyright 2003,2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.reflect;
+
+import java.lang.reflect.*;
+import java.util.*;
+import org.springframework.cglib.core.*;
+import org.springframework.asm.ClassVisitor;
+import org.springframework.asm.Label;
+import org.springframework.asm.Type;
+
+@SuppressWarnings({"rawtypes", "unchecked", "deprecation"})
+class FastClassEmitter extends ClassEmitter {
+ private static final Signature CSTRUCT_CLASS =
+ TypeUtils.parseConstructor("Class");
+ private static final Signature METHOD_GET_INDEX =
+ TypeUtils.parseSignature("int getIndex(String, Class[])");
+ private static final Signature SIGNATURE_GET_INDEX =
+ new Signature("getIndex", Type.INT_TYPE, new Type[]{ Constants.TYPE_SIGNATURE });
+ private static final Signature TO_STRING =
+ TypeUtils.parseSignature("String toString()");
+ private static final Signature CONSTRUCTOR_GET_INDEX =
+ TypeUtils.parseSignature("int getIndex(Class[])");
+ private static final Signature INVOKE =
+ TypeUtils.parseSignature("Object invoke(int, Object, Object[])");
+ private static final Signature NEW_INSTANCE =
+ TypeUtils.parseSignature("Object newInstance(int, Object[])");
+ private static final Signature GET_MAX_INDEX =
+ TypeUtils.parseSignature("int getMaxIndex()");
+ private static final Signature GET_SIGNATURE_WITHOUT_RETURN_TYPE =
+ TypeUtils.parseSignature("String getSignatureWithoutReturnType(String, Class[])");
+ private static final Type FAST_CLASS =
+ TypeUtils.parseType("org.springframework.cglib.reflect.FastClass");
+ private static final Type ILLEGAL_ARGUMENT_EXCEPTION =
+ TypeUtils.parseType("IllegalArgumentException");
+ private static final Type INVOCATION_TARGET_EXCEPTION =
+ TypeUtils.parseType("java.lang.reflect.InvocationTargetException");
+ private static final Type[] INVOCATION_TARGET_EXCEPTION_ARRAY = { INVOCATION_TARGET_EXCEPTION };
+
+ public FastClassEmitter(ClassVisitor v, String className, Class type) {
+ super(v);
+
+ Type base = Type.getType(type);
+ begin_class(Constants.V1_8, Constants.ACC_PUBLIC, className, FAST_CLASS, null, Constants.SOURCE_FILE);
+
+ // constructor
+ CodeEmitter e = begin_method(Constants.ACC_PUBLIC, CSTRUCT_CLASS, null);
+ e.load_this();
+ e.load_args();
+ e.super_invoke_constructor(CSTRUCT_CLASS);
+ e.return_value();
+ e.end_method();
+
+ VisibilityPredicate vp = new VisibilityPredicate(type, false);
+ List methods = ReflectUtils.addAllMethods(type, new ArrayList());
+ CollectionUtils.filter(methods, vp);
+ CollectionUtils.filter(methods, new DuplicatesPredicate());
+ List constructors = new ArrayList(Arrays.asList(type.getDeclaredConstructors()));
+ CollectionUtils.filter(constructors, vp);
+
+ // getIndex(String)
+ emitIndexBySignature(methods);
+
+ // getIndex(String, Class[])
+ emitIndexByClassArray(methods);
+
+ // getIndex(Class[])
+ e = begin_method(Constants.ACC_PUBLIC, CONSTRUCTOR_GET_INDEX, null);
+ e.load_args();
+ List info = CollectionUtils.transform(constructors, MethodInfoTransformer.getInstance());
+ EmitUtils.constructor_switch(e, info, new GetIndexCallback(e, info));
+ e.end_method();
+
+ // invoke(int, Object, Object[])
+ e = begin_method(Constants.ACC_PUBLIC, INVOKE, INVOCATION_TARGET_EXCEPTION_ARRAY);
+ e.load_arg(1);
+ e.checkcast(base);
+ e.load_arg(0);
+ invokeSwitchHelper(e, methods, 2, base);
+ e.end_method();
+
+ // newInstance(int, Object[])
+ e = begin_method(Constants.ACC_PUBLIC, NEW_INSTANCE, INVOCATION_TARGET_EXCEPTION_ARRAY);
+ e.new_instance(base);
+ e.dup();
+ e.load_arg(0);
+ invokeSwitchHelper(e, constructors, 1, base);
+ e.end_method();
+
+ // getMaxIndex()
+ e = begin_method(Constants.ACC_PUBLIC, GET_MAX_INDEX, null);
+ e.push(methods.size() - 1);
+ e.return_value();
+ e.end_method();
+
+ end_class();
+ }
+
+ // TODO: support constructor indices ("Delegate
+ *
+ * public interface MainDelegate {
+ * int main(String[] args);
+ * }
+ *
+ *
+ * MethodDelegate.create(this, "alternateMain", MainDelegate.class).
+ * The following program will show how to use it:
+ *
+ * public class Main {
+ * public static int main( String[] args ) {
+ * Main newMain = new Main();
+ * MainDelegate start = (MainDelegate)
+ * MethodDelegate.create(newMain, "alternateMain", MainDelegate.class);
+ * return start.main( args );
+ * }
+ *
+ * public int alternateMain( String[] args ) {
+ * for (int i = 0; i < args.length; i++) {
+ * System.out.println( args[i] );
+ * }
+ * return args.length;
+ * }
+ * }
+ *
+ *
+ * main method by
+ * substituting the delegate creation call with this:
+ * MethodDelegate.createStatic(getClass(), "main", MainDelegate.class).
+ * Equality
+ * The criteria that we use to test if two delegates are equal are:
+ *
+ *
+ *
+ * @version $Id: MethodDelegate.java,v 1.25 2006/03/05 02:43:19 herbyderby Exp $
+ */
+@SuppressWarnings({"rawtypes", "unchecked"})
+abstract public class MethodDelegate {
+ private static final MethodDelegateKey KEY_FACTORY =
+ (MethodDelegateKey)KeyFactory.create(MethodDelegateKey.class, KeyFactory.CLASS_BY_NAME);
+
+ protected Object target;
+ protected String eqMethod;
+
+ interface MethodDelegateKey {
+ Object newInstance(Class delegateClass, String methodName, Class iface);
+ }
+
+ public static MethodDelegate createStatic(Class targetClass, String methodName, Class iface) {
+ Generator gen = new Generator();
+ gen.setTargetClass(targetClass);
+ gen.setMethodName(methodName);
+ gen.setInterface(iface);
+ return gen.create();
+ }
+
+ public static MethodDelegate create(Object target, String methodName, Class iface) {
+ Generator gen = new Generator();
+ gen.setTarget(target);
+ gen.setMethodName(methodName);
+ gen.setInterface(iface);
+ return gen.create();
+ }
+
+ public boolean equals(Object obj) {
+ MethodDelegate other = (MethodDelegate)obj;
+ return (other != null && target == other.target) && eqMethod.equals(other.eqMethod);
+ }
+
+ public int hashCode() {
+ return target.hashCode() ^ eqMethod.hashCode();
+ }
+
+ public Object getTarget() {
+ return target;
+ }
+
+ abstract public MethodDelegate newInstance(Object target);
+
+ public static class Generator extends AbstractClassGenerator {
+ private static final Source SOURCE = new Source(MethodDelegate.class.getName());
+ private static final Type METHOD_DELEGATE =
+ TypeUtils.parseType("org.springframework.cglib.reflect.MethodDelegate");
+ private static final Signature NEW_INSTANCE =
+ new Signature("newInstance", METHOD_DELEGATE, new Type[]{ Constants.TYPE_OBJECT });
+
+ private Object target;
+ private Class targetClass;
+ private String methodName;
+ private Class iface;
+
+ public Generator() {
+ super(SOURCE);
+ }
+
+ public void setTarget(Object target) {
+ this.target = target;
+ this.targetClass = target.getClass();
+ }
+
+ public void setTargetClass(Class targetClass) {
+ this.targetClass = targetClass;
+ }
+
+ public void setMethodName(String methodName) {
+ this.methodName = methodName;
+ }
+
+ public void setInterface(Class iface) {
+ this.iface = iface;
+ }
+
+ protected ClassLoader getDefaultClassLoader() {
+ return targetClass.getClassLoader();
+ }
+
+ protected ProtectionDomain getProtectionDomain() {
+ return ReflectUtils.getProtectionDomain(targetClass);
+ }
+
+ public MethodDelegate create() {
+ setNamePrefix(targetClass.getName());
+ Object key = KEY_FACTORY.newInstance(targetClass, methodName, iface);
+ return (MethodDelegate)super.create(key);
+ }
+
+ protected Object firstInstance(Class type) {
+ return ((MethodDelegate)ReflectUtils.newInstance(type)).newInstance(target);
+ }
+
+ protected Object nextInstance(Object instance) {
+ return ((MethodDelegate)instance).newInstance(target);
+ }
+
+ public void generateClass(ClassVisitor v) throws NoSuchMethodException {
+ Method proxy = ReflectUtils.findInterfaceMethod(iface);
+ final Method method = targetClass.getMethod(methodName, proxy.getParameterTypes());
+ if (!proxy.getReturnType().isAssignableFrom(method.getReturnType())) {
+ throw new IllegalArgumentException("incompatible return types");
+ }
+
+ MethodInfo methodInfo = ReflectUtils.getMethodInfo(method);
+
+ boolean isStatic = TypeUtils.isStatic(methodInfo.getModifiers());
+ if ((target == null) ^ isStatic) {
+ throw new IllegalArgumentException("Static method " + (isStatic ? "not " : "") + "expected");
+ }
+
+ ClassEmitter ce = new ClassEmitter(v);
+ CodeEmitter e;
+ ce.begin_class(Constants.V1_8,
+ Constants.ACC_PUBLIC,
+ getClassName(),
+ METHOD_DELEGATE,
+ new Type[]{ Type.getType(iface) },
+ Constants.SOURCE_FILE);
+ ce.declare_field(Constants.PRIVATE_FINAL_STATIC, "eqMethod", Constants.TYPE_STRING, null);
+ EmitUtils.null_constructor(ce);
+
+ // generate proxied method
+ MethodInfo proxied = ReflectUtils.getMethodInfo(iface.getDeclaredMethods()[0]);
+ int modifiers = Constants.ACC_PUBLIC;
+ if ((proxied.getModifiers() & Constants.ACC_VARARGS) == Constants.ACC_VARARGS) {
+ modifiers |= Constants.ACC_VARARGS;
+ }
+ e = EmitUtils.begin_method(ce, proxied, modifiers);
+ e.load_this();
+ e.super_getfield("target", Constants.TYPE_OBJECT);
+ e.checkcast(methodInfo.getClassInfo().getType());
+ e.load_args();
+ e.invoke(methodInfo);
+ e.return_value();
+ e.end_method();
+
+ // newInstance
+ e = ce.begin_method(Constants.ACC_PUBLIC, NEW_INSTANCE, null);
+ e.new_instance_this();
+ e.dup();
+ e.dup2();
+ e.invoke_constructor_this();
+ e.getfield("eqMethod");
+ e.super_putfield("eqMethod", Constants.TYPE_STRING);
+ e.load_arg(0);
+ e.super_putfield("target", Constants.TYPE_OBJECT);
+ e.return_value();
+ e.end_method();
+
+ // static initializer
+ e = ce.begin_static();
+ e.push(methodInfo.getSignature().toString());
+ e.putfield("eqMethod");
+ e.return_value();
+ e.end_method();
+
+ ce.end_class();
+ }
+ }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/reflect/MulticastDelegate.java b/spring-core/src/main/java/org/springframework/cglib/reflect/MulticastDelegate.java
new file mode 100644
index 0000000000..1842d4f051
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/reflect/MulticastDelegate.java
@@ -0,0 +1,180 @@
+/*
+ * Copyright 2003,2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.reflect;
+
+import java.lang.reflect.*;
+import java.security.ProtectionDomain;
+import java.util.*;
+import org.springframework.cglib.core.*;
+import org.springframework.asm.ClassVisitor;
+import org.springframework.asm.MethodVisitor;
+import org.springframework.asm.Type;
+
+@SuppressWarnings({"rawtypes", "unchecked"})
+abstract public class MulticastDelegate implements Cloneable {
+ protected Object[] targets = {};
+
+ protected MulticastDelegate() {
+ }
+
+ public List getTargets() {
+ return new ArrayList(Arrays.asList(targets));
+ }
+
+ abstract public MulticastDelegate add(Object target);
+
+ protected MulticastDelegate addHelper(Object target) {
+ MulticastDelegate copy = newInstance();
+ copy.targets = new Object[targets.length + 1];
+ System.arraycopy(targets, 0, copy.targets, 0, targets.length);
+ copy.targets[targets.length] = target;
+ return copy;
+ }
+
+ public MulticastDelegate remove(Object target) {
+ for (int i = targets.length - 1; i >= 0; i--) {
+ if (targets[i].equals(target)) {
+ MulticastDelegate copy = newInstance();
+ copy.targets = new Object[targets.length - 1];
+ System.arraycopy(targets, 0, copy.targets, 0, i);
+ System.arraycopy(targets, i + 1, copy.targets, i, targets.length - i - 1);
+ return copy;
+ }
+ }
+ return this;
+ }
+
+ abstract public MulticastDelegate newInstance();
+
+ public static MulticastDelegate create(Class iface) {
+ Generator gen = new Generator();
+ gen.setInterface(iface);
+ return gen.create();
+ }
+
+ public static class Generator extends AbstractClassGenerator {
+ private static final Source SOURCE = new Source(MulticastDelegate.class.getName());
+ private static final Type MULTICAST_DELEGATE =
+ TypeUtils.parseType("org.springframework.cglib.reflect.MulticastDelegate");
+ private static final Signature NEW_INSTANCE =
+ new Signature("newInstance", MULTICAST_DELEGATE, new Type[0]);
+ private static final Signature ADD_DELEGATE =
+ new Signature("add", MULTICAST_DELEGATE, new Type[]{ Constants.TYPE_OBJECT });
+ private static final Signature ADD_HELPER =
+ new Signature("addHelper", MULTICAST_DELEGATE, new Type[]{ Constants.TYPE_OBJECT });
+
+ private Class iface;
+
+ public Generator() {
+ super(SOURCE);
+ }
+
+ protected ClassLoader getDefaultClassLoader() {
+ return iface.getClassLoader();
+ }
+
+ protected ProtectionDomain getProtectionDomain() {
+ return ReflectUtils.getProtectionDomain(iface);
+ }
+
+ public void setInterface(Class iface) {
+ this.iface = iface;
+ }
+
+ public MulticastDelegate create() {
+ setNamePrefix(MulticastDelegate.class.getName());
+ return (MulticastDelegate)super.create(iface.getName());
+ }
+
+ public void generateClass(ClassVisitor cv) {
+ final MethodInfo method = ReflectUtils.getMethodInfo(ReflectUtils.findInterfaceMethod(iface));
+
+ ClassEmitter ce = new ClassEmitter(cv);
+ ce.begin_class(Constants.V1_8,
+ Constants.ACC_PUBLIC,
+ getClassName(),
+ MULTICAST_DELEGATE,
+ new Type[]{ Type.getType(iface) },
+ Constants.SOURCE_FILE);
+ EmitUtils.null_constructor(ce);
+
+ // generate proxied method
+ emitProxy(ce, method);
+
+ // newInstance
+ CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, NEW_INSTANCE, null);
+ e.new_instance_this();
+ e.dup();
+ e.invoke_constructor_this();
+ e.return_value();
+ e.end_method();
+
+ // add
+ e = ce.begin_method(Constants.ACC_PUBLIC, ADD_DELEGATE, null);
+ e.load_this();
+ e.load_arg(0);
+ e.checkcast(Type.getType(iface));
+ e.invoke_virtual_this(ADD_HELPER);
+ e.return_value();
+ e.end_method();
+
+ ce.end_class();
+ }
+
+ private void emitProxy(ClassEmitter ce, final MethodInfo method) {
+ int modifiers = Constants.ACC_PUBLIC;
+ if ((method.getModifiers() & Constants.ACC_VARARGS) == Constants.ACC_VARARGS) {
+ modifiers |= Constants.ACC_VARARGS;
+ }
+ final CodeEmitter e = EmitUtils.begin_method(ce, method, modifiers);
+ Type returnType = method.getSignature().getReturnType();
+ final boolean returns = returnType != Type.VOID_TYPE;
+ Local result = null;
+ if (returns) {
+ result = e.make_local(returnType);
+ e.zero_or_null(returnType);
+ e.store_local(result);
+ }
+ e.load_this();
+ e.super_getfield("targets", Constants.TYPE_OBJECT_ARRAY);
+ final Local result2 = result;
+ EmitUtils.process_array(e, Constants.TYPE_OBJECT_ARRAY, new ProcessArrayCallback() {
+ public void processElement(Type type) {
+ e.checkcast(Type.getType(iface));
+ e.load_args();
+ e.invoke(method);
+ if (returns) {
+ e.store_local(result2);
+ }
+ }
+ });
+ if (returns) {
+ e.load_local(result);
+ }
+ e.return_value();
+ e.end_method();
+ }
+
+ protected Object firstInstance(Class type) {
+ // make a new instance in case first object is used with a long list of targets
+ return ((MulticastDelegate)ReflectUtils.newInstance(type)).newInstance();
+ }
+
+ protected Object nextInstance(Object instance) {
+ return ((MulticastDelegate)instance).newInstance();
+ }
+ }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/transform/AbstractClassFilterTransformer.java b/spring-core/src/main/java/org/springframework/cglib/transform/AbstractClassFilterTransformer.java
new file mode 100644
index 0000000000..e82cc31a0d
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/transform/AbstractClassFilterTransformer.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.transform;
+
+import org.springframework.asm.*;
+
+abstract public class AbstractClassFilterTransformer extends AbstractClassTransformer {
+ private ClassTransformer pass;
+ private ClassVisitor target;
+
+ public void setTarget(ClassVisitor target) {
+ super.setTarget(target);
+ pass.setTarget(target);
+ }
+
+ protected AbstractClassFilterTransformer(ClassTransformer pass) {
+ this.pass = pass;
+ }
+
+ abstract protected boolean accept(int version, int access, String name, String signature, String superName, String[] interfaces);
+
+ public void visit(int version,
+ int access,
+ String name,
+ String signature,
+ String superName,
+ String[] interfaces) {
+ target = accept(version, access, name, signature, superName, interfaces) ? pass : cv;
+ target.visit(version, access, name, signature, superName, interfaces);
+ }
+
+ public void visitSource(String source, String debug) {
+ target.visitSource(source, debug);
+ }
+
+ public void visitOuterClass(String owner, String name, String desc) {
+ target.visitOuterClass(owner, name, desc);
+ }
+
+ public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+ return target.visitAnnotation(desc, visible);
+ }
+
+ public void visitAttribute(Attribute attr) {
+ target.visitAttribute(attr);
+ }
+
+ public void visitInnerClass(String name, String outerName, String innerName, int access) {
+ target.visitInnerClass(name, outerName, innerName, access);
+ }
+
+ public FieldVisitor visitField(int access,
+ String name,
+ String desc,
+ String signature,
+ Object value) {
+ return target.visitField(access, name, desc, signature, value);
+ }
+
+ public MethodVisitor visitMethod(int access,
+ String name,
+ String desc,
+ String signature,
+ String[] exceptions) {
+ return target.visitMethod(access, name, desc, signature, exceptions);
+ }
+
+ public void visitEnd() {
+ target.visitEnd();
+ target = null; // just to be safe
+ }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/transform/AbstractClassLoader.java b/spring-core/src/main/java/org/springframework/cglib/transform/AbstractClassLoader.java
new file mode 100644
index 0000000000..293037bb9a
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/transform/AbstractClassLoader.java
@@ -0,0 +1,112 @@
+/*
+ * Copyright 2003,2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.transform;
+
+import org.springframework.cglib.core.CodeGenerationException;
+import org.springframework.cglib.core.ClassGenerator;
+import org.springframework.cglib.core.DebuggingClassWriter;
+import org.springframework.asm.ClassReader;
+import org.springframework.asm.ClassWriter;
+import org.springframework.asm.Attribute;
+
+import java.io.IOException;
+
+@SuppressWarnings({"rawtypes", "unchecked"})
+abstract public class AbstractClassLoader extends ClassLoader {
+ private ClassFilter filter;
+ private ClassLoader classPath;
+ private static java.security.ProtectionDomain DOMAIN ;
+
+ static{
+ DOMAIN = AbstractClassLoader.class.getProtectionDomain();
+ }
+
+ protected AbstractClassLoader(ClassLoader parent, ClassLoader classPath, ClassFilter filter) {
+ super(parent);
+ this.filter = filter;
+ this.classPath = classPath;
+ }
+
+ public Class loadClass(String name) throws ClassNotFoundException {
+
+ Class loaded = findLoadedClass(name);
+
+ if( loaded != null ){
+ if( loaded.getClassLoader() == this ){
+ return loaded;
+ }//else reload with this class loader
+ }
+
+ if (!filter.accept(name)) {
+ return super.loadClass(name);
+ }
+ ClassReader r;
+ try {
+
+ java.io.InputStream is = classPath.getResourceAsStream(
+ name.replace('.','/') + ".class"
+ );
+
+ if (is == null) {
+
+ throw new ClassNotFoundException(name);
+
+ }
+ try {
+
+ r = new ClassReader(is);
+
+ } finally {
+
+ is.close();
+
+ }
+ } catch (IOException e) {
+ throw new ClassNotFoundException(name + ":" + e.getMessage());
+ }
+
+ try {
+ DebuggingClassWriter w =
+ new DebuggingClassWriter(ClassWriter.COMPUTE_FRAMES);
+ getGenerator(r).generateClass(w);
+ byte[] b = w.toByteArray();
+ Class c = super.defineClass(name, b, 0, b.length, DOMAIN);
+ postProcess(c);
+ return c;
+ } catch (RuntimeException e) {
+ throw e;
+ } catch (Error e) {
+ throw e;
+ } catch (Exception e) {
+ throw new CodeGenerationException(e);
+ }
+ }
+
+ protected ClassGenerator getGenerator(ClassReader r) {
+ return new ClassReaderGenerator(r, attributes(), getFlags());
+ }
+
+ protected int getFlags() {
+ return 0;
+ }
+
+ protected Attribute[] attributes() {
+ return null;
+ }
+
+ protected void postProcess(Class c) {
+ }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/transform/AbstractClassTransformer.java b/spring-core/src/main/java/org/springframework/cglib/transform/AbstractClassTransformer.java
new file mode 100644
index 0000000000..7236f1d50e
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/transform/AbstractClassTransformer.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2003 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.transform;
+
+import org.springframework.cglib.core.Constants;
+import org.springframework.asm.ClassVisitor;
+
+abstract public class AbstractClassTransformer extends ClassTransformer {
+ protected AbstractClassTransformer() {
+ super(Constants.ASM_API);
+ }
+
+ public void setTarget(ClassVisitor target) {
+ cv = target;
+ }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/transform/AnnotationVisitorTee.java b/spring-core/src/main/java/org/springframework/cglib/transform/AnnotationVisitorTee.java
new file mode 100644
index 0000000000..f194d9a037
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/transform/AnnotationVisitorTee.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2003 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.transform;
+
+import org.springframework.cglib.core.Constants;
+import org.springframework.asm.AnnotationVisitor;
+
+public class AnnotationVisitorTee extends AnnotationVisitor {
+ private AnnotationVisitor av1, av2;
+
+ public static AnnotationVisitor getInstance(AnnotationVisitor av1, AnnotationVisitor av2) {
+ if (av1 == null)
+ return av2;
+ if (av2 == null)
+ return av1;
+ return new AnnotationVisitorTee(av1, av2);
+ }
+
+ public AnnotationVisitorTee(AnnotationVisitor av1, AnnotationVisitor av2) {
+ super(Constants.ASM_API);
+ this.av1 = av1;
+ this.av2 = av2;
+ }
+
+ public void visit(String name, Object value) {
+ av2.visit(name, value);
+ av2.visit(name, value);
+ }
+
+ public void visitEnum(String name, String desc, String value) {
+ av1.visitEnum(name, desc, value);
+ av2.visitEnum(name, desc, value);
+ }
+
+ public AnnotationVisitor visitAnnotation(String name, String desc) {
+ return getInstance(av1.visitAnnotation(name, desc),
+ av2.visitAnnotation(name, desc));
+ }
+
+ public AnnotationVisitor visitArray(String name) {
+ return getInstance(av1.visitArray(name), av2.visitArray(name));
+ }
+
+ public void visitEnd() {
+ av1.visitEnd();
+ av2.visitEnd();
+ }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/transform/ClassEmitterTransformer.java b/spring-core/src/main/java/org/springframework/cglib/transform/ClassEmitterTransformer.java
new file mode 100644
index 0000000000..60236b0a99
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/transform/ClassEmitterTransformer.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2003 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.transform;
+
+import org.springframework.cglib.core.ClassEmitter;
+
+abstract public class ClassEmitterTransformer extends ClassEmitter {
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/transform/ClassFilter.java b/spring-core/src/main/java/org/springframework/cglib/transform/ClassFilter.java
new file mode 100644
index 0000000000..adb63550fd
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/transform/ClassFilter.java
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2003 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.springframework.cglib.transform;
+
+/**
+ *
+ * @author baliuka
+ */
+public interface ClassFilter {
+
+ boolean accept(String className);
+
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/transform/ClassFilterTransformer.java b/spring-core/src/main/java/org/springframework/cglib/transform/ClassFilterTransformer.java
new file mode 100644
index 0000000000..d4690db6c8
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/transform/ClassFilterTransformer.java
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2003,2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.transform;
+
+import org.springframework.asm.*;
+
+public class ClassFilterTransformer extends AbstractClassFilterTransformer {
+ private ClassFilter filter;
+
+ public ClassFilterTransformer(ClassFilter filter, ClassTransformer pass) {
+ super(pass);
+ this.filter = filter;
+ }
+
+ protected boolean accept(int version, int access, String name, String signature, String superName, String[] interfaces) {
+ return filter.accept(name.replace('/', '.'));
+ }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/transform/ClassReaderGenerator.java b/spring-core/src/main/java/org/springframework/cglib/transform/ClassReaderGenerator.java
new file mode 100644
index 0000000000..152d4089de
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/transform/ClassReaderGenerator.java
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2003 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.transform;
+
+import org.springframework.cglib.core.ClassGenerator;
+import org.springframework.asm.Attribute;
+import org.springframework.asm.ClassReader;
+import org.springframework.asm.ClassVisitor;
+
+public class ClassReaderGenerator implements ClassGenerator {
+ private final ClassReader r;
+ private final Attribute[] attrs;
+ private final int flags;
+
+ public ClassReaderGenerator(ClassReader r, int flags) {
+ this(r, null, flags);
+ }
+
+ public ClassReaderGenerator(ClassReader r, Attribute[] attrs, int flags) {
+ this.r = r;
+ this.attrs = (attrs != null) ? attrs : new Attribute[0];
+ this.flags = flags;
+ }
+
+ public void generateClass(ClassVisitor v) {
+ r.accept(v, attrs, flags);
+ }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/transform/ClassTransformer.java b/spring-core/src/main/java/org/springframework/cglib/transform/ClassTransformer.java
new file mode 100644
index 0000000000..0c678d9b50
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/transform/ClassTransformer.java
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2003 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.transform;
+
+import org.springframework.cglib.core.Constants;
+import org.springframework.asm.ClassVisitor;
+
+public abstract class ClassTransformer extends ClassVisitor {
+ public ClassTransformer() {
+ super(Constants.ASM_API);
+ }
+ public ClassTransformer(int opcode) {
+ super(opcode);
+ }
+ public abstract void setTarget(ClassVisitor target);
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/transform/ClassTransformerChain.java b/spring-core/src/main/java/org/springframework/cglib/transform/ClassTransformerChain.java
new file mode 100644
index 0000000000..482464ebee
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/transform/ClassTransformerChain.java
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2003,2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.transform;
+
+import org.springframework.asm.*;
+
+public class ClassTransformerChain extends AbstractClassTransformer {
+ private ClassTransformer[] chain;
+
+ public ClassTransformerChain(ClassTransformer[] chain) {
+ this.chain = chain.clone();
+ }
+
+ public void setTarget(ClassVisitor v) {
+ super.setTarget(chain[0]);
+ ClassVisitor next = v;
+ for (int i = chain.length - 1; i >= 0; i--) {
+ chain[i].setTarget(next);
+ next = chain[i];
+ }
+ }
+
+ public MethodVisitor visitMethod(int access,
+ String name,
+ String desc,
+ String signature,
+ String[] exceptions) {
+ return cv.visitMethod(access, name, desc, signature, exceptions);
+ }
+
+ public String toString() {
+ StringBuffer sb = new StringBuffer();
+ sb.append("ClassTransformerChain{");
+ for (int i = 0; i < chain.length; i++) {
+ if (i > 0) {
+ sb.append(", ");
+ }
+ sb.append(chain[i].toString());
+ }
+ sb.append("}");
+ return sb.toString();
+ }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/transform/ClassTransformerFactory.java b/spring-core/src/main/java/org/springframework/cglib/transform/ClassTransformerFactory.java
new file mode 100644
index 0000000000..8f9305a627
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/transform/ClassTransformerFactory.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2003 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.transform;
+
+public interface ClassTransformerFactory {
+ ClassTransformer newInstance();
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/transform/ClassTransformerTee.java b/spring-core/src/main/java/org/springframework/cglib/transform/ClassTransformerTee.java
new file mode 100644
index 0000000000..1588a0ac66
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/transform/ClassTransformerTee.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright 2003 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.transform;
+
+import org.springframework.cglib.core.Constants;
+import org.springframework.asm.ClassVisitor;
+
+public class ClassTransformerTee extends ClassTransformer {
+ private ClassVisitor branch;
+
+ public ClassTransformerTee(ClassVisitor branch) {
+ super(Constants.ASM_API);
+ this.branch = branch;
+ }
+
+ public void setTarget(ClassVisitor target) {
+ cv = new ClassVisitorTee(branch, target);
+ }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/transform/ClassVisitorTee.java b/spring-core/src/main/java/org/springframework/cglib/transform/ClassVisitorTee.java
new file mode 100644
index 0000000000..ba94335feb
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/transform/ClassVisitorTee.java
@@ -0,0 +1,104 @@
+/*
+ * Copyright 2003 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.transform;
+
+import org.springframework.cglib.core.Constants;
+import org.springframework.asm.*;
+
+public class ClassVisitorTee extends ClassVisitor {
+ private ClassVisitor cv1, cv2;
+
+ public ClassVisitorTee(ClassVisitor cv1, ClassVisitor cv2) {
+ super(Constants.ASM_API);
+ this.cv1 = cv1;
+ this.cv2 = cv2;
+ }
+
+ public void visit(int version,
+ int access,
+ String name,
+ String signature,
+ String superName,
+ String[] interfaces) {
+ cv1.visit(version, access, name, signature, superName, interfaces);
+ cv2.visit(version, access, name, signature, superName, interfaces);
+ }
+
+ public void visitEnd() {
+ cv1.visitEnd();
+ cv2.visitEnd();
+ cv1 = cv2 = null;
+ }
+
+ public void visitInnerClass(String name, String outerName, String innerName, int access) {
+ cv1.visitInnerClass(name, outerName, innerName, access);
+ cv2.visitInnerClass(name, outerName, innerName, access);
+ }
+
+ public FieldVisitor visitField(int access,
+ String name,
+ String desc,
+ String signature,
+ Object value) {
+ FieldVisitor fv1 = cv1.visitField(access, name, desc, signature, value);
+ FieldVisitor fv2 = cv2.visitField(access, name, desc, signature, value);
+ if (fv1 == null)
+ return fv2;
+ if (fv2 == null)
+ return fv1;
+ return new FieldVisitorTee(fv1, fv2);
+ }
+
+
+ public MethodVisitor visitMethod(int access,
+ String name,
+ String desc,
+ String signature,
+ String[] exceptions) {
+ MethodVisitor mv1 = cv1.visitMethod(access, name, desc, signature, exceptions);
+ MethodVisitor mv2 = cv2.visitMethod(access, name, desc, signature, exceptions);
+ if (mv1 == null)
+ return mv2;
+ if (mv2 == null)
+ return mv1;
+ return new MethodVisitorTee(mv1, mv2);
+ }
+
+ public void visitSource(String source, String debug) {
+ cv1.visitSource(source, debug);
+ cv2.visitSource(source, debug);
+ }
+
+ public void visitOuterClass(String owner, String name, String desc) {
+ cv1.visitOuterClass(owner, name, desc);
+ cv2.visitOuterClass(owner, name, desc);
+ }
+
+ public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+ return AnnotationVisitorTee.getInstance(cv1.visitAnnotation(desc, visible),
+ cv2.visitAnnotation(desc, visible));
+ }
+
+ public void visitAttribute(Attribute attrs) {
+ cv1.visitAttribute(attrs);
+ cv2.visitAttribute(attrs);
+ }
+
+ public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
+ return AnnotationVisitorTee.getInstance(cv1.visitTypeAnnotation(typeRef, typePath, desc, visible),
+ cv2.visitTypeAnnotation(typeRef, typePath, desc, visible));
+ }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/transform/FieldVisitorTee.java b/spring-core/src/main/java/org/springframework/cglib/transform/FieldVisitorTee.java
new file mode 100644
index 0000000000..a6c538099d
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/transform/FieldVisitorTee.java
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2003 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.transform;
+
+import org.springframework.cglib.core.Constants;
+import org.springframework.asm.AnnotationVisitor;
+import org.springframework.asm.Attribute;
+import org.springframework.asm.FieldVisitor;
+import org.springframework.asm.TypePath;
+
+public class FieldVisitorTee extends FieldVisitor {
+ private FieldVisitor fv1, fv2;
+
+ public FieldVisitorTee(FieldVisitor fv1, FieldVisitor fv2) {
+ super(Constants.ASM_API);
+ this.fv1 = fv1;
+ this.fv2 = fv2;
+ }
+
+ public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+ return AnnotationVisitorTee.getInstance(fv1.visitAnnotation(desc, visible),
+ fv2.visitAnnotation(desc, visible));
+ }
+
+ public void visitAttribute(Attribute attr) {
+ fv1.visitAttribute(attr);
+ fv2.visitAttribute(attr);
+ }
+
+ public void visitEnd() {
+ fv1.visitEnd();
+ fv2.visitEnd();
+ }
+
+ public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
+ return AnnotationVisitorTee.getInstance(fv1.visitTypeAnnotation(typeRef, typePath, desc, visible),
+ fv2.visitTypeAnnotation(typeRef, typePath, desc, visible));
+ }
+}
+
diff --git a/spring-core/src/main/java/org/springframework/cglib/transform/MethodFilter.java b/spring-core/src/main/java/org/springframework/cglib/transform/MethodFilter.java
new file mode 100644
index 0000000000..401c880dea
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/transform/MethodFilter.java
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2003 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.transform;
+
+import org.springframework.asm.Attribute;
+
+public interface MethodFilter {
+ // TODO: pass class name too?
+ boolean accept(int access, String name, String desc, String signature, String[] exceptions);
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/transform/MethodFilterTransformer.java b/spring-core/src/main/java/org/springframework/cglib/transform/MethodFilterTransformer.java
new file mode 100644
index 0000000000..aa7591dccd
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/transform/MethodFilterTransformer.java
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2003 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.transform;
+
+import org.springframework.asm.*;
+
+public class MethodFilterTransformer extends AbstractClassTransformer {
+ private MethodFilter filter;
+ private ClassTransformer pass;
+ private ClassVisitor direct;
+
+ public MethodFilterTransformer(MethodFilter filter, ClassTransformer pass) {
+ this.filter = filter;
+ this.pass = pass;
+ super.setTarget(pass);
+ }
+
+ public MethodVisitor visitMethod(int access,
+ String name,
+ String desc,
+ String signature,
+ String[] exceptions) {
+ return (filter.accept(access, name, desc, signature, exceptions) ? pass : direct).visitMethod(access, name, desc, signature, exceptions);
+ }
+
+ public void setTarget(ClassVisitor target) {
+ pass.setTarget(target);
+ direct = target;
+ }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/transform/MethodVisitorTee.java b/spring-core/src/main/java/org/springframework/cglib/transform/MethodVisitorTee.java
new file mode 100644
index 0000000000..20470bda9d
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/transform/MethodVisitorTee.java
@@ -0,0 +1,189 @@
+/*
+ * Copyright 2003 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.transform;
+
+import org.springframework.cglib.core.Constants;
+import org.springframework.asm.*;
+
+@SuppressWarnings("deprecation")
+public class MethodVisitorTee extends MethodVisitor {
+ private final MethodVisitor mv1;
+ private final MethodVisitor mv2;
+
+ public MethodVisitorTee(MethodVisitor mv1, MethodVisitor mv2) {
+ super(Constants.ASM_API);
+ this.mv1 = mv1;
+ this.mv2 = mv2;
+ }
+
+ public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) {
+ mv1.visitFrame(type, nLocal, local, nStack, stack);
+ mv2.visitFrame(type, nLocal, local, nStack, stack);
+ }
+
+ public AnnotationVisitor visitAnnotationDefault() {
+ return AnnotationVisitorTee.getInstance(mv1.visitAnnotationDefault(),
+ mv2.visitAnnotationDefault());
+ }
+
+ public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
+ return AnnotationVisitorTee.getInstance(mv1.visitAnnotation(desc, visible),
+ mv2.visitAnnotation(desc, visible));
+ }
+
+ public AnnotationVisitor visitParameterAnnotation(int parameter,
+ String desc,
+ boolean visible) {
+ return AnnotationVisitorTee.getInstance(mv1.visitParameterAnnotation(parameter, desc, visible),
+ mv2.visitParameterAnnotation(parameter, desc, visible));
+ }
+
+ public void visitAttribute(Attribute attr) {
+ mv1.visitAttribute(attr);
+ mv2.visitAttribute(attr);
+ }
+
+ public void visitCode() {
+ mv1.visitCode();
+ mv2.visitCode();
+ }
+
+ public void visitInsn(int opcode) {
+ mv1.visitInsn(opcode);
+ mv2.visitInsn(opcode);
+ }
+
+ public void visitIntInsn(int opcode, int operand) {
+ mv1.visitIntInsn(opcode, operand);
+ mv2.visitIntInsn(opcode, operand);
+ }
+
+ public void visitVarInsn(int opcode, int var) {
+ mv1.visitVarInsn(opcode, var);
+ mv2.visitVarInsn(opcode, var);
+ }
+
+ public void visitTypeInsn(int opcode, String desc) {
+ mv1.visitTypeInsn(opcode, desc);
+ mv2.visitTypeInsn(opcode, desc);
+ }
+
+ public void visitFieldInsn(int opcode, String owner, String name, String desc) {
+ mv1.visitFieldInsn(opcode, owner, name, desc);
+ mv2.visitFieldInsn(opcode, owner, name, desc);
+ }
+
+ public void visitMethodInsn(int opcode, String owner, String name, String desc) {
+ mv1.visitMethodInsn(opcode, owner, name, desc);
+ mv2.visitMethodInsn(opcode, owner, name, desc);
+ }
+
+ public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
+ mv1.visitMethodInsn(opcode, owner, name, desc, itf);
+ mv2.visitMethodInsn(opcode, owner, name, desc, itf);
+ }
+
+ public void visitJumpInsn(int opcode, Label label) {
+ mv1.visitJumpInsn(opcode, label);
+ mv2.visitJumpInsn(opcode, label);
+ }
+
+ public void visitLabel(Label label) {
+ mv1.visitLabel(label);
+ mv2.visitLabel(label);
+ }
+
+ public void visitLdcInsn(Object cst) {
+ mv1.visitLdcInsn(cst);
+ mv2.visitLdcInsn(cst);
+ }
+
+ public void visitIincInsn(int var, int increment) {
+ mv1.visitIincInsn(var, increment);
+ mv2.visitIincInsn(var, increment);
+ }
+
+ public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) {
+ mv1.visitTableSwitchInsn(min, max, dflt, labels);
+ mv2.visitTableSwitchInsn(min, max, dflt, labels);
+ }
+
+ public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
+ mv1.visitLookupSwitchInsn(dflt, keys, labels);
+ mv2.visitLookupSwitchInsn(dflt, keys, labels);
+ }
+
+ public void visitMultiANewArrayInsn(String desc, int dims) {
+ mv1.visitMultiANewArrayInsn(desc, dims);
+ mv2.visitMultiANewArrayInsn(desc, dims);
+ }
+
+ public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
+ mv1.visitTryCatchBlock(start, end, handler, type);
+ mv2.visitTryCatchBlock(start, end, handler, type);
+ }
+
+ public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
+ mv1.visitLocalVariable(name, desc, signature, start, end, index);
+ mv2.visitLocalVariable(name, desc, signature, start, end, index);
+ }
+
+ public void visitLineNumber(int line, Label start) {
+ mv1.visitLineNumber(line, start);
+ mv2.visitLineNumber(line, start);
+ }
+
+ public void visitMaxs(int maxStack, int maxLocals) {
+ mv1.visitMaxs(maxStack, maxLocals);
+ mv2.visitMaxs(maxStack, maxLocals);
+ }
+
+ public void visitEnd() {
+ mv1.visitEnd();
+ mv2.visitEnd();
+ }
+
+ public void visitParameter(String name, int access) {
+ mv1.visitParameter(name, access);
+ mv2.visitParameter(name, access);
+ }
+
+ public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
+ return AnnotationVisitorTee.getInstance(mv1.visitTypeAnnotation(typeRef, typePath, desc, visible),
+ mv2.visitTypeAnnotation(typeRef, typePath, desc, visible));
+ }
+
+ public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) {
+ mv1.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
+ mv2.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
+ }
+
+ public AnnotationVisitor visitInsnAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
+ return AnnotationVisitorTee.getInstance(mv1.visitInsnAnnotation(typeRef, typePath, desc, visible),
+ mv2.visitInsnAnnotation(typeRef, typePath, desc, visible));
+ }
+
+ public AnnotationVisitor visitTryCatchAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
+ return AnnotationVisitorTee.getInstance(mv1.visitTryCatchAnnotation(typeRef, typePath, desc, visible),
+ mv2.visitTryCatchAnnotation(typeRef, typePath, desc, visible));
+ }
+
+ public AnnotationVisitor visitLocalVariableAnnotation(int typeRef, TypePath typePath, Label[] start, Label[] end, int[] index, String desc, boolean visible) {
+ return AnnotationVisitorTee.getInstance(mv1.visitLocalVariableAnnotation(typeRef, typePath, start, end, index, desc, visible),
+ mv2.visitLocalVariableAnnotation(typeRef, typePath, start, end, index, desc, visible));
+ }
+}
+
diff --git a/spring-core/src/main/java/org/springframework/cglib/transform/TransformingClassGenerator.java b/spring-core/src/main/java/org/springframework/cglib/transform/TransformingClassGenerator.java
new file mode 100644
index 0000000000..a57f4dd776
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/transform/TransformingClassGenerator.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2003 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.transform;
+
+import org.springframework.cglib.core.ClassGenerator;
+import org.springframework.cglib.core.Transformer;
+import org.springframework.asm.ClassVisitor;
+
+public class TransformingClassGenerator implements ClassGenerator {
+ private ClassGenerator gen;
+ private ClassTransformer t;
+
+ public TransformingClassGenerator(ClassGenerator gen, ClassTransformer t) {
+ this.gen = gen;
+ this.t = t;
+ }
+
+ public void generateClass(ClassVisitor v) throws Exception {
+ t.setTarget(v);
+ gen.generateClass(t);
+ }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/transform/TransformingClassLoader.java b/spring-core/src/main/java/org/springframework/cglib/transform/TransformingClassLoader.java
new file mode 100644
index 0000000000..0b1861560c
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/transform/TransformingClassLoader.java
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2003 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.transform;
+
+import java.util.*;
+import org.springframework.cglib.core.ClassGenerator;
+import org.springframework.asm.*;
+
+public class TransformingClassLoader extends AbstractClassLoader {
+ private ClassTransformerFactory t;
+
+ public TransformingClassLoader(ClassLoader parent, ClassFilter filter, ClassTransformerFactory t) {
+ super(parent, parent, filter);
+ this.t = t;
+ }
+
+ protected ClassGenerator getGenerator(ClassReader r) {
+ ClassTransformer t2 = t.newInstance();
+ return new TransformingClassGenerator(super.getGenerator(r), t2);
+ }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/transform/impl/AbstractInterceptFieldCallback.java b/spring-core/src/main/java/org/springframework/cglib/transform/impl/AbstractInterceptFieldCallback.java
new file mode 100644
index 0000000000..3ac5bcc360
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/transform/impl/AbstractInterceptFieldCallback.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2004 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.transform.impl;
+
+/**
+ * @author Chris Nokleberg
+ */
+public class AbstractInterceptFieldCallback implements InterceptFieldCallback {
+
+ public int writeInt(Object obj, String name, int oldValue, int newValue) { return newValue; }
+ public char writeChar(Object obj, String name, char oldValue, char newValue) { return newValue; }
+ public byte writeByte(Object obj, String name, byte oldValue, byte newValue) { return newValue; }
+ public boolean writeBoolean(Object obj, String name, boolean oldValue, boolean newValue) { return newValue; }
+ public short writeShort(Object obj, String name, short oldValue, short newValue) { return newValue; }
+ public float writeFloat(Object obj, String name, float oldValue, float newValue) { return newValue; }
+ public double writeDouble(Object obj, String name, double oldValue, double newValue) { return newValue; }
+ public long writeLong(Object obj, String name, long oldValue, long newValue) { return newValue; }
+ public Object writeObject(Object obj, String name, Object oldValue, Object newValue) { return newValue; }
+
+ public int readInt(Object obj, String name, int oldValue) { return oldValue; }
+ public char readChar(Object obj, String name, char oldValue) { return oldValue; }
+ public byte readByte(Object obj, String name, byte oldValue) { return oldValue; }
+ public boolean readBoolean(Object obj, String name, boolean oldValue) { return oldValue; }
+ public short readShort(Object obj, String name, short oldValue) { return oldValue; }
+ public float readFloat(Object obj, String name, float oldValue) { return oldValue; }
+ public double readDouble(Object obj, String name, double oldValue) { return oldValue; }
+ public long readLong(Object obj, String name, long oldValue) { return oldValue; }
+ public Object readObject(Object obj, String name, Object oldValue) { return oldValue; }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/transform/impl/AccessFieldTransformer.java b/spring-core/src/main/java/org/springframework/cglib/transform/impl/AccessFieldTransformer.java
new file mode 100644
index 0000000000..2d322e5c00
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/transform/impl/AccessFieldTransformer.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2003 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.transform.impl;
+
+import org.springframework.cglib.transform.*;
+import org.springframework.cglib.core.*;
+import org.springframework.asm.ClassVisitor;
+import org.springframework.asm.MethodVisitor;
+import org.springframework.asm.Attribute;
+import org.springframework.asm.Type;
+
+public class AccessFieldTransformer extends ClassEmitterTransformer {
+ private Callback callback;
+
+ public AccessFieldTransformer(Callback callback) {
+ this.callback = callback;
+ }
+
+ public interface Callback {
+ String getPropertyName(Type owner, String fieldName);
+ }
+
+ public void declare_field(int access, final String name, Type type, Object value) {
+ super.declare_field(access, name, type, value);
+
+ String property = TypeUtils.upperFirst(callback.getPropertyName(getClassType(), name));
+ if (property != null) {
+ CodeEmitter e;
+ e = begin_method(Constants.ACC_PUBLIC,
+ new Signature("get" + property,
+ type,
+ Constants.TYPES_EMPTY),
+ null);
+ e.load_this();
+ e.getfield(name);
+ e.return_value();
+ e.end_method();
+
+ e = begin_method(Constants.ACC_PUBLIC,
+ new Signature("set" + property,
+ Type.VOID_TYPE,
+ new Type[]{ type }),
+ null);
+ e.load_this();
+ e.load_arg(0);
+ e.putfield(name);
+ e.return_value();
+ e.end_method();
+ }
+ }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/transform/impl/AddDelegateTransformer.java b/spring-core/src/main/java/org/springframework/cglib/transform/impl/AddDelegateTransformer.java
new file mode 100644
index 0000000000..79097818ad
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/transform/impl/AddDelegateTransformer.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2003 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.transform.impl;
+
+import org.springframework.cglib.transform.*;
+import java.lang.reflect.*;
+import java.util.*;
+import org.springframework.cglib.core.*;
+import org.springframework.asm.Attribute;
+import org.springframework.asm.Type;
+
+/**
+ * @author Juozas Baliuka
+ */
+@SuppressWarnings({"rawtypes", "unchecked"})
+public class AddDelegateTransformer extends ClassEmitterTransformer {
+ private static final String DELEGATE = "$CGLIB_DELEGATE";
+ private static final Signature CSTRUCT_OBJECT =
+ TypeUtils.parseSignature("void instance
+ * parameter passed to the newDelegate method was the same for both. The
+ * instances are compared with the identity equality operator, ==.
+ * Method.equals.Throwable and which has at least one
+ * constructor that takes a single argument of type
+ * Throwable, for example
+ * java.lang.reflect.UndeclaredThrowableException.class
+ */
+ public UndeclaredThrowableStrategy(Class wrapper) {
+ this.wrapper = wrapper;
+ }
+
+ private static final MethodFilter TRANSFORM_FILTER = new MethodFilter() {
+ public boolean accept(int access, String name, String desc, String signature, String[] exceptions) {
+ return !TypeUtils.isPrivate(access) && name.indexOf('$') < 0;
+ }
+ };
+
+ protected ClassGenerator transform(ClassGenerator cg) throws Exception {
+ ClassTransformer tr = new UndeclaredThrowableTransformer(wrapper);
+ tr = new MethodFilterTransformer(TRANSFORM_FILTER, tr);
+ return new TransformingClassGenerator(cg, tr);
+ }
+}
+
diff --git a/spring-core/src/main/java/org/springframework/cglib/transform/impl/UndeclaredThrowableTransformer.java b/spring-core/src/main/java/org/springframework/cglib/transform/impl/UndeclaredThrowableTransformer.java
new file mode 100644
index 0000000000..8415ac5958
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/transform/impl/UndeclaredThrowableTransformer.java
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2003 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.transform.impl;
+
+import java.lang.reflect.Constructor;
+import org.springframework.cglib.core.*;
+import org.springframework.cglib.transform.*;
+import org.springframework.asm.Attribute;
+import org.springframework.asm.Type;
+import org.springframework.asm.ClassVisitor;
+
+@SuppressWarnings({"rawtypes", "unchecked"})
+public class UndeclaredThrowableTransformer extends ClassEmitterTransformer {
+ private Type wrapper;
+
+ public UndeclaredThrowableTransformer(Class wrapper) {
+ this.wrapper = Type.getType(wrapper);
+ boolean found = false;
+ Constructor[] cstructs = wrapper.getConstructors();
+ for (int i = 0; i < cstructs.length; i++) {
+ Class[] types = cstructs[i].getParameterTypes();
+ if (types.length == 1 && types[0].equals(Throwable.class)) {
+ found = true;
+ break;
+ }
+ }
+ if (!found)
+ throw new IllegalArgumentException(wrapper + " does not have a single-arg constructor that takes a Throwable");
+ }
+
+ public CodeEmitter begin_method(int access, final Signature sig, final Type[] exceptions) {
+ CodeEmitter e = super.begin_method(access, sig, exceptions);
+ if (TypeUtils.isAbstract(access) || sig.equals(Constants.SIG_STATIC)) {
+ return e;
+ }
+ return new CodeEmitter(e) {
+ private Block handler;
+ /* init */ {
+ handler = begin_block();
+ }
+ public void visitMaxs(int maxStack, int maxLocals) {
+ handler.end();
+ EmitUtils.wrap_undeclared_throwable(this, handler, exceptions, wrapper);
+ super.visitMaxs(maxStack, maxLocals);
+ }
+ };
+ }
+}
diff --git a/spring-core/src/main/java/org/springframework/cglib/util/ParallelSorter.java b/spring-core/src/main/java/org/springframework/cglib/util/ParallelSorter.java
new file mode 100644
index 0000000000..7f9821add8
--- /dev/null
+++ b/spring-core/src/main/java/org/springframework/cglib/util/ParallelSorter.java
@@ -0,0 +1,295 @@
+/*
+ * Copyright 2003 The Apache Software Foundation
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.springframework.cglib.util;
+
+import java.lang.reflect.*;
+import java.util.Comparator;
+import org.springframework.cglib.core.*;
+import org.springframework.asm.ClassVisitor;
+
+/**
+ * For the efficient sorting of multiple arrays in parallel.
+ * -1; if true,
+ * the result will be undefined, and the resulting code will be faster
+ */
+ public static StringSwitcher create(String[] strings, int[] ints, boolean fixedInput) {
+ Generator gen = new Generator();
+ gen.setStrings(strings);
+ gen.setInts(ints);
+ gen.setFixedInput(fixedInput);
+ return gen.create();
+ }
+
+ protected StringSwitcher() {
+ }
+
+ /**
+ * Return the integer associated with the given key.
+ * @param s the key
+ * @return the associated integer value, or -1 if the key is unknown (unless
+ * fixedInput was specified when this StringSwitcher was created,
+ * in which case the return value for an unknown key is undefined)
+ */
+ abstract public int intValue(String s);
+
+ public static class Generator extends AbstractClassGenerator {
+ private static final Source SOURCE = new Source(StringSwitcher.class.getName());
+
+ private String[] strings;
+ private int[] ints;
+ private boolean fixedInput;
+
+ public Generator() {
+ super(SOURCE);
+ }
+
+ /**
+ * Set the array of recognized Strings.
+ * @param strings the array of String keys; must be the same length as the value array
+ * @see #setInts
+ */
+ public void setStrings(String[] strings) {
+ this.strings = strings;
+ }
+
+ /**
+ * Set the array of integer results.
+ * @param ints the array of integer results; must be the same length as the key array
+ * @see #setStrings
+ */
+ public void setInts(int[] ints) {
+ this.ints = ints;
+ }
+
+ /**
+ * Configure how unknown String keys will be handled.
+ * @param fixedInput if false, an unknown key will be returned from {@link #intValue} as -1; if true,
+ * the result will be undefined, and the resulting code will be faster
+ */
+ public void setFixedInput(boolean fixedInput) {
+ this.fixedInput = fixedInput;
+ }
+
+ protected ClassLoader getDefaultClassLoader() {
+ return getClass().getClassLoader();
+ }
+
+ /**
+ * Generate the StringSwitcher.
+ */
+ public StringSwitcher create() {
+ setNamePrefix(StringSwitcher.class.getName());
+ Object key = KEY_FACTORY.newInstance(strings, ints, fixedInput);
+ return (StringSwitcher)super.create(key);
+ }
+
+ public void generateClass(ClassVisitor v) throws Exception {
+ ClassEmitter ce = new ClassEmitter(v);
+ ce.begin_class(Constants.V1_8,
+ Constants.ACC_PUBLIC,
+ getClassName(),
+ STRING_SWITCHER,
+ null,
+ Constants.SOURCE_FILE);
+ EmitUtils.null_constructor(ce);
+ final CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, INT_VALUE, null);
+ e.load_arg(0);
+ final List stringList = Arrays.asList(strings);
+ int style = fixedInput ? Constants.SWITCH_STYLE_HASHONLY : Constants.SWITCH_STYLE_HASH;
+ EmitUtils.string_switch(e, strings, style, new ObjectSwitchCallback() {
+ public void processCase(Object key, Label end) {
+ e.push(ints[stringList.indexOf(key)]);
+ e.return_value();
+ }
+ public void processDefault() {
+ e.push(-1);
+ e.return_value();
+ }
+ });
+ e.end_method();
+ ce.end_class();
+ }
+
+ protected Object firstInstance(Class type) {
+ return (StringSwitcher)ReflectUtils.newInstance(type);
+ }
+
+ protected Object nextInstance(Object instance) {
+ return instance;
+ }
+ }
+}