superman
7 years ago
159 changed files with 30459 additions and 0 deletions
@ -0,0 +1,50 @@ |
|||||||
|
Casuarinaceae |
||||||
|
hylomorphic |
||||||
|
granitize |
||||||
|
biddably |
||||||
|
repulsive |
||||||
|
amphimictical |
||||||
|
trio |
||||||
|
toxodont |
||||||
|
nonreigning |
||||||
|
dragbar |
||||||
|
Moronidae |
||||||
|
unlanguishing |
||||||
|
metabolizable |
||||||
|
Osmerus |
||||||
|
goran |
||||||
|
spiritfulness |
||||||
|
tetrachloromethane |
||||||
|
baobab |
||||||
|
caroline |
||||||
|
radioconductor |
||||||
|
imband |
||||||
|
crinoline |
||||||
|
circummundane |
||||||
|
incontractile |
||||||
|
forerank |
||||||
|
modernization |
||||||
|
meal |
||||||
|
fishman |
||||||
|
underbuy |
||||||
|
pertain |
||||||
|
equiped |
||||||
|
cockal |
||||||
|
unshrined |
||||||
|
Harb |
||||||
|
heterotaxis |
||||||
|
commensurableness |
||||||
|
baggy |
||||||
|
sarcophilous |
||||||
|
tankard |
||||||
|
acervuline |
||||||
|
unverifiably |
||||||
|
premidnight |
||||||
|
strangles |
||||||
|
vitellus |
||||||
|
Socratean |
||||||
|
flock |
||||||
|
scourage |
||||||
|
feverlike |
||||||
|
citharist |
||||||
|
harn |
@ -0,0 +1,176 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.beans; |
||||||
|
|
||||||
|
import java.beans.PropertyDescriptor; |
||||||
|
import java.lang.reflect.*; |
||||||
|
import java.security.ProtectionDomain; |
||||||
|
import com.fr.third.net.sf.cglib.core.*; |
||||||
|
import com.fr.third.org.objectweb.asm.ClassVisitor; |
||||||
|
import com.fr.third.org.objectweb.asm.Type; |
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Chris Nokleberg |
||||||
|
*/ |
||||||
|
abstract public class BeanCopier |
||||||
|
{ |
||||||
|
private static final BeanCopierKey KEY_FACTORY = |
||||||
|
(BeanCopierKey)KeyFactory.create(BeanCopierKey.class); |
||||||
|
private static final Type CONVERTER = |
||||||
|
TypeUtils.parseType("com.fr.third.net.sf.cglib.core.Converter"); |
||||||
|
private static final Type BEAN_COPIER = |
||||||
|
TypeUtils.parseType("com.fr.third.net.sf.cglib.beans.BeanCopier"); |
||||||
|
private static final Signature COPY = |
||||||
|
new Signature("copy", Type.VOID_TYPE, new Type[]{ Constants.TYPE_OBJECT, Constants.TYPE_OBJECT, CONVERTER }); |
||||||
|
private static final Signature CONVERT = |
||||||
|
TypeUtils.parseSignature("Object convert(Object, Class, Object)"); |
||||||
|
|
||||||
|
interface BeanCopierKey { |
||||||
|
public Object newInstance(String source, String target, boolean useConverter); |
||||||
|
} |
||||||
|
|
||||||
|
public static BeanCopier create(Class source, Class target, boolean useConverter) { |
||||||
|
Generator gen = new Generator(); |
||||||
|
gen.setSource(source); |
||||||
|
gen.setTarget(target); |
||||||
|
gen.setUseConverter(useConverter); |
||||||
|
return gen.create(); |
||||||
|
} |
||||||
|
|
||||||
|
abstract public void copy(Object from, Object to, Converter converter); |
||||||
|
|
||||||
|
public static class Generator extends AbstractClassGenerator { |
||||||
|
private static final Source SOURCE = new Source(BeanCopier.class.getName()); |
||||||
|
private Class source; |
||||||
|
private Class target; |
||||||
|
private boolean useConverter; |
||||||
|
|
||||||
|
public Generator() { |
||||||
|
super(SOURCE); |
||||||
|
} |
||||||
|
|
||||||
|
public void setSource(Class source) { |
||||||
|
if(!Modifier.isPublic(source.getModifiers())){ |
||||||
|
setNamePrefix(source.getName()); |
||||||
|
} |
||||||
|
this.source = source; |
||||||
|
} |
||||||
|
|
||||||
|
public void setTarget(Class target) { |
||||||
|
if(!Modifier.isPublic(target.getModifiers())){ |
||||||
|
setNamePrefix(target.getName()); |
||||||
|
} |
||||||
|
|
||||||
|
this.target = target; |
||||||
|
} |
||||||
|
|
||||||
|
public void setUseConverter(boolean useConverter) { |
||||||
|
this.useConverter = useConverter; |
||||||
|
} |
||||||
|
|
||||||
|
protected ClassLoader getDefaultClassLoader() { |
||||||
|
return source.getClassLoader(); |
||||||
|
} |
||||||
|
|
||||||
|
protected ProtectionDomain getProtectionDomain() { |
||||||
|
return ReflectUtils.getProtectionDomain(source); |
||||||
|
} |
||||||
|
|
||||||
|
public BeanCopier create() { |
||||||
|
Object key = KEY_FACTORY.newInstance(source.getName(), target.getName(), useConverter); |
||||||
|
return (BeanCopier)super.create(key); |
||||||
|
} |
||||||
|
|
||||||
|
public void generateClass(ClassVisitor v) { |
||||||
|
Type sourceType = Type.getType(source); |
||||||
|
Type targetType = Type.getType(target); |
||||||
|
ClassEmitter ce = new ClassEmitter(v); |
||||||
|
ce.begin_class(Constants.V1_2, |
||||||
|
Constants.ACC_PUBLIC, |
||||||
|
getClassName(), |
||||||
|
BEAN_COPIER, |
||||||
|
null, |
||||||
|
Constants.SOURCE_FILE); |
||||||
|
|
||||||
|
EmitUtils.null_constructor(ce); |
||||||
|
CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, COPY, null); |
||||||
|
PropertyDescriptor[] getters = ReflectUtils.getBeanGetters(source); |
||||||
|
PropertyDescriptor[] setters = ReflectUtils.getBeanSetters(target); |
||||||
|
|
||||||
|
Map names = new HashMap(); |
||||||
|
for (int i = 0; i < getters.length; i++) { |
||||||
|
names.put(getters[i].getName(), getters[i]); |
||||||
|
} |
||||||
|
Local targetLocal = e.make_local(); |
||||||
|
Local sourceLocal = e.make_local(); |
||||||
|
if (useConverter) { |
||||||
|
e.load_arg(1); |
||||||
|
e.checkcast(targetType); |
||||||
|
e.store_local(targetLocal); |
||||||
|
e.load_arg(0); |
||||||
|
e.checkcast(sourceType); |
||||||
|
e.store_local(sourceLocal); |
||||||
|
} else { |
||||||
|
e.load_arg(1); |
||||||
|
e.checkcast(targetType); |
||||||
|
e.load_arg(0); |
||||||
|
e.checkcast(sourceType); |
||||||
|
} |
||||||
|
for (int i = 0; i < setters.length; i++) { |
||||||
|
PropertyDescriptor setter = setters[i]; |
||||||
|
PropertyDescriptor getter = (PropertyDescriptor)names.get(setter.getName()); |
||||||
|
if (getter != null) { |
||||||
|
MethodInfo read = ReflectUtils.getMethodInfo(getter.getReadMethod()); |
||||||
|
MethodInfo write = ReflectUtils.getMethodInfo(setter.getWriteMethod()); |
||||||
|
if (useConverter) { |
||||||
|
Type setterType = write.getSignature().getArgumentTypes()[0]; |
||||||
|
e.load_local(targetLocal); |
||||||
|
e.load_arg(2); |
||||||
|
e.load_local(sourceLocal); |
||||||
|
e.invoke(read); |
||||||
|
e.box(read.getSignature().getReturnType()); |
||||||
|
EmitUtils.load_class(e, setterType); |
||||||
|
e.push(write.getSignature().getName()); |
||||||
|
e.invoke_interface(CONVERTER, CONVERT); |
||||||
|
e.unbox_or_zero(setterType); |
||||||
|
e.invoke(write); |
||||||
|
} else if (compatible(getter, setter)) { |
||||||
|
e.dup2(); |
||||||
|
e.invoke(read); |
||||||
|
e.invoke(write); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
e.return_value(); |
||||||
|
e.end_method(); |
||||||
|
ce.end_class(); |
||||||
|
} |
||||||
|
|
||||||
|
private static boolean compatible(PropertyDescriptor getter, PropertyDescriptor setter) { |
||||||
|
// TODO: allow automatic widening conversions?
|
||||||
|
return setter.getPropertyType().isAssignableFrom(getter.getPropertyType()); |
||||||
|
} |
||||||
|
|
||||||
|
protected Object firstInstance(Class type) { |
||||||
|
return ReflectUtils.newInstance(type); |
||||||
|
} |
||||||
|
|
||||||
|
protected Object nextInstance(Object instance) { |
||||||
|
return instance; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,149 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.beans; |
||||||
|
|
||||||
|
import java.beans.PropertyDescriptor; |
||||||
|
import java.security.ProtectionDomain; |
||||||
|
import java.util.*; |
||||||
|
import com.fr.third.net.sf.cglib.core.*; |
||||||
|
import com.fr.third.org.objectweb.asm.ClassVisitor; |
||||||
|
import com.fr.third.org.objectweb.asm.Type; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Juozas Baliuka, Chris Nokleberg |
||||||
|
*/ |
||||||
|
public class BeanGenerator extends AbstractClassGenerator |
||||||
|
{ |
||||||
|
private static final Source SOURCE = new Source(BeanGenerator.class.getName()); |
||||||
|
private static final BeanGeneratorKey KEY_FACTORY = |
||||||
|
(BeanGeneratorKey)KeyFactory.create(BeanGeneratorKey.class); |
||||||
|
|
||||||
|
interface BeanGeneratorKey { |
||||||
|
public Object newInstance(String superclass, Map props); |
||||||
|
} |
||||||
|
|
||||||
|
private Class superclass; |
||||||
|
private Map props = new HashMap(); |
||||||
|
private boolean classOnly; |
||||||
|
|
||||||
|
public BeanGenerator() { |
||||||
|
super(SOURCE); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set the class which the generated class will extend. The class
|
||||||
|
* must not be declared as final, and must have a non-private |
||||||
|
* no-argument constructor. |
||||||
|
* @param superclass class to extend, or null to extend Object |
||||||
|
*/ |
||||||
|
public void setSuperclass(Class superclass) { |
||||||
|
if (superclass != null && superclass.equals(Object.class)) { |
||||||
|
superclass = null; |
||||||
|
} |
||||||
|
this.superclass = superclass; |
||||||
|
} |
||||||
|
|
||||||
|
public void addProperty(String name, Class type) { |
||||||
|
if (props.containsKey(name)) { |
||||||
|
throw new IllegalArgumentException("Duplicate property name \"" + name + "\""); |
||||||
|
} |
||||||
|
props.put(name, Type.getType(type)); |
||||||
|
} |
||||||
|
|
||||||
|
protected ClassLoader getDefaultClassLoader() { |
||||||
|
if (superclass != null) { |
||||||
|
return superclass.getClassLoader(); |
||||||
|
} else { |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected ProtectionDomain getProtectionDomain() { |
||||||
|
return ReflectUtils.getProtectionDomain(superclass); |
||||||
|
} |
||||||
|
|
||||||
|
public Object create() { |
||||||
|
classOnly = false; |
||||||
|
return createHelper(); |
||||||
|
} |
||||||
|
|
||||||
|
public Object createClass() { |
||||||
|
classOnly = true; |
||||||
|
return createHelper(); |
||||||
|
} |
||||||
|
|
||||||
|
private Object createHelper() { |
||||||
|
if (superclass != null) { |
||||||
|
setNamePrefix(superclass.getName()); |
||||||
|
} |
||||||
|
String superName = (superclass != null) ? superclass.getName() : "java.lang.Object"; |
||||||
|
Object key = KEY_FACTORY.newInstance(superName, props); |
||||||
|
return super.create(key); |
||||||
|
} |
||||||
|
|
||||||
|
public void generateClass(ClassVisitor v) throws Exception { |
||||||
|
int size = props.size(); |
||||||
|
String[] names = (String[])props.keySet().toArray(new String[size]); |
||||||
|
Type[] types = new Type[size]; |
||||||
|
for (int i = 0; i < size; i++) { |
||||||
|
types[i] = (Type)props.get(names[i]); |
||||||
|
} |
||||||
|
ClassEmitter ce = new ClassEmitter(v); |
||||||
|
ce.begin_class(Constants.V1_2, |
||||||
|
Constants.ACC_PUBLIC, |
||||||
|
getClassName(), |
||||||
|
superclass != null ? Type.getType(superclass) : Constants.TYPE_OBJECT, |
||||||
|
null, |
||||||
|
null); |
||||||
|
EmitUtils.null_constructor(ce); |
||||||
|
EmitUtils.add_properties(ce, names, types); |
||||||
|
ce.end_class(); |
||||||
|
} |
||||||
|
|
||||||
|
protected Object firstInstance(Class type) { |
||||||
|
if (classOnly) { |
||||||
|
return type; |
||||||
|
} else { |
||||||
|
return ReflectUtils.newInstance(type); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected Object nextInstance(Object instance) { |
||||||
|
Class protoclass = (instance instanceof Class) ? (Class)instance : instance.getClass(); |
||||||
|
if (classOnly) { |
||||||
|
return protoclass; |
||||||
|
} else { |
||||||
|
return ReflectUtils.newInstance(protoclass); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static void addProperties(BeanGenerator gen, Map props) { |
||||||
|
for (Iterator it = props.keySet().iterator(); it.hasNext();) { |
||||||
|
String name = (String)it.next(); |
||||||
|
gen.addProperty(name, (Class)props.get(name)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static void addProperties(BeanGenerator gen, Class type) { |
||||||
|
addProperties(gen, ReflectUtils.getBeanProperties(type)); |
||||||
|
} |
||||||
|
|
||||||
|
public static void addProperties(BeanGenerator gen, PropertyDescriptor[] descriptors) { |
||||||
|
for (int i = 0; i < descriptors.length; i++) { |
||||||
|
gen.addProperty(descriptors[i].getName(), descriptors[i].getPropertyType()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,320 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.beans; |
||||||
|
|
||||||
|
import java.security.ProtectionDomain; |
||||||
|
import java.beans.*; |
||||||
|
import java.lang.reflect.Constructor; |
||||||
|
import java.lang.reflect.Method; |
||||||
|
import java.util.*; |
||||||
|
import com.fr.third.net.sf.cglib.core.*; |
||||||
|
import com.fr.third.org.objectweb.asm.ClassVisitor; |
||||||
|
|
||||||
|
/** |
||||||
|
* A <code>Map</code>-based view of a JavaBean. The default set of keys is the |
||||||
|
* union of all property names (getters or setters). An attempt to set |
||||||
|
* a read-only property will be ignored, and write-only properties will |
||||||
|
* be returned as <code>null</code>. Removal of objects is not a |
||||||
|
* supported (the key set is fixed). |
||||||
|
* @author Chris Nokleberg |
||||||
|
*/ |
||||||
|
abstract public class BeanMap implements Map { |
||||||
|
/** |
||||||
|
* Limit the properties reflected in the key set of the map |
||||||
|
* to readable properties. |
||||||
|
* @see BeanMap.Generator#setRequire |
||||||
|
*/ |
||||||
|
public static final int REQUIRE_GETTER = 1; |
||||||
|
|
||||||
|
/** |
||||||
|
* Limit the properties reflected in the key set of the map |
||||||
|
* to writable properties. |
||||||
|
* @see BeanMap.Generator#setRequire |
||||||
|
*/ |
||||||
|
public static final int REQUIRE_SETTER = 2; |
||||||
|
|
||||||
|
/** |
||||||
|
* Helper method to create a new <code>BeanMap</code>. For finer |
||||||
|
* control over the generated instance, use a new instance of |
||||||
|
* <code>BeanMap.Generator</code> instead of this static method. |
||||||
|
* @param bean the JavaBean underlying the map |
||||||
|
* @return a new <code>BeanMap</code> instance |
||||||
|
*/ |
||||||
|
public static BeanMap create(Object bean) { |
||||||
|
Generator gen = new Generator(); |
||||||
|
gen.setBean(bean); |
||||||
|
return gen.create(); |
||||||
|
} |
||||||
|
|
||||||
|
public static class Generator extends AbstractClassGenerator { |
||||||
|
private static final Source SOURCE = new Source(BeanMap.class.getName()); |
||||||
|
|
||||||
|
private static final BeanMapKey KEY_FACTORY = |
||||||
|
(BeanMapKey)KeyFactory.create(BeanMapKey.class, KeyFactory.CLASS_BY_NAME); |
||||||
|
|
||||||
|
interface BeanMapKey { |
||||||
|
public Object newInstance(Class type, int require); |
||||||
|
} |
||||||
|
|
||||||
|
private Object bean; |
||||||
|
private Class beanClass; |
||||||
|
private int require; |
||||||
|
|
||||||
|
public Generator() { |
||||||
|
super(SOURCE); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set the bean that the generated map should reflect. The bean may be swapped |
||||||
|
* out for another bean of the same type using {@link #setBean}. |
||||||
|
* Calling this method overrides any value previously set using {@link #setBeanClass}. |
||||||
|
* You must call either this method or {@link #setBeanClass} before {@link #create}. |
||||||
|
* @param bean the initial bean |
||||||
|
*/ |
||||||
|
public void setBean(Object bean) { |
||||||
|
this.bean = bean; |
||||||
|
if (bean != null) |
||||||
|
beanClass = bean.getClass(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set the class of the bean that the generated map should support. |
||||||
|
* You must call either this method or {@link #setBeanClass} before {@link #create}. |
||||||
|
* @param beanClass the class of the bean |
||||||
|
*/ |
||||||
|
public void setBeanClass(Class beanClass) { |
||||||
|
this.beanClass = beanClass; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Limit the properties reflected by the generated map. |
||||||
|
* @param require any combination of {@link #REQUIRE_GETTER} and |
||||||
|
* {@link #REQUIRE_SETTER}; default is zero (any property allowed) |
||||||
|
*/ |
||||||
|
public void setRequire(int require) { |
||||||
|
this.require = require; |
||||||
|
} |
||||||
|
|
||||||
|
protected ClassLoader getDefaultClassLoader() { |
||||||
|
return beanClass.getClassLoader(); |
||||||
|
} |
||||||
|
|
||||||
|
protected ProtectionDomain getProtectionDomain() { |
||||||
|
return ReflectUtils.getProtectionDomain(beanClass); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Create a new instance of the <code>BeanMap</code>. An existing |
||||||
|
* generated class will be reused if possible. |
||||||
|
*/ |
||||||
|
public BeanMap create() { |
||||||
|
if (beanClass == null) |
||||||
|
throw new IllegalArgumentException("Class of bean unknown"); |
||||||
|
setNamePrefix(beanClass.getName()); |
||||||
|
return (BeanMap)super.create(KEY_FACTORY.newInstance(beanClass, require)); |
||||||
|
} |
||||||
|
|
||||||
|
public void generateClass(ClassVisitor v) throws Exception { |
||||||
|
new BeanMapEmitter(v, getClassName(), beanClass, require); |
||||||
|
} |
||||||
|
|
||||||
|
protected Object firstInstance(Class type) { |
||||||
|
return ((BeanMap)ReflectUtils.newInstance(type)).newInstance(bean); |
||||||
|
} |
||||||
|
|
||||||
|
protected Object nextInstance(Object instance) { |
||||||
|
return ((BeanMap)instance).newInstance(bean); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Create a new <code>BeanMap</code> instance using the specified bean. |
||||||
|
* This is faster than using the {@link #create} static method. |
||||||
|
* @param bean the JavaBean underlying the map |
||||||
|
* @return a new <code>BeanMap</code> instance |
||||||
|
*/ |
||||||
|
abstract public BeanMap newInstance(Object bean); |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the type of a property. |
||||||
|
* @param name the name of the JavaBean property |
||||||
|
* @return the type of the property, or null if the property does not exist |
||||||
|
*/ |
||||||
|
abstract public Class getPropertyType(String name); |
||||||
|
|
||||||
|
protected Object bean; |
||||||
|
|
||||||
|
protected BeanMap() { |
||||||
|
} |
||||||
|
|
||||||
|
protected BeanMap(Object bean) { |
||||||
|
setBean(bean); |
||||||
|
} |
||||||
|
|
||||||
|
public Object get(Object key) { |
||||||
|
return get(bean, key); |
||||||
|
} |
||||||
|
|
||||||
|
public Object put(Object key, Object value) { |
||||||
|
return put(bean, key, value); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the property of a bean. This allows a <code>BeanMap</code> |
||||||
|
* to be used statically for multiple beans--the bean instance tied to the |
||||||
|
* map is ignored and the bean passed to this method is used instead. |
||||||
|
* @param bean the bean to query; must be compatible with the type of |
||||||
|
* this <code>BeanMap</code> |
||||||
|
* @param key must be a String |
||||||
|
* @return the current value, or null if there is no matching property |
||||||
|
*/ |
||||||
|
abstract public Object get(Object bean, Object key); |
||||||
|
|
||||||
|
/** |
||||||
|
* Set the property of a bean. This allows a <code>BeanMap</code> |
||||||
|
* to be used statically for multiple beans--the bean instance tied to the |
||||||
|
* map is ignored and the bean passed to this method is used instead. |
||||||
|
* @param key must be a String |
||||||
|
* @return the old value, if there was one, or null |
||||||
|
*/ |
||||||
|
abstract public Object put(Object bean, Object key, Object value); |
||||||
|
|
||||||
|
/** |
||||||
|
* Change the underlying bean this map should use. |
||||||
|
* @param bean the new JavaBean |
||||||
|
* @see #getBean |
||||||
|
*/ |
||||||
|
public void setBean(Object bean) { |
||||||
|
this.bean = bean; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Return the bean currently in use by this map. |
||||||
|
* @return the current JavaBean |
||||||
|
* @see #setBean |
||||||
|
*/ |
||||||
|
public Object getBean() { |
||||||
|
return bean; |
||||||
|
} |
||||||
|
|
||||||
|
public void clear() { |
||||||
|
throw new UnsupportedOperationException(); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean containsKey(Object key) { |
||||||
|
return keySet().contains(key); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean containsValue(Object value) { |
||||||
|
for (Iterator it = keySet().iterator(); it.hasNext();) { |
||||||
|
Object v = get(it.next()); |
||||||
|
if (((value == null) && (v == null)) || (value != null && value.equals(v))) |
||||||
|
return true; |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
public int size() { |
||||||
|
return keySet().size(); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isEmpty() { |
||||||
|
return size() == 0; |
||||||
|
} |
||||||
|
|
||||||
|
public Object remove(Object key) { |
||||||
|
throw new UnsupportedOperationException(); |
||||||
|
} |
||||||
|
|
||||||
|
public void putAll(Map t) { |
||||||
|
for (Iterator it = t.keySet().iterator(); it.hasNext();) { |
||||||
|
Object key = it.next(); |
||||||
|
put(key, t.get(key)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public boolean equals(Object o) { |
||||||
|
if (o == null || !(o instanceof Map)) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
Map other = (Map)o; |
||||||
|
if (size() != other.size()) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
for (Iterator it = keySet().iterator(); it.hasNext();) { |
||||||
|
Object key = it.next(); |
||||||
|
if (!other.containsKey(key)) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
Object v1 = get(key); |
||||||
|
Object v2 = other.get(key); |
||||||
|
if (!((v1 == null) ? v2 == null : v1.equals(v2))) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public int hashCode() { |
||||||
|
int code = 0; |
||||||
|
for (Iterator it = keySet().iterator(); it.hasNext();) { |
||||||
|
Object key = it.next(); |
||||||
|
Object value = get(key); |
||||||
|
code += ((key == null) ? 0 : key.hashCode()) ^ |
||||||
|
((value == null) ? 0 : value.hashCode()); |
||||||
|
} |
||||||
|
return code; |
||||||
|
} |
||||||
|
|
||||||
|
// TODO: optimize
|
||||||
|
public Set entrySet() { |
||||||
|
HashMap copy = new HashMap(); |
||||||
|
for (Iterator it = keySet().iterator(); it.hasNext();) { |
||||||
|
Object key = it.next(); |
||||||
|
copy.put(key, get(key)); |
||||||
|
} |
||||||
|
return Collections.unmodifiableMap(copy).entrySet(); |
||||||
|
} |
||||||
|
|
||||||
|
public Collection values() { |
||||||
|
Set keys = keySet(); |
||||||
|
List values = new ArrayList(keys.size()); |
||||||
|
for (Iterator it = keys.iterator(); it.hasNext();) { |
||||||
|
values.add(get(it.next())); |
||||||
|
} |
||||||
|
return Collections.unmodifiableCollection(values); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
* @see java.util.AbstractMap#toString |
||||||
|
*/ |
||||||
|
public String toString() |
||||||
|
{ |
||||||
|
StringBuffer sb = new StringBuffer(); |
||||||
|
sb.append('{'); |
||||||
|
for (Iterator it = keySet().iterator(); it.hasNext();) { |
||||||
|
Object key = it.next(); |
||||||
|
sb.append(key); |
||||||
|
sb.append('='); |
||||||
|
sb.append(get(key)); |
||||||
|
if (it.hasNext()) { |
||||||
|
sb.append(", "); |
||||||
|
} |
||||||
|
} |
||||||
|
sb.append('}'); |
||||||
|
return sb.toString(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,192 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.beans; |
||||||
|
|
||||||
|
import java.beans.*; |
||||||
|
import java.util.*; |
||||||
|
import com.fr.third.net.sf.cglib.core.*; |
||||||
|
import com.fr.third.org.objectweb.asm.ClassVisitor; |
||||||
|
import com.fr.third.org.objectweb.asm.Label; |
||||||
|
import com.fr.third.org.objectweb.asm.Type; |
||||||
|
|
||||||
|
class BeanMapEmitter extends ClassEmitter { |
||||||
|
private static final Type BEAN_MAP = |
||||||
|
TypeUtils.parseType("com.fr.third.net.sf.cglib.beans.BeanMap"); |
||||||
|
private static final Type FIXED_KEY_SET = |
||||||
|
TypeUtils.parseType("com.fr.third.net.sf.cglib.beans.FixedKeySet"); |
||||||
|
private static final Signature CSTRUCT_OBJECT = |
||||||
|
TypeUtils.parseConstructor("Object"); |
||||||
|
private static final Signature CSTRUCT_STRING_ARRAY = |
||||||
|
TypeUtils.parseConstructor("String[]"); |
||||||
|
private static final Signature BEAN_MAP_GET = |
||||||
|
TypeUtils.parseSignature("Object get(Object, Object)"); |
||||||
|
private static final Signature BEAN_MAP_PUT = |
||||||
|
TypeUtils.parseSignature("Object put(Object, Object, Object)"); |
||||||
|
private static final Signature KEY_SET = |
||||||
|
TypeUtils.parseSignature("java.util.Set keySet()"); |
||||||
|
private static final Signature NEW_INSTANCE = |
||||||
|
new Signature("newInstance", BEAN_MAP, new Type[]{ Constants.TYPE_OBJECT }); |
||||||
|
private static final Signature GET_PROPERTY_TYPE = |
||||||
|
TypeUtils.parseSignature("Class getPropertyType(String)"); |
||||||
|
|
||||||
|
public BeanMapEmitter(ClassVisitor v, String className, Class type, int require) { |
||||||
|
super(v); |
||||||
|
|
||||||
|
begin_class(Constants.V1_2, Constants.ACC_PUBLIC, className, BEAN_MAP, null, Constants.SOURCE_FILE); |
||||||
|
EmitUtils.null_constructor(this); |
||||||
|
EmitUtils.factory_method(this, NEW_INSTANCE); |
||||||
|
generateConstructor(); |
||||||
|
|
||||||
|
Map getters = makePropertyMap(ReflectUtils.getBeanGetters(type)); |
||||||
|
Map setters = makePropertyMap(ReflectUtils.getBeanSetters(type)); |
||||||
|
Map allProps = new HashMap(); |
||||||
|
allProps.putAll(getters); |
||||||
|
allProps.putAll(setters); |
||||||
|
|
||||||
|
if (require != 0) { |
||||||
|
for (Iterator it = allProps.keySet().iterator(); it.hasNext();) { |
||||||
|
String name = (String)it.next(); |
||||||
|
if ((((require & BeanMap.REQUIRE_GETTER) != 0) && !getters.containsKey(name)) || |
||||||
|
(((require & BeanMap.REQUIRE_SETTER) != 0) && !setters.containsKey(name))) { |
||||||
|
it.remove(); |
||||||
|
getters.remove(name); |
||||||
|
setters.remove(name); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
generateGet(type, getters); |
||||||
|
generatePut(type, setters); |
||||||
|
|
||||||
|
String[] allNames = getNames(allProps); |
||||||
|
generateKeySet(allNames); |
||||||
|
generateGetPropertyType(allProps, allNames); |
||||||
|
end_class(); |
||||||
|
} |
||||||
|
|
||||||
|
private Map makePropertyMap(PropertyDescriptor[] props) { |
||||||
|
Map names = new HashMap(); |
||||||
|
for (int i = 0; i < props.length; i++) { |
||||||
|
names.put(((PropertyDescriptor)props[i]).getName(), props[i]); |
||||||
|
} |
||||||
|
return names; |
||||||
|
} |
||||||
|
|
||||||
|
private String[] getNames(Map propertyMap) { |
||||||
|
return (String[])propertyMap.keySet().toArray(new String[propertyMap.size()]); |
||||||
|
} |
||||||
|
|
||||||
|
private void generateConstructor() { |
||||||
|
CodeEmitter e = begin_method(Constants.ACC_PUBLIC, CSTRUCT_OBJECT, null); |
||||||
|
e.load_this(); |
||||||
|
e.load_arg(0); |
||||||
|
e.super_invoke_constructor(CSTRUCT_OBJECT); |
||||||
|
e.return_value(); |
||||||
|
e.end_method(); |
||||||
|
} |
||||||
|
|
||||||
|
private void generateGet(Class type, final Map getters) { |
||||||
|
final CodeEmitter e = begin_method(Constants.ACC_PUBLIC, BEAN_MAP_GET, null); |
||||||
|
e.load_arg(0); |
||||||
|
e.checkcast(Type.getType(type)); |
||||||
|
e.load_arg(1); |
||||||
|
e.checkcast(Constants.TYPE_STRING); |
||||||
|
EmitUtils.string_switch(e, getNames(getters), Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() { |
||||||
|
public void processCase(Object key, Label end) { |
||||||
|
PropertyDescriptor pd = (PropertyDescriptor)getters.get(key); |
||||||
|
MethodInfo method = ReflectUtils.getMethodInfo(pd.getReadMethod()); |
||||||
|
e.invoke(method); |
||||||
|
e.box(method.getSignature().getReturnType()); |
||||||
|
e.return_value(); |
||||||
|
} |
||||||
|
public void processDefault() { |
||||||
|
e.aconst_null(); |
||||||
|
e.return_value(); |
||||||
|
} |
||||||
|
}); |
||||||
|
e.end_method(); |
||||||
|
} |
||||||
|
|
||||||
|
private void generatePut(Class type, final Map setters) { |
||||||
|
final CodeEmitter e = begin_method(Constants.ACC_PUBLIC, BEAN_MAP_PUT, null); |
||||||
|
e.load_arg(0); |
||||||
|
e.checkcast(Type.getType(type)); |
||||||
|
e.load_arg(1); |
||||||
|
e.checkcast(Constants.TYPE_STRING); |
||||||
|
EmitUtils.string_switch(e, getNames(setters), Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() { |
||||||
|
public void processCase(Object key, Label end) { |
||||||
|
PropertyDescriptor pd = (PropertyDescriptor)setters.get(key); |
||||||
|
if (pd.getReadMethod() == null) { |
||||||
|
e.aconst_null(); |
||||||
|
} else { |
||||||
|
MethodInfo read = ReflectUtils.getMethodInfo(pd.getReadMethod()); |
||||||
|
e.dup(); |
||||||
|
e.invoke(read); |
||||||
|
e.box(read.getSignature().getReturnType()); |
||||||
|
} |
||||||
|
e.swap(); // move old value behind bean
|
||||||
|
e.load_arg(2); // new value
|
||||||
|
MethodInfo write = ReflectUtils.getMethodInfo(pd.getWriteMethod()); |
||||||
|
e.unbox(write.getSignature().getArgumentTypes()[0]); |
||||||
|
e.invoke(write); |
||||||
|
e.return_value(); |
||||||
|
} |
||||||
|
public void processDefault() { |
||||||
|
// fall-through
|
||||||
|
} |
||||||
|
}); |
||||||
|
e.aconst_null(); |
||||||
|
e.return_value(); |
||||||
|
e.end_method(); |
||||||
|
} |
||||||
|
|
||||||
|
private void generateKeySet(String[] allNames) { |
||||||
|
// static initializer
|
||||||
|
declare_field(Constants.ACC_STATIC | Constants.ACC_PRIVATE, "keys", FIXED_KEY_SET, null); |
||||||
|
|
||||||
|
CodeEmitter e = begin_static(); |
||||||
|
e.new_instance(FIXED_KEY_SET); |
||||||
|
e.dup(); |
||||||
|
EmitUtils.push_array(e, allNames); |
||||||
|
e.invoke_constructor(FIXED_KEY_SET, CSTRUCT_STRING_ARRAY); |
||||||
|
e.putfield("keys"); |
||||||
|
e.return_value(); |
||||||
|
e.end_method(); |
||||||
|
|
||||||
|
// keySet
|
||||||
|
e = begin_method(Constants.ACC_PUBLIC, KEY_SET, null); |
||||||
|
e.load_this(); |
||||||
|
e.getfield("keys"); |
||||||
|
e.return_value(); |
||||||
|
e.end_method(); |
||||||
|
} |
||||||
|
|
||||||
|
private void generateGetPropertyType(final Map allProps, String[] allNames) { |
||||||
|
final CodeEmitter e = begin_method(Constants.ACC_PUBLIC, GET_PROPERTY_TYPE, null); |
||||||
|
e.load_arg(0); |
||||||
|
EmitUtils.string_switch(e, allNames, Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() { |
||||||
|
public void processCase(Object key, Label end) { |
||||||
|
PropertyDescriptor pd = (PropertyDescriptor)allProps.get(key); |
||||||
|
EmitUtils.load_class(e, Type.getType(pd.getPropertyType())); |
||||||
|
e.return_value(); |
||||||
|
} |
||||||
|
public void processDefault() { |
||||||
|
e.aconst_null(); |
||||||
|
e.return_value(); |
||||||
|
} |
||||||
|
}); |
||||||
|
e.end_method(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,142 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.beans; |
||||||
|
|
||||||
|
import java.lang.reflect.Constructor; |
||||||
|
import java.lang.reflect.Method; |
||||||
|
import java.lang.reflect.Modifier; |
||||||
|
import java.security.ProtectionDomain; |
||||||
|
import java.util.*; |
||||||
|
import com.fr.third.net.sf.cglib.core.*; |
||||||
|
import com.fr.third.org.objectweb.asm.ClassVisitor; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Juozas Baliuka |
||||||
|
*/ |
||||||
|
abstract public class BulkBean |
||||||
|
{ |
||||||
|
private static final BulkBeanKey KEY_FACTORY = |
||||||
|
(BulkBeanKey)KeyFactory.create(BulkBeanKey.class); |
||||||
|
|
||||||
|
interface BulkBeanKey { |
||||||
|
public Object newInstance(String target, String[] getters, String[] setters, String[] types); |
||||||
|
} |
||||||
|
|
||||||
|
protected Class target; |
||||||
|
protected String[] getters, setters; |
||||||
|
protected Class[] types; |
||||||
|
|
||||||
|
protected BulkBean() { } |
||||||
|
|
||||||
|
abstract public void getPropertyValues(Object bean, Object[] values); |
||||||
|
abstract public void setPropertyValues(Object bean, Object[] values); |
||||||
|
|
||||||
|
public Object[] getPropertyValues(Object bean) { |
||||||
|
Object[] values = new Object[getters.length]; |
||||||
|
getPropertyValues(bean, values); |
||||||
|
return values; |
||||||
|
} |
||||||
|
|
||||||
|
public Class[] getPropertyTypes() { |
||||||
|
return (Class[])types.clone(); |
||||||
|
} |
||||||
|
|
||||||
|
public String[] getGetters() { |
||||||
|
return (String[])getters.clone(); |
||||||
|
} |
||||||
|
|
||||||
|
public String[] getSetters() { |
||||||
|
return (String[])setters.clone(); |
||||||
|
} |
||||||
|
|
||||||
|
public static BulkBean create(Class target, String[] getters, String[] setters, Class[] types) { |
||||||
|
Generator gen = new Generator(); |
||||||
|
gen.setTarget(target); |
||||||
|
gen.setGetters(getters); |
||||||
|
gen.setSetters(setters); |
||||||
|
gen.setTypes(types); |
||||||
|
return gen.create(); |
||||||
|
} |
||||||
|
|
||||||
|
public static class Generator extends AbstractClassGenerator { |
||||||
|
private static final Source SOURCE = new Source(BulkBean.class.getName()); |
||||||
|
private Class target; |
||||||
|
private String[] getters; |
||||||
|
private String[] setters; |
||||||
|
private Class[] types; |
||||||
|
|
||||||
|
public Generator() { |
||||||
|
super(SOURCE); |
||||||
|
} |
||||||
|
|
||||||
|
public void setTarget(Class target) { |
||||||
|
this.target = target; |
||||||
|
} |
||||||
|
|
||||||
|
public void setGetters(String[] getters) { |
||||||
|
this.getters = getters; |
||||||
|
} |
||||||
|
|
||||||
|
public void setSetters(String[] setters) { |
||||||
|
this.setters = setters; |
||||||
|
} |
||||||
|
|
||||||
|
public void setTypes(Class[] types) { |
||||||
|
this.types = types; |
||||||
|
} |
||||||
|
|
||||||
|
protected ClassLoader getDefaultClassLoader() { |
||||||
|
return target.getClassLoader(); |
||||||
|
} |
||||||
|
|
||||||
|
protected ProtectionDomain getProtectionDomain() { |
||||||
|
return ReflectUtils.getProtectionDomain(target); |
||||||
|
} |
||||||
|
|
||||||
|
public BulkBean create() { |
||||||
|
setNamePrefix(target.getName()); |
||||||
|
String targetClassName = target.getName(); |
||||||
|
String[] typeClassNames = ReflectUtils.getNames(types); |
||||||
|
Object key = KEY_FACTORY.newInstance(targetClassName, getters, setters, typeClassNames); |
||||||
|
return (BulkBean)super.create(key); |
||||||
|
} |
||||||
|
|
||||||
|
public void generateClass(ClassVisitor v) throws Exception { |
||||||
|
new BulkBeanEmitter(v, getClassName(), target, getters, setters, types); |
||||||
|
} |
||||||
|
|
||||||
|
protected Object firstInstance(Class type) { |
||||||
|
BulkBean instance = (BulkBean)ReflectUtils.newInstance(type); |
||||||
|
instance.target = target; |
||||||
|
|
||||||
|
int length = getters.length; |
||||||
|
instance.getters = new String[length]; |
||||||
|
System.arraycopy(getters, 0, instance.getters, 0, length); |
||||||
|
|
||||||
|
instance.setters = new String[length]; |
||||||
|
System.arraycopy(setters, 0, instance.setters, 0, length); |
||||||
|
|
||||||
|
instance.types = new Class[types.length]; |
||||||
|
System.arraycopy(types, 0, instance.types, 0, types.length); |
||||||
|
|
||||||
|
return instance; |
||||||
|
} |
||||||
|
|
||||||
|
protected Object nextInstance(Object instance) { |
||||||
|
return instance; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,156 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.beans; |
||||||
|
|
||||||
|
import java.lang.reflect.Constructor; |
||||||
|
import java.lang.reflect.Method; |
||||||
|
import java.lang.reflect.Modifier; |
||||||
|
import java.util.*; |
||||||
|
import com.fr.third.net.sf.cglib.core.*; |
||||||
|
import com.fr.third.org.objectweb.asm.ClassVisitor; |
||||||
|
import com.fr.third.org.objectweb.asm.Type; |
||||||
|
|
||||||
|
class BulkBeanEmitter extends ClassEmitter { |
||||||
|
private static final Signature GET_PROPERTY_VALUES = |
||||||
|
TypeUtils.parseSignature("void getPropertyValues(Object, Object[])"); |
||||||
|
private static final Signature SET_PROPERTY_VALUES = |
||||||
|
TypeUtils.parseSignature("void setPropertyValues(Object, Object[])"); |
||||||
|
private static final Signature CSTRUCT_EXCEPTION = |
||||||
|
TypeUtils.parseConstructor("Throwable, int"); |
||||||
|
private static final Type BULK_BEAN = |
||||||
|
TypeUtils.parseType("com.fr.third.net.sf.cglib.beans.BulkBean"); |
||||||
|
private static final Type BULK_BEAN_EXCEPTION = |
||||||
|
TypeUtils.parseType("com.fr.third.net.sf.cglib.beans.BulkBeanException"); |
||||||
|
|
||||||
|
public BulkBeanEmitter(ClassVisitor v, |
||||||
|
String className, |
||||||
|
Class target, |
||||||
|
String[] getterNames, |
||||||
|
String[] setterNames, |
||||||
|
Class[] types) { |
||||||
|
super(v); |
||||||
|
|
||||||
|
Method[] getters = new Method[getterNames.length]; |
||||||
|
Method[] setters = new Method[setterNames.length]; |
||||||
|
validate(target, getterNames, setterNames, types, getters, setters); |
||||||
|
|
||||||
|
begin_class(Constants.V1_2, Constants.ACC_PUBLIC, className, BULK_BEAN, null, Constants.SOURCE_FILE); |
||||||
|
EmitUtils.null_constructor(this); |
||||||
|
generateGet(target, getters); |
||||||
|
generateSet(target, setters); |
||||||
|
end_class(); |
||||||
|
} |
||||||
|
|
||||||
|
private void generateGet(final Class target, final Method[] getters) { |
||||||
|
CodeEmitter e = begin_method(Constants.ACC_PUBLIC, GET_PROPERTY_VALUES, null); |
||||||
|
if (getters.length >= 0) { |
||||||
|
e.load_arg(0); |
||||||
|
e.checkcast(Type.getType(target)); |
||||||
|
Local bean = e.make_local(); |
||||||
|
e.store_local(bean); |
||||||
|
for (int i = 0; i < getters.length; i++) { |
||||||
|
if (getters[i] != null) { |
||||||
|
MethodInfo getter = ReflectUtils.getMethodInfo(getters[i]); |
||||||
|
e.load_arg(1); |
||||||
|
e.push(i); |
||||||
|
e.load_local(bean); |
||||||
|
e.invoke(getter); |
||||||
|
e.box(getter.getSignature().getReturnType()); |
||||||
|
e.aastore(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
e.return_value(); |
||||||
|
e.end_method(); |
||||||
|
} |
||||||
|
|
||||||
|
private void generateSet(final Class target, final Method[] setters) { |
||||||
|
// setPropertyValues
|
||||||
|
CodeEmitter e = begin_method(Constants.ACC_PUBLIC, SET_PROPERTY_VALUES, null); |
||||||
|
if (setters.length > 0) { |
||||||
|
Local index = e.make_local(Type.INT_TYPE); |
||||||
|
e.push(0); |
||||||
|
e.store_local(index); |
||||||
|
e.load_arg(0); |
||||||
|
e.checkcast(Type.getType(target)); |
||||||
|
e.load_arg(1); |
||||||
|
Block handler = e.begin_block(); |
||||||
|
int lastIndex = 0; |
||||||
|
for (int i = 0; i < setters.length; i++) { |
||||||
|
if (setters[i] != null) { |
||||||
|
MethodInfo setter = ReflectUtils.getMethodInfo(setters[i]); |
||||||
|
int diff = i - lastIndex; |
||||||
|
if (diff > 0) { |
||||||
|
e.iinc(index, diff); |
||||||
|
lastIndex = i; |
||||||
|
} |
||||||
|
e.dup2(); |
||||||
|
e.aaload(i); |
||||||
|
e.unbox(setter.getSignature().getArgumentTypes()[0]); |
||||||
|
e.invoke(setter); |
||||||
|
} |
||||||
|
} |
||||||
|
handler.end(); |
||||||
|
e.return_value(); |
||||||
|
e.catch_exception(handler, Constants.TYPE_THROWABLE); |
||||||
|
e.new_instance(BULK_BEAN_EXCEPTION); |
||||||
|
e.dup_x1(); |
||||||
|
e.swap(); |
||||||
|
e.load_local(index); |
||||||
|
e.invoke_constructor(BULK_BEAN_EXCEPTION, CSTRUCT_EXCEPTION); |
||||||
|
e.athrow(); |
||||||
|
} else { |
||||||
|
e.return_value(); |
||||||
|
} |
||||||
|
e.end_method(); |
||||||
|
} |
||||||
|
|
||||||
|
private static void validate(Class target, |
||||||
|
String[] getters, |
||||||
|
String[] setters, |
||||||
|
Class[] types, |
||||||
|
Method[] getters_out, |
||||||
|
Method[] setters_out) { |
||||||
|
int i = -1; |
||||||
|
if (setters.length != types.length || getters.length != types.length) { |
||||||
|
throw new BulkBeanException("accessor array length must be equal type array length", i); |
||||||
|
} |
||||||
|
try { |
||||||
|
for (i = 0; i < types.length; i++) { |
||||||
|
if (getters[i] != null) { |
||||||
|
Method method = ReflectUtils.findDeclaredMethod(target, getters[i], null); |
||||||
|
if (method.getReturnType() != types[i]) { |
||||||
|
throw new BulkBeanException("Specified type " + types[i] + |
||||||
|
" does not match declared type " + method.getReturnType(), i); |
||||||
|
} |
||||||
|
if (Modifier.isPrivate(method.getModifiers())) { |
||||||
|
throw new BulkBeanException("Property is private", i); |
||||||
|
} |
||||||
|
getters_out[i] = method; |
||||||
|
} |
||||||
|
if (setters[i] != null) { |
||||||
|
Method method = ReflectUtils.findDeclaredMethod(target, setters[i], new Class[]{ types[i] }); |
||||||
|
if (Modifier.isPrivate(method.getModifiers()) ){ |
||||||
|
throw new BulkBeanException("Property is private", i); |
||||||
|
} |
||||||
|
setters_out[i] = method; |
||||||
|
} |
||||||
|
} |
||||||
|
} catch (NoSuchMethodException e) { |
||||||
|
throw new BulkBeanException("Cannot find specified property", i); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.beans; |
||||||
|
|
||||||
|
import com.fr.third.net.sf.cglib.core.CodeGenerationException; |
||||||
|
|
||||||
|
public class BulkBeanException extends RuntimeException |
||||||
|
{ |
||||||
|
private int index; |
||||||
|
private Throwable cause; |
||||||
|
|
||||||
|
public BulkBeanException(String message, int index) { |
||||||
|
super(message); |
||||||
|
this.index = index; |
||||||
|
} |
||||||
|
|
||||||
|
public BulkBeanException(Throwable cause, int index) { |
||||||
|
super(cause.getMessage()); |
||||||
|
this.index = index; |
||||||
|
this.cause = cause; |
||||||
|
} |
||||||
|
|
||||||
|
public int getIndex() { |
||||||
|
return index; |
||||||
|
} |
||||||
|
|
||||||
|
public Throwable getCause() { |
||||||
|
return cause; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,36 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.beans; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
public /* need it for class loading */ class FixedKeySet extends AbstractSet { |
||||||
|
private Set set; |
||||||
|
private int size; |
||||||
|
|
||||||
|
public FixedKeySet(String[] keys) { |
||||||
|
size = keys.length; |
||||||
|
set = Collections.unmodifiableSet(new HashSet(Arrays.asList(keys))); |
||||||
|
} |
||||||
|
|
||||||
|
public Iterator iterator() { |
||||||
|
return set.iterator(); |
||||||
|
} |
||||||
|
|
||||||
|
public int size() { |
||||||
|
return size; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,128 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.beans; |
||||||
|
|
||||||
|
import java.beans.PropertyDescriptor; |
||||||
|
import java.lang.reflect.Method; |
||||||
|
import java.security.ProtectionDomain; |
||||||
|
import com.fr.third.net.sf.cglib.core.*; |
||||||
|
import com.fr.third.org.objectweb.asm.ClassVisitor; |
||||||
|
import com.fr.third.org.objectweb.asm.Type; |
||||||
|
/** |
||||||
|
* @author Chris Nokleberg |
||||||
|
*/ |
||||||
|
public class ImmutableBean |
||||||
|
{ |
||||||
|
private static final Type ILLEGAL_STATE_EXCEPTION = |
||||||
|
TypeUtils.parseType("IllegalStateException"); |
||||||
|
private static final Signature CSTRUCT_OBJECT = |
||||||
|
TypeUtils.parseConstructor("Object"); |
||||||
|
private static final Class[] OBJECT_CLASSES = { Object.class }; |
||||||
|
private static final String FIELD_NAME = "CGLIB$RWBean"; |
||||||
|
|
||||||
|
private ImmutableBean() { |
||||||
|
} |
||||||
|
|
||||||
|
public static Object create(Object bean) { |
||||||
|
Generator gen = new Generator(); |
||||||
|
gen.setBean(bean); |
||||||
|
return gen.create(); |
||||||
|
} |
||||||
|
|
||||||
|
public static class Generator extends AbstractClassGenerator { |
||||||
|
private static final Source SOURCE = new Source(ImmutableBean.class.getName()); |
||||||
|
private Object bean; |
||||||
|
private Class target; |
||||||
|
|
||||||
|
public Generator() { |
||||||
|
super(SOURCE); |
||||||
|
} |
||||||
|
|
||||||
|
public void setBean(Object bean) { |
||||||
|
this.bean = bean; |
||||||
|
target = bean.getClass(); |
||||||
|
} |
||||||
|
|
||||||
|
protected ClassLoader getDefaultClassLoader() { |
||||||
|
return target.getClassLoader(); |
||||||
|
} |
||||||
|
|
||||||
|
protected ProtectionDomain getProtectionDomain() { |
||||||
|
return ReflectUtils.getProtectionDomain(target); |
||||||
|
} |
||||||
|
|
||||||
|
public Object create() { |
||||||
|
String name = target.getName(); |
||||||
|
setNamePrefix(name); |
||||||
|
return super.create(name); |
||||||
|
} |
||||||
|
|
||||||
|
public void generateClass(ClassVisitor v) { |
||||||
|
Type targetType = Type.getType(target); |
||||||
|
ClassEmitter ce = new ClassEmitter(v); |
||||||
|
ce.begin_class(Constants.V1_2, |
||||||
|
Constants.ACC_PUBLIC, |
||||||
|
getClassName(), |
||||||
|
targetType, |
||||||
|
null, |
||||||
|
Constants.SOURCE_FILE); |
||||||
|
|
||||||
|
ce.declare_field(Constants.ACC_FINAL | Constants.ACC_PRIVATE, FIELD_NAME, targetType, null); |
||||||
|
|
||||||
|
CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, CSTRUCT_OBJECT, null); |
||||||
|
e.load_this(); |
||||||
|
e.super_invoke_constructor(); |
||||||
|
e.load_this(); |
||||||
|
e.load_arg(0); |
||||||
|
e.checkcast(targetType); |
||||||
|
e.putfield(FIELD_NAME); |
||||||
|
e.return_value(); |
||||||
|
e.end_method(); |
||||||
|
|
||||||
|
PropertyDescriptor[] descriptors = ReflectUtils.getBeanProperties(target); |
||||||
|
Method[] getters = ReflectUtils.getPropertyMethods(descriptors, true, false); |
||||||
|
Method[] setters = ReflectUtils.getPropertyMethods(descriptors, false, true); |
||||||
|
|
||||||
|
for (int i = 0; i < getters.length; i++) { |
||||||
|
MethodInfo getter = ReflectUtils.getMethodInfo(getters[i]); |
||||||
|
e = EmitUtils.begin_method(ce, getter, Constants.ACC_PUBLIC); |
||||||
|
e.load_this(); |
||||||
|
e.getfield(FIELD_NAME); |
||||||
|
e.invoke(getter); |
||||||
|
e.return_value(); |
||||||
|
e.end_method(); |
||||||
|
} |
||||||
|
|
||||||
|
for (int i = 0; i < setters.length; i++) { |
||||||
|
MethodInfo setter = ReflectUtils.getMethodInfo(setters[i]); |
||||||
|
e = EmitUtils.begin_method(ce, setter, Constants.ACC_PUBLIC); |
||||||
|
e.throw_exception(ILLEGAL_STATE_EXCEPTION, "Bean is immutable"); |
||||||
|
e.end_method(); |
||||||
|
} |
||||||
|
|
||||||
|
ce.end_class(); |
||||||
|
} |
||||||
|
|
||||||
|
protected Object firstInstance(Class type) { |
||||||
|
return ReflectUtils.newInstance(type, OBJECT_CLASSES, new Object[]{ bean }); |
||||||
|
} |
||||||
|
|
||||||
|
// TODO: optimize
|
||||||
|
protected Object nextInstance(Object instance) { |
||||||
|
return firstInstance(instance.getClass()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,353 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.core; |
||||||
|
|
||||||
|
import com.fr.third.net.sf.cglib.core.internal.Function; |
||||||
|
import com.fr.third.net.sf.cglib.core.internal.LoadingCache; |
||||||
|
import com.fr.third.org.objectweb.asm.ClassReader; |
||||||
|
|
||||||
|
import java.lang.ref.WeakReference; |
||||||
|
import java.security.ProtectionDomain; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.Set; |
||||||
|
import java.util.HashSet; |
||||||
|
import java.util.WeakHashMap; |
||||||
|
|
||||||
|
/** |
||||||
|
* Abstract class for all code-generating CGLIB utilities. |
||||||
|
* In addition to caching generated classes for performance, it provides hooks for |
||||||
|
* customizing the <code>ClassLoader</code>, name of the generated class, and transformations |
||||||
|
* applied before generation. |
||||||
|
*/ |
||||||
|
abstract public class AbstractClassGenerator<T> |
||||||
|
implements ClassGenerator |
||||||
|
{ |
||||||
|
private static final ThreadLocal CURRENT = new ThreadLocal(); |
||||||
|
|
||||||
|
private static volatile Map<ClassLoader, ClassLoaderData> CACHE = new WeakHashMap<ClassLoader, ClassLoaderData>(); |
||||||
|
|
||||||
|
private GeneratorStrategy strategy = DefaultGeneratorStrategy.INSTANCE; |
||||||
|
private NamingPolicy namingPolicy = DefaultNamingPolicy.INSTANCE; |
||||||
|
private Source source; |
||||||
|
private ClassLoader classLoader; |
||||||
|
private String namePrefix; |
||||||
|
private Object key; |
||||||
|
private boolean useCache = true; |
||||||
|
private String className; |
||||||
|
private boolean attemptLoad; |
||||||
|
|
||||||
|
protected static class ClassLoaderData { |
||||||
|
private final Set<String> reservedClassNames = new HashSet<String>(); |
||||||
|
|
||||||
|
/** |
||||||
|
* {@link AbstractClassGenerator} here holds "cache key" (e.g. {@link com.fr.third.net.sf.cglib.proxy.Enhancer} |
||||||
|
* configuration), and the value is the generated class plus some additional values |
||||||
|
* (see {@link #unwrapCachedValue(Object)}. |
||||||
|
* <p>The generated classes can be reused as long as their classloader is reachable.</p> |
||||||
|
* <p>Note: the only way to access a class is to find it through generatedClasses cache, thus |
||||||
|
* the key should not expire as long as the class itself is alive (its classloader is alive).</p> |
||||||
|
*/ |
||||||
|
private final LoadingCache<AbstractClassGenerator, Object, Object> generatedClasses; |
||||||
|
|
||||||
|
/** |
||||||
|
* Note: ClassLoaderData object is stored as a value of {@code WeakHashMap<ClassLoader, ...>} thus |
||||||
|
* this classLoader reference should be weak otherwise it would make classLoader strongly reachable |
||||||
|
* and alive forever. |
||||||
|
* Reference queue is not required since the cleanup is handled by {@link WeakHashMap}. |
||||||
|
*/ |
||||||
|
private final WeakReference<ClassLoader> classLoader; |
||||||
|
|
||||||
|
private final Predicate uniqueNamePredicate = new Predicate() { |
||||||
|
public boolean evaluate(Object name) { |
||||||
|
return reservedClassNames.contains(name); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
private static final Function<AbstractClassGenerator, Object> GET_KEY = new Function<AbstractClassGenerator, Object>() { |
||||||
|
public Object apply(AbstractClassGenerator gen) { |
||||||
|
return gen.key; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
public ClassLoaderData(ClassLoader classLoader) { |
||||||
|
if (classLoader == null) { |
||||||
|
throw new IllegalArgumentException("classLoader == null is not yet supported"); |
||||||
|
} |
||||||
|
this.classLoader = new WeakReference<ClassLoader>(classLoader); |
||||||
|
Function<AbstractClassGenerator, Object> load = |
||||||
|
new Function<AbstractClassGenerator, Object>() { |
||||||
|
public Object apply(AbstractClassGenerator gen) { |
||||||
|
Class klass = gen.generate(ClassLoaderData.this); |
||||||
|
return gen.wrapCachedClass(klass); |
||||||
|
} |
||||||
|
}; |
||||||
|
generatedClasses = new LoadingCache<AbstractClassGenerator, Object, Object>(GET_KEY, load); |
||||||
|
} |
||||||
|
|
||||||
|
public ClassLoader getClassLoader() { |
||||||
|
return classLoader.get(); |
||||||
|
} |
||||||
|
|
||||||
|
public void reserveName(String name) { |
||||||
|
reservedClassNames.add(name); |
||||||
|
} |
||||||
|
|
||||||
|
public Predicate getUniqueNamePredicate() { |
||||||
|
return uniqueNamePredicate; |
||||||
|
} |
||||||
|
|
||||||
|
public Object get(AbstractClassGenerator gen, boolean useCache) { |
||||||
|
if (!useCache) { |
||||||
|
return gen.generate(ClassLoaderData.this); |
||||||
|
} else { |
||||||
|
Object cachedValue = generatedClasses.get(gen); |
||||||
|
return gen.unwrapCachedValue(cachedValue); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected T wrapCachedClass(Class klass) { |
||||||
|
return (T) new WeakReference(klass); |
||||||
|
} |
||||||
|
|
||||||
|
protected Object unwrapCachedValue(T cached) { |
||||||
|
return ((WeakReference) cached).get(); |
||||||
|
} |
||||||
|
|
||||||
|
protected static class Source { |
||||||
|
String name; |
||||||
|
public Source(String name) { |
||||||
|
this.name = name; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected AbstractClassGenerator(Source source) { |
||||||
|
this.source = source; |
||||||
|
} |
||||||
|
|
||||||
|
protected void setNamePrefix(String namePrefix) { |
||||||
|
this.namePrefix = namePrefix; |
||||||
|
} |
||||||
|
|
||||||
|
final protected String getClassName() { |
||||||
|
return className; |
||||||
|
} |
||||||
|
|
||||||
|
private void setClassName(String className) { |
||||||
|
this.className = className; |
||||||
|
} |
||||||
|
|
||||||
|
private String generateClassName(Predicate nameTestPredicate) { |
||||||
|
return namingPolicy.getClassName(namePrefix, source.name, key, nameTestPredicate); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set the <code>ClassLoader</code> in which the class will be generated. |
||||||
|
* Concrete subclasses of <code>AbstractClassGenerator</code> (such as <code>Enhancer</code>) |
||||||
|
* will try to choose an appropriate default if this is unset. |
||||||
|
* <p> |
||||||
|
* Classes are cached per-<code>ClassLoader</code> using a <code>WeakHashMap</code>, to allow |
||||||
|
* the generated classes to be removed when the associated loader is garbage collected. |
||||||
|
* @param classLoader the loader to generate the new class with, or null to use the default |
||||||
|
*/ |
||||||
|
public void setClassLoader(ClassLoader classLoader) { |
||||||
|
this.classLoader = classLoader; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Override the default naming policy. |
||||||
|
* @see DefaultNamingPolicy |
||||||
|
* @param namingPolicy the custom policy, or null to use the default |
||||||
|
*/ |
||||||
|
public void setNamingPolicy(NamingPolicy namingPolicy) { |
||||||
|
if (namingPolicy == null) |
||||||
|
namingPolicy = DefaultNamingPolicy.INSTANCE; |
||||||
|
this.namingPolicy = namingPolicy; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @see #setNamingPolicy |
||||||
|
*/ |
||||||
|
public NamingPolicy getNamingPolicy() { |
||||||
|
return namingPolicy; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Whether use and update the static cache of generated classes |
||||||
|
* for a class with the same properties. Default is <code>true</code>. |
||||||
|
*/ |
||||||
|
public void setUseCache(boolean useCache) { |
||||||
|
this.useCache = useCache; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @see #setUseCache |
||||||
|
*/ |
||||||
|
public boolean getUseCache() { |
||||||
|
return useCache; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* If set, CGLIB will attempt to load classes from the specified |
||||||
|
* <code>ClassLoader</code> before generating them. Because generated |
||||||
|
* class names are not guaranteed to be unique, the default is <code>false</code>. |
||||||
|
*/ |
||||||
|
public void setAttemptLoad(boolean attemptLoad) { |
||||||
|
this.attemptLoad = attemptLoad; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean getAttemptLoad() { |
||||||
|
return attemptLoad; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set the strategy to use to create the bytecode from this generator. |
||||||
|
* By default an instance of {@see DefaultGeneratorStrategy} is used. |
||||||
|
*/ |
||||||
|
public void setStrategy(GeneratorStrategy strategy) { |
||||||
|
if (strategy == null) |
||||||
|
strategy = DefaultGeneratorStrategy.INSTANCE; |
||||||
|
this.strategy = strategy; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @see #setStrategy |
||||||
|
*/ |
||||||
|
public GeneratorStrategy getStrategy() { |
||||||
|
return strategy; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Used internally by CGLIB. Returns the <code>AbstractClassGenerator</code> |
||||||
|
* that is being used to generate a class in the current thread. |
||||||
|
*/ |
||||||
|
public static AbstractClassGenerator getCurrent() { |
||||||
|
return (AbstractClassGenerator)CURRENT.get(); |
||||||
|
} |
||||||
|
|
||||||
|
public ClassLoader getClassLoader() { |
||||||
|
ClassLoader t = classLoader; |
||||||
|
if (t == null) { |
||||||
|
t = getDefaultClassLoader(); |
||||||
|
} |
||||||
|
if (t == null) { |
||||||
|
t = getClass().getClassLoader(); |
||||||
|
} |
||||||
|
if (t == null) { |
||||||
|
t = Thread.currentThread().getContextClassLoader(); |
||||||
|
} |
||||||
|
if (t == null) { |
||||||
|
throw new IllegalStateException("Cannot determine classloader"); |
||||||
|
} |
||||||
|
return t; |
||||||
|
} |
||||||
|
|
||||||
|
abstract protected ClassLoader getDefaultClassLoader(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Returns the protection domain to use when defining the class. |
||||||
|
* <p> |
||||||
|
* Default implementation returns <code>null</code> for using a default protection domain. Sub-classes may |
||||||
|
* override to use a more specific protection domain. |
||||||
|
* </p> |
||||||
|
* |
||||||
|
* @return the protection domain (<code>null</code> for using a default) |
||||||
|
*/ |
||||||
|
protected ProtectionDomain getProtectionDomain() { |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
protected Object create(Object key) { |
||||||
|
try { |
||||||
|
ClassLoader loader = getClassLoader(); |
||||||
|
Map<ClassLoader, ClassLoaderData> cache = CACHE; |
||||||
|
ClassLoaderData data = cache.get(loader); |
||||||
|
if (data == null) { |
||||||
|
synchronized (AbstractClassGenerator.class) { |
||||||
|
cache = CACHE; |
||||||
|
data = cache.get(loader); |
||||||
|
if (data == null) { |
||||||
|
Map<ClassLoader, ClassLoaderData> newCache = new WeakHashMap<ClassLoader, ClassLoaderData>(cache); |
||||||
|
data = new ClassLoaderData(loader); |
||||||
|
newCache.put(loader, data); |
||||||
|
CACHE = newCache; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
this.key = key; |
||||||
|
Object obj = data.get(this, getUseCache()); |
||||||
|
if (obj instanceof Class) { |
||||||
|
return firstInstance((Class) obj); |
||||||
|
} |
||||||
|
return nextInstance(obj); |
||||||
|
} catch (RuntimeException e) { |
||||||
|
throw e; |
||||||
|
} catch (Error e) { |
||||||
|
throw e; |
||||||
|
} catch (Exception e) { |
||||||
|
throw new CodeGenerationException(e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
protected Class generate(ClassLoaderData data) { |
||||||
|
Class gen; |
||||||
|
Object save = CURRENT.get(); |
||||||
|
CURRENT.set(this); |
||||||
|
try { |
||||||
|
ClassLoader classLoader = data.getClassLoader(); |
||||||
|
if (classLoader == null) { |
||||||
|
throw new IllegalStateException("ClassLoader is null while trying to define class " + |
||||||
|
getClassName() + ". It seems that the loader has been expired from a weak reference somehow. " + |
||||||
|
"Please file an issue at cglib's issue tracker."); |
||||||
|
} |
||||||
|
synchronized (classLoader) { |
||||||
|
String name = generateClassName(data.getUniqueNamePredicate()); |
||||||
|
data.reserveName(name); |
||||||
|
this.setClassName(name); |
||||||
|
} |
||||||
|
if (attemptLoad) { |
||||||
|
try { |
||||||
|
gen = classLoader.loadClass(getClassName()); |
||||||
|
return gen; |
||||||
|
} catch (ClassNotFoundException e) { |
||||||
|
// ignore
|
||||||
|
} |
||||||
|
} |
||||||
|
byte[] b = strategy.generate(this); |
||||||
|
String className = ClassNameReader.getClassName(new ClassReader(b)); |
||||||
|
ProtectionDomain protectionDomain = getProtectionDomain(); |
||||||
|
synchronized (classLoader) { // just in case
|
||||||
|
if (protectionDomain == null) { |
||||||
|
gen = ReflectUtils.defineClass(className, b, classLoader); |
||||||
|
} else { |
||||||
|
gen = ReflectUtils.defineClass(className, b, classLoader, protectionDomain); |
||||||
|
} |
||||||
|
} |
||||||
|
return gen; |
||||||
|
} catch (RuntimeException e) { |
||||||
|
throw e; |
||||||
|
} catch (Error e) { |
||||||
|
throw e; |
||||||
|
} catch (Exception e) { |
||||||
|
throw new CodeGenerationException(e); |
||||||
|
} finally { |
||||||
|
CURRENT.set(save); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
abstract protected Object firstInstance(Class type) throws Exception; |
||||||
|
abstract protected Object nextInstance(Object instance) throws Exception; |
||||||
|
} |
@ -0,0 +1,49 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.core; |
||||||
|
|
||||||
|
import com.fr.third.org.objectweb.asm.Label; |
||||||
|
|
||||||
|
public class Block |
||||||
|
{ |
||||||
|
private CodeEmitter e; |
||||||
|
private Label start; |
||||||
|
private Label end; |
||||||
|
|
||||||
|
public Block(CodeEmitter e) { |
||||||
|
this.e = e; |
||||||
|
start = e.mark(); |
||||||
|
} |
||||||
|
|
||||||
|
public CodeEmitter getCodeEmitter() { |
||||||
|
return e; |
||||||
|
} |
||||||
|
|
||||||
|
public void end() { |
||||||
|
if (end != null) { |
||||||
|
throw new IllegalStateException("end of label already set"); |
||||||
|
} |
||||||
|
end = e.mark(); |
||||||
|
} |
||||||
|
|
||||||
|
public Label getStart() { |
||||||
|
return start; |
||||||
|
} |
||||||
|
|
||||||
|
public Label getEnd() { |
||||||
|
return end; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,282 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.core; |
||||||
|
|
||||||
|
import com.fr.third.net.sf.cglib.transform.ClassTransformer; |
||||||
|
|
||||||
|
import com.fr.third.org.objectweb.asm.ClassVisitor; |
||||||
|
import com.fr.third.org.objectweb.asm.FieldVisitor; |
||||||
|
import com.fr.third.org.objectweb.asm.MethodVisitor; |
||||||
|
import com.fr.third.org.objectweb.asm.Opcodes; |
||||||
|
import com.fr.third.org.objectweb.asm.Type; |
||||||
|
|
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Juozas Baliuka, Chris Nokleberg |
||||||
|
*/ |
||||||
|
public class ClassEmitter extends ClassTransformer { |
||||||
|
private ClassInfo classInfo; |
||||||
|
private Map fieldInfo; |
||||||
|
|
||||||
|
private static int hookCounter; |
||||||
|
private MethodVisitor rawStaticInit; |
||||||
|
private CodeEmitter staticInit; |
||||||
|
private CodeEmitter staticHook; |
||||||
|
private Signature staticHookSig; |
||||||
|
|
||||||
|
public ClassEmitter(ClassVisitor cv) { |
||||||
|
setTarget(cv); |
||||||
|
} |
||||||
|
|
||||||
|
public ClassEmitter() { |
||||||
|
super(Opcodes.ASM6); |
||||||
|
} |
||||||
|
|
||||||
|
public void setTarget(ClassVisitor cv) { |
||||||
|
this.cv = cv; |
||||||
|
fieldInfo = new HashMap(); |
||||||
|
|
||||||
|
// just to be safe
|
||||||
|
staticInit = staticHook = null; |
||||||
|
staticHookSig = null; |
||||||
|
} |
||||||
|
|
||||||
|
synchronized private static int getNextHook() { |
||||||
|
return ++hookCounter; |
||||||
|
} |
||||||
|
|
||||||
|
public ClassInfo getClassInfo() { |
||||||
|
return classInfo; |
||||||
|
} |
||||||
|
|
||||||
|
public void begin_class(int version, final int access, String className, final Type superType, final Type[] interfaces, String source) { |
||||||
|
final Type classType = Type.getType("L" + className.replace('.', '/') + ";"); |
||||||
|
classInfo = new ClassInfo() { |
||||||
|
public Type getType() { |
||||||
|
return classType; |
||||||
|
} |
||||||
|
public Type getSuperType() { |
||||||
|
return (superType != null) ? superType : Constants.TYPE_OBJECT; |
||||||
|
} |
||||||
|
public Type[] getInterfaces() { |
||||||
|
return interfaces; |
||||||
|
} |
||||||
|
public int getModifiers() { |
||||||
|
return access; |
||||||
|
} |
||||||
|
}; |
||||||
|
cv.visit(version, |
||||||
|
access, |
||||||
|
classInfo.getType().getInternalName(), |
||||||
|
null, |
||||||
|
classInfo.getSuperType().getInternalName(), |
||||||
|
TypeUtils.toInternalNames(interfaces)); |
||||||
|
if (source != null) |
||||||
|
cv.visitSource(source, null); |
||||||
|
init(); |
||||||
|
} |
||||||
|
|
||||||
|
public CodeEmitter getStaticHook() { |
||||||
|
if (TypeUtils.isInterface(getAccess())) { |
||||||
|
throw new IllegalStateException("static hook is invalid for this class"); |
||||||
|
} |
||||||
|
if (staticHook == null) { |
||||||
|
staticHookSig = new Signature("CGLIB$STATICHOOK" + getNextHook(), "()V"); |
||||||
|
staticHook = begin_method(Constants.ACC_STATIC, |
||||||
|
staticHookSig, |
||||||
|
null); |
||||||
|
if (staticInit != null) { |
||||||
|
staticInit.invoke_static_this(staticHookSig); |
||||||
|
} |
||||||
|
} |
||||||
|
return staticHook; |
||||||
|
} |
||||||
|
|
||||||
|
protected void init() { |
||||||
|
} |
||||||
|
|
||||||
|
public int getAccess() { |
||||||
|
return classInfo.getModifiers(); |
||||||
|
} |
||||||
|
|
||||||
|
public Type getClassType() { |
||||||
|
return classInfo.getType(); |
||||||
|
} |
||||||
|
|
||||||
|
public Type getSuperType() { |
||||||
|
return classInfo.getSuperType(); |
||||||
|
} |
||||||
|
|
||||||
|
public void end_class() { |
||||||
|
if (staticHook != null && staticInit == null) { |
||||||
|
// force creation of static init
|
||||||
|
begin_static(); |
||||||
|
} |
||||||
|
if (staticInit != null) { |
||||||
|
staticHook.return_value(); |
||||||
|
staticHook.end_method(); |
||||||
|
rawStaticInit.visitInsn(Constants.RETURN); |
||||||
|
rawStaticInit.visitMaxs(0, 0); |
||||||
|
staticInit = staticHook = null; |
||||||
|
staticHookSig = null; |
||||||
|
} |
||||||
|
cv.visitEnd(); |
||||||
|
} |
||||||
|
|
||||||
|
public CodeEmitter begin_method(int access, Signature sig, Type[] exceptions) { |
||||||
|
if (classInfo == null) |
||||||
|
throw new IllegalStateException("classInfo is null! " + this); |
||||||
|
MethodVisitor v = cv.visitMethod(access, |
||||||
|
sig.getName(), |
||||||
|
sig.getDescriptor(), |
||||||
|
null, |
||||||
|
TypeUtils.toInternalNames(exceptions)); |
||||||
|
if (sig.equals(Constants.SIG_STATIC) && !TypeUtils.isInterface(getAccess())) { |
||||||
|
rawStaticInit = v; |
||||||
|
MethodVisitor wrapped = new MethodVisitor(Opcodes.ASM6, v) { |
||||||
|
public void visitMaxs(int maxStack, int maxLocals) { |
||||||
|
// ignore
|
||||||
|
} |
||||||
|
public void visitInsn(int insn) { |
||||||
|
if (insn != Constants.RETURN) { |
||||||
|
super.visitInsn(insn); |
||||||
|
} |
||||||
|
} |
||||||
|
}; |
||||||
|
staticInit = new CodeEmitter(this, wrapped, access, sig, exceptions); |
||||||
|
if (staticHook == null) { |
||||||
|
// force static hook creation
|
||||||
|
getStaticHook(); |
||||||
|
} else { |
||||||
|
staticInit.invoke_static_this(staticHookSig); |
||||||
|
} |
||||||
|
return staticInit; |
||||||
|
} else if (sig.equals(staticHookSig)) { |
||||||
|
return new CodeEmitter(this, v, access, sig, exceptions) { |
||||||
|
public boolean isStaticHook() { |
||||||
|
return true; |
||||||
|
} |
||||||
|
}; |
||||||
|
} else { |
||||||
|
return new CodeEmitter(this, v, access, sig, exceptions); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public CodeEmitter begin_static() { |
||||||
|
return begin_method(Constants.ACC_STATIC, Constants.SIG_STATIC, null); |
||||||
|
} |
||||||
|
|
||||||
|
public void declare_field(int access, String name, Type type, Object value) { |
||||||
|
FieldInfo existing = (FieldInfo)fieldInfo.get(name); |
||||||
|
FieldInfo info = new FieldInfo(access, name, type, value); |
||||||
|
if (existing != null) { |
||||||
|
if (!info.equals(existing)) { |
||||||
|
throw new IllegalArgumentException("Field \"" + name + "\" has been declared differently"); |
||||||
|
} |
||||||
|
} else { |
||||||
|
fieldInfo.put(name, info); |
||||||
|
cv.visitField(access, name, type.getDescriptor(), null, value); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
// TODO: make public?
|
||||||
|
boolean isFieldDeclared(String name) { |
||||||
|
return fieldInfo.get(name) != null; |
||||||
|
} |
||||||
|
|
||||||
|
FieldInfo getFieldInfo(String name) { |
||||||
|
FieldInfo field = (FieldInfo)fieldInfo.get(name); |
||||||
|
if (field == null) { |
||||||
|
throw new IllegalArgumentException("Field " + name + " is not declared in " + getClassType().getClassName()); |
||||||
|
} |
||||||
|
return field; |
||||||
|
} |
||||||
|
|
||||||
|
static class FieldInfo { |
||||||
|
int access; |
||||||
|
String name; |
||||||
|
Type type; |
||||||
|
Object value; |
||||||
|
|
||||||
|
public FieldInfo(int access, String name, Type type, Object value) { |
||||||
|
this.access = access; |
||||||
|
this.name = name; |
||||||
|
this.type = type; |
||||||
|
this.value = value; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean equals(Object o) { |
||||||
|
if (o == null) |
||||||
|
return false; |
||||||
|
if (!(o instanceof FieldInfo)) |
||||||
|
return false; |
||||||
|
FieldInfo other = (FieldInfo)o; |
||||||
|
if (access != other.access || |
||||||
|
!name.equals(other.name) || |
||||||
|
!type.equals(other.type)) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
if ((value == null) ^ (other.value == null)) |
||||||
|
return false; |
||||||
|
if (value != null && !value.equals(other.value)) |
||||||
|
return false; |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public int hashCode() { |
||||||
|
return access ^ name.hashCode() ^ type.hashCode() ^ ((value == null) ? 0 : value.hashCode()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visit(int version, |
||||||
|
int access, |
||||||
|
String name, |
||||||
|
String signature, |
||||||
|
String superName, |
||||||
|
String[] interfaces) { |
||||||
|
begin_class(version, |
||||||
|
access, |
||||||
|
name.replace('/', '.'), |
||||||
|
TypeUtils.fromInternalName(superName), |
||||||
|
TypeUtils.fromInternalNames(interfaces), |
||||||
|
null); // TODO
|
||||||
|
} |
||||||
|
|
||||||
|
public void visitEnd() { |
||||||
|
end_class(); |
||||||
|
} |
||||||
|
|
||||||
|
public FieldVisitor visitField(int access, |
||||||
|
String name, |
||||||
|
String desc, |
||||||
|
String signature, |
||||||
|
Object value) { |
||||||
|
declare_field(access, name, Type.getType(desc), value); |
||||||
|
return null; // TODO
|
||||||
|
} |
||||||
|
|
||||||
|
public MethodVisitor visitMethod(int access, |
||||||
|
String name, |
||||||
|
String desc, |
||||||
|
String signature, |
||||||
|
String[] exceptions) { |
||||||
|
return begin_method(access, |
||||||
|
new Signature(name, desc), |
||||||
|
TypeUtils.fromInternalNames(exceptions)); |
||||||
|
} |
||||||
|
} |
@ -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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.core; |
||||||
|
|
||||||
|
import com.fr.third.org.objectweb.asm.ClassVisitor; |
||||||
|
|
||||||
|
public interface ClassGenerator { |
||||||
|
void generateClass(ClassVisitor v) throws Exception; |
||||||
|
} |
@ -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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.core; |
||||||
|
|
||||||
|
import com.fr.third.org.objectweb.asm.Attribute; |
||||||
|
import com.fr.third.org.objectweb.asm.Type; |
||||||
|
|
||||||
|
abstract public class ClassInfo { |
||||||
|
|
||||||
|
protected ClassInfo() { |
||||||
|
} |
||||||
|
|
||||||
|
abstract public Type getType(); |
||||||
|
abstract public Type getSuperType(); |
||||||
|
abstract public Type[] getInterfaces(); |
||||||
|
abstract public int getModifiers(); |
||||||
|
|
||||||
|
public boolean equals(Object o) { |
||||||
|
if (o == null) |
||||||
|
return false; |
||||||
|
if (!(o instanceof ClassInfo)) |
||||||
|
return false; |
||||||
|
return getType().equals(((ClassInfo)o).getType()); |
||||||
|
} |
||||||
|
|
||||||
|
public int hashCode() { |
||||||
|
return getType().hashCode(); |
||||||
|
} |
||||||
|
|
||||||
|
public String toString() { |
||||||
|
// TODO: include modifiers, superType, interfaces
|
||||||
|
return getType().getClassName(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,63 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.core; |
||||||
|
|
||||||
|
import com.fr.third.org.objectweb.asm.ClassReader; |
||||||
|
import com.fr.third.org.objectweb.asm.ClassVisitor; |
||||||
|
import com.fr.third.org.objectweb.asm.Opcodes; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
// TODO: optimize (ClassReader buffers entire class before accept)
|
||||||
|
public class ClassNameReader { |
||||||
|
private ClassNameReader() { |
||||||
|
} |
||||||
|
|
||||||
|
private static final EarlyExitException EARLY_EXIT = new EarlyExitException(); |
||||||
|
private static class EarlyExitException extends RuntimeException { } |
||||||
|
|
||||||
|
public static String getClassName(ClassReader r) { |
||||||
|
|
||||||
|
return getClassInfo(r)[0]; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public static String[] getClassInfo(ClassReader r) { |
||||||
|
final List array = new ArrayList(); |
||||||
|
try { |
||||||
|
r.accept(new ClassVisitor(Opcodes.ASM6, null) { |
||||||
|
public void visit(int version, |
||||||
|
int access, |
||||||
|
String name, |
||||||
|
String signature, |
||||||
|
String superName, |
||||||
|
String[] interfaces) { |
||||||
|
array.add( name.replace('/', '.') ); |
||||||
|
if(superName != null){ |
||||||
|
array.add( superName.replace('/', '.') ); |
||||||
|
} |
||||||
|
for(int i = 0; i < interfaces.length; i++ ){ |
||||||
|
array.add( interfaces[i].replace('/', '.') ); |
||||||
|
} |
||||||
|
|
||||||
|
throw EARLY_EXIT; |
||||||
|
} |
||||||
|
}, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES); |
||||||
|
} catch (EarlyExitException e) { } |
||||||
|
|
||||||
|
return (String[])array.toArray( new String[]{} ); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,46 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.core; |
||||||
|
|
||||||
|
public class ClassesKey { |
||||||
|
private static final Key FACTORY = (Key)KeyFactory.create(Key.class); |
||||||
|
|
||||||
|
interface Key { |
||||||
|
Object newInstance(Object[] array); |
||||||
|
} |
||||||
|
|
||||||
|
private ClassesKey() { |
||||||
|
} |
||||||
|
|
||||||
|
public static Object create(Object[] array) { |
||||||
|
return FACTORY.newInstance(classNames(array)); |
||||||
|
} |
||||||
|
|
||||||
|
private static String[] classNames(Object[] objects) { |
||||||
|
if (objects == null) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
String[] classNames = new String[objects.length]; |
||||||
|
for (int i = 0; i < objects.length; i++) { |
||||||
|
Object object = objects[i]; |
||||||
|
if (object != null) { |
||||||
|
Class<?> aClass = object.getClass(); |
||||||
|
classNames[i] = aClass == null ? null : aClass.getName(); |
||||||
|
} |
||||||
|
} |
||||||
|
return classNames; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,864 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.core; |
||||||
|
|
||||||
|
import java.io.*; |
||||||
|
import java.util.*; |
||||||
|
import com.fr.third.org.objectweb.asm.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Juozas Baliuka, Chris Nokleberg |
||||||
|
*/ |
||||||
|
public class CodeEmitter extends LocalVariablesSorter { |
||||||
|
private static final Signature BOOLEAN_VALUE = |
||||||
|
TypeUtils.parseSignature("boolean booleanValue()"); |
||||||
|
private static final Signature CHAR_VALUE = |
||||||
|
TypeUtils.parseSignature("char charValue()"); |
||||||
|
private static final Signature LONG_VALUE = |
||||||
|
TypeUtils.parseSignature("long longValue()"); |
||||||
|
private static final Signature DOUBLE_VALUE = |
||||||
|
TypeUtils.parseSignature("double doubleValue()"); |
||||||
|
private static final Signature FLOAT_VALUE = |
||||||
|
TypeUtils.parseSignature("float floatValue()"); |
||||||
|
private static final Signature INT_VALUE = |
||||||
|
TypeUtils.parseSignature("int intValue()"); |
||||||
|
private static final Signature CSTRUCT_NULL = |
||||||
|
TypeUtils.parseConstructor(""); |
||||||
|
private static final Signature CSTRUCT_STRING = |
||||||
|
TypeUtils.parseConstructor("String"); |
||||||
|
|
||||||
|
public static final int ADD = Constants.IADD; |
||||||
|
public static final int MUL = Constants.IMUL; |
||||||
|
public static final int XOR = Constants.IXOR; |
||||||
|
public static final int USHR = Constants.IUSHR; |
||||||
|
public static final int SUB = Constants.ISUB; |
||||||
|
public static final int DIV = Constants.IDIV; |
||||||
|
public static final int NEG = Constants.INEG; |
||||||
|
public static final int REM = Constants.IREM; |
||||||
|
public static final int AND = Constants.IAND; |
||||||
|
public static final int OR = Constants.IOR; |
||||||
|
|
||||||
|
public static final int GT = Constants.IFGT; |
||||||
|
public static final int LT = Constants.IFLT; |
||||||
|
public static final int GE = Constants.IFGE; |
||||||
|
public static final int LE = Constants.IFLE; |
||||||
|
public static final int NE = Constants.IFNE; |
||||||
|
public static final int EQ = Constants.IFEQ; |
||||||
|
|
||||||
|
private ClassEmitter ce; |
||||||
|
private State state; |
||||||
|
|
||||||
|
private static class State |
||||||
|
extends MethodInfo |
||||||
|
{ |
||||||
|
ClassInfo classInfo; |
||||||
|
int access; |
||||||
|
Signature sig; |
||||||
|
Type[] argumentTypes; |
||||||
|
int localOffset; |
||||||
|
Type[] exceptionTypes; |
||||||
|
|
||||||
|
State(ClassInfo classInfo, int access, Signature sig, Type[] exceptionTypes) { |
||||||
|
this.classInfo = classInfo; |
||||||
|
this.access = access; |
||||||
|
this.sig = sig; |
||||||
|
this.exceptionTypes = exceptionTypes; |
||||||
|
localOffset = TypeUtils.isStatic(access) ? 0 : 1; |
||||||
|
argumentTypes = sig.getArgumentTypes(); |
||||||
|
} |
||||||
|
|
||||||
|
public ClassInfo getClassInfo() { |
||||||
|
return classInfo; |
||||||
|
} |
||||||
|
|
||||||
|
public int getModifiers() { |
||||||
|
return access; |
||||||
|
} |
||||||
|
|
||||||
|
public Signature getSignature() { |
||||||
|
return sig; |
||||||
|
} |
||||||
|
|
||||||
|
public Type[] getExceptionTypes() { |
||||||
|
return exceptionTypes; |
||||||
|
} |
||||||
|
|
||||||
|
public Attribute getAttribute() { |
||||||
|
// TODO
|
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
CodeEmitter(ClassEmitter ce, MethodVisitor mv, int access, Signature sig, Type[] exceptionTypes) { |
||||||
|
super(access, sig.getDescriptor(), mv); |
||||||
|
this.ce = ce; |
||||||
|
state = new State(ce.getClassInfo(), access, sig, exceptionTypes); |
||||||
|
} |
||||||
|
|
||||||
|
public CodeEmitter(CodeEmitter wrap) { |
||||||
|
super(wrap); |
||||||
|
this.ce = wrap.ce; |
||||||
|
this.state = wrap.state; |
||||||
|
} |
||||||
|
|
||||||
|
public boolean isStaticHook() { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
public Signature getSignature() { |
||||||
|
return state.sig; |
||||||
|
} |
||||||
|
|
||||||
|
public Type getReturnType() { |
||||||
|
return state.sig.getReturnType(); |
||||||
|
} |
||||||
|
|
||||||
|
public MethodInfo getMethodInfo() { |
||||||
|
return state; |
||||||
|
} |
||||||
|
|
||||||
|
public ClassEmitter getClassEmitter() { |
||||||
|
return ce; |
||||||
|
} |
||||||
|
|
||||||
|
public void end_method() { |
||||||
|
visitMaxs(0, 0); |
||||||
|
} |
||||||
|
|
||||||
|
public Block begin_block() { |
||||||
|
return new Block(this); |
||||||
|
} |
||||||
|
|
||||||
|
public void catch_exception(Block block, Type exception) { |
||||||
|
if (block.getEnd() == null) { |
||||||
|
throw new IllegalStateException("end of block is unset"); |
||||||
|
} |
||||||
|
mv.visitTryCatchBlock(block.getStart(), |
||||||
|
block.getEnd(), |
||||||
|
mark(), |
||||||
|
exception.getInternalName()); |
||||||
|
} |
||||||
|
|
||||||
|
public void goTo(Label label) { mv.visitJumpInsn(Constants.GOTO, label); } |
||||||
|
public void ifnull(Label label) { mv.visitJumpInsn(Constants.IFNULL, label); } |
||||||
|
public void ifnonnull(Label label) { mv.visitJumpInsn(Constants.IFNONNULL, label); } |
||||||
|
|
||||||
|
public void if_jump(int mode, Label label) { |
||||||
|
mv.visitJumpInsn(mode, label); |
||||||
|
} |
||||||
|
|
||||||
|
public void if_icmp(int mode, Label label) { |
||||||
|
if_cmp(Type.INT_TYPE, mode, label); |
||||||
|
} |
||||||
|
|
||||||
|
public void if_cmp(Type type, int mode, Label label) { |
||||||
|
int intOp = -1; |
||||||
|
int jumpmode = mode; |
||||||
|
switch (mode) { |
||||||
|
case GE: jumpmode = LT; break; |
||||||
|
case LE: jumpmode = GT; break; |
||||||
|
} |
||||||
|
switch (type.getSort()) { |
||||||
|
case Type.LONG: |
||||||
|
mv.visitInsn(Constants.LCMP); |
||||||
|
break; |
||||||
|
case Type.DOUBLE: |
||||||
|
mv.visitInsn(Constants.DCMPG); |
||||||
|
break; |
||||||
|
case Type.FLOAT: |
||||||
|
mv.visitInsn(Constants.FCMPG); |
||||||
|
break; |
||||||
|
case Type.ARRAY: |
||||||
|
case Type.OBJECT: |
||||||
|
switch (mode) { |
||||||
|
case EQ: |
||||||
|
mv.visitJumpInsn(Constants.IF_ACMPEQ, label); |
||||||
|
return; |
||||||
|
case NE: |
||||||
|
mv.visitJumpInsn(Constants.IF_ACMPNE, label); |
||||||
|
return; |
||||||
|
} |
||||||
|
throw new IllegalArgumentException("Bad comparison for type " + type); |
||||||
|
default: |
||||||
|
switch (mode) { |
||||||
|
case EQ: intOp = Constants.IF_ICMPEQ; break; |
||||||
|
case NE: intOp = Constants.IF_ICMPNE; break; |
||||||
|
case GE: swap(); /* fall through */ |
||||||
|
case LT: intOp = Constants.IF_ICMPLT; break; |
||||||
|
case LE: swap(); /* fall through */ |
||||||
|
case GT: intOp = Constants.IF_ICMPGT; break; |
||||||
|
} |
||||||
|
mv.visitJumpInsn(intOp, label); |
||||||
|
return; |
||||||
|
} |
||||||
|
if_jump(jumpmode, label); |
||||||
|
} |
||||||
|
|
||||||
|
public void pop() { mv.visitInsn(Constants.POP); } |
||||||
|
public void pop2() { mv.visitInsn(Constants.POP2); } |
||||||
|
public void dup() { mv.visitInsn(Constants.DUP); } |
||||||
|
public void dup2() { mv.visitInsn(Constants.DUP2); } |
||||||
|
public void dup_x1() { mv.visitInsn(Constants.DUP_X1); } |
||||||
|
public void dup_x2() { mv.visitInsn(Constants.DUP_X2); } |
||||||
|
public void dup2_x1() { mv.visitInsn(Constants.DUP2_X1); } |
||||||
|
public void dup2_x2() { mv.visitInsn(Constants.DUP2_X2); } |
||||||
|
public void swap() { mv.visitInsn(Constants.SWAP); } |
||||||
|
public void aconst_null() { mv.visitInsn(Constants.ACONST_NULL); } |
||||||
|
|
||||||
|
public void swap(Type prev, Type type) { |
||||||
|
if (type.getSize() == 1) { |
||||||
|
if (prev.getSize() == 1) { |
||||||
|
swap(); // same as dup_x1(), pop();
|
||||||
|
} else { |
||||||
|
dup_x2(); |
||||||
|
pop(); |
||||||
|
} |
||||||
|
} else { |
||||||
|
if (prev.getSize() == 1) { |
||||||
|
dup2_x1(); |
||||||
|
pop2(); |
||||||
|
} else { |
||||||
|
dup2_x2(); |
||||||
|
pop2(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void monitorenter() { mv.visitInsn(Constants.MONITORENTER); } |
||||||
|
public void monitorexit() { mv.visitInsn(Constants.MONITOREXIT); } |
||||||
|
|
||||||
|
public void math(int op, Type type) { mv.visitInsn(type.getOpcode(op)); } |
||||||
|
|
||||||
|
public void array_load(Type type) { mv.visitInsn(type.getOpcode(Constants.IALOAD)); } |
||||||
|
public void array_store(Type type) { mv.visitInsn(type.getOpcode(Constants.IASTORE)); } |
||||||
|
|
||||||
|
/** |
||||||
|
* Casts from one primitive numeric type to another |
||||||
|
*/ |
||||||
|
public void cast_numeric(Type from, Type to) { |
||||||
|
if (from != to) { |
||||||
|
if (from == Type.DOUBLE_TYPE) { |
||||||
|
if (to == Type.FLOAT_TYPE) { |
||||||
|
mv.visitInsn(Constants.D2F); |
||||||
|
} else if (to == Type.LONG_TYPE) { |
||||||
|
mv.visitInsn(Constants.D2L); |
||||||
|
} else { |
||||||
|
mv.visitInsn(Constants.D2I); |
||||||
|
cast_numeric(Type.INT_TYPE, to); |
||||||
|
} |
||||||
|
} else if (from == Type.FLOAT_TYPE) { |
||||||
|
if (to == Type.DOUBLE_TYPE) { |
||||||
|
mv.visitInsn(Constants.F2D); |
||||||
|
} else if (to == Type.LONG_TYPE) { |
||||||
|
mv.visitInsn(Constants.F2L); |
||||||
|
} else { |
||||||
|
mv.visitInsn(Constants.F2I); |
||||||
|
cast_numeric(Type.INT_TYPE, to); |
||||||
|
} |
||||||
|
} else if (from == Type.LONG_TYPE) { |
||||||
|
if (to == Type.DOUBLE_TYPE) { |
||||||
|
mv.visitInsn(Constants.L2D); |
||||||
|
} else if (to == Type.FLOAT_TYPE) { |
||||||
|
mv.visitInsn(Constants.L2F); |
||||||
|
} else { |
||||||
|
mv.visitInsn(Constants.L2I); |
||||||
|
cast_numeric(Type.INT_TYPE, to); |
||||||
|
} |
||||||
|
} else { |
||||||
|
if (to == Type.BYTE_TYPE) { |
||||||
|
mv.visitInsn(Constants.I2B); |
||||||
|
} else if (to == Type.CHAR_TYPE) { |
||||||
|
mv.visitInsn(Constants.I2C); |
||||||
|
} else if (to == Type.DOUBLE_TYPE) { |
||||||
|
mv.visitInsn(Constants.I2D); |
||||||
|
} else if (to == Type.FLOAT_TYPE) { |
||||||
|
mv.visitInsn(Constants.I2F); |
||||||
|
} else if (to == Type.LONG_TYPE) { |
||||||
|
mv.visitInsn(Constants.I2L); |
||||||
|
} else if (to == Type.SHORT_TYPE) { |
||||||
|
mv.visitInsn(Constants.I2S); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void push(int i) { |
||||||
|
if (i < -1) { |
||||||
|
mv.visitLdcInsn(new Integer(i)); |
||||||
|
} else if (i <= 5) { |
||||||
|
mv.visitInsn(TypeUtils.ICONST(i)); |
||||||
|
} else if (i <= Byte.MAX_VALUE) { |
||||||
|
mv.visitIntInsn(Constants.BIPUSH, i); |
||||||
|
} else if (i <= Short.MAX_VALUE) { |
||||||
|
mv.visitIntInsn(Constants.SIPUSH, i); |
||||||
|
} else { |
||||||
|
mv.visitLdcInsn(new Integer(i)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void push(long value) { |
||||||
|
if (value == 0L || value == 1L) { |
||||||
|
mv.visitInsn(TypeUtils.LCONST(value)); |
||||||
|
} else { |
||||||
|
mv.visitLdcInsn(new Long(value)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void push(float value) { |
||||||
|
if (value == 0f || value == 1f || value == 2f) { |
||||||
|
mv.visitInsn(TypeUtils.FCONST(value)); |
||||||
|
} else { |
||||||
|
mv.visitLdcInsn(new Float(value)); |
||||||
|
} |
||||||
|
} |
||||||
|
public void push(double value) { |
||||||
|
if (value == 0d || value == 1d) { |
||||||
|
mv.visitInsn(TypeUtils.DCONST(value)); |
||||||
|
} else { |
||||||
|
mv.visitLdcInsn(new Double(value)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void push(String value) { |
||||||
|
mv.visitLdcInsn(value); |
||||||
|
} |
||||||
|
|
||||||
|
public void newarray() { |
||||||
|
newarray(Constants.TYPE_OBJECT); |
||||||
|
} |
||||||
|
|
||||||
|
public void newarray(Type type) { |
||||||
|
if (TypeUtils.isPrimitive(type)) { |
||||||
|
mv.visitIntInsn(Constants.NEWARRAY, TypeUtils.NEWARRAY(type)); |
||||||
|
} else { |
||||||
|
emit_type(Constants.ANEWARRAY, type); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void arraylength() { |
||||||
|
mv.visitInsn(Constants.ARRAYLENGTH); |
||||||
|
} |
||||||
|
|
||||||
|
public void load_this() { |
||||||
|
if (TypeUtils.isStatic(state.access)) { |
||||||
|
throw new IllegalStateException("no 'this' pointer within static method"); |
||||||
|
} |
||||||
|
mv.visitVarInsn(Constants.ALOAD, 0); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Pushes all of the arguments of the current method onto the stack. |
||||||
|
*/ |
||||||
|
public void load_args() { |
||||||
|
load_args(0, state.argumentTypes.length); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Pushes the specified argument of the current method onto the stack. |
||||||
|
* @param index the zero-based index into the argument list |
||||||
|
*/ |
||||||
|
public void load_arg(int index) { |
||||||
|
load_local(state.argumentTypes[index], |
||||||
|
state.localOffset + skipArgs(index)); |
||||||
|
} |
||||||
|
|
||||||
|
// zero-based (see load_this)
|
||||||
|
public void load_args(int fromArg, int count) { |
||||||
|
int pos = state.localOffset + skipArgs(fromArg); |
||||||
|
for (int i = 0; i < count; i++) { |
||||||
|
Type t = state.argumentTypes[fromArg + i]; |
||||||
|
load_local(t, pos); |
||||||
|
pos += t.getSize(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private int skipArgs(int numArgs) { |
||||||
|
int amount = 0; |
||||||
|
for (int i = 0; i < numArgs; i++) { |
||||||
|
amount += state.argumentTypes[i].getSize(); |
||||||
|
} |
||||||
|
return amount; |
||||||
|
} |
||||||
|
|
||||||
|
private void load_local(Type t, int pos) { |
||||||
|
// TODO: make t == null ok?
|
||||||
|
mv.visitVarInsn(t.getOpcode(Constants.ILOAD), pos); |
||||||
|
} |
||||||
|
|
||||||
|
private void store_local(Type t, int pos) { |
||||||
|
// TODO: make t == null ok?
|
||||||
|
mv.visitVarInsn(t.getOpcode(Constants.ISTORE), pos); |
||||||
|
} |
||||||
|
|
||||||
|
public void iinc(Local local, int amount) { |
||||||
|
mv.visitIincInsn(local.getIndex(), amount); |
||||||
|
} |
||||||
|
|
||||||
|
public void store_local(Local local) { |
||||||
|
store_local(local.getType(), local.getIndex()); |
||||||
|
} |
||||||
|
|
||||||
|
public void load_local(Local local) { |
||||||
|
load_local(local.getType(), local.getIndex()); |
||||||
|
} |
||||||
|
|
||||||
|
public void return_value() { |
||||||
|
mv.visitInsn(state.sig.getReturnType().getOpcode(Constants.IRETURN)); |
||||||
|
} |
||||||
|
|
||||||
|
public void getfield(String name) { |
||||||
|
ClassEmitter.FieldInfo info = ce.getFieldInfo(name); |
||||||
|
int opcode = TypeUtils.isStatic(info.access) ? Constants.GETSTATIC : Constants.GETFIELD; |
||||||
|
emit_field(opcode, ce.getClassType(), name, info.type); |
||||||
|
} |
||||||
|
|
||||||
|
public void putfield(String name) { |
||||||
|
ClassEmitter.FieldInfo info = ce.getFieldInfo(name); |
||||||
|
int opcode = TypeUtils.isStatic(info.access) ? Constants.PUTSTATIC : Constants.PUTFIELD; |
||||||
|
emit_field(opcode, ce.getClassType(), name, info.type); |
||||||
|
} |
||||||
|
|
||||||
|
public void super_getfield(String name, Type type) { |
||||||
|
emit_field(Constants.GETFIELD, ce.getSuperType(), name, type); |
||||||
|
} |
||||||
|
|
||||||
|
public void super_putfield(String name, Type type) { |
||||||
|
emit_field(Constants.PUTFIELD, ce.getSuperType(), name, type); |
||||||
|
} |
||||||
|
|
||||||
|
public void super_getstatic(String name, Type type) { |
||||||
|
emit_field(Constants.GETSTATIC, ce.getSuperType(), name, type); |
||||||
|
} |
||||||
|
|
||||||
|
public void super_putstatic(String name, Type type) { |
||||||
|
emit_field(Constants.PUTSTATIC, ce.getSuperType(), name, type); |
||||||
|
} |
||||||
|
|
||||||
|
public void getfield(Type owner, String name, Type type) { |
||||||
|
emit_field(Constants.GETFIELD, owner, name, type); |
||||||
|
} |
||||||
|
|
||||||
|
public void putfield(Type owner, String name, Type type) { |
||||||
|
emit_field(Constants.PUTFIELD, owner, name, type); |
||||||
|
} |
||||||
|
|
||||||
|
public void getstatic(Type owner, String name, Type type) { |
||||||
|
emit_field(Constants.GETSTATIC, owner, name, type); |
||||||
|
} |
||||||
|
|
||||||
|
public void putstatic(Type owner, String name, Type type) { |
||||||
|
emit_field(Constants.PUTSTATIC, owner, name, type); |
||||||
|
} |
||||||
|
|
||||||
|
// package-protected for EmitUtils, try to fix
|
||||||
|
void emit_field(int opcode, Type ctype, String name, Type ftype) { |
||||||
|
mv.visitFieldInsn(opcode, |
||||||
|
ctype.getInternalName(), |
||||||
|
name, |
||||||
|
ftype.getDescriptor()); |
||||||
|
} |
||||||
|
|
||||||
|
public void super_invoke() { |
||||||
|
super_invoke(state.sig); |
||||||
|
} |
||||||
|
|
||||||
|
public void super_invoke(Signature sig) { |
||||||
|
emit_invoke(Constants.INVOKESPECIAL, ce.getSuperType(), sig); |
||||||
|
} |
||||||
|
|
||||||
|
public void invoke_constructor(Type type) { |
||||||
|
invoke_constructor(type, CSTRUCT_NULL); |
||||||
|
} |
||||||
|
|
||||||
|
public void super_invoke_constructor() { |
||||||
|
invoke_constructor(ce.getSuperType()); |
||||||
|
} |
||||||
|
|
||||||
|
public void invoke_constructor_this() { |
||||||
|
invoke_constructor(ce.getClassType()); |
||||||
|
} |
||||||
|
|
||||||
|
private void emit_invoke(int opcode, Type type, Signature sig) { |
||||||
|
if (sig.getName().equals(Constants.CONSTRUCTOR_NAME) && |
||||||
|
((opcode == Constants.INVOKEVIRTUAL) || |
||||||
|
(opcode == Constants.INVOKESTATIC))) { |
||||||
|
// TODO: error
|
||||||
|
} |
||||||
|
mv.visitMethodInsn(opcode, |
||||||
|
type.getInternalName(), |
||||||
|
sig.getName(), |
||||||
|
sig.getDescriptor(), |
||||||
|
opcode == Opcodes.INVOKEINTERFACE); |
||||||
|
} |
||||||
|
|
||||||
|
public void invoke_interface(Type owner, Signature sig) { |
||||||
|
emit_invoke(Constants.INVOKEINTERFACE, owner, sig); |
||||||
|
} |
||||||
|
|
||||||
|
public void invoke_virtual(Type owner, Signature sig) { |
||||||
|
emit_invoke(Constants.INVOKEVIRTUAL, owner, sig); |
||||||
|
} |
||||||
|
|
||||||
|
public void invoke_static(Type owner, Signature sig) { |
||||||
|
emit_invoke(Constants.INVOKESTATIC, owner, sig); |
||||||
|
} |
||||||
|
|
||||||
|
public void invoke_virtual_this(Signature sig) { |
||||||
|
invoke_virtual(ce.getClassType(), sig); |
||||||
|
} |
||||||
|
|
||||||
|
public void invoke_static_this(Signature sig) { |
||||||
|
invoke_static(ce.getClassType(), sig); |
||||||
|
} |
||||||
|
|
||||||
|
public void invoke_constructor(Type type, Signature sig) { |
||||||
|
emit_invoke(Constants.INVOKESPECIAL, type, sig); |
||||||
|
} |
||||||
|
|
||||||
|
public void invoke_constructor_this(Signature sig) { |
||||||
|
invoke_constructor(ce.getClassType(), sig); |
||||||
|
} |
||||||
|
|
||||||
|
public void super_invoke_constructor(Signature sig) { |
||||||
|
invoke_constructor(ce.getSuperType(), sig); |
||||||
|
} |
||||||
|
|
||||||
|
public void new_instance_this() { |
||||||
|
new_instance(ce.getClassType()); |
||||||
|
} |
||||||
|
|
||||||
|
public void new_instance(Type type) { |
||||||
|
emit_type(Constants.NEW, type); |
||||||
|
} |
||||||
|
|
||||||
|
private void emit_type(int opcode, Type type) { |
||||||
|
String desc; |
||||||
|
if (TypeUtils.isArray(type)) { |
||||||
|
desc = type.getDescriptor(); |
||||||
|
} else { |
||||||
|
desc = type.getInternalName(); |
||||||
|
} |
||||||
|
mv.visitTypeInsn(opcode, desc); |
||||||
|
} |
||||||
|
|
||||||
|
public void aaload(int index) { |
||||||
|
push(index); |
||||||
|
aaload(); |
||||||
|
} |
||||||
|
|
||||||
|
public void aaload() { mv.visitInsn(Constants.AALOAD); } |
||||||
|
public void aastore() { mv.visitInsn(Constants.AASTORE); } |
||||||
|
public void athrow() { mv.visitInsn(Constants.ATHROW); } |
||||||
|
|
||||||
|
public Label make_label() { |
||||||
|
return new Label(); |
||||||
|
} |
||||||
|
|
||||||
|
public Local make_local() { |
||||||
|
return make_local(Constants.TYPE_OBJECT); |
||||||
|
} |
||||||
|
|
||||||
|
public Local make_local(Type type) { |
||||||
|
return new Local(newLocal(type.getSize()), type); |
||||||
|
} |
||||||
|
|
||||||
|
public void checkcast_this() { |
||||||
|
checkcast(ce.getClassType()); |
||||||
|
} |
||||||
|
|
||||||
|
public void checkcast(Type type) { |
||||||
|
if (!type.equals(Constants.TYPE_OBJECT)) { |
||||||
|
emit_type(Constants.CHECKCAST, type); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void instance_of(Type type) { |
||||||
|
emit_type(Constants.INSTANCEOF, type); |
||||||
|
} |
||||||
|
|
||||||
|
public void instance_of_this() { |
||||||
|
instance_of(ce.getClassType()); |
||||||
|
} |
||||||
|
|
||||||
|
public void process_switch(int[] keys, ProcessSwitchCallback callback) { |
||||||
|
float density; |
||||||
|
if (keys.length == 0) { |
||||||
|
density = 0; |
||||||
|
} else { |
||||||
|
density = (float)keys.length / (keys[keys.length - 1] - keys[0] + 1); |
||||||
|
} |
||||||
|
process_switch(keys, callback, density >= 0.5f); |
||||||
|
} |
||||||
|
|
||||||
|
public void process_switch(int[] keys, ProcessSwitchCallback callback, boolean useTable) { |
||||||
|
if (!isSorted(keys)) |
||||||
|
throw new IllegalArgumentException("keys to switch must be sorted ascending"); |
||||||
|
Label def = make_label(); |
||||||
|
Label end = make_label(); |
||||||
|
|
||||||
|
try { |
||||||
|
if (keys.length > 0) { |
||||||
|
int len = keys.length; |
||||||
|
int min = keys[0]; |
||||||
|
int max = keys[len - 1]; |
||||||
|
int range = max - min + 1; |
||||||
|
|
||||||
|
if (useTable) { |
||||||
|
Label[] labels = new Label[range]; |
||||||
|
Arrays.fill(labels, def); |
||||||
|
for (int i = 0; i < len; i++) { |
||||||
|
labels[keys[i] - min] = make_label(); |
||||||
|
} |
||||||
|
mv.visitTableSwitchInsn(min, max, def, labels); |
||||||
|
for (int i = 0; i < range; i++) { |
||||||
|
Label label = labels[i]; |
||||||
|
if (label != def) { |
||||||
|
mark(label); |
||||||
|
callback.processCase(i + min, end); |
||||||
|
} |
||||||
|
} |
||||||
|
} else { |
||||||
|
Label[] labels = new Label[len]; |
||||||
|
for (int i = 0; i < len; i++) { |
||||||
|
labels[i] = make_label(); |
||||||
|
} |
||||||
|
mv.visitLookupSwitchInsn(def, keys, labels); |
||||||
|
for (int i = 0; i < len; i++) { |
||||||
|
mark(labels[i]); |
||||||
|
callback.processCase(keys[i], end); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
mark(def); |
||||||
|
callback.processDefault(); |
||||||
|
mark(end); |
||||||
|
|
||||||
|
} catch (RuntimeException e) { |
||||||
|
throw e; |
||||||
|
} catch (Error e) { |
||||||
|
throw e; |
||||||
|
} catch (Exception e) { |
||||||
|
throw new CodeGenerationException(e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static boolean isSorted(int[] keys) { |
||||||
|
for (int i = 1; i < keys.length; i++) { |
||||||
|
if (keys[i] < keys[i - 1]) |
||||||
|
return false; |
||||||
|
} |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
public void mark(Label label) { |
||||||
|
mv.visitLabel(label); |
||||||
|
} |
||||||
|
|
||||||
|
Label mark() { |
||||||
|
Label label = make_label(); |
||||||
|
mv.visitLabel(label); |
||||||
|
return label; |
||||||
|
} |
||||||
|
|
||||||
|
public void push(boolean value) { |
||||||
|
push(value ? 1 : 0); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Toggles the integer on the top of the stack from 1 to 0 or vice versa |
||||||
|
*/ |
||||||
|
public void not() { |
||||||
|
push(1); |
||||||
|
math(XOR, Type.INT_TYPE); |
||||||
|
} |
||||||
|
|
||||||
|
public void throw_exception(Type type, String msg) { |
||||||
|
new_instance(type); |
||||||
|
dup(); |
||||||
|
push(msg); |
||||||
|
invoke_constructor(type, CSTRUCT_STRING); |
||||||
|
athrow(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* If the argument is a primitive class, replaces the primitive value |
||||||
|
* on the top of the stack with the wrapped (Object) equivalent. For |
||||||
|
* example, char -> Character. |
||||||
|
* If the class is Void, a null is pushed onto the stack instead. |
||||||
|
* @param type the class indicating the current type of the top stack value |
||||||
|
*/ |
||||||
|
public void box(Type type) { |
||||||
|
if (TypeUtils.isPrimitive(type)) { |
||||||
|
if (type == Type.VOID_TYPE) { |
||||||
|
aconst_null(); |
||||||
|
} else { |
||||||
|
Type boxed = TypeUtils.getBoxedType(type); |
||||||
|
new_instance(boxed); |
||||||
|
if (type.getSize() == 2) { |
||||||
|
// Pp -> Ppo -> oPpo -> ooPpo -> ooPp -> o
|
||||||
|
dup_x2(); |
||||||
|
dup_x2(); |
||||||
|
pop(); |
||||||
|
} else { |
||||||
|
// p -> po -> opo -> oop -> o
|
||||||
|
dup_x1(); |
||||||
|
swap(); |
||||||
|
} |
||||||
|
invoke_constructor(boxed, new Signature(Constants.CONSTRUCTOR_NAME, Type.VOID_TYPE, new Type[]{ type })); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* If the argument is a primitive class, replaces the object |
||||||
|
* on the top of the stack with the unwrapped (primitive) |
||||||
|
* equivalent. For example, Character -> char. |
||||||
|
* @param type the class indicating the desired type of the top stack value |
||||||
|
* @return true if the value was unboxed |
||||||
|
*/ |
||||||
|
public void unbox(Type type) { |
||||||
|
Type t = Constants.TYPE_NUMBER; |
||||||
|
Signature sig = null; |
||||||
|
switch (type.getSort()) { |
||||||
|
case Type.VOID: |
||||||
|
return; |
||||||
|
case Type.CHAR: |
||||||
|
t = Constants.TYPE_CHARACTER; |
||||||
|
sig = CHAR_VALUE; |
||||||
|
break; |
||||||
|
case Type.BOOLEAN: |
||||||
|
t = Constants.TYPE_BOOLEAN; |
||||||
|
sig = BOOLEAN_VALUE; |
||||||
|
break; |
||||||
|
case Type.DOUBLE: |
||||||
|
sig = DOUBLE_VALUE; |
||||||
|
break; |
||||||
|
case Type.FLOAT: |
||||||
|
sig = FLOAT_VALUE; |
||||||
|
break; |
||||||
|
case Type.LONG: |
||||||
|
sig = LONG_VALUE; |
||||||
|
break; |
||||||
|
case Type.INT: |
||||||
|
case Type.SHORT: |
||||||
|
case Type.BYTE: |
||||||
|
sig = INT_VALUE; |
||||||
|
} |
||||||
|
|
||||||
|
if (sig == null) { |
||||||
|
checkcast(type); |
||||||
|
} else { |
||||||
|
checkcast(t); |
||||||
|
invoke_virtual(t, sig); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Allocates and fills an Object[] array with the arguments to the |
||||||
|
* current method. Primitive values are inserted as their boxed |
||||||
|
* (Object) equivalents. |
||||||
|
*/ |
||||||
|
public void create_arg_array() { |
||||||
|
/* generates: |
||||||
|
Object[] args = new Object[]{ arg1, new Integer(arg2) }; |
||||||
|
*/ |
||||||
|
|
||||||
|
push(state.argumentTypes.length); |
||||||
|
newarray(); |
||||||
|
for (int i = 0; i < state.argumentTypes.length; i++) { |
||||||
|
dup(); |
||||||
|
push(i); |
||||||
|
load_arg(i); |
||||||
|
box(state.argumentTypes[i]); |
||||||
|
aastore(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* Pushes a zero onto the stack if the argument is a primitive class, or a null otherwise. |
||||||
|
*/ |
||||||
|
public void zero_or_null(Type type) { |
||||||
|
if (TypeUtils.isPrimitive(type)) { |
||||||
|
switch (type.getSort()) { |
||||||
|
case Type.DOUBLE: |
||||||
|
push(0d); |
||||||
|
break; |
||||||
|
case Type.LONG: |
||||||
|
push(0L); |
||||||
|
break; |
||||||
|
case Type.FLOAT: |
||||||
|
push(0f); |
||||||
|
break; |
||||||
|
case Type.VOID: |
||||||
|
aconst_null(); |
||||||
|
default: |
||||||
|
push(0); |
||||||
|
} |
||||||
|
} else { |
||||||
|
aconst_null(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Unboxes the object on the top of the stack. If the object is null, the |
||||||
|
* unboxed primitive value becomes zero. |
||||||
|
*/ |
||||||
|
public void unbox_or_zero(Type type) { |
||||||
|
if (TypeUtils.isPrimitive(type)) { |
||||||
|
if (type != Type.VOID_TYPE) { |
||||||
|
Label nonNull = make_label(); |
||||||
|
Label end = make_label(); |
||||||
|
dup(); |
||||||
|
ifnonnull(nonNull); |
||||||
|
pop(); |
||||||
|
zero_or_null(type); |
||||||
|
goTo(end); |
||||||
|
mark(nonNull); |
||||||
|
unbox(type); |
||||||
|
mark(end); |
||||||
|
} |
||||||
|
} else { |
||||||
|
checkcast(type); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void visitMaxs(int maxStack, int maxLocals) { |
||||||
|
if (!TypeUtils.isAbstract(state.access)) { |
||||||
|
mv.visitMaxs(0, 0); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void invoke(MethodInfo method, Type virtualType) { |
||||||
|
ClassInfo classInfo = method.getClassInfo(); |
||||||
|
Type type = classInfo.getType(); |
||||||
|
Signature sig = method.getSignature(); |
||||||
|
if (sig.getName().equals(Constants.CONSTRUCTOR_NAME)) { |
||||||
|
invoke_constructor(type, sig); |
||||||
|
} else if (TypeUtils.isInterface(classInfo.getModifiers())) { |
||||||
|
invoke_interface(type, sig); |
||||||
|
} else if (TypeUtils.isStatic(method.getModifiers())) { |
||||||
|
invoke_static(type, sig); |
||||||
|
} else { |
||||||
|
invoke_virtual(virtualType, sig); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void invoke(MethodInfo method) { |
||||||
|
invoke(method, method.getClassInfo().getType()); |
||||||
|
} |
||||||
|
} |
@ -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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.core; |
||||||
|
|
||||||
|
/** |
||||||
|
* @version $Id: CodeGenerationException.java,v 1.3 2004/06/24 21:15:21 herbyderby Exp $ |
||||||
|
*/ |
||||||
|
public class CodeGenerationException extends RuntimeException { |
||||||
|
private Throwable cause; |
||||||
|
|
||||||
|
public CodeGenerationException(Throwable cause) { |
||||||
|
super(cause.getClass().getName() + "-->" + cause.getMessage()); |
||||||
|
this.cause = cause; |
||||||
|
} |
||||||
|
|
||||||
|
public Throwable getCause() { |
||||||
|
return cause; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,76 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.core; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
import java.lang.reflect.Array; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Chris Nokleberg |
||||||
|
* @version $Id: CollectionUtils.java,v 1.7 2004/06/24 21:15:21 herbyderby Exp $ |
||||||
|
*/ |
||||||
|
public class CollectionUtils { |
||||||
|
private CollectionUtils() { } |
||||||
|
|
||||||
|
public static Map bucket(Collection c, Transformer t) { |
||||||
|
Map buckets = new HashMap(); |
||||||
|
for (Iterator it = c.iterator(); it.hasNext();) { |
||||||
|
Object value = (Object)it.next(); |
||||||
|
Object key = t.transform(value); |
||||||
|
List bucket = (List)buckets.get(key); |
||||||
|
if (bucket == null) { |
||||||
|
buckets.put(key, bucket = new LinkedList()); |
||||||
|
} |
||||||
|
bucket.add(value); |
||||||
|
} |
||||||
|
return buckets; |
||||||
|
} |
||||||
|
|
||||||
|
public static void reverse(Map source, Map target) { |
||||||
|
for (Iterator it = source.keySet().iterator(); it.hasNext();) { |
||||||
|
Object key = it.next(); |
||||||
|
target.put(source.get(key), key); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static Collection filter(Collection c, Predicate p) { |
||||||
|
Iterator it = c.iterator(); |
||||||
|
while (it.hasNext()) { |
||||||
|
if (!p.evaluate(it.next())) { |
||||||
|
it.remove(); |
||||||
|
} |
||||||
|
} |
||||||
|
return c; |
||||||
|
} |
||||||
|
|
||||||
|
public static List transform(Collection c, Transformer t) { |
||||||
|
List result = new ArrayList(c.size()); |
||||||
|
for (Iterator it = c.iterator(); it.hasNext();) { |
||||||
|
result.add(t.transform(it.next())); |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
|
||||||
|
public static Map getIndexMap(List list) { |
||||||
|
Map indexes = new HashMap(); |
||||||
|
int index = 0; |
||||||
|
for (Iterator it = list.iterator(); it.hasNext();) { |
||||||
|
indexes.put(it.next(), new Integer(index++)); |
||||||
|
} |
||||||
|
return indexes; |
||||||
|
} |
||||||
|
} |
||||||
|
|
@ -0,0 +1,68 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.core; |
||||||
|
|
||||||
|
import com.fr.third.org.objectweb.asm.Type; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Juozas Baliuka <a href="mailto:baliuka@mwm.lt">baliuka@mwm.lt</a> |
||||||
|
* @version $Id: Constants.java,v 1.21 2006/03/05 02:43:19 herbyderby Exp $ |
||||||
|
*/ |
||||||
|
public interface Constants extends com.fr.third.org.objectweb.asm.Opcodes { |
||||||
|
public static final Class[] EMPTY_CLASS_ARRAY = {}; |
||||||
|
public static final Type[] TYPES_EMPTY = {}; |
||||||
|
|
||||||
|
public static final Signature SIG_STATIC = |
||||||
|
TypeUtils.parseSignature("void <clinit>()"); |
||||||
|
|
||||||
|
public static final Type TYPE_OBJECT_ARRAY = TypeUtils.parseType("Object[]"); |
||||||
|
public static final Type TYPE_CLASS_ARRAY = TypeUtils.parseType("Class[]"); |
||||||
|
public static final Type TYPE_STRING_ARRAY = TypeUtils.parseType("String[]"); |
||||||
|
|
||||||
|
public static final Type TYPE_OBJECT = TypeUtils.parseType("Object"); |
||||||
|
public static final Type TYPE_CLASS = TypeUtils.parseType("Class"); |
||||||
|
public static final Type TYPE_CLASS_LOADER = TypeUtils.parseType("ClassLoader"); |
||||||
|
public static final Type TYPE_CHARACTER = TypeUtils.parseType("Character"); |
||||||
|
public static final Type TYPE_BOOLEAN = TypeUtils.parseType("Boolean"); |
||||||
|
public static final Type TYPE_DOUBLE = TypeUtils.parseType("Double"); |
||||||
|
public static final Type TYPE_FLOAT = TypeUtils.parseType("Float"); |
||||||
|
public static final Type TYPE_LONG = TypeUtils.parseType("Long"); |
||||||
|
public static final Type TYPE_INTEGER = TypeUtils.parseType("Integer"); |
||||||
|
public static final Type TYPE_SHORT = TypeUtils.parseType("Short"); |
||||||
|
public static final Type TYPE_BYTE = TypeUtils.parseType("Byte"); |
||||||
|
public static final Type TYPE_NUMBER = TypeUtils.parseType("Number"); |
||||||
|
public static final Type TYPE_STRING = TypeUtils.parseType("String"); |
||||||
|
public static final Type TYPE_THROWABLE = TypeUtils.parseType("Throwable"); |
||||||
|
public static final Type TYPE_BIG_INTEGER = TypeUtils.parseType("java.math.BigInteger"); |
||||||
|
public static final Type TYPE_BIG_DECIMAL = TypeUtils.parseType("java.math.BigDecimal"); |
||||||
|
public static final Type TYPE_STRING_BUFFER = TypeUtils.parseType("StringBuffer"); |
||||||
|
public static final Type TYPE_RUNTIME_EXCEPTION = TypeUtils.parseType("RuntimeException"); |
||||||
|
public static final Type TYPE_ERROR = TypeUtils.parseType("Error"); |
||||||
|
public static final Type TYPE_SYSTEM = TypeUtils.parseType("System"); |
||||||
|
public static final Type TYPE_SIGNATURE = TypeUtils.parseType("com.fr.third.net.sf.cglib.core.Signature"); |
||||||
|
public static final Type TYPE_TYPE = Type.getType(Type.class); |
||||||
|
|
||||||
|
public static final String CONSTRUCTOR_NAME = "<init>"; |
||||||
|
public static final String STATIC_NAME = "<clinit>"; |
||||||
|
public static final String SOURCE_FILE = "<generated>"; |
||||||
|
public static final String SUID_FIELD_NAME = "serialVersionUID"; |
||||||
|
|
||||||
|
public static final int PRIVATE_FINAL_STATIC = ACC_PRIVATE | ACC_FINAL | ACC_STATIC; |
||||||
|
|
||||||
|
public static final int SWITCH_STYLE_TRIE = 0; |
||||||
|
public static final int SWITCH_STYLE_HASH = 1; |
||||||
|
public static final int SWITCH_STYLE_HASHONLY = 2; |
||||||
|
} |
@ -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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.core; |
||||||
|
|
||||||
|
public interface Converter { |
||||||
|
Object convert(Object value, Class target, Object context); |
||||||
|
} |
@ -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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.core; |
||||||
|
|
||||||
|
import com.fr.third.org.objectweb.asm.Type; |
||||||
|
|
||||||
|
/** |
||||||
|
* Customizes key types for {@link KeyFactory} when building equals, hashCode, and toString. |
||||||
|
* For customization of field types, use {@link FieldTypeCustomizer} |
||||||
|
* |
||||||
|
* @see KeyFactory#CLASS_BY_NAME |
||||||
|
*/ |
||||||
|
public interface Customizer extends KeyFactoryCustomizer { |
||||||
|
void customize(CodeEmitter e, Type type); |
||||||
|
} |
@ -0,0 +1,114 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.core; |
||||||
|
|
||||||
|
import com.fr.third.org.objectweb.asm.ClassWriter; |
||||||
|
import com.fr.third.org.objectweb.asm.ClassReader; |
||||||
|
import com.fr.third.org.objectweb.asm.ClassVisitor; |
||||||
|
import com.fr.third.org.objectweb.asm.Opcodes; |
||||||
|
|
||||||
|
import java.io.*; |
||||||
|
import java.lang.reflect.Constructor; |
||||||
|
|
||||||
|
public class DebuggingClassWriter extends ClassVisitor { |
||||||
|
|
||||||
|
public static final String DEBUG_LOCATION_PROPERTY = "cglib.debugLocation"; |
||||||
|
|
||||||
|
private static String debugLocation; |
||||||
|
private static Constructor traceCtor; |
||||||
|
|
||||||
|
private String className; |
||||||
|
private String superName; |
||||||
|
|
||||||
|
static { |
||||||
|
debugLocation = System.getProperty(DEBUG_LOCATION_PROPERTY); |
||||||
|
if (debugLocation != null) { |
||||||
|
System.err.println("CGLIB debugging enabled, writing to '" + debugLocation + "'"); |
||||||
|
try { |
||||||
|
Class clazz = Class.forName("com.fr.third.org.objectweb.asm.util.TraceClassVisitor"); |
||||||
|
traceCtor = clazz.getConstructor(new Class[]{ClassVisitor.class, PrintWriter.class}); |
||||||
|
} catch (Throwable ignore) { |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public DebuggingClassWriter(int flags) { |
||||||
|
super(Opcodes.ASM6, new ClassWriter(flags)); |
||||||
|
} |
||||||
|
|
||||||
|
public void visit(int version, |
||||||
|
int access, |
||||||
|
String name, |
||||||
|
String signature, |
||||||
|
String superName, |
||||||
|
String[] interfaces) { |
||||||
|
className = name.replace('/', '.'); |
||||||
|
this.superName = superName.replace('/', '.'); |
||||||
|
super.visit(version, access, name, signature, superName, interfaces); |
||||||
|
} |
||||||
|
|
||||||
|
public String getClassName() { |
||||||
|
return className; |
||||||
|
} |
||||||
|
|
||||||
|
public String getSuperName() { |
||||||
|
return superName; |
||||||
|
} |
||||||
|
|
||||||
|
public byte[] toByteArray() { |
||||||
|
|
||||||
|
return (byte[]) java.security.AccessController.doPrivileged( |
||||||
|
new java.security.PrivilegedAction() { |
||||||
|
public Object run() { |
||||||
|
|
||||||
|
|
||||||
|
byte[] b = ((ClassWriter) DebuggingClassWriter.super.cv).toByteArray(); |
||||||
|
if (debugLocation != null) { |
||||||
|
String dirs = className.replace('.', File.separatorChar); |
||||||
|
try { |
||||||
|
new File(debugLocation + File.separatorChar + dirs).getParentFile().mkdirs(); |
||||||
|
|
||||||
|
File file = new File(new File(debugLocation), dirs + ".class"); |
||||||
|
OutputStream out = new BufferedOutputStream(new FileOutputStream(file)); |
||||||
|
try { |
||||||
|
out.write(b); |
||||||
|
} finally { |
||||||
|
out.close(); |
||||||
|
} |
||||||
|
|
||||||
|
if (traceCtor != null) { |
||||||
|
file = new File(new File(debugLocation), dirs + ".asm"); |
||||||
|
out = new BufferedOutputStream(new FileOutputStream(file)); |
||||||
|
try { |
||||||
|
ClassReader cr = new ClassReader(b); |
||||||
|
PrintWriter pw = new PrintWriter(new OutputStreamWriter(out)); |
||||||
|
ClassVisitor tcv = (ClassVisitor)traceCtor.newInstance(new Object[]{null, pw}); |
||||||
|
cr.accept(tcv, 0); |
||||||
|
pw.flush(); |
||||||
|
} finally { |
||||||
|
out.close(); |
||||||
|
} |
||||||
|
} |
||||||
|
} catch (Exception e) { |
||||||
|
throw new CodeGenerationException(e); |
||||||
|
} |
||||||
|
} |
||||||
|
return b; |
||||||
|
} |
||||||
|
}); |
||||||
|
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,47 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.core; |
||||||
|
|
||||||
|
import com.fr.third.org.objectweb.asm.ClassWriter; |
||||||
|
|
||||||
|
public class DefaultGeneratorStrategy implements GeneratorStrategy { |
||||||
|
public static final DefaultGeneratorStrategy INSTANCE = new DefaultGeneratorStrategy(); |
||||||
|
|
||||||
|
public byte[] generate(ClassGenerator cg) throws Exception { |
||||||
|
DebuggingClassWriter cw = getClassVisitor(); |
||||||
|
transform(cg).generateClass(cw); |
||||||
|
return transform(cw.toByteArray()); |
||||||
|
} |
||||||
|
|
||||||
|
protected DebuggingClassWriter getClassVisitor() throws Exception { |
||||||
|
return new DebuggingClassWriter(ClassWriter.COMPUTE_FRAMES); |
||||||
|
} |
||||||
|
|
||||||
|
protected final ClassWriter getClassWriter() { |
||||||
|
// Cause compile / runtime errors for people who implemented the old
|
||||||
|
// interface without using @Override
|
||||||
|
throw new UnsupportedOperationException("You are calling " + |
||||||
|
"getClassWriter, which no longer exists in this cglib version."); |
||||||
|
} |
||||||
|
|
||||||
|
protected byte[] transform(byte[] b) throws Exception { |
||||||
|
return b; |
||||||
|
} |
||||||
|
|
||||||
|
protected ClassGenerator transform(ClassGenerator cg) throws Exception { |
||||||
|
return cg; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,71 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.core; |
||||||
|
|
||||||
|
import java.util.Set; |
||||||
|
|
||||||
|
/** |
||||||
|
* The default policy used by {@link AbstractClassGenerator}. |
||||||
|
* Generates names such as |
||||||
|
* <p><code>com.fr.third.net.sf.cglib.Foo$$EnhancerByCGLIB$$38272841</code><p> |
||||||
|
* 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 <code>ClassLoader</code>, 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("com.fr.third.net.sf.cglib.test.stressHashCodes"); |
||||||
|
|
||||||
|
public String getClassName(String prefix, String source, Object key, Predicate names) { |
||||||
|
if (prefix == null) { |
||||||
|
prefix = "com.fr.third.net.sf.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()); |
||||||
|
} |
||||||
|
} |
@ -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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.core; |
||||||
|
|
||||||
|
import java.lang.reflect.Method; |
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
public class DuplicatesPredicate implements Predicate { |
||||||
|
private Set unique = new HashSet(); |
||||||
|
|
||||||
|
public boolean evaluate(Object arg) { |
||||||
|
return unique.add(MethodWrapper.create((Method)arg)); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,960 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.core; |
||||||
|
|
||||||
|
import java.math.BigDecimal; |
||||||
|
import java.math.BigInteger; |
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
import com.fr.third.net.sf.cglib.core.internal.CustomizerRegistry; |
||||||
|
import com.fr.third.org.objectweb.asm.Label; |
||||||
|
import com.fr.third.org.objectweb.asm.Type; |
||||||
|
|
||||||
|
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 new Integer(((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(new Integer(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 new Integer(((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(new Integer(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()).intValue(); |
||||||
|
} |
||||||
|
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 new Integer(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(new Integer(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 <code>equals</code> 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 { |
||||||
|
List<Customizer> customizers = registry.get(Customizer.class); |
||||||
|
if (!customizers.isEmpty()) { |
||||||
|
for (Customizer customizer : customizers) { |
||||||
|
customizer.customize(e, type); |
||||||
|
} |
||||||
|
e.swap(); |
||||||
|
for (Customizer customizer : customizers) { |
||||||
|
customizer.customize(e, type); |
||||||
|
} |
||||||
|
} |
||||||
|
e.invoke_virtual(Constants.TYPE_OBJECT, EQUALS); |
||||||
|
e.if_jump(e.EQ, notEquals); |
||||||
|
} |
||||||
|
e.mark(end); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* If both objects on the top of the stack are non-null, does nothing. |
||||||
|
* If one is null, or both are null, both are popped off and execution |
||||||
|
* branches to the respective label. |
||||||
|
* @param oneNull label to branch to if only one of the objects is null |
||||||
|
* @param bothNull label to branch to if both of the objects are null |
||||||
|
*/ |
||||||
|
private static void nullcmp(CodeEmitter e, Label oneNull, Label bothNull) { |
||||||
|
e.dup2(); |
||||||
|
Label nonNull = e.make_label(); |
||||||
|
Label oneNullHelper = e.make_label(); |
||||||
|
Label end = e.make_label(); |
||||||
|
e.ifnonnull(nonNull); |
||||||
|
e.ifnonnull(oneNullHelper); |
||||||
|
e.pop2(); |
||||||
|
e.goTo(bothNull); |
||||||
|
|
||||||
|
e.mark(nonNull); |
||||||
|
e.ifnull(oneNullHelper); |
||||||
|
e.goTo(end); |
||||||
|
|
||||||
|
e.mark(oneNullHelper); |
||||||
|
e.pop2(); |
||||||
|
e.goTo(oneNull); |
||||||
|
|
||||||
|
e.mark(end); |
||||||
|
} |
||||||
|
|
||||||
|
/* |
||||||
|
public static void to_string(CodeEmitter e, |
||||||
|
Type type, |
||||||
|
ArrayDelimiters delims, |
||||||
|
CustomizerRegistry registry) { |
||||||
|
e.new_instance(Constants.TYPE_STRING_BUFFER); |
||||||
|
e.dup(); |
||||||
|
e.invoke_constructor(Constants.TYPE_STRING_BUFFER); |
||||||
|
e.swap(); |
||||||
|
append_string(e, type, delims, registry); |
||||||
|
e.invoke_virtual(Constants.TYPE_STRING_BUFFER, TO_STRING); |
||||||
|
} |
||||||
|
*/ |
||||||
|
|
||||||
|
/** |
||||||
|
* @deprecated use {@link #append_string(CodeEmitter, Type, ArrayDelimiters, CustomizerRegistry)} instead |
||||||
|
*/ |
||||||
|
@Deprecated |
||||||
|
public static void append_string(final CodeEmitter e, |
||||||
|
Type type, |
||||||
|
final ArrayDelimiters delims, |
||||||
|
final Customizer customizer) { |
||||||
|
append_string(e, type, delims, CustomizerRegistry.singleton(customizer)); |
||||||
|
} |
||||||
|
|
||||||
|
public static void append_string(final CodeEmitter e, |
||||||
|
Type type, |
||||||
|
final ArrayDelimiters delims, |
||||||
|
final CustomizerRegistry registry) { |
||||||
|
final ArrayDelimiters d = (delims != null) ? delims : DEFAULT_DELIMITERS; |
||||||
|
ProcessArrayCallback callback = new ProcessArrayCallback() { |
||||||
|
public void processElement(Type type) { |
||||||
|
append_string_helper(e, type, d, registry, this); |
||||||
|
e.push(d.inside); |
||||||
|
e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_STRING); |
||||||
|
} |
||||||
|
}; |
||||||
|
append_string_helper(e, type, d, registry, callback); |
||||||
|
} |
||||||
|
|
||||||
|
private static void append_string_helper(CodeEmitter e, |
||||||
|
Type type, |
||||||
|
ArrayDelimiters delims, |
||||||
|
CustomizerRegistry registry, |
||||||
|
ProcessArrayCallback callback) { |
||||||
|
Label skip = e.make_label(); |
||||||
|
Label end = e.make_label(); |
||||||
|
if (TypeUtils.isPrimitive(type)) { |
||||||
|
switch (type.getSort()) { |
||||||
|
case Type.INT: |
||||||
|
case Type.SHORT: |
||||||
|
case Type.BYTE: |
||||||
|
e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_INT); |
||||||
|
break; |
||||||
|
case Type.DOUBLE: |
||||||
|
e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_DOUBLE); |
||||||
|
break; |
||||||
|
case Type.FLOAT: |
||||||
|
e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_FLOAT); |
||||||
|
break; |
||||||
|
case Type.LONG: |
||||||
|
e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_LONG); |
||||||
|
break; |
||||||
|
case Type.BOOLEAN: |
||||||
|
e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_BOOLEAN); |
||||||
|
break; |
||||||
|
case Type.CHAR: |
||||||
|
e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_CHAR); |
||||||
|
break; |
||||||
|
} |
||||||
|
} else if (TypeUtils.isArray(type)) { |
||||||
|
e.dup(); |
||||||
|
e.ifnull(skip); |
||||||
|
e.swap(); |
||||||
|
if (delims != null && delims.before != null && !"".equals(delims.before)) { |
||||||
|
e.push(delims.before); |
||||||
|
e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_STRING); |
||||||
|
e.swap(); |
||||||
|
} |
||||||
|
EmitUtils.process_array(e, type, callback); |
||||||
|
shrinkStringBuffer(e, 2); |
||||||
|
if (delims != null && delims.after != null && !"".equals(delims.after)) { |
||||||
|
e.push(delims.after); |
||||||
|
e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_STRING); |
||||||
|
} |
||||||
|
} else { |
||||||
|
e.dup(); |
||||||
|
e.ifnull(skip); |
||||||
|
for (Customizer customizer : registry.get(Customizer.class)) { |
||||||
|
customizer.customize(e, type); |
||||||
|
} |
||||||
|
e.invoke_virtual(Constants.TYPE_OBJECT, TO_STRING); |
||||||
|
e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_STRING); |
||||||
|
} |
||||||
|
e.goTo(end); |
||||||
|
e.mark(skip); |
||||||
|
e.pop(); |
||||||
|
e.push("null"); |
||||||
|
e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_STRING); |
||||||
|
e.mark(end); |
||||||
|
} |
||||||
|
|
||||||
|
private static void shrinkStringBuffer(CodeEmitter e, int amt) { |
||||||
|
e.dup(); |
||||||
|
e.dup(); |
||||||
|
e.invoke_virtual(Constants.TYPE_STRING_BUFFER, LENGTH); |
||||||
|
e.push(amt); |
||||||
|
e.math(e.SUB, Type.INT_TYPE); |
||||||
|
e.invoke_virtual(Constants.TYPE_STRING_BUFFER, SET_LENGTH); |
||||||
|
} |
||||||
|
|
||||||
|
public static class ArrayDelimiters { |
||||||
|
private String before; |
||||||
|
private String inside; |
||||||
|
private String after; |
||||||
|
|
||||||
|
public ArrayDelimiters(String before, String inside, String after) { |
||||||
|
this.before = before; |
||||||
|
this.inside = inside; |
||||||
|
this.after = after; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static void load_method(CodeEmitter e, MethodInfo method) { |
||||||
|
load_class(e, method.getClassInfo().getType()); |
||||||
|
e.push(method.getSignature().getName()); |
||||||
|
push_object(e, method.getSignature().getArgumentTypes()); |
||||||
|
e.invoke_virtual(Constants.TYPE_CLASS, GET_DECLARED_METHOD); |
||||||
|
} |
||||||
|
|
||||||
|
private interface ParameterTyper { |
||||||
|
Type[] getParameterTypes(MethodInfo member); |
||||||
|
} |
||||||
|
|
||||||
|
public static void method_switch(CodeEmitter e, |
||||||
|
List methods, |
||||||
|
ObjectSwitchCallback callback) { |
||||||
|
member_switch_helper(e, methods, callback, true); |
||||||
|
} |
||||||
|
|
||||||
|
public static void constructor_switch(CodeEmitter e, |
||||||
|
List constructors, |
||||||
|
ObjectSwitchCallback callback) { |
||||||
|
member_switch_helper(e, constructors, callback, false); |
||||||
|
} |
||||||
|
|
||||||
|
private static void member_switch_helper(final CodeEmitter e, |
||||||
|
List members, |
||||||
|
final ObjectSwitchCallback callback, |
||||||
|
boolean useName) { |
||||||
|
try { |
||||||
|
final Map cache = new HashMap(); |
||||||
|
final ParameterTyper cached = new ParameterTyper() { |
||||||
|
public Type[] getParameterTypes(MethodInfo member) { |
||||||
|
Type[] types = (Type[])cache.get(member); |
||||||
|
if (types == null) { |
||||||
|
cache.put(member, types = member.getSignature().getArgumentTypes()); |
||||||
|
} |
||||||
|
return types; |
||||||
|
} |
||||||
|
}; |
||||||
|
final Label def = e.make_label(); |
||||||
|
final Label end = e.make_label(); |
||||||
|
if (useName) { |
||||||
|
e.swap(); |
||||||
|
final Map buckets = CollectionUtils.bucket(members, new Transformer() { |
||||||
|
public Object transform(Object value) { |
||||||
|
return ((MethodInfo)value).getSignature().getName(); |
||||||
|
} |
||||||
|
}); |
||||||
|
String[] names = (String[])buckets.keySet().toArray(new String[buckets.size()]); |
||||||
|
EmitUtils.string_switch(e, names, Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() { |
||||||
|
public void processCase(Object key, Label dontUseEnd) throws Exception { |
||||||
|
member_helper_size(e, (List)buckets.get(key), callback, cached, def, end); |
||||||
|
} |
||||||
|
public void processDefault() throws Exception { |
||||||
|
e.goTo(def); |
||||||
|
} |
||||||
|
}); |
||||||
|
} else { |
||||||
|
member_helper_size(e, members, callback, cached, def, end); |
||||||
|
} |
||||||
|
e.mark(def); |
||||||
|
e.pop(); |
||||||
|
callback.processDefault(); |
||||||
|
e.mark(end); |
||||||
|
} catch (RuntimeException ex) { |
||||||
|
throw ex; |
||||||
|
} catch (Error ex) { |
||||||
|
throw ex; |
||||||
|
} catch (Exception ex) { |
||||||
|
throw new CodeGenerationException(ex); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static void member_helper_size(final CodeEmitter e, |
||||||
|
List members, |
||||||
|
final ObjectSwitchCallback callback, |
||||||
|
final ParameterTyper typer, |
||||||
|
final Label def, |
||||||
|
final Label end) throws Exception { |
||||||
|
final Map buckets = CollectionUtils.bucket(members, new Transformer() { |
||||||
|
public Object transform(Object value) { |
||||||
|
return new Integer(typer.getParameterTypes((MethodInfo)value).length); |
||||||
|
} |
||||||
|
}); |
||||||
|
e.dup(); |
||||||
|
e.arraylength(); |
||||||
|
e.process_switch(EmitUtils.getSwitchKeys(buckets), new ProcessSwitchCallback() { |
||||||
|
public void processCase(int key, Label dontUseEnd) throws Exception { |
||||||
|
List bucket = (List)buckets.get(new Integer(key)); |
||||||
|
member_helper_type(e, bucket, callback, typer, def, end, new BitSet()); |
||||||
|
} |
||||||
|
public void processDefault() throws Exception { |
||||||
|
e.goTo(def); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
private static void member_helper_type(final CodeEmitter e, |
||||||
|
List members, |
||||||
|
final ObjectSwitchCallback callback, |
||||||
|
final ParameterTyper typer, |
||||||
|
final Label def, |
||||||
|
final Label end, |
||||||
|
final BitSet checked) throws Exception { |
||||||
|
if (members.size() == 1) { |
||||||
|
MethodInfo member = (MethodInfo)members.get(0); |
||||||
|
Type[] types = typer.getParameterTypes(member); |
||||||
|
// need to check classes that have not already been checked via switches
|
||||||
|
for (int i = 0; i < types.length; i++) { |
||||||
|
if (checked == null || !checked.get(i)) { |
||||||
|
e.dup(); |
||||||
|
e.aaload(i); |
||||||
|
e.invoke_virtual(Constants.TYPE_CLASS, GET_NAME); |
||||||
|
e.push(TypeUtils.emulateClassGetName(types[i])); |
||||||
|
e.invoke_virtual(Constants.TYPE_OBJECT, EQUALS); |
||||||
|
e.if_jump(e.EQ, def); |
||||||
|
} |
||||||
|
} |
||||||
|
e.pop(); |
||||||
|
callback.processCase(member, end); |
||||||
|
} else { |
||||||
|
// choose the index that has the best chance of uniquely identifying member
|
||||||
|
Type[] example = typer.getParameterTypes((MethodInfo)members.get(0)); |
||||||
|
Map buckets = null; |
||||||
|
int index = -1; |
||||||
|
for (int i = 0; i < example.length; i++) { |
||||||
|
final int j = i; |
||||||
|
Map test = CollectionUtils.bucket(members, new Transformer() { |
||||||
|
public Object transform(Object value) { |
||||||
|
return TypeUtils.emulateClassGetName(typer.getParameterTypes((MethodInfo)value)[j]); |
||||||
|
} |
||||||
|
}); |
||||||
|
if (buckets == null || test.size() > buckets.size()) { |
||||||
|
buckets = test; |
||||||
|
index = i; |
||||||
|
} |
||||||
|
} |
||||||
|
if (buckets == null || buckets.size() == 1) { |
||||||
|
// TODO: switch by returnType
|
||||||
|
// must have two methods with same name, types, and different return types
|
||||||
|
e.goTo(def); |
||||||
|
} else { |
||||||
|
checked.set(index); |
||||||
|
|
||||||
|
e.dup(); |
||||||
|
e.aaload(index); |
||||||
|
e.invoke_virtual(Constants.TYPE_CLASS, GET_NAME); |
||||||
|
|
||||||
|
final Map fbuckets = buckets; |
||||||
|
String[] names = (String[])buckets.keySet().toArray(new String[buckets.size()]); |
||||||
|
EmitUtils.string_switch(e, names, Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() { |
||||||
|
public void processCase(Object key, Label dontUseEnd) throws Exception { |
||||||
|
member_helper_type(e, (List)fbuckets.get(key), callback, typer, def, end, checked); |
||||||
|
} |
||||||
|
public void processDefault() throws Exception { |
||||||
|
e.goTo(def); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static void wrap_throwable(Block block, Type wrapper) { |
||||||
|
CodeEmitter e = block.getCodeEmitter(); |
||||||
|
e.catch_exception(block, Constants.TYPE_THROWABLE); |
||||||
|
e.new_instance(wrapper); |
||||||
|
e.dup_x1(); |
||||||
|
e.swap(); |
||||||
|
e.invoke_constructor(wrapper, CSTRUCT_THROWABLE); |
||||||
|
e.athrow(); |
||||||
|
} |
||||||
|
|
||||||
|
public static void add_properties(ClassEmitter ce, String[] names, Type[] types) { |
||||||
|
for (int i = 0; i < names.length; i++) { |
||||||
|
String fieldName = "$cglib_prop_" + names[i]; |
||||||
|
ce.declare_field(Constants.ACC_PRIVATE, fieldName, types[i], null); |
||||||
|
EmitUtils.add_property(ce, names[i], types[i], fieldName); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static void add_property(ClassEmitter ce, String name, Type type, String fieldName) { |
||||||
|
String property = TypeUtils.upperFirst(name); |
||||||
|
CodeEmitter e; |
||||||
|
e = ce.begin_method(Constants.ACC_PUBLIC, |
||||||
|
new Signature("get" + property, |
||||||
|
type, |
||||||
|
Constants.TYPES_EMPTY), |
||||||
|
null); |
||||||
|
e.load_this(); |
||||||
|
e.getfield(fieldName); |
||||||
|
e.return_value(); |
||||||
|
e.end_method(); |
||||||
|
|
||||||
|
e = ce.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(fieldName); |
||||||
|
e.return_value(); |
||||||
|
e.end_method(); |
||||||
|
} |
||||||
|
|
||||||
|
/* generates: |
||||||
|
} catch (RuntimeException e) { |
||||||
|
throw e; |
||||||
|
} catch (Error e) { |
||||||
|
throw e; |
||||||
|
} catch (<DeclaredException> e) { |
||||||
|
throw e; |
||||||
|
} catch (Throwable e) { |
||||||
|
throw new <Wrapper>(e); |
||||||
|
} |
||||||
|
*/ |
||||||
|
public static void wrap_undeclared_throwable(CodeEmitter e, Block handler, Type[] exceptions, Type wrapper) { |
||||||
|
Set set = (exceptions == null) ? Collections.EMPTY_SET : new HashSet(Arrays.asList(exceptions)); |
||||||
|
|
||||||
|
if (set.contains(Constants.TYPE_THROWABLE)) |
||||||
|
return; |
||||||
|
|
||||||
|
boolean needThrow = exceptions != null; |
||||||
|
if (!set.contains(Constants.TYPE_RUNTIME_EXCEPTION)) { |
||||||
|
e.catch_exception(handler, Constants.TYPE_RUNTIME_EXCEPTION); |
||||||
|
needThrow = true; |
||||||
|
} |
||||||
|
if (!set.contains(Constants.TYPE_ERROR)) { |
||||||
|
e.catch_exception(handler, Constants.TYPE_ERROR); |
||||||
|
needThrow = true; |
||||||
|
} |
||||||
|
if (exceptions != null) { |
||||||
|
for (int i = 0; i < exceptions.length; i++) { |
||||||
|
e.catch_exception(handler, exceptions[i]); |
||||||
|
} |
||||||
|
} |
||||||
|
if (needThrow) { |
||||||
|
e.athrow(); |
||||||
|
} |
||||||
|
// e -> eo -> oeo -> ooe -> o
|
||||||
|
e.catch_exception(handler, Constants.TYPE_THROWABLE); |
||||||
|
e.new_instance(wrapper); |
||||||
|
e.dup_x1(); |
||||||
|
e.swap(); |
||||||
|
e.invoke_constructor(wrapper, CSTRUCT_THROWABLE); |
||||||
|
e.athrow(); |
||||||
|
} |
||||||
|
|
||||||
|
public static CodeEmitter begin_method(ClassEmitter e, MethodInfo method) { |
||||||
|
return begin_method(e, method, method.getModifiers()); |
||||||
|
} |
||||||
|
|
||||||
|
public static CodeEmitter begin_method(ClassEmitter e, MethodInfo method, int access) { |
||||||
|
return e.begin_method(access, |
||||||
|
method.getSignature(), |
||||||
|
method.getExceptionTypes()); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,23 @@ |
|||||||
|
package com.fr.third.net.sf.cglib.core; |
||||||
|
|
||||||
|
import com.fr.third.org.objectweb.asm.Type; |
||||||
|
|
||||||
|
/** |
||||||
|
* Customizes key types for {@link KeyFactory} right in constructor. |
||||||
|
*/ |
||||||
|
public interface FieldTypeCustomizer extends KeyFactoryCustomizer { |
||||||
|
/** |
||||||
|
* Customizes {@code this.FIELD_0 = ?} assignment in key constructor |
||||||
|
* @param e code emitter |
||||||
|
* @param index parameter index |
||||||
|
* @param type parameter type |
||||||
|
*/ |
||||||
|
void customize(CodeEmitter e, int index, Type type); |
||||||
|
|
||||||
|
/** |
||||||
|
* Computes type of field for storing given parameter |
||||||
|
* @param index parameter index |
||||||
|
* @param type parameter type |
||||||
|
*/ |
||||||
|
Type getOutType(int index, Type type); |
||||||
|
} |
@ -0,0 +1,44 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.core; |
||||||
|
|
||||||
|
/** |
||||||
|
* The <code>GeneratorStrategy</code. is responsible for taking a |
||||||
|
* {@link ClassGenerator} and producing a byte array containing the |
||||||
|
* data for the generated <code>Class</code>. 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 <code>GeneratorStrategy</code> 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 <code>equals</code> and <code>hashCode</code> |
||||||
|
* to avoid generating too many classes. |
||||||
|
*/ |
||||||
|
boolean equals(Object o); |
||||||
|
} |
@ -0,0 +1,12 @@ |
|||||||
|
package com.fr.third.net.sf.cglib.core; |
||||||
|
|
||||||
|
import com.fr.third.org.objectweb.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); |
||||||
|
} |
@ -0,0 +1,346 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.core; |
||||||
|
|
||||||
|
import com.fr.third.net.sf.cglib.core.internal.CustomizerRegistry; |
||||||
|
import com.fr.third.org.objectweb.asm.ClassVisitor; |
||||||
|
import com.fr.third.org.objectweb.asm.Label; |
||||||
|
import com.fr.third.org.objectweb.asm.Type; |
||||||
|
|
||||||
|
import java.lang.reflect.Method; |
||||||
|
import java.security.ProtectionDomain; |
||||||
|
import java.util.Collections; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* Generates classes to handle multi-valued keys, for use in things such as Maps and Sets. |
||||||
|
* Code for <code>equals</code> and <code>hashCode</code> methods follow the |
||||||
|
* the rules laid out in <i>Effective Java</i> by Joshua Bloch. |
||||||
|
* <p> |
||||||
|
* To generate a <code>KeyFactory</code>, you need to supply an interface which |
||||||
|
* describes the structure of the key. The interface should have a |
||||||
|
* single method named <code>newInstance</code>, which returns an |
||||||
|
* <code>Object</code>. The arguments array can be |
||||||
|
* <i>anything</i>--Objects, primitive values, or single or |
||||||
|
* multi-dimension arrays of either. For example: |
||||||
|
* <p><pre> |
||||||
|
* private interface IntStringKey { |
||||||
|
* public Object newInstance(int i, String s); |
||||||
|
* } |
||||||
|
* </pre><p> |
||||||
|
* Once you have made a <code>KeyFactory</code>, you generate a new key by calling |
||||||
|
* the <code>newInstance</code> method defined by your interface. |
||||||
|
* <p><pre> |
||||||
|
* IntStringKey factory = (IntStringKey)KeyFactory.create(IntStringKey.class); |
||||||
|
* Object key1 = factory.newInstance(4, "Hello"); |
||||||
|
* Object key2 = factory.newInstance(4, "World"); |
||||||
|
* </pre><p> |
||||||
|
* <b>Note:</b> |
||||||
|
* <code>hashCode</code> equality between two keys <code>key1</code> and <code>key2</code> is only guaranteed if |
||||||
|
* <code>key1.equals(key2)</code> <i>and</i> the keys were produced by the same factory. |
||||||
|
* |
||||||
|
* @version $Id: KeyFactory.java,v 1.26 2006/03/05 02:43:19 herbyderby Exp $ |
||||||
|
*/ |
||||||
|
abstract public class KeyFactory { |
||||||
|
private static final Signature GET_NAME = |
||||||
|
TypeUtils.parseSignature("String getName()"); |
||||||
|
private static final Signature GET_CLASS = |
||||||
|
TypeUtils.parseSignature("Class getClass()"); |
||||||
|
private static final Signature HASH_CODE = |
||||||
|
TypeUtils.parseSignature("int hashCode()"); |
||||||
|
private static final Signature EQUALS = |
||||||
|
TypeUtils.parseSignature("boolean equals(Object)"); |
||||||
|
private static final Signature TO_STRING = |
||||||
|
TypeUtils.parseSignature("String toString()"); |
||||||
|
private static final Signature APPEND_STRING = |
||||||
|
TypeUtils.parseSignature("StringBuffer append(String)"); |
||||||
|
private static final Type KEY_FACTORY = |
||||||
|
TypeUtils.parseType("com.fr.third.net.sf.cglib.core.KeyFactory"); |
||||||
|
private static final Signature GET_SORT = |
||||||
|
TypeUtils.parseSignature("int getSort()"); |
||||||
|
|
||||||
|
//generated numbers:
|
||||||
|
private final static int PRIMES[] = { |
||||||
|
11, 73, 179, 331, |
||||||
|
521, 787, 1213, 1823, |
||||||
|
2609, 3691, 5189, 7247, |
||||||
|
10037, 13931, 19289, 26627, |
||||||
|
36683, 50441, 69403, 95401, |
||||||
|
131129, 180179, 247501, 340057, |
||||||
|
467063, 641371, 880603, 1209107, |
||||||
|
1660097, 2279161, 3129011, 4295723, |
||||||
|
5897291, 8095873, 11114263, 15257791, |
||||||
|
20946017, 28754629, 39474179, 54189869, |
||||||
|
74391461, 102123817, 140194277, 192456917, |
||||||
|
264202273, 362693231, 497900099, 683510293, |
||||||
|
938313161, 1288102441, 1768288259 }; |
||||||
|
|
||||||
|
|
||||||
|
public static final Customizer CLASS_BY_NAME = new Customizer() { |
||||||
|
public void customize(CodeEmitter e, Type type) { |
||||||
|
if (type.equals(Constants.TYPE_CLASS)) { |
||||||
|
e.invoke_virtual(Constants.TYPE_CLASS, GET_NAME); |
||||||
|
} |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
public static final FieldTypeCustomizer STORE_CLASS_AS_STRING = new FieldTypeCustomizer() { |
||||||
|
public void customize(CodeEmitter e, int index, Type type) { |
||||||
|
if (type.equals(Constants.TYPE_CLASS)) { |
||||||
|
e.invoke_virtual(Constants.TYPE_CLASS, GET_NAME); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public Type getOutType(int index, Type type) { |
||||||
|
if (type.equals(Constants.TYPE_CLASS)) { |
||||||
|
return Constants.TYPE_STRING; |
||||||
|
} |
||||||
|
return type; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
/** |
||||||
|
* {@link Type#hashCode()} is very expensive as it traverses full descriptor to calculate hash code. |
||||||
|
* This customizer uses {@link Type#getSort()} as a hash code. |
||||||
|
*/ |
||||||
|
public static final HashCodeCustomizer HASH_ASM_TYPE = new HashCodeCustomizer() { |
||||||
|
public boolean customize(CodeEmitter e, Type type) { |
||||||
|
if (Constants.TYPE_TYPE.equals(type)) { |
||||||
|
e.invoke_virtual(type, GET_SORT); |
||||||
|
return true; |
||||||
|
} |
||||||
|
return false; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
/** |
||||||
|
* @deprecated this customizer might result in unexpected class leak since key object still holds a strong reference to the Object and class. |
||||||
|
* It is recommended to have pre-processing method that would strip Objects and represent Classes as Strings |
||||||
|
*/ |
||||||
|
@Deprecated |
||||||
|
public static final Customizer OBJECT_BY_CLASS = new Customizer() { |
||||||
|
public void customize(CodeEmitter e, Type type) { |
||||||
|
e.invoke_virtual(Constants.TYPE_OBJECT, GET_CLASS); |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
protected KeyFactory() { |
||||||
|
} |
||||||
|
|
||||||
|
public static KeyFactory create(Class keyInterface) { |
||||||
|
return create(keyInterface, null); |
||||||
|
} |
||||||
|
|
||||||
|
public static KeyFactory create(Class keyInterface, Customizer customizer) { |
||||||
|
return create(keyInterface.getClassLoader(), keyInterface, customizer); |
||||||
|
} |
||||||
|
|
||||||
|
public static KeyFactory create(Class keyInterface, KeyFactoryCustomizer first, List<KeyFactoryCustomizer> next) { |
||||||
|
return create(keyInterface.getClassLoader(), keyInterface, first, next); |
||||||
|
} |
||||||
|
|
||||||
|
public static KeyFactory create(ClassLoader loader, Class keyInterface, Customizer customizer) { |
||||||
|
return create(loader, keyInterface, customizer, Collections.<KeyFactoryCustomizer>emptyList()); |
||||||
|
} |
||||||
|
|
||||||
|
public static KeyFactory create(ClassLoader loader, Class keyInterface, KeyFactoryCustomizer customizer, |
||||||
|
List<KeyFactoryCustomizer> next) { |
||||||
|
Generator gen = new Generator(); |
||||||
|
gen.setInterface(keyInterface); |
||||||
|
|
||||||
|
if (customizer != null) { |
||||||
|
gen.addCustomizer(customizer); |
||||||
|
} |
||||||
|
if (next != null && !next.isEmpty()) { |
||||||
|
for (KeyFactoryCustomizer keyFactoryCustomizer : next) { |
||||||
|
gen.addCustomizer(keyFactoryCustomizer); |
||||||
|
} |
||||||
|
} |
||||||
|
gen.setClassLoader(loader); |
||||||
|
return gen.create(); |
||||||
|
} |
||||||
|
|
||||||
|
public static class Generator extends AbstractClassGenerator { |
||||||
|
private static final Source SOURCE = new Source(KeyFactory.class.getName()); |
||||||
|
private static final Class[] KNOWN_CUSTOMIZER_TYPES = new Class[]{Customizer.class, FieldTypeCustomizer.class}; |
||||||
|
|
||||||
|
private Class keyInterface; |
||||||
|
// TODO: Make me final when deprecated methods are removed
|
||||||
|
private CustomizerRegistry customizers = new CustomizerRegistry(KNOWN_CUSTOMIZER_TYPES); |
||||||
|
private int constant; |
||||||
|
private int multiplier; |
||||||
|
|
||||||
|
public Generator() { |
||||||
|
super(SOURCE); |
||||||
|
} |
||||||
|
|
||||||
|
protected ClassLoader getDefaultClassLoader() { |
||||||
|
return keyInterface.getClassLoader(); |
||||||
|
} |
||||||
|
|
||||||
|
protected ProtectionDomain getProtectionDomain() { |
||||||
|
return ReflectUtils.getProtectionDomain(keyInterface); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @deprecated Use {@link #addCustomizer(KeyFactoryCustomizer)} instead. |
||||||
|
*/ |
||||||
|
@Deprecated |
||||||
|
public void setCustomizer(Customizer customizer) { |
||||||
|
customizers = CustomizerRegistry.singleton(customizer); |
||||||
|
} |
||||||
|
|
||||||
|
public void addCustomizer(KeyFactoryCustomizer customizer) { |
||||||
|
customizers.add(customizer); |
||||||
|
} |
||||||
|
|
||||||
|
public <T> List<T> getCustomizers(Class<T> klass) { |
||||||
|
return customizers.get(klass); |
||||||
|
} |
||||||
|
|
||||||
|
public void setInterface(Class keyInterface) { |
||||||
|
this.keyInterface = keyInterface; |
||||||
|
} |
||||||
|
|
||||||
|
public KeyFactory create() { |
||||||
|
setNamePrefix(keyInterface.getName()); |
||||||
|
return (KeyFactory)super.create(keyInterface.getName()); |
||||||
|
} |
||||||
|
|
||||||
|
public void setHashConstant(int constant) { |
||||||
|
this.constant = constant; |
||||||
|
} |
||||||
|
|
||||||
|
public void setHashMultiplier(int multiplier) { |
||||||
|
this.multiplier = multiplier; |
||||||
|
} |
||||||
|
|
||||||
|
protected Object firstInstance(Class type) { |
||||||
|
return ReflectUtils.newInstance(type); |
||||||
|
} |
||||||
|
|
||||||
|
protected Object nextInstance(Object instance) { |
||||||
|
return instance; |
||||||
|
} |
||||||
|
|
||||||
|
public void generateClass(ClassVisitor v) { |
||||||
|
ClassEmitter ce = new ClassEmitter(v); |
||||||
|
|
||||||
|
Method newInstance = ReflectUtils.findNewInstance(keyInterface); |
||||||
|
if (!newInstance.getReturnType().equals(Object.class)) { |
||||||
|
throw new IllegalArgumentException("newInstance method must return Object"); |
||||||
|
} |
||||||
|
|
||||||
|
Type[] parameterTypes = TypeUtils.getTypes(newInstance.getParameterTypes()); |
||||||
|
ce.begin_class(Constants.V1_2, |
||||||
|
Constants.ACC_PUBLIC, |
||||||
|
getClassName(), |
||||||
|
KEY_FACTORY, |
||||||
|
new Type[]{ Type.getType(keyInterface) }, |
||||||
|
Constants.SOURCE_FILE); |
||||||
|
EmitUtils.null_constructor(ce); |
||||||
|
EmitUtils.factory_method(ce, ReflectUtils.getSignature(newInstance)); |
||||||
|
|
||||||
|
int seed = 0; |
||||||
|
CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, |
||||||
|
TypeUtils.parseConstructor(parameterTypes), |
||||||
|
null); |
||||||
|
e.load_this(); |
||||||
|
e.super_invoke_constructor(); |
||||||
|
e.load_this(); |
||||||
|
List<FieldTypeCustomizer> fieldTypeCustomizers = getCustomizers(FieldTypeCustomizer.class); |
||||||
|
for (int i = 0; i < parameterTypes.length; i++) { |
||||||
|
Type parameterType = parameterTypes[i]; |
||||||
|
Type fieldType = parameterType; |
||||||
|
for (FieldTypeCustomizer customizer : fieldTypeCustomizers) { |
||||||
|
fieldType = customizer.getOutType(i, fieldType); |
||||||
|
} |
||||||
|
seed += fieldType.hashCode(); |
||||||
|
ce.declare_field(Constants.ACC_PRIVATE | Constants.ACC_FINAL, |
||||||
|
getFieldName(i), |
||||||
|
fieldType, |
||||||
|
null); |
||||||
|
e.dup(); |
||||||
|
e.load_arg(i); |
||||||
|
for (FieldTypeCustomizer customizer : fieldTypeCustomizers) { |
||||||
|
customizer.customize(e, i, parameterType); |
||||||
|
} |
||||||
|
e.putfield(getFieldName(i)); |
||||||
|
} |
||||||
|
e.return_value(); |
||||||
|
e.end_method(); |
||||||
|
|
||||||
|
// hash code
|
||||||
|
e = ce.begin_method(Constants.ACC_PUBLIC, HASH_CODE, null); |
||||||
|
int hc = (constant != 0) ? constant : PRIMES[(int)(Math.abs(seed) % PRIMES.length)]; |
||||||
|
int hm = (multiplier != 0) ? multiplier : PRIMES[(int)(Math.abs(seed * 13) % PRIMES.length)]; |
||||||
|
e.push(hc); |
||||||
|
for (int i = 0; i < parameterTypes.length; i++) { |
||||||
|
e.load_this(); |
||||||
|
e.getfield(getFieldName(i)); |
||||||
|
EmitUtils.hash_code(e, parameterTypes[i], hm, customizers); |
||||||
|
} |
||||||
|
e.return_value(); |
||||||
|
e.end_method(); |
||||||
|
|
||||||
|
// equals
|
||||||
|
e = ce.begin_method(Constants.ACC_PUBLIC, EQUALS, null); |
||||||
|
Label fail = e.make_label(); |
||||||
|
e.load_arg(0); |
||||||
|
e.instance_of_this(); |
||||||
|
e.if_jump(e.EQ, fail); |
||||||
|
for (int i = 0; i < parameterTypes.length; i++) { |
||||||
|
e.load_this(); |
||||||
|
e.getfield(getFieldName(i)); |
||||||
|
e.load_arg(0); |
||||||
|
e.checkcast_this(); |
||||||
|
e.getfield(getFieldName(i)); |
||||||
|
EmitUtils.not_equals(e, parameterTypes[i], fail, customizers); |
||||||
|
} |
||||||
|
e.push(1); |
||||||
|
e.return_value(); |
||||||
|
e.mark(fail); |
||||||
|
e.push(0); |
||||||
|
e.return_value(); |
||||||
|
e.end_method(); |
||||||
|
|
||||||
|
// toString
|
||||||
|
e = ce.begin_method(Constants.ACC_PUBLIC, TO_STRING, null); |
||||||
|
e.new_instance(Constants.TYPE_STRING_BUFFER); |
||||||
|
e.dup(); |
||||||
|
e.invoke_constructor(Constants.TYPE_STRING_BUFFER); |
||||||
|
for (int i = 0; i < parameterTypes.length; i++) { |
||||||
|
if (i > 0) { |
||||||
|
e.push(", "); |
||||||
|
e.invoke_virtual(Constants.TYPE_STRING_BUFFER, APPEND_STRING); |
||||||
|
} |
||||||
|
e.load_this(); |
||||||
|
e.getfield(getFieldName(i)); |
||||||
|
EmitUtils.append_string(e, parameterTypes[i], EmitUtils.DEFAULT_DELIMITERS, customizers); |
||||||
|
} |
||||||
|
e.invoke_virtual(Constants.TYPE_STRING_BUFFER, TO_STRING); |
||||||
|
e.return_value(); |
||||||
|
e.end_method(); |
||||||
|
|
||||||
|
ce.end_class(); |
||||||
|
} |
||||||
|
|
||||||
|
private String getFieldName(int arg) { |
||||||
|
return "FIELD_" + arg; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,7 @@ |
|||||||
|
package com.fr.third.net.sf.cglib.core; |
||||||
|
|
||||||
|
/** |
||||||
|
* Marker interface for customizers of {@link KeyFactory} |
||||||
|
*/ |
||||||
|
public interface KeyFactoryCustomizer { |
||||||
|
} |
@ -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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.core; |
||||||
|
|
||||||
|
import com.fr.third.org.objectweb.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; |
||||||
|
} |
||||||
|
} |
@ -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 com.fr.third.net.sf.cglib.core; |
||||||
|
|
||||||
|
import com.fr.third.org.objectweb.asm.Label; |
||||||
|
import com.fr.third.org.objectweb.asm.MethodVisitor; |
||||||
|
import com.fr.third.org.objectweb.asm.Opcodes; |
||||||
|
import com.fr.third.org.objectweb.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(Opcodes.ASM6, 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(Opcodes.ASM6, 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; |
||||||
|
} |
||||||
|
} |
@ -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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.core; |
||||||
|
|
||||||
|
import com.fr.third.org.objectweb.asm.Attribute; |
||||||
|
import com.fr.third.org.objectweb.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(); |
||||||
|
} |
||||||
|
} |
@ -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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.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); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,46 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.core; |
||||||
|
|
||||||
|
import java.lang.reflect.Method; |
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
public class MethodWrapper { |
||||||
|
private static final MethodWrapperKey KEY_FACTORY = |
||||||
|
(MethodWrapperKey)KeyFactory.create(MethodWrapperKey.class); |
||||||
|
|
||||||
|
/** Internal interface, only public due to ClassLoader issues. */ |
||||||
|
public interface MethodWrapperKey { |
||||||
|
public Object newInstance(String name, String[] parameterTypes, String returnType); |
||||||
|
} |
||||||
|
|
||||||
|
private MethodWrapper() { |
||||||
|
} |
||||||
|
|
||||||
|
public static Object create(Method method) { |
||||||
|
return KEY_FACTORY.newInstance(method.getName(), |
||||||
|
ReflectUtils.getNames(method.getParameterTypes()), |
||||||
|
method.getReturnType().getName()); |
||||||
|
} |
||||||
|
|
||||||
|
public static Set createSet(Collection methods) { |
||||||
|
Set set = new HashSet(); |
||||||
|
for (Iterator it = methods.iterator(); it.hasNext();) { |
||||||
|
set.add(create((Method)it.next())); |
||||||
|
} |
||||||
|
return set; |
||||||
|
} |
||||||
|
} |
@ -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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.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 "com.fr.third.net.sf.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 <code>key.hashCode()</code> 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 <code>NamingPolicy</code> 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 <code>equals</code> and <code>hashCode</code> |
||||||
|
* to avoid generating too many classes. |
||||||
|
*/ |
||||||
|
boolean equals(Object o); |
||||||
|
} |
@ -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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.core; |
||||||
|
|
||||||
|
import com.fr.third.org.objectweb.asm.Label; |
||||||
|
|
||||||
|
public interface ObjectSwitchCallback { |
||||||
|
void processCase(Object key, Label end) throws Exception; |
||||||
|
void processDefault() throws Exception; |
||||||
|
} |
||||||
|
|
@ -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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.core; |
||||||
|
|
||||||
|
public interface Predicate { |
||||||
|
boolean evaluate(Object arg); |
||||||
|
} |
||||||
|
|
@ -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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.core; |
||||||
|
|
||||||
|
import com.fr.third.org.objectweb.asm.Type; |
||||||
|
|
||||||
|
public interface ProcessArrayCallback { |
||||||
|
void processElement(Type type); |
||||||
|
} |
@ -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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.core; |
||||||
|
|
||||||
|
import com.fr.third.org.objectweb.asm.Label; |
||||||
|
|
||||||
|
public interface ProcessSwitchCallback { |
||||||
|
void processCase(int key, Label end) throws Exception; |
||||||
|
void processDefault() throws Exception; |
||||||
|
} |
@ -0,0 +1,544 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.core; |
||||||
|
|
||||||
|
import java.beans.*; |
||||||
|
import java.lang.reflect.*; |
||||||
|
import java.security.AccessController; |
||||||
|
import java.security.PrivilegedAction; |
||||||
|
import java.security.PrivilegedExceptionAction; |
||||||
|
import java.security.ProtectionDomain; |
||||||
|
import java.util.*; |
||||||
|
import com.fr.third.org.objectweb.asm.Attribute; |
||||||
|
import com.fr.third.org.objectweb.asm.Type; |
||||||
|
|
||||||
|
/** |
||||||
|
* @version $Id: ReflectUtils.java,v 1.30 2009/01/11 19:47:49 herbyderby Exp $ |
||||||
|
*/ |
||||||
|
public class ReflectUtils { |
||||||
|
private ReflectUtils() { } |
||||||
|
|
||||||
|
private static final Map primitives = new HashMap(8); |
||||||
|
private static final Map transforms = new HashMap(8); |
||||||
|
private static final ClassLoader defaultLoader = ReflectUtils.class.getClassLoader(); |
||||||
|
private static Method DEFINE_CLASS, DEFINE_CLASS_UNSAFE; |
||||||
|
private static final ProtectionDomain PROTECTION_DOMAIN; |
||||||
|
private static final Object UNSAFE; |
||||||
|
private static final Throwable THROWABLE; |
||||||
|
|
||||||
|
private static final List<Method> OBJECT_METHODS = new ArrayList<Method>(); |
||||||
|
|
||||||
|
static { |
||||||
|
ProtectionDomain protectionDomain; |
||||||
|
Method defineClass, defineClassUnsafe; |
||||||
|
Object unsafe; |
||||||
|
Throwable throwable = null; |
||||||
|
try { |
||||||
|
protectionDomain = getProtectionDomain(ReflectUtils.class); |
||||||
|
try { |
||||||
|
defineClass = (Method) AccessController.doPrivileged(new PrivilegedExceptionAction() { |
||||||
|
public Object run() throws Exception { |
||||||
|
Class loader = Class.forName("java.lang.ClassLoader"); // JVM crash w/o this
|
||||||
|
Method defineClass = loader.getDeclaredMethod("defineClass", |
||||||
|
new Class[]{ String.class, |
||||||
|
byte[].class, |
||||||
|
Integer.TYPE, |
||||||
|
Integer.TYPE, |
||||||
|
ProtectionDomain.class }); |
||||||
|
defineClass.setAccessible(true); |
||||||
|
return defineClass; |
||||||
|
} |
||||||
|
}); |
||||||
|
defineClassUnsafe = null; |
||||||
|
unsafe = null; |
||||||
|
} catch (Throwable t) { |
||||||
|
// Fallback on Jigsaw where this method is not available.
|
||||||
|
throwable = t; |
||||||
|
defineClass = null; |
||||||
|
unsafe = AccessController.doPrivileged(new PrivilegedExceptionAction() { |
||||||
|
public Object run() throws Exception { |
||||||
|
Class u = Class.forName("sun.misc.Unsafe"); |
||||||
|
Field theUnsafe = u.getDeclaredField("theUnsafe"); |
||||||
|
theUnsafe.setAccessible(true); |
||||||
|
return theUnsafe.get(null); |
||||||
|
} |
||||||
|
}); |
||||||
|
Class u = Class.forName("sun.misc.Unsafe"); |
||||||
|
defineClassUnsafe = u.getMethod("defineClass", |
||||||
|
new Class[]{ String.class, |
||||||
|
byte[].class, |
||||||
|
Integer.TYPE, |
||||||
|
Integer.TYPE, |
||||||
|
ClassLoader.class, |
||||||
|
ProtectionDomain.class }); |
||||||
|
} |
||||||
|
AccessController.doPrivileged(new PrivilegedExceptionAction() { |
||||||
|
public Object run() throws Exception { |
||||||
|
Method[] methods = Object.class.getDeclaredMethods(); |
||||||
|
for (Method method : methods) { |
||||||
|
if ("finalize".equals(method.getName()) |
||||||
|
|| (method.getModifiers() & (Modifier.FINAL | Modifier.STATIC)) > 0) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
OBJECT_METHODS.add(method); |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
}); |
||||||
|
} catch (Throwable t) { |
||||||
|
if (throwable == null) { |
||||||
|
throwable = t; |
||||||
|
} |
||||||
|
protectionDomain = null; |
||||||
|
defineClass = null; |
||||||
|
defineClassUnsafe = null; |
||||||
|
unsafe = null; |
||||||
|
} |
||||||
|
PROTECTION_DOMAIN = protectionDomain; |
||||||
|
DEFINE_CLASS = defineClass; |
||||||
|
DEFINE_CLASS_UNSAFE = defineClassUnsafe; |
||||||
|
UNSAFE = unsafe; |
||||||
|
THROWABLE = throwable; |
||||||
|
} |
||||||
|
|
||||||
|
private static final String[] CGLIB_PACKAGES = { |
||||||
|
"java.lang", |
||||||
|
}; |
||||||
|
|
||||||
|
static { |
||||||
|
primitives.put("byte", Byte.TYPE); |
||||||
|
primitives.put("char", Character.TYPE); |
||||||
|
primitives.put("double", Double.TYPE); |
||||||
|
primitives.put("float", Float.TYPE); |
||||||
|
primitives.put("int", Integer.TYPE); |
||||||
|
primitives.put("long", Long.TYPE); |
||||||
|
primitives.put("short", Short.TYPE); |
||||||
|
primitives.put("boolean", Boolean.TYPE); |
||||||
|
|
||||||
|
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"); |
||||||
|
} |
||||||
|
|
||||||
|
public static ProtectionDomain getProtectionDomain(final Class source) { |
||||||
|
if(source == null) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
return (ProtectionDomain)AccessController.doPrivileged(new PrivilegedAction() { |
||||||
|
public Object run() { |
||||||
|
return source.getProtectionDomain(); |
||||||
|
} |
||||||
|
}); |
||||||
|
} |
||||||
|
|
||||||
|
public static Type[] getExceptionTypes(Member member) { |
||||||
|
if (member instanceof Method) { |
||||||
|
return TypeUtils.getTypes(((Method)member).getExceptionTypes()); |
||||||
|
} else if (member instanceof Constructor) { |
||||||
|
return TypeUtils.getTypes(((Constructor)member).getExceptionTypes()); |
||||||
|
} else { |
||||||
|
throw new IllegalArgumentException("Cannot get exception types of a field"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static Signature getSignature(Member member) { |
||||||
|
if (member instanceof Method) { |
||||||
|
return new Signature(member.getName(), Type.getMethodDescriptor((Method)member)); |
||||||
|
} else if (member instanceof Constructor) { |
||||||
|
Type[] types = TypeUtils.getTypes(((Constructor)member).getParameterTypes()); |
||||||
|
return new Signature(Constants.CONSTRUCTOR_NAME, |
||||||
|
Type.getMethodDescriptor(Type.VOID_TYPE, types)); |
||||||
|
|
||||||
|
} else { |
||||||
|
throw new IllegalArgumentException("Cannot get signature of a field"); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static Constructor findConstructor(String desc) { |
||||||
|
return findConstructor(desc, defaultLoader); |
||||||
|
} |
||||||
|
|
||||||
|
public static Constructor findConstructor(String desc, ClassLoader loader) { |
||||||
|
try { |
||||||
|
int lparen = desc.indexOf('('); |
||||||
|
String className = desc.substring(0, lparen).trim(); |
||||||
|
return getClass(className, loader).getConstructor(parseTypes(desc, loader)); |
||||||
|
} catch (ClassNotFoundException e) { |
||||||
|
throw new CodeGenerationException(e); |
||||||
|
} catch (NoSuchMethodException e) { |
||||||
|
throw new CodeGenerationException(e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static Method findMethod(String desc) { |
||||||
|
return findMethod(desc, defaultLoader); |
||||||
|
} |
||||||
|
|
||||||
|
public static Method findMethod(String desc, ClassLoader loader) { |
||||||
|
try { |
||||||
|
int lparen = desc.indexOf('('); |
||||||
|
int dot = desc.lastIndexOf('.', lparen); |
||||||
|
String className = desc.substring(0, dot).trim(); |
||||||
|
String methodName = desc.substring(dot + 1, lparen).trim(); |
||||||
|
return getClass(className, loader).getDeclaredMethod(methodName, parseTypes(desc, loader)); |
||||||
|
} catch (ClassNotFoundException e) { |
||||||
|
throw new CodeGenerationException(e); |
||||||
|
} catch (NoSuchMethodException e) { |
||||||
|
throw new CodeGenerationException(e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static Class[] parseTypes(String desc, ClassLoader loader) throws ClassNotFoundException { |
||||||
|
int lparen = desc.indexOf('('); |
||||||
|
int rparen = desc.indexOf(')', lparen); |
||||||
|
List params = new ArrayList(); |
||||||
|
int start = lparen + 1; |
||||||
|
for (;;) { |
||||||
|
int comma = desc.indexOf(',', start); |
||||||
|
if (comma < 0) { |
||||||
|
break; |
||||||
|
} |
||||||
|
params.add(desc.substring(start, comma).trim()); |
||||||
|
start = comma + 1; |
||||||
|
} |
||||||
|
if (start < rparen) { |
||||||
|
params.add(desc.substring(start, rparen).trim()); |
||||||
|
} |
||||||
|
Class[] types = new Class[params.size()]; |
||||||
|
for (int i = 0; i < types.length; i++) { |
||||||
|
types[i] = getClass((String)params.get(i), loader); |
||||||
|
} |
||||||
|
return types; |
||||||
|
} |
||||||
|
|
||||||
|
private static Class getClass(String className, ClassLoader loader) throws ClassNotFoundException { |
||||||
|
return getClass(className, loader, CGLIB_PACKAGES); |
||||||
|
} |
||||||
|
|
||||||
|
private static Class getClass(String className, ClassLoader loader, String[] packages) throws ClassNotFoundException { |
||||||
|
String save = className; |
||||||
|
int dimensions = 0; |
||||||
|
int index = 0; |
||||||
|
while ((index = className.indexOf("[]", index) + 1) > 0) { |
||||||
|
dimensions++; |
||||||
|
} |
||||||
|
StringBuffer brackets = new StringBuffer(className.length() - dimensions); |
||||||
|
for (int i = 0; i < dimensions; i++) { |
||||||
|
brackets.append('['); |
||||||
|
} |
||||||
|
className = className.substring(0, className.length() - 2 * dimensions); |
||||||
|
|
||||||
|
String prefix = (dimensions > 0) ? brackets + "L" : ""; |
||||||
|
String suffix = (dimensions > 0) ? ";" : ""; |
||||||
|
try { |
||||||
|
return Class.forName(prefix + className + suffix, false, loader); |
||||||
|
} catch (ClassNotFoundException ignore) { } |
||||||
|
for (int i = 0; i < packages.length; i++) { |
||||||
|
try { |
||||||
|
return Class.forName(prefix + packages[i] + '.' + className + suffix, false, loader); |
||||||
|
} catch (ClassNotFoundException ignore) { } |
||||||
|
} |
||||||
|
if (dimensions == 0) { |
||||||
|
Class c = (Class)primitives.get(className); |
||||||
|
if (c != null) { |
||||||
|
return c; |
||||||
|
} |
||||||
|
} else { |
||||||
|
String transform = (String)transforms.get(className); |
||||||
|
if (transform != null) { |
||||||
|
try { |
||||||
|
return Class.forName(brackets + transform, false, loader); |
||||||
|
} catch (ClassNotFoundException ignore) { } |
||||||
|
} |
||||||
|
} |
||||||
|
throw new ClassNotFoundException(save); |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public static Object newInstance(Class type) { |
||||||
|
return newInstance(type, Constants.EMPTY_CLASS_ARRAY, null); |
||||||
|
} |
||||||
|
|
||||||
|
public static Object newInstance(Class type, Class[] parameterTypes, Object[] args) { |
||||||
|
return newInstance(getConstructor(type, parameterTypes), args); |
||||||
|
} |
||||||
|
|
||||||
|
public static Object newInstance(final Constructor cstruct, final Object[] args) { |
||||||
|
|
||||||
|
boolean flag = cstruct.isAccessible(); |
||||||
|
try { |
||||||
|
if (!flag) { |
||||||
|
cstruct.setAccessible(true); |
||||||
|
} |
||||||
|
Object result = cstruct.newInstance(args); |
||||||
|
return result; |
||||||
|
} catch (InstantiationException e) { |
||||||
|
throw new CodeGenerationException(e); |
||||||
|
} catch (IllegalAccessException e) { |
||||||
|
throw new CodeGenerationException(e); |
||||||
|
} catch (InvocationTargetException e) { |
||||||
|
throw new CodeGenerationException(e.getTargetException()); |
||||||
|
} finally { |
||||||
|
if (!flag) { |
||||||
|
cstruct.setAccessible(flag); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public static Constructor getConstructor(Class type, Class[] parameterTypes) { |
||||||
|
try { |
||||||
|
Constructor constructor = type.getDeclaredConstructor(parameterTypes); |
||||||
|
constructor.setAccessible(true); |
||||||
|
return constructor; |
||||||
|
} catch (NoSuchMethodException e) { |
||||||
|
throw new CodeGenerationException(e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static String[] getNames(Class[] classes) |
||||||
|
{ |
||||||
|
if (classes == null) |
||||||
|
return null; |
||||||
|
String[] names = new String[classes.length]; |
||||||
|
for (int i = 0; i < names.length; i++) { |
||||||
|
names[i] = classes[i].getName(); |
||||||
|
} |
||||||
|
return names; |
||||||
|
} |
||||||
|
|
||||||
|
public static Class[] getClasses(Object[] objects) { |
||||||
|
Class[] classes = new Class[objects.length]; |
||||||
|
for (int i = 0; i < objects.length; i++) { |
||||||
|
classes[i] = objects[i].getClass(); |
||||||
|
} |
||||||
|
return classes; |
||||||
|
} |
||||||
|
|
||||||
|
public static Method findNewInstance(Class iface) { |
||||||
|
Method m = findInterfaceMethod(iface); |
||||||
|
if (!m.getName().equals("newInstance")) { |
||||||
|
throw new IllegalArgumentException(iface + " missing newInstance method"); |
||||||
|
} |
||||||
|
return m; |
||||||
|
} |
||||||
|
|
||||||
|
public static Method[] getPropertyMethods(PropertyDescriptor[] properties, boolean read, boolean write) { |
||||||
|
Set methods = new HashSet(); |
||||||
|
for (int i = 0; i < properties.length; i++) { |
||||||
|
PropertyDescriptor pd = properties[i]; |
||||||
|
if (read) { |
||||||
|
methods.add(pd.getReadMethod()); |
||||||
|
} |
||||||
|
if (write) { |
||||||
|
methods.add(pd.getWriteMethod()); |
||||||
|
} |
||||||
|
} |
||||||
|
methods.remove(null); |
||||||
|
return (Method[])methods.toArray(new Method[methods.size()]); |
||||||
|
} |
||||||
|
|
||||||
|
public static PropertyDescriptor[] getBeanProperties(Class type) { |
||||||
|
return getPropertiesHelper(type, true, true); |
||||||
|
} |
||||||
|
|
||||||
|
public static PropertyDescriptor[] getBeanGetters(Class type) { |
||||||
|
return getPropertiesHelper(type, true, false); |
||||||
|
} |
||||||
|
|
||||||
|
public static PropertyDescriptor[] getBeanSetters(Class type) { |
||||||
|
return getPropertiesHelper(type, false, true); |
||||||
|
} |
||||||
|
|
||||||
|
private static PropertyDescriptor[] getPropertiesHelper(Class type, boolean read, boolean write) { |
||||||
|
try { |
||||||
|
BeanInfo info = Introspector.getBeanInfo(type, Object.class); |
||||||
|
PropertyDescriptor[] all = info.getPropertyDescriptors(); |
||||||
|
if (read && write) { |
||||||
|
return all; |
||||||
|
} |
||||||
|
List properties = new ArrayList(all.length); |
||||||
|
for (int i = 0; i < all.length; i++) { |
||||||
|
PropertyDescriptor pd = all[i]; |
||||||
|
if ((read && pd.getReadMethod() != null) || |
||||||
|
(write && pd.getWriteMethod() != null)) { |
||||||
|
properties.add(pd); |
||||||
|
} |
||||||
|
} |
||||||
|
return (PropertyDescriptor[])properties.toArray(new PropertyDescriptor[properties.size()]); |
||||||
|
} catch (IntrospectionException e) { |
||||||
|
throw new CodeGenerationException(e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public static Method findDeclaredMethod(final Class type, |
||||||
|
final String methodName, final Class[] parameterTypes) |
||||||
|
throws NoSuchMethodException { |
||||||
|
|
||||||
|
Class cl = type; |
||||||
|
while (cl != null) { |
||||||
|
try { |
||||||
|
return cl.getDeclaredMethod(methodName, parameterTypes); |
||||||
|
} catch (NoSuchMethodException e) { |
||||||
|
cl = cl.getSuperclass(); |
||||||
|
} |
||||||
|
} |
||||||
|
throw new NoSuchMethodException(methodName); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public static List addAllMethods(final Class type, final List list) { |
||||||
|
|
||||||
|
|
||||||
|
if (type == Object.class) { |
||||||
|
list.addAll(OBJECT_METHODS); |
||||||
|
} else |
||||||
|
list.addAll(java.util.Arrays.asList(type.getDeclaredMethods())); |
||||||
|
|
||||||
|
Class superclass = type.getSuperclass(); |
||||||
|
if (superclass != null) { |
||||||
|
addAllMethods(superclass, list); |
||||||
|
} |
||||||
|
Class[] interfaces = type.getInterfaces(); |
||||||
|
for (int i = 0; i < interfaces.length; i++) { |
||||||
|
addAllMethods(interfaces[i], list); |
||||||
|
} |
||||||
|
|
||||||
|
return list; |
||||||
|
} |
||||||
|
|
||||||
|
public static List addAllInterfaces(Class type, List list) { |
||||||
|
Class superclass = type.getSuperclass(); |
||||||
|
if (superclass != null) { |
||||||
|
list.addAll(Arrays.asList(type.getInterfaces())); |
||||||
|
addAllInterfaces(superclass, list); |
||||||
|
} |
||||||
|
return list; |
||||||
|
} |
||||||
|
|
||||||
|
|
||||||
|
public static Method findInterfaceMethod(Class iface) { |
||||||
|
if (!iface.isInterface()) { |
||||||
|
throw new IllegalArgumentException(iface + " is not an interface"); |
||||||
|
} |
||||||
|
Method[] methods = iface.getDeclaredMethods(); |
||||||
|
if (methods.length != 1) { |
||||||
|
throw new IllegalArgumentException("expecting exactly 1 method in " + iface); |
||||||
|
} |
||||||
|
return methods[0]; |
||||||
|
} |
||||||
|
|
||||||
|
public static Class defineClass(String className, byte[] b, ClassLoader loader) throws Exception { |
||||||
|
return defineClass(className, b, loader, PROTECTION_DOMAIN); |
||||||
|
} |
||||||
|
|
||||||
|
public static Class defineClass(String className, byte[] b, ClassLoader loader, ProtectionDomain protectionDomain) throws Exception { |
||||||
|
Class c; |
||||||
|
if (DEFINE_CLASS != null) { |
||||||
|
Object[] args = new Object[]{className, b, new Integer(0), new Integer(b.length), protectionDomain }; |
||||||
|
c = (Class)DEFINE_CLASS.invoke(loader, args); |
||||||
|
} else if (DEFINE_CLASS_UNSAFE != null) { |
||||||
|
Object[] args = new Object[]{className, b, new Integer(0), new Integer(b.length), loader, protectionDomain }; |
||||||
|
c = (Class)DEFINE_CLASS_UNSAFE.invoke(UNSAFE, args); |
||||||
|
} else { |
||||||
|
throw new CodeGenerationException(THROWABLE); |
||||||
|
} |
||||||
|
// Force static initializers to run.
|
||||||
|
Class.forName(className, true, loader); |
||||||
|
return c; |
||||||
|
} |
||||||
|
|
||||||
|
public static int findPackageProtected(Class[] classes) { |
||||||
|
for (int i = 0; i < classes.length; i++) { |
||||||
|
if (!Modifier.isPublic(classes[i].getModifiers())) { |
||||||
|
return i; |
||||||
|
} |
||||||
|
} |
||||||
|
return 0; |
||||||
|
} |
||||||
|
|
||||||
|
public static MethodInfo getMethodInfo(final Member member, final int modifiers) { |
||||||
|
final Signature sig = getSignature(member); |
||||||
|
return new MethodInfo() { |
||||||
|
private ClassInfo ci; |
||||||
|
public ClassInfo getClassInfo() { |
||||||
|
if (ci == null) |
||||||
|
ci = ReflectUtils.getClassInfo(member.getDeclaringClass()); |
||||||
|
return ci; |
||||||
|
} |
||||||
|
public int getModifiers() { |
||||||
|
return modifiers; |
||||||
|
} |
||||||
|
public Signature getSignature() { |
||||||
|
return sig; |
||||||
|
} |
||||||
|
public Type[] getExceptionTypes() { |
||||||
|
return ReflectUtils.getExceptionTypes(member); |
||||||
|
} |
||||||
|
public Attribute getAttribute() { |
||||||
|
return null; |
||||||
|
} |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
public static MethodInfo getMethodInfo(Member member) { |
||||||
|
return getMethodInfo(member, member.getModifiers()); |
||||||
|
} |
||||||
|
|
||||||
|
public static ClassInfo getClassInfo(final Class clazz) { |
||||||
|
final Type type = Type.getType(clazz); |
||||||
|
final Type sc = (clazz.getSuperclass() == null) ? null : Type.getType(clazz.getSuperclass()); |
||||||
|
return new ClassInfo() { |
||||||
|
public Type getType() { |
||||||
|
return type; |
||||||
|
} |
||||||
|
public Type getSuperType() { |
||||||
|
return sc; |
||||||
|
} |
||||||
|
public Type[] getInterfaces() { |
||||||
|
return TypeUtils.getTypes(clazz.getInterfaces()); |
||||||
|
} |
||||||
|
public int getModifiers() { |
||||||
|
return clazz.getModifiers(); |
||||||
|
} |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
// used by MethodInterceptorGenerated generated code
|
||||||
|
public static Method[] findMethods(String[] namesAndDescriptors, Method[] methods) |
||||||
|
{ |
||||||
|
Map map = new HashMap(); |
||||||
|
for (int i = 0; i < methods.length; i++) { |
||||||
|
Method method = methods[i]; |
||||||
|
map.put(method.getName() + Type.getMethodDescriptor(method), method); |
||||||
|
} |
||||||
|
Method[] result = new Method[namesAndDescriptors.length / 2]; |
||||||
|
for (int i = 0; i < result.length; i++) { |
||||||
|
result[i] = (Method)map.get(namesAndDescriptors[i * 2] + namesAndDescriptors[i * 2 + 1]); |
||||||
|
if (result[i] == null) { |
||||||
|
// TODO: error?
|
||||||
|
} |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
} |
@ -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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.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; |
||||||
|
} |
||||||
|
} |
@ -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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.core; |
||||||
|
|
||||||
|
import com.fr.third.org.objectweb.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(); |
||||||
|
} |
||||||
|
} |
@ -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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.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 <code>true</code> 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); |
||||||
|
} |
||||||
|
} |
@ -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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.core; |
||||||
|
|
||||||
|
public interface Transformer { |
||||||
|
Object transform(Object value); |
||||||
|
} |
@ -0,0 +1,421 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.core; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
import com.fr.third.org.objectweb.asm.Type; |
||||||
|
|
||||||
|
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 <init>(" + sig + ")"); // TODO
|
||||||
|
} |
||||||
|
|
||||||
|
private static List parseTypes(String s, int mark, int end) { |
||||||
|
List types = new ArrayList(5); |
||||||
|
for (;;) { |
||||||
|
int next = s.indexOf(',', mark); |
||||||
|
if (next < 0) { |
||||||
|
break; |
||||||
|
} |
||||||
|
types.add(map(s.substring(mark, next).trim())); |
||||||
|
mark = next + 1; |
||||||
|
} |
||||||
|
types.add(map(s.substring(mark, end).trim())); |
||||||
|
return types; |
||||||
|
} |
||||||
|
|
||||||
|
private static String map(String type) { |
||||||
|
if (type.equals("")) { |
||||||
|
return type; |
||||||
|
} |
||||||
|
String t = (String)transforms.get(type); |
||||||
|
if (t != null) { |
||||||
|
return t; |
||||||
|
} else if (type.indexOf('.') < 0) { |
||||||
|
return map("java.lang." + type); |
||||||
|
} else { |
||||||
|
StringBuffer sb = new StringBuffer(); |
||||||
|
int index = 0; |
||||||
|
while ((index = type.indexOf("[]", index) + 1) > 0) { |
||||||
|
sb.append('['); |
||||||
|
} |
||||||
|
type = type.substring(0, type.length() - sb.length() * 2); |
||||||
|
sb.append('L').append(type.replace('.', '/')).append(';'); |
||||||
|
return sb.toString(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static Type getBoxedType(Type type) { |
||||||
|
switch (type.getSort()) { |
||||||
|
case Type.CHAR: |
||||||
|
return Constants.TYPE_CHARACTER; |
||||||
|
case Type.BOOLEAN: |
||||||
|
return Constants.TYPE_BOOLEAN; |
||||||
|
case Type.DOUBLE: |
||||||
|
return Constants.TYPE_DOUBLE; |
||||||
|
case Type.FLOAT: |
||||||
|
return Constants.TYPE_FLOAT; |
||||||
|
case Type.LONG: |
||||||
|
return Constants.TYPE_LONG; |
||||||
|
case Type.INT: |
||||||
|
return Constants.TYPE_INTEGER; |
||||||
|
case Type.SHORT: |
||||||
|
return Constants.TYPE_SHORT; |
||||||
|
case Type.BYTE: |
||||||
|
return Constants.TYPE_BYTE; |
||||||
|
default: |
||||||
|
return type; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static Type getUnboxedType(Type type) { |
||||||
|
if (Constants.TYPE_INTEGER.equals(type)) { |
||||||
|
return Type.INT_TYPE; |
||||||
|
} else if (Constants.TYPE_BOOLEAN.equals(type)) { |
||||||
|
return Type.BOOLEAN_TYPE; |
||||||
|
} else if (Constants.TYPE_DOUBLE.equals(type)) { |
||||||
|
return Type.DOUBLE_TYPE; |
||||||
|
} else if (Constants.TYPE_LONG.equals(type)) { |
||||||
|
return Type.LONG_TYPE; |
||||||
|
} else if (Constants.TYPE_CHARACTER.equals(type)) { |
||||||
|
return Type.CHAR_TYPE; |
||||||
|
} else if (Constants.TYPE_BYTE.equals(type)) { |
||||||
|
return Type.BYTE_TYPE; |
||||||
|
} else if (Constants.TYPE_FLOAT.equals(type)) { |
||||||
|
return Type.FLOAT_TYPE; |
||||||
|
} else if (Constants.TYPE_SHORT.equals(type)) { |
||||||
|
return Type.SHORT_TYPE; |
||||||
|
} else { |
||||||
|
return type; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static boolean isArray(Type type) { |
||||||
|
return type.getSort() == Type.ARRAY; |
||||||
|
} |
||||||
|
|
||||||
|
public static Type getComponentType(Type type) { |
||||||
|
if (!isArray(type)) { |
||||||
|
throw new IllegalArgumentException("Type " + type + " is not an array"); |
||||||
|
} |
||||||
|
return Type.getType(type.getDescriptor().substring(1)); |
||||||
|
} |
||||||
|
|
||||||
|
public static boolean isPrimitive(Type type) { |
||||||
|
switch (type.getSort()) { |
||||||
|
case Type.ARRAY: |
||||||
|
case Type.OBJECT: |
||||||
|
return false; |
||||||
|
default: |
||||||
|
return true; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static String emulateClassGetName(Type type) { |
||||||
|
if (isArray(type)) { |
||||||
|
return type.getDescriptor().replace('/', '.'); |
||||||
|
} else { |
||||||
|
return getClassName(type); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static boolean isConstructor(MethodInfo method) { |
||||||
|
return method.getSignature().getName().equals(Constants.CONSTRUCTOR_NAME); |
||||||
|
} |
||||||
|
|
||||||
|
public static Type[] getTypes(Class[] classes) { |
||||||
|
if (classes == null) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
Type[] types = new Type[classes.length]; |
||||||
|
for (int i = 0; i < classes.length; i++) { |
||||||
|
types[i] = Type.getType(classes[i]); |
||||||
|
} |
||||||
|
return types; |
||||||
|
} |
||||||
|
|
||||||
|
public static int ICONST(int value) { |
||||||
|
switch (value) { |
||||||
|
case -1: return Constants.ICONST_M1; |
||||||
|
case 0: return Constants.ICONST_0; |
||||||
|
case 1: return Constants.ICONST_1; |
||||||
|
case 2: return Constants.ICONST_2; |
||||||
|
case 3: return Constants.ICONST_3; |
||||||
|
case 4: return Constants.ICONST_4; |
||||||
|
case 5: return Constants.ICONST_5; |
||||||
|
} |
||||||
|
return -1; // error
|
||||||
|
} |
||||||
|
|
||||||
|
public static int LCONST(long value) { |
||||||
|
if (value == 0L) { |
||||||
|
return Constants.LCONST_0; |
||||||
|
} else if (value == 1L) { |
||||||
|
return Constants.LCONST_1; |
||||||
|
} else { |
||||||
|
return -1; // error
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static int FCONST(float value) { |
||||||
|
if (value == 0f) { |
||||||
|
return Constants.FCONST_0; |
||||||
|
} else if (value == 1f) { |
||||||
|
return Constants.FCONST_1; |
||||||
|
} else if (value == 2f) { |
||||||
|
return Constants.FCONST_2; |
||||||
|
} else { |
||||||
|
return -1; // error
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static int DCONST(double value) { |
||||||
|
if (value == 0d) { |
||||||
|
return Constants.DCONST_0; |
||||||
|
} else if (value == 1d) { |
||||||
|
return Constants.DCONST_1; |
||||||
|
} else { |
||||||
|
return -1; // error
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static int NEWARRAY(Type type) { |
||||||
|
switch (type.getSort()) { |
||||||
|
case Type.BYTE: |
||||||
|
return Constants.T_BYTE; |
||||||
|
case Type.CHAR: |
||||||
|
return Constants.T_CHAR; |
||||||
|
case Type.DOUBLE: |
||||||
|
return Constants.T_DOUBLE; |
||||||
|
case Type.FLOAT: |
||||||
|
return Constants.T_FLOAT; |
||||||
|
case Type.INT: |
||||||
|
return Constants.T_INT; |
||||||
|
case Type.LONG: |
||||||
|
return Constants.T_LONG; |
||||||
|
case Type.SHORT: |
||||||
|
return Constants.T_SHORT; |
||||||
|
case Type.BOOLEAN: |
||||||
|
return Constants.T_BOOLEAN; |
||||||
|
default: |
||||||
|
return -1; // error
|
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public static String escapeType(String s) { |
||||||
|
StringBuffer sb = new StringBuffer(); |
||||||
|
for (int i = 0, len = s.length(); i < len; i++) { |
||||||
|
char c = s.charAt(i); |
||||||
|
switch (c) { |
||||||
|
case '$': sb.append("$24"); break; |
||||||
|
case '.': sb.append("$2E"); break; |
||||||
|
case '[': sb.append("$5B"); break; |
||||||
|
case ';': sb.append("$3B"); break; |
||||||
|
case '(': sb.append("$28"); break; |
||||||
|
case ')': sb.append("$29"); break; |
||||||
|
case '/': sb.append("$2F"); break; |
||||||
|
default: |
||||||
|
sb.append(c); |
||||||
|
} |
||||||
|
} |
||||||
|
return sb.toString(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,52 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.core; |
||||||
|
|
||||||
|
import java.lang.reflect.*; |
||||||
|
import com.fr.third.org.objectweb.asm.Type; |
||||||
|
|
||||||
|
public class VisibilityPredicate implements Predicate { |
||||||
|
private boolean protectedOk; |
||||||
|
private String pkg; |
||||||
|
private boolean samePackageOk; |
||||||
|
|
||||||
|
public VisibilityPredicate(Class source, boolean protectedOk) { |
||||||
|
this.protectedOk = protectedOk; |
||||||
|
// same package is not ok for the bootstrap loaded classes. In all other cases we are
|
||||||
|
// generating classes in the same classloader
|
||||||
|
this.samePackageOk = source.getClassLoader() != null; |
||||||
|
pkg = TypeUtils.getPackageName(Type.getType(source)); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean evaluate(Object arg) { |
||||||
|
Member member = (Member)arg; |
||||||
|
int mod = member.getModifiers(); |
||||||
|
if (Modifier.isPrivate(mod)) { |
||||||
|
return false; |
||||||
|
} else if (Modifier.isPublic(mod)) { |
||||||
|
return true; |
||||||
|
} else if (Modifier.isProtected(mod) && protectedOk) { |
||||||
|
// protected is fine if 'protectedOk' is true (for subclasses)
|
||||||
|
return true; |
||||||
|
} else { |
||||||
|
// protected/package private if the member is in the same package as the source class
|
||||||
|
// and we are generating into the same classloader.
|
||||||
|
return samePackageOk |
||||||
|
&& pkg.equals(TypeUtils.getPackageName(Type.getType(member.getDeclaringClass()))); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
@ -0,0 +1,42 @@ |
|||||||
|
package com.fr.third.net.sf.cglib.core; |
||||||
|
|
||||||
|
import java.lang.ref.WeakReference; |
||||||
|
|
||||||
|
/** |
||||||
|
* Allows to check for object equality, yet the class does not keep strong reference to the target. |
||||||
|
* {@link #equals(Object)} returns true if and only if the reference is not yet expired and target |
||||||
|
* objects are equal in terms of {@link #equals(Object)}. |
||||||
|
* <p> |
||||||
|
* This an internal class, thus it might disappear in future cglib releases. |
||||||
|
* |
||||||
|
* @param <T> type of the reference |
||||||
|
*/ |
||||||
|
public class WeakCacheKey<T> extends WeakReference<T> { |
||||||
|
private final int hash; |
||||||
|
|
||||||
|
public WeakCacheKey(T referent) { |
||||||
|
super(referent); |
||||||
|
this.hash = referent.hashCode(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean equals(Object obj) { |
||||||
|
if (!(obj instanceof WeakCacheKey)) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
Object ours = get(); |
||||||
|
Object theirs = ((WeakCacheKey) obj).get(); |
||||||
|
return ours != null && theirs != null && ours.equals(theirs); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public int hashCode() { |
||||||
|
return hash; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String toString() { |
||||||
|
T t = get(); |
||||||
|
return t == null ? "Clean WeakIdentityKey, hash: " + hash : t.toString(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,48 @@ |
|||||||
|
package com.fr.third.net.sf.cglib.core.internal; |
||||||
|
|
||||||
|
import com.fr.third.net.sf.cglib.core.Customizer; |
||||||
|
import com.fr.third.net.sf.cglib.core.FieldTypeCustomizer; |
||||||
|
import com.fr.third.net.sf.cglib.core.KeyFactoryCustomizer; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
|
||||||
|
public class CustomizerRegistry { |
||||||
|
private final Class[] customizerTypes; |
||||||
|
private Map<Class, List<KeyFactoryCustomizer>> customizers = new HashMap<Class, List<KeyFactoryCustomizer>>(); |
||||||
|
|
||||||
|
public CustomizerRegistry(Class[] customizerTypes) { |
||||||
|
this.customizerTypes = customizerTypes; |
||||||
|
} |
||||||
|
|
||||||
|
public void add(KeyFactoryCustomizer customizer) { |
||||||
|
Class<? extends KeyFactoryCustomizer> klass = customizer.getClass(); |
||||||
|
for (Class type : customizerTypes) { |
||||||
|
if (type.isAssignableFrom(klass)) { |
||||||
|
List<KeyFactoryCustomizer> list = customizers.get(type); |
||||||
|
if (list == null) { |
||||||
|
customizers.put(type, list = new ArrayList<KeyFactoryCustomizer>()); |
||||||
|
} |
||||||
|
list.add(customizer); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public <T> List<T> get(Class<T> klass) { |
||||||
|
List<KeyFactoryCustomizer> list = customizers.get(klass); |
||||||
|
if (list == null) { |
||||||
|
return Collections.emptyList(); |
||||||
|
} |
||||||
|
return (List<T>) list; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* @deprecated Only to keep backward compatibility. |
||||||
|
*/ |
||||||
|
@Deprecated |
||||||
|
public static CustomizerRegistry singleton(Customizer customizer) |
||||||
|
{ |
||||||
|
CustomizerRegistry registry = new CustomizerRegistry(new Class[]{Customizer.class}); |
||||||
|
registry.add(customizer); |
||||||
|
return registry; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,5 @@ |
|||||||
|
package com.fr.third.net.sf.cglib.core.internal; |
||||||
|
|
||||||
|
public interface Function<K, V> { |
||||||
|
V apply(K key); |
||||||
|
} |
@ -0,0 +1,86 @@ |
|||||||
|
package com.fr.third.net.sf.cglib.core.internal; |
||||||
|
|
||||||
|
import java.util.concurrent.*; |
||||||
|
|
||||||
|
public class LoadingCache<K, KK, V> { |
||||||
|
protected final ConcurrentMap<KK, Object> map; |
||||||
|
protected final Function<K, V> loader; |
||||||
|
protected final Function<K, KK> keyMapper; |
||||||
|
|
||||||
|
public static final Function IDENTITY = new Function() { |
||||||
|
public Object apply(Object key) { |
||||||
|
return key; |
||||||
|
} |
||||||
|
}; |
||||||
|
|
||||||
|
public LoadingCache(Function<K, KK> keyMapper, Function<K, V> loader) { |
||||||
|
this.keyMapper = keyMapper; |
||||||
|
this.loader = loader; |
||||||
|
this.map = new ConcurrentHashMap<KK, Object>(); |
||||||
|
} |
||||||
|
|
||||||
|
@SuppressWarnings("unchecked") |
||||||
|
public static <K> Function<K, K> identity() { |
||||||
|
return IDENTITY; |
||||||
|
} |
||||||
|
|
||||||
|
public V get(K key) { |
||||||
|
final KK cacheKey = keyMapper.apply(key); |
||||||
|
Object v = map.get(cacheKey); |
||||||
|
if (v != null && !(v instanceof FutureTask)) { |
||||||
|
return (V) v; |
||||||
|
} |
||||||
|
|
||||||
|
return createEntry(key, cacheKey, v); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Loads entry to the cache. |
||||||
|
* If entry is missing, put {@link FutureTask} first so other competing thread might wait for the result. |
||||||
|
* @param key original key that would be used to load the instance |
||||||
|
* @param cacheKey key that would be used to store the entry in internal map |
||||||
|
* @param v null or {@link FutureTask<V>} |
||||||
|
* @return newly created instance |
||||||
|
*/ |
||||||
|
protected V createEntry(final K key, KK cacheKey, Object v) { |
||||||
|
FutureTask<V> task; |
||||||
|
boolean creator = false; |
||||||
|
if (v != null) { |
||||||
|
// Another thread is already loading an instance
|
||||||
|
task = (FutureTask<V>) v; |
||||||
|
} else { |
||||||
|
task = new FutureTask<V>(new Callable<V>() { |
||||||
|
public V call() throws Exception { |
||||||
|
return loader.apply(key); |
||||||
|
} |
||||||
|
}); |
||||||
|
Object prevTask = map.putIfAbsent(cacheKey, task); |
||||||
|
if (prevTask == null) { |
||||||
|
// creator does the load
|
||||||
|
creator = true; |
||||||
|
task.run(); |
||||||
|
} else if (prevTask instanceof FutureTask) { |
||||||
|
task = (FutureTask<V>) prevTask; |
||||||
|
} else { |
||||||
|
return (V) prevTask; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
V result; |
||||||
|
try { |
||||||
|
result = task.get(); |
||||||
|
} catch (InterruptedException e) { |
||||||
|
throw new IllegalStateException("Interrupted while loading cache item", e); |
||||||
|
} catch (ExecutionException e) { |
||||||
|
Throwable cause = e.getCause(); |
||||||
|
if (cause instanceof RuntimeException) { |
||||||
|
throw ((RuntimeException) cause); |
||||||
|
} |
||||||
|
throw new IllegalStateException("Unable to load cache item", cause); |
||||||
|
} |
||||||
|
if (creator) { |
||||||
|
map.put(cacheKey, result); |
||||||
|
} |
||||||
|
return result; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,125 @@ |
|||||||
|
/* |
||||||
|
* Copyright 2011 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.proxy; |
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
import java.io.InputStream; |
||||||
|
import java.util.HashMap; |
||||||
|
import java.util.Iterator; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.Set; |
||||||
|
|
||||||
|
import com.fr.third.net.sf.cglib.core.Signature; |
||||||
|
|
||||||
|
import com.fr.third.org.objectweb.asm.AnnotationVisitor; |
||||||
|
import com.fr.third.org.objectweb.asm.Attribute; |
||||||
|
import com.fr.third.org.objectweb.asm.ClassReader; |
||||||
|
import com.fr.third.org.objectweb.asm.ClassVisitor; |
||||||
|
import com.fr.third.org.objectweb.asm.FieldVisitor; |
||||||
|
import com.fr.third.org.objectweb.asm.Label; |
||||||
|
import com.fr.third.org.objectweb.asm.MethodVisitor; |
||||||
|
import com.fr.third.org.objectweb.asm.Opcodes; |
||||||
|
|
||||||
|
/** |
||||||
|
* Uses bytecode reflection to figure out the targets of all bridge methods |
||||||
|
* that use invokespecial, so that we can later rewrite them to use invokevirtual. |
||||||
|
* |
||||||
|
* @author sberlin@gmail.com (Sam Berlin) |
||||||
|
*/ |
||||||
|
class BridgeMethodResolver { |
||||||
|
|
||||||
|
private final Map/* <Class, Set<Signature> */declToBridge; |
||||||
|
private final ClassLoader classLoader; |
||||||
|
|
||||||
|
public BridgeMethodResolver(Map declToBridge, ClassLoader classLoader) { |
||||||
|
this.declToBridge = declToBridge; |
||||||
|
this.classLoader = classLoader; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Finds all bridge methods that are being called with invokespecial & |
||||||
|
* returns them. |
||||||
|
*/ |
||||||
|
public Map/*<Signature, Signature>*/resolveAll() { |
||||||
|
Map resolved = new HashMap(); |
||||||
|
for (Iterator entryIter = declToBridge.entrySet().iterator(); entryIter.hasNext(); ) { |
||||||
|
Map.Entry entry = (Map.Entry) entryIter.next(); |
||||||
|
Class owner = (Class) entry.getKey(); |
||||||
|
Set bridges = (Set) entry.getValue(); |
||||||
|
try { |
||||||
|
InputStream is = classLoader.getResourceAsStream(owner.getName().replace('.', '/') + ".class"); |
||||||
|
if (is == null) { |
||||||
|
return resolved; |
||||||
|
} |
||||||
|
try { |
||||||
|
new ClassReader(is) |
||||||
|
.accept(new BridgedFinder(bridges, resolved), |
||||||
|
ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG); |
||||||
|
} finally { |
||||||
|
is.close(); |
||||||
|
} |
||||||
|
} catch (IOException ignored) {} |
||||||
|
} |
||||||
|
return resolved; |
||||||
|
} |
||||||
|
|
||||||
|
private static class BridgedFinder extends ClassVisitor { |
||||||
|
private Map/*<Signature, Signature>*/ resolved; |
||||||
|
private Set/*<Signature>*/ eligibleMethods; |
||||||
|
|
||||||
|
private Signature currentMethod = null; |
||||||
|
|
||||||
|
BridgedFinder(Set eligibleMethods, Map resolved) { |
||||||
|
super(Opcodes.ASM6); |
||||||
|
this.resolved = resolved; |
||||||
|
this.eligibleMethods = eligibleMethods; |
||||||
|
} |
||||||
|
|
||||||
|
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); |
||||||
|
if (eligibleMethods.remove(sig)) { |
||||||
|
currentMethod = sig; |
||||||
|
return new MethodVisitor(Opcodes.ASM6) { |
||||||
|
public void visitMethodInsn(int opcode, String owner, String name, |
||||||
|
String desc, boolean itf) { |
||||||
|
if (opcode == Opcodes.INVOKESPECIAL && currentMethod != null) { |
||||||
|
Signature target = new Signature(name, desc); |
||||||
|
// If the target signature is the same as the current,
|
||||||
|
// we shouldn't change our bridge becaues invokespecial
|
||||||
|
// is the only way to make progress (otherwise we'll
|
||||||
|
// get infinite recursion). This would typically
|
||||||
|
// only happen when a bridge method is created to widen
|
||||||
|
// the visibility of a superclass' method.
|
||||||
|
if (!target.equals(currentMethod)) { |
||||||
|
resolved.put(currentMethod, target); |
||||||
|
} |
||||||
|
currentMethod = null; |
||||||
|
} |
||||||
|
} |
||||||
|
}; |
||||||
|
} else { |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.proxy; |
||||||
|
|
||||||
|
/** |
||||||
|
* All callback interfaces used by {@link Enhancer} extend this interface. |
||||||
|
* @see MethodInterceptor |
||||||
|
* @see NoOp |
||||||
|
* @see LazyLoader |
||||||
|
* @see Dispatcher |
||||||
|
* @see InvocationHandler |
||||||
|
* @see FixedValue |
||||||
|
*/ |
||||||
|
public interface Callback |
||||||
|
{ |
||||||
|
} |
@ -0,0 +1,46 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.proxy; |
||||||
|
|
||||||
|
import java.lang.reflect.Method; |
||||||
|
|
||||||
|
/** |
||||||
|
* Map methods of subclasses generated by {@link Enhancer} to a particular |
||||||
|
* callback. The type of the callbacks chosen for each method affects |
||||||
|
* the bytecode generated for that method in the subclass, and cannot |
||||||
|
* change for the life of the class. |
||||||
|
* <p>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}.</p> |
||||||
|
*/ |
||||||
|
public interface CallbackFilter { |
||||||
|
/** |
||||||
|
* Map a method to a callback. |
||||||
|
* @param method the intercepted method |
||||||
|
* @return the index into the array of callbacks (as specified by {@link Enhancer#setCallbacks}) to use for the method, |
||||||
|
*/ |
||||||
|
int accept(Method method); |
||||||
|
|
||||||
|
/** |
||||||
|
* The <code>CallbackFilter</code> in use affects which cached class
|
||||||
|
* the <code>Enhancer</code> will use, so this is a reminder that |
||||||
|
* you should correctly implement <code>equals</code> and |
||||||
|
* <code>hashCode</code> for custom <code>CallbackFilter</code> |
||||||
|
* implementations in order to improve performance. |
||||||
|
*/ |
||||||
|
boolean equals(Object o); |
||||||
|
} |
@ -0,0 +1,36 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.proxy; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
import com.fr.third.net.sf.cglib.core.*; |
||||||
|
|
||||||
|
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); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,98 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.proxy; |
||||||
|
|
||||||
|
import com.fr.third.net.sf.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 $ |
||||||
|
*/ |
||||||
|
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 = new Integer(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); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,116 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.proxy; |
||||||
|
|
||||||
|
import com.fr.third.org.objectweb.asm.Type; |
||||||
|
|
||||||
|
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); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
|
@ -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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.proxy; |
||||||
|
|
||||||
|
/** |
||||||
|
* Dispatching {@link Enhancer} callback. This is identical to the |
||||||
|
* {@link LazyLoader} interface but needs to be separate so that <code>Enhancer</code> |
||||||
|
* 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 <b>every</b> method invocation. |
||||||
|
* @return an object that can invoke the method |
||||||
|
*/ |
||||||
|
Object loadObject() throws Exception; |
||||||
|
} |
@ -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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.proxy; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
import com.fr.third.net.sf.cglib.core.*; |
||||||
|
import com.fr.third.org.objectweb.asm.Type; |
||||||
|
|
||||||
|
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("com.fr.third.net.sf.cglib.proxy.Dispatcher"); |
||||||
|
private static final Type PROXY_REF_DISPATCHER = |
||||||
|
TypeUtils.parseType("com.fr.third.net.sf.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) { } |
||||||
|
} |
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,79 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.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 <code>Enhancer</code> |
||||||
|
* interface or using reflection. In addition, to intercept methods called during |
||||||
|
* object construction you <b>must</b> use these methods instead of reflection. |
||||||
|
* @author Juozas Baliuka <a href="mailto:baliuka@mwm.lt">baliuka@mwm.lt</a> |
||||||
|
* @version $Id: Factory.java,v 1.13 2004/06/24 21:15:20 herbyderby Exp $ |
||||||
|
*/ |
||||||
|
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 <code>Callback</code> 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(); |
||||||
|
} |
@ -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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.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 <b>every</b> method invocation. |
||||||
|
* @return an object matching the type of the return value for every |
||||||
|
* method this callback is mapped to |
||||||
|
*/ |
||||||
|
Object loadObject() throws Exception; |
||||||
|
} |
@ -0,0 +1,42 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.proxy; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
import com.fr.third.net.sf.cglib.core.*; |
||||||
|
import com.fr.third.org.objectweb.asm.Type; |
||||||
|
|
||||||
|
class FixedValueGenerator implements CallbackGenerator { |
||||||
|
public static final FixedValueGenerator INSTANCE = new FixedValueGenerator(); |
||||||
|
private static final Type FIXED_VALUE = |
||||||
|
TypeUtils.parseType("com.fr.third.net.sf.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) { } |
||||||
|
} |
@ -0,0 +1,118 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.proxy; |
||||||
|
|
||||||
|
import java.lang.reflect.*; |
||||||
|
import java.util.*; |
||||||
|
import com.fr.third.net.sf.cglib.core.*; |
||||||
|
import com.fr.third.org.objectweb.asm.ClassVisitor; |
||||||
|
import com.fr.third.org.objectweb.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 $ |
||||||
|
*/ |
||||||
|
public class InterfaceMaker extends AbstractClassGenerator |
||||||
|
{ |
||||||
|
private static final Source SOURCE = new Source(InterfaceMaker.class.getName()); |
||||||
|
private Map signatures = new HashMap(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Create a new <code>InterfaceMaker</code>. A new <code>InterfaceMaker</code> |
||||||
|
* 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. <code>getClass</code>, <code>equals</code>, <code>hashCode</code>). |
||||||
|
* @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_2, |
||||||
|
Constants.ACC_PUBLIC | Constants.ACC_INTERFACE, |
||||||
|
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(); |
||||||
|
} |
||||||
|
} |
@ -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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.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 <a href="mailto:neeme@apache.org">neeme@apache.org</a> |
||||||
|
* @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; |
||||||
|
|
||||||
|
} |
@ -0,0 +1,64 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.proxy; |
||||||
|
|
||||||
|
import com.fr.third.net.sf.cglib.core.*; |
||||||
|
import java.util.*; |
||||||
|
import com.fr.third.org.objectweb.asm.Type; |
||||||
|
|
||||||
|
class InvocationHandlerGenerator |
||||||
|
implements CallbackGenerator |
||||||
|
{ |
||||||
|
public static final InvocationHandlerGenerator INSTANCE = new InvocationHandlerGenerator(); |
||||||
|
|
||||||
|
private static final Type INVOCATION_HANDLER = |
||||||
|
TypeUtils.parseType("com.fr.third.net.sf.cglib.proxy.InvocationHandler"); |
||||||
|
private static final Type UNDECLARED_THROWABLE_EXCEPTION = |
||||||
|
TypeUtils.parseType("com.fr.third.net.sf.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()); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.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; |
||||||
|
} |
@ -0,0 +1,88 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.proxy; |
||||||
|
|
||||||
|
import java.util.*; |
||||||
|
import com.fr.third.net.sf.cglib.core.*; |
||||||
|
import com.fr.third.org.objectweb.asm.Label; |
||||||
|
import com.fr.third.org.objectweb.asm.Type; |
||||||
|
|
||||||
|
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("com.fr.third.net.sf.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(new Integer(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()).intValue(); |
||||||
|
|
||||||
|
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) { } |
||||||
|
} |
@ -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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.proxy; |
||||||
|
|
||||||
|
/** |
||||||
|
* General-purpose {@link Enhancer} callback which provides for "around advice". |
||||||
|
* @author Juozas Baliuka <a href="mailto:baliuka@mwm.lt">baliuka@mwm.lt</a> |
||||||
|
* @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; |
||||||
|
|
||||||
|
} |
@ -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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.proxy; |
||||||
|
|
||||||
|
import java.lang.reflect.Method; |
||||||
|
import java.util.*; |
||||||
|
import com.fr.third.net.sf.cglib.core.*; |
||||||
|
import com.fr.third.org.objectweb.asm.Label; |
||||||
|
import com.fr.third.org.objectweb.asm.Type; |
||||||
|
|
||||||
|
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("com.fr.third.net.sf.cglib.core.ReflectUtils"); |
||||||
|
private static final Type METHOD_PROXY = |
||||||
|
TypeUtils.parseType("com.fr.third.net.sf.cglib.proxy.MethodProxy"); |
||||||
|
private static final Type METHOD_INTERCEPTOR = |
||||||
|
TypeUtils.parseType("com.fr.third.net.sf.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(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,233 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.proxy; |
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException; |
||||||
|
import java.lang.reflect.Method; |
||||||
|
|
||||||
|
import com.fr.third.net.sf.cglib.core.AbstractClassGenerator; |
||||||
|
import com.fr.third.net.sf.cglib.core.CodeGenerationException; |
||||||
|
import com.fr.third.net.sf.cglib.core.GeneratorStrategy; |
||||||
|
import com.fr.third.net.sf.cglib.core.NamingPolicy; |
||||||
|
import com.fr.third.net.sf.cglib.core.Signature; |
||||||
|
import com.fr.third.net.sf.cglib.reflect.FastClass; |
||||||
|
|
||||||
|
/** |
||||||
|
* Classes generated by {@link Enhancer} pass this object to the |
||||||
|
* registered {@link MethodInterceptor} objects when an intercepted method is invoked. It can |
||||||
|
* be used to either invoke the original method, or call the same method on a different |
||||||
|
* object of the same type. |
||||||
|
* @version $Id: MethodProxy.java,v 1.16 2009/01/11 20:09:48 herbyderby Exp $ |
||||||
|
*/ |
||||||
|
public class MethodProxy { |
||||||
|
private Signature sig1; |
||||||
|
private Signature sig2; |
||||||
|
private CreateInfo createInfo; |
||||||
|
|
||||||
|
private final Object initLock = new Object(); |
||||||
|
private volatile FastClassInfo fastClassInfo; |
||||||
|
|
||||||
|
/** |
||||||
|
* For internal use by {@link Enhancer} only; see the {@link com.fr.third.net.sf.cglib.reflect.FastMethod} class
|
||||||
|
* for similar functionality. |
||||||
|
*/ |
||||||
|
public static MethodProxy create(Class c1, Class c2, String desc, String name1, String name2) { |
||||||
|
MethodProxy proxy = new MethodProxy(); |
||||||
|
proxy.sig1 = new Signature(name1, desc); |
||||||
|
proxy.sig2 = new Signature(name2, desc); |
||||||
|
proxy.createInfo = new CreateInfo(c1, c2); |
||||||
|
return proxy; |
||||||
|
} |
||||||
|
|
||||||
|
private void init() |
||||||
|
{ |
||||||
|
/* |
||||||
|
* Using a volatile invariant allows us to initialize the FastClass and |
||||||
|
* method index pairs atomically. |
||||||
|
* |
||||||
|
* Double-checked locking is safe with volatile in Java 5. Before 1.5 this |
||||||
|
* code could allow fastClassInfo to be instantiated more than once, which |
||||||
|
* appears to be benign. |
||||||
|
*/ |
||||||
|
if (fastClassInfo == null) |
||||||
|
{ |
||||||
|
synchronized (initLock) |
||||||
|
{ |
||||||
|
if (fastClassInfo == null) |
||||||
|
{ |
||||||
|
CreateInfo ci = createInfo; |
||||||
|
|
||||||
|
FastClassInfo fci = new FastClassInfo(); |
||||||
|
fci.f1 = helper(ci, ci.c1); |
||||||
|
fci.f2 = helper(ci, ci.c2); |
||||||
|
fci.i1 = fci.f1.getIndex(sig1); |
||||||
|
fci.i2 = fci.f2.getIndex(sig2); |
||||||
|
fastClassInfo = fci; |
||||||
|
createInfo = null; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static class FastClassInfo |
||||||
|
{ |
||||||
|
FastClass f1; |
||||||
|
FastClass f2; |
||||||
|
int i1; |
||||||
|
int i2; |
||||||
|
} |
||||||
|
|
||||||
|
private static class CreateInfo |
||||||
|
{ |
||||||
|
Class c1; |
||||||
|
Class c2; |
||||||
|
NamingPolicy namingPolicy; |
||||||
|
GeneratorStrategy strategy; |
||||||
|
boolean attemptLoad; |
||||||
|
|
||||||
|
public CreateInfo(Class c1, Class c2) |
||||||
|
{ |
||||||
|
this.c1 = c1; |
||||||
|
this.c2 = c2; |
||||||
|
AbstractClassGenerator fromEnhancer = AbstractClassGenerator.getCurrent(); |
||||||
|
if (fromEnhancer != null) { |
||||||
|
namingPolicy = fromEnhancer.getNamingPolicy(); |
||||||
|
strategy = fromEnhancer.getStrategy(); |
||||||
|
attemptLoad = fromEnhancer.getAttemptLoad(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static FastClass helper(CreateInfo ci, Class type) { |
||||||
|
FastClass.Generator g = new FastClass.Generator(); |
||||||
|
g.setType(type); |
||||||
|
g.setClassLoader(ci.c2.getClassLoader()); |
||||||
|
g.setNamingPolicy(ci.namingPolicy); |
||||||
|
g.setStrategy(ci.strategy); |
||||||
|
g.setAttemptLoad(ci.attemptLoad); |
||||||
|
return g.create(); |
||||||
|
} |
||||||
|
|
||||||
|
private MethodProxy() { |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Return the signature of the proxied method. |
||||||
|
*/ |
||||||
|
public Signature getSignature() { |
||||||
|
return sig1; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Return the name of the synthetic method created by CGLIB which is |
||||||
|
* used by {@link #invokeSuper} to invoke the superclass |
||||||
|
* (non-intercepted) method implementation. The parameter types are |
||||||
|
* the same as the proxied method. |
||||||
|
*/ |
||||||
|
public String getSuperName() { |
||||||
|
return sig2.getName(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Return the {@link com.fr.third.net.sf.cglib.reflect.FastClass} method index |
||||||
|
* for the method used by {@link #invokeSuper}. This index uniquely |
||||||
|
* identifies the method within the generated proxy, and therefore |
||||||
|
* can be useful to reference external metadata. |
||||||
|
* @see #getSuperName |
||||||
|
*/ |
||||||
|
public int getSuperIndex() { |
||||||
|
init(); |
||||||
|
return fastClassInfo.i2; |
||||||
|
} |
||||||
|
|
||||||
|
// For testing
|
||||||
|
FastClass getFastClass() { |
||||||
|
init(); |
||||||
|
return fastClassInfo.f1; |
||||||
|
} |
||||||
|
|
||||||
|
// For testing
|
||||||
|
FastClass getSuperFastClass() { |
||||||
|
init(); |
||||||
|
return fastClassInfo.f2; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Return the <code>MethodProxy</code> used when intercepting the method |
||||||
|
* matching the given signature. |
||||||
|
* @param type the class generated by Enhancer |
||||||
|
* @param sig the signature to match |
||||||
|
* @return the MethodProxy instance, or null if no applicable matching method is found |
||||||
|
* @throws IllegalArgumentException if the Class was not created by Enhancer or does not use a MethodInterceptor |
||||||
|
*/ |
||||||
|
public static MethodProxy find(Class type, Signature sig) { |
||||||
|
try { |
||||||
|
Method m = type.getDeclaredMethod(MethodInterceptorGenerator.FIND_PROXY_NAME, |
||||||
|
MethodInterceptorGenerator.FIND_PROXY_TYPES); |
||||||
|
return (MethodProxy)m.invoke(null, new Object[]{ sig }); |
||||||
|
} catch (NoSuchMethodException e) { |
||||||
|
throw new IllegalArgumentException("Class " + type + " does not use a MethodInterceptor"); |
||||||
|
} catch (IllegalAccessException e) { |
||||||
|
throw new CodeGenerationException(e); |
||||||
|
} catch (InvocationTargetException e) { |
||||||
|
throw new CodeGenerationException(e); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Invoke the original method, on a different object of the same type. |
||||||
|
* @param obj the compatible object; recursion will result if you use the object passed as the first |
||||||
|
* argument to the MethodInterceptor (usually not what you want) |
||||||
|
* @param args the arguments passed to the intercepted method; you may substitute a different |
||||||
|
* argument array as long as the types are compatible |
||||||
|
* @see MethodInterceptor#intercept |
||||||
|
* @throws Throwable the bare exceptions thrown by the called method are passed through |
||||||
|
* without wrapping in an <code>InvocationTargetException</code> |
||||||
|
*/ |
||||||
|
public Object invoke(Object obj, Object[] args) throws Throwable { |
||||||
|
try { |
||||||
|
init(); |
||||||
|
FastClassInfo fci = fastClassInfo; |
||||||
|
return fci.f1.invoke(fci.i1, obj, args); |
||||||
|
} catch (InvocationTargetException e) { |
||||||
|
throw e.getTargetException(); |
||||||
|
} catch (IllegalArgumentException e) { |
||||||
|
if (fastClassInfo.i1 < 0) |
||||||
|
throw new IllegalArgumentException("Protected method: " + sig1); |
||||||
|
throw e; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Invoke the original (super) method on the specified object. |
||||||
|
* @param obj the enhanced object, must be the object passed as the first |
||||||
|
* argument to the MethodInterceptor |
||||||
|
* @param args the arguments passed to the intercepted method; you may substitute a different |
||||||
|
* argument array as long as the types are compatible |
||||||
|
* @see MethodInterceptor#intercept |
||||||
|
* @throws Throwable the bare exceptions thrown by the called method are passed through |
||||||
|
* without wrapping in an <code>InvocationTargetException</code> |
||||||
|
*/ |
||||||
|
public Object invokeSuper(Object obj, Object[] args) throws Throwable { |
||||||
|
try { |
||||||
|
init(); |
||||||
|
FastClassInfo fci = fastClassInfo; |
||||||
|
return fci.f2.invoke(fci.i2, obj, args); |
||||||
|
} catch (InvocationTargetException e) { |
||||||
|
throw e.getTargetException(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,242 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.proxy; |
||||||
|
|
||||||
|
import java.security.ProtectionDomain; |
||||||
|
import java.lang.reflect.Constructor; |
||||||
|
import java.lang.reflect.Modifier; |
||||||
|
import java.util.*; |
||||||
|
import com.fr.third.net.sf.cglib.core.*; |
||||||
|
import com.fr.third.org.objectweb.asm.ClassVisitor; |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/** |
||||||
|
* <code>Mixin</code> 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 $ |
||||||
|
*/ |
||||||
|
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 <code>Mixin</code> |
||||||
|
* 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 <code>Mixin</code> |
||||||
|
* 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 <code>Mixin</code> |
||||||
|
* 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 (Class[])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, new Integer(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)).intValue(); |
||||||
|
index++; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,38 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.proxy; |
||||||
|
|
||||||
|
import java.lang.reflect.Method; |
||||||
|
import com.fr.third.net.sf.cglib.core.ReflectUtils; |
||||||
|
import com.fr.third.org.objectweb.asm.ClassVisitor; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Chris Nokleberg |
||||||
|
* @version $Id: MixinBeanEmitter.java,v 1.2 2004/06/24 21:15:20 herbyderby Exp $ |
||||||
|
*/ |
||||||
|
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); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,93 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.proxy; |
||||||
|
|
||||||
|
import java.lang.reflect.Method; |
||||||
|
import java.util.*; |
||||||
|
import com.fr.third.net.sf.cglib.core.*; |
||||||
|
import com.fr.third.org.objectweb.asm.ClassVisitor; |
||||||
|
import com.fr.third.org.objectweb.asm.Type; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Chris Nokleberg |
||||||
|
* @version $Id: MixinEmitter.java,v 1.9 2006/08/27 21:04:37 herbyderby Exp $ |
||||||
|
*/ |
||||||
|
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("com.fr.third.net.sf.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_2, |
||||||
|
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(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,49 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.proxy; |
||||||
|
|
||||||
|
import java.lang.reflect.Method; |
||||||
|
import java.lang.reflect.Modifier; |
||||||
|
import java.util.*; |
||||||
|
import com.fr.third.net.sf.cglib.core.CollectionUtils; |
||||||
|
import com.fr.third.net.sf.cglib.core.ReflectUtils; |
||||||
|
import com.fr.third.net.sf.cglib.core.RejectModifierPredicate; |
||||||
|
import com.fr.third.org.objectweb.asm.ClassVisitor; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Chris Nokleberg |
||||||
|
* @version $Id: MixinEverythingEmitter.java,v 1.3 2004/06/24 21:15:19 herbyderby Exp $ |
||||||
|
*/ |
||||||
|
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()]); |
||||||
|
} |
||||||
|
} |
@ -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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.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 <code>NoOp</code> callback. |
||||||
|
*/ |
||||||
|
public static final NoOp INSTANCE = new NoOp() { }; |
||||||
|
} |
@ -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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.proxy; |
||||||
|
|
||||||
|
import java.util.Iterator; |
||||||
|
import java.util.List; |
||||||
|
import com.fr.third.net.sf.cglib.core.*; |
||||||
|
|
||||||
|
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) { } |
||||||
|
} |
@ -0,0 +1,101 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.proxy; |
||||||
|
|
||||||
|
import java.io.Serializable; |
||||||
|
import java.lang.reflect.Method; |
||||||
|
import java.lang.reflect.Member; |
||||||
|
import com.fr.third.net.sf.cglib.core.CodeGenerationException; |
||||||
|
|
||||||
|
/** |
||||||
|
* This class is meant to be used as replacement for |
||||||
|
* <code>java.lang.reflect.Proxy</code> under JDK 1.2. There are some known |
||||||
|
* subtle differences: |
||||||
|
* <ul> |
||||||
|
* <li>The exceptions returned by invoking <code>getExceptionTypes</code> |
||||||
|
* on the <code>Method</code> passed to the <code>invoke</code> method |
||||||
|
* <b>are</b> the exact set that can be thrown without resulting in an |
||||||
|
* <code>UndeclaredThrowableException</code> being thrown. |
||||||
|
* <li>{@link UndeclaredThrowableException} is used instead |
||||||
|
* of <code>java.lang.reflect.UndeclaredThrowableException</code>. |
||||||
|
* </ul> |
||||||
|
* <p> |
||||||
|
* @version $Id: Proxy.java,v 1.6 2004/06/24 21:15:19 herbyderby Exp $ |
||||||
|
*/ |
||||||
|
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); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.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 <b>every</b> 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; |
||||||
|
} |
@ -0,0 +1,36 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.proxy; |
||||||
|
|
||||||
|
import com.fr.third.net.sf.cglib.core.CodeGenerationException; |
||||||
|
|
||||||
|
/** |
||||||
|
* Used by {@link Proxy} as a replacement for <code>java.lang.reflect.UndeclaredThrowableException</code>. |
||||||
|
* @author Juozas Baliuka |
||||||
|
*/ |
||||||
|
public class UndeclaredThrowableException extends CodeGenerationException { |
||||||
|
/** |
||||||
|
* Creates a new instance of <code>UndeclaredThrowableException</code> without detail message. |
||||||
|
*/ |
||||||
|
public UndeclaredThrowableException(Throwable t) { |
||||||
|
super(t); |
||||||
|
} |
||||||
|
|
||||||
|
public Throwable getUndeclaredThrowable() { |
||||||
|
return getCause(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,123 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.reflect; |
||||||
|
|
||||||
|
import java.lang.reflect.*; |
||||||
|
import java.security.ProtectionDomain; |
||||||
|
import com.fr.third.net.sf.cglib.core.*; |
||||||
|
import com.fr.third.org.objectweb.asm.ClassVisitor; |
||||||
|
import com.fr.third.org.objectweb.asm.Type; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author Chris Nokleberg |
||||||
|
* @version $Id: ConstructorDelegate.java,v 1.20 2006/03/05 02:43:19 herbyderby Exp $ |
||||||
|
*/ |
||||||
|
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("com.fr.third.net.sf.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_2, |
||||||
|
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; |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,207 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.reflect; |
||||||
|
|
||||||
|
import com.fr.third.net.sf.cglib.core.*; |
||||||
|
import java.lang.reflect.Constructor; |
||||||
|
import java.lang.reflect.InvocationTargetException; |
||||||
|
import java.lang.reflect.Method; |
||||||
|
import java.security.ProtectionDomain; |
||||||
|
import com.fr.third.org.objectweb.asm.ClassVisitor; |
||||||
|
import com.fr.third.org.objectweb.asm.Type; |
||||||
|
|
||||||
|
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 <code>-1</code> 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 <code>-1</code> 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(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,226 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.reflect; |
||||||
|
|
||||||
|
import java.lang.reflect.*; |
||||||
|
import java.util.*; |
||||||
|
import com.fr.third.net.sf.cglib.core.*; |
||||||
|
import com.fr.third.org.objectweb.asm.ClassVisitor; |
||||||
|
import com.fr.third.org.objectweb.asm.Label; |
||||||
|
import com.fr.third.org.objectweb.asm.Type; |
||||||
|
|
||||||
|
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("com.fr.third.net.sf.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_2, 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 ("<init>")
|
||||||
|
private void emitIndexBySignature(List methods) { |
||||||
|
CodeEmitter e = begin_method(Constants.ACC_PUBLIC, SIGNATURE_GET_INDEX, null); |
||||||
|
List signatures = CollectionUtils.transform(methods, new Transformer() { |
||||||
|
public Object transform(Object obj) { |
||||||
|
return ReflectUtils.getSignature((Method)obj).toString(); |
||||||
|
} |
||||||
|
}); |
||||||
|
e.load_arg(0); |
||||||
|
e.invoke_virtual(Constants.TYPE_OBJECT, TO_STRING); |
||||||
|
signatureSwitchHelper(e, signatures); |
||||||
|
e.end_method(); |
||||||
|
} |
||||||
|
|
||||||
|
private static final int TOO_MANY_METHODS = 100; // TODO
|
||||||
|
private void emitIndexByClassArray(List methods) { |
||||||
|
CodeEmitter e = begin_method(Constants.ACC_PUBLIC, METHOD_GET_INDEX, null); |
||||||
|
if (methods.size() > TOO_MANY_METHODS) { |
||||||
|
// hack for big classes
|
||||||
|
List signatures = CollectionUtils.transform(methods, new Transformer() { |
||||||
|
public Object transform(Object obj) { |
||||||
|
String s = ReflectUtils.getSignature((Method)obj).toString(); |
||||||
|
return s.substring(0, s.lastIndexOf(')') + 1); |
||||||
|
} |
||||||
|
}); |
||||||
|
e.load_args(); |
||||||
|
e.invoke_static(FAST_CLASS, GET_SIGNATURE_WITHOUT_RETURN_TYPE); |
||||||
|
signatureSwitchHelper(e, signatures); |
||||||
|
} else { |
||||||
|
e.load_args(); |
||||||
|
List info = CollectionUtils.transform(methods, MethodInfoTransformer.getInstance()); |
||||||
|
EmitUtils.method_switch(e, info, new GetIndexCallback(e, info)); |
||||||
|
} |
||||||
|
e.end_method(); |
||||||
|
} |
||||||
|
|
||||||
|
private void signatureSwitchHelper(final CodeEmitter e, final List signatures) { |
||||||
|
ObjectSwitchCallback callback = new ObjectSwitchCallback() { |
||||||
|
public void processCase(Object key, Label end) { |
||||||
|
// TODO: remove linear indexOf
|
||||||
|
e.push(signatures.indexOf(key)); |
||||||
|
e.return_value(); |
||||||
|
} |
||||||
|
public void processDefault() { |
||||||
|
e.push(-1); |
||||||
|
e.return_value(); |
||||||
|
} |
||||||
|
}; |
||||||
|
EmitUtils.string_switch(e, |
||||||
|
(String[])signatures.toArray(new String[signatures.size()]), |
||||||
|
Constants.SWITCH_STYLE_HASH, |
||||||
|
callback); |
||||||
|
} |
||||||
|
|
||||||
|
private static void invokeSwitchHelper(final CodeEmitter e, List members, final int arg, final Type base) { |
||||||
|
final List info = CollectionUtils.transform(members, MethodInfoTransformer.getInstance()); |
||||||
|
final Label illegalArg = e.make_label(); |
||||||
|
Block block = e.begin_block(); |
||||||
|
e.process_switch(getIntRange(info.size()), new ProcessSwitchCallback() { |
||||||
|
public void processCase(int key, Label end) { |
||||||
|
MethodInfo method = (MethodInfo)info.get(key); |
||||||
|
Type[] types = method.getSignature().getArgumentTypes(); |
||||||
|
for (int i = 0; i < types.length; i++) { |
||||||
|
e.load_arg(arg); |
||||||
|
e.aaload(i); |
||||||
|
e.unbox(types[i]); |
||||||
|
} |
||||||
|
// TODO: change method lookup process so MethodInfo will already reference base
|
||||||
|
// instead of superclass when superclass method is inaccessible
|
||||||
|
e.invoke(method, base); |
||||||
|
if (!TypeUtils.isConstructor(method)) { |
||||||
|
e.box(method.getSignature().getReturnType()); |
||||||
|
} |
||||||
|
e.return_value(); |
||||||
|
} |
||||||
|
public void processDefault() { |
||||||
|
e.goTo(illegalArg); |
||||||
|
} |
||||||
|
}); |
||||||
|
block.end(); |
||||||
|
EmitUtils.wrap_throwable(block, INVOCATION_TARGET_EXCEPTION); |
||||||
|
e.mark(illegalArg); |
||||||
|
e.throw_exception(ILLEGAL_ARGUMENT_EXCEPTION, "Cannot find matching method/constructor"); |
||||||
|
} |
||||||
|
|
||||||
|
private static class GetIndexCallback implements ObjectSwitchCallback { |
||||||
|
private CodeEmitter e; |
||||||
|
private Map indexes = new HashMap(); |
||||||
|
|
||||||
|
public GetIndexCallback(CodeEmitter e, List methods) { |
||||||
|
this.e = e; |
||||||
|
int index = 0; |
||||||
|
for (Iterator it = methods.iterator(); it.hasNext();) { |
||||||
|
indexes.put(it.next(), new Integer(index++)); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void processCase(Object key, Label end) { |
||||||
|
e.push(((Integer)indexes.get(key)).intValue()); |
||||||
|
e.return_value(); |
||||||
|
} |
||||||
|
|
||||||
|
public void processDefault() { |
||||||
|
e.push(-1); |
||||||
|
e.return_value(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
private static int[] getIntRange(int length) { |
||||||
|
int[] range = new int[length]; |
||||||
|
for (int i = 0; i < length; i++) { |
||||||
|
range[i] = i; |
||||||
|
} |
||||||
|
return range; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,46 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.reflect; |
||||||
|
|
||||||
|
import java.lang.reflect.Constructor; |
||||||
|
import java.lang.reflect.InvocationTargetException; |
||||||
|
|
||||||
|
public class FastConstructor extends FastMember |
||||||
|
{ |
||||||
|
FastConstructor(FastClass fc, Constructor constructor) { |
||||||
|
super(fc, constructor, fc.getIndex(constructor.getParameterTypes())); |
||||||
|
} |
||||||
|
|
||||||
|
public Class[] getParameterTypes() { |
||||||
|
return ((Constructor)member).getParameterTypes(); |
||||||
|
} |
||||||
|
|
||||||
|
public Class[] getExceptionTypes() { |
||||||
|
return ((Constructor)member).getExceptionTypes(); |
||||||
|
} |
||||||
|
|
||||||
|
public Object newInstance() throws InvocationTargetException { |
||||||
|
return fc.newInstance(index, null); |
||||||
|
} |
||||||
|
|
||||||
|
public Object newInstance(Object[] args) throws InvocationTargetException { |
||||||
|
return fc.newInstance(index, args); |
||||||
|
} |
||||||
|
|
||||||
|
public Constructor getJavaConstructor() { |
||||||
|
return (Constructor)member; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,65 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.reflect; |
||||||
|
|
||||||
|
import java.lang.reflect.Member; |
||||||
|
|
||||||
|
abstract public class FastMember |
||||||
|
{ |
||||||
|
protected FastClass fc; |
||||||
|
protected Member member; |
||||||
|
protected int index; |
||||||
|
|
||||||
|
protected FastMember(FastClass fc, Member member, int index) { |
||||||
|
this.fc = fc; |
||||||
|
this.member = member; |
||||||
|
this.index = index; |
||||||
|
} |
||||||
|
|
||||||
|
abstract public Class[] getParameterTypes(); |
||||||
|
abstract public Class[] getExceptionTypes(); |
||||||
|
|
||||||
|
public int getIndex() { |
||||||
|
return index; |
||||||
|
} |
||||||
|
|
||||||
|
public String getName() { |
||||||
|
return member.getName(); |
||||||
|
} |
||||||
|
|
||||||
|
public Class getDeclaringClass() { |
||||||
|
return fc.getJavaClass(); |
||||||
|
} |
||||||
|
|
||||||
|
public int getModifiers() { |
||||||
|
return member.getModifiers(); |
||||||
|
} |
||||||
|
|
||||||
|
public String toString() { |
||||||
|
return member.toString(); |
||||||
|
} |
||||||
|
|
||||||
|
public int hashCode() { |
||||||
|
return member.hashCode(); |
||||||
|
} |
||||||
|
|
||||||
|
public boolean equals(Object o) { |
||||||
|
if (o == null || !(o instanceof FastMember)) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
return member.equals(((FastMember)o).member); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,63 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.reflect; |
||||||
|
|
||||||
|
import java.lang.reflect.InvocationTargetException; |
||||||
|
import java.lang.reflect.Method; |
||||||
|
|
||||||
|
import com.fr.third.net.sf.cglib.core.Signature; |
||||||
|
|
||||||
|
import com.fr.third.org.objectweb.asm.Type; |
||||||
|
|
||||||
|
public class FastMethod extends FastMember |
||||||
|
{ |
||||||
|
FastMethod(FastClass fc, Method method) { |
||||||
|
super(fc, method, helper(fc, method)); |
||||||
|
} |
||||||
|
|
||||||
|
private static int helper(FastClass fc, Method method) { |
||||||
|
int index = fc.getIndex(new Signature(method.getName(), Type.getMethodDescriptor(method))); |
||||||
|
if (index < 0) { |
||||||
|
Class[] types = method.getParameterTypes(); |
||||||
|
System.err.println("hash=" + method.getName().hashCode() + " size=" + types.length); |
||||||
|
for (int i = 0; i < types.length; i++) { |
||||||
|
System.err.println(" types[" + i + "]=" + types[i].getName()); |
||||||
|
} |
||||||
|
throw new IllegalArgumentException("Cannot find method " + method); |
||||||
|
} |
||||||
|
return index; |
||||||
|
} |
||||||
|
|
||||||
|
public Class getReturnType() { |
||||||
|
return ((Method)member).getReturnType(); |
||||||
|
} |
||||||
|
|
||||||
|
public Class[] getParameterTypes() { |
||||||
|
return ((Method)member).getParameterTypes(); |
||||||
|
} |
||||||
|
|
||||||
|
public Class[] getExceptionTypes() { |
||||||
|
return ((Method)member).getExceptionTypes(); |
||||||
|
} |
||||||
|
|
||||||
|
public Object invoke(Object obj, Object[] args) throws InvocationTargetException { |
||||||
|
return fc.invoke(index, obj, args); |
||||||
|
} |
||||||
|
|
||||||
|
public Method getJavaMethod() { |
||||||
|
return (Method)member; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,268 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.reflect; |
||||||
|
|
||||||
|
import java.lang.reflect.*; |
||||||
|
import java.security.ProtectionDomain; |
||||||
|
import com.fr.third.net.sf.cglib.*; |
||||||
|
import com.fr.third.net.sf.cglib.core.*; |
||||||
|
import com.fr.third.org.objectweb.asm.ClassVisitor; |
||||||
|
import com.fr.third.org.objectweb.asm.Type; |
||||||
|
|
||||||
|
// TODO: don't require exact match for return type
|
||||||
|
|
||||||
|
/** |
||||||
|
* <b>DOCUMENTATION FROM APACHE AVALON DELEGATE CLASS</b> |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* 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. |
||||||
|
* </p> |
||||||
|
* |
||||||
|
* <h2>Delegate</h2> |
||||||
|
* <p> |
||||||
|
* Any interface with one method can become the interface for a delegate. |
||||||
|
* Consider the example below: |
||||||
|
* </p> |
||||||
|
* |
||||||
|
* <pre> |
||||||
|
* public interface MainDelegate { |
||||||
|
* int main(String[] args); |
||||||
|
* } |
||||||
|
* </pre> |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* 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 <code>MethodDelegate.create(this, "alternateMain", MainDelegate.class)</code>. |
||||||
|
* The following program will show how to use it: |
||||||
|
* </p> |
||||||
|
* |
||||||
|
* <pre> |
||||||
|
* 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; |
||||||
|
* } |
||||||
|
* } |
||||||
|
* </pre> |
||||||
|
* |
||||||
|
* <p> |
||||||
|
* 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 <code>main</code> method by |
||||||
|
* substituting the delegate creation call with this: |
||||||
|
* <code>MethodDelegate.createStatic(getClass(), "main", MainDelegate.class)</code>. |
||||||
|
* </p> |
||||||
|
* <p> |
||||||
|
* 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). |
||||||
|
* </p> |
||||||
|
* |
||||||
|
* <h3>Equality</h3> |
||||||
|
* The criteria that we use to test if two delegates are equal are: |
||||||
|
* <ul> |
||||||
|
* <li> |
||||||
|
* They both refer to the same instance. That is, the <code>instance</code> |
||||||
|
* parameter passed to the newDelegate method was the same for both. The |
||||||
|
* instances are compared with the identity equality operator, <code>==</code>. |
||||||
|
* </li> |
||||||
|
* <li>They refer to the same method as resolved by <code>Method.equals</code>.</li> |
||||||
|
* </ul> |
||||||
|
* |
||||||
|
* @version $Id: MethodDelegate.java,v 1.25 2006/03/05 02:43:19 herbyderby Exp $ |
||||||
|
*/ |
||||||
|
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("com.fr.third.net.sf.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_2, |
||||||
|
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(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,179 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.reflect; |
||||||
|
|
||||||
|
import java.lang.reflect.*; |
||||||
|
import java.security.ProtectionDomain; |
||||||
|
import java.util.*; |
||||||
|
import com.fr.third.net.sf.cglib.core.*; |
||||||
|
import com.fr.third.org.objectweb.asm.ClassVisitor; |
||||||
|
import com.fr.third.org.objectweb.asm.MethodVisitor; |
||||||
|
import com.fr.third.org.objectweb.asm.Type; |
||||||
|
|
||||||
|
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("com.fr.third.net.sf.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_2, |
||||||
|
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(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.transform; |
||||||
|
|
||||||
|
import com.fr.third.org.objectweb.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
|
||||||
|
} |
||||||
|
} |
@ -0,0 +1,118 @@ |
|||||||
|
/* |
||||||
|
* 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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.transform; |
||||||
|
|
||||||
|
import com.fr.third.net.sf.cglib.core.CodeGenerationException; |
||||||
|
import com.fr.third.net.sf.cglib.core.ClassGenerator; |
||||||
|
import com.fr.third.net.sf.cglib.core.DebuggingClassWriter; |
||||||
|
import com.fr.third.org.objectweb.asm.ClassReader; |
||||||
|
import com.fr.third.org.objectweb.asm.ClassWriter; |
||||||
|
import com.fr.third.org.objectweb.asm.Attribute; |
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
|
||||||
|
abstract public class AbstractClassLoader extends ClassLoader { |
||||||
|
private ClassFilter filter; |
||||||
|
private ClassLoader classPath; |
||||||
|
private static java.security.ProtectionDomain DOMAIN ; |
||||||
|
|
||||||
|
static{ |
||||||
|
|
||||||
|
DOMAIN = (java.security.ProtectionDomain) |
||||||
|
java.security.AccessController.doPrivileged( |
||||||
|
new java.security.PrivilegedAction() { |
||||||
|
public Object run() { |
||||||
|
return 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) { |
||||||
|
} |
||||||
|
} |
@ -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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.transform; |
||||||
|
|
||||||
|
import com.fr.third.org.objectweb.asm.ClassVisitor; |
||||||
|
import com.fr.third.org.objectweb.asm.Opcodes; |
||||||
|
|
||||||
|
abstract public class AbstractClassTransformer extends ClassTransformer { |
||||||
|
protected AbstractClassTransformer() { |
||||||
|
super(Opcodes.ASM6); |
||||||
|
} |
||||||
|
|
||||||
|
public void setTarget(ClassVisitor target) { |
||||||
|
cv = target; |
||||||
|
} |
||||||
|
} |
@ -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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.transform; |
||||||
|
|
||||||
|
import com.fr.third.org.objectweb.asm.AnnotationVisitor; |
||||||
|
import com.fr.third.org.objectweb.asm.Opcodes; |
||||||
|
|
||||||
|
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(Opcodes.ASM6); |
||||||
|
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(); |
||||||
|
} |
||||||
|
} |
@ -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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.transform; |
||||||
|
|
||||||
|
import com.fr.third.net.sf.cglib.core.ClassEmitter; |
||||||
|
|
||||||
|
abstract public class ClassEmitterTransformer extends ClassEmitter { |
||||||
|
} |
@ -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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.transform; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author baliuka |
||||||
|
*/ |
||||||
|
public interface ClassFilter { |
||||||
|
|
||||||
|
boolean accept(String className); |
||||||
|
|
||||||
|
} |
@ -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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.transform; |
||||||
|
|
||||||
|
import com.fr.third.org.objectweb.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('/', '.')); |
||||||
|
} |
||||||
|
} |
@ -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 |
||||||
|
* |
||||||
|
* http://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 com.fr.third.net.sf.cglib.transform; |
||||||
|
|
||||||
|
import com.fr.third.net.sf.cglib.core.ClassGenerator; |
||||||
|
import com.fr.third.org.objectweb.asm.Attribute; |
||||||
|
import com.fr.third.org.objectweb.asm.ClassReader; |
||||||
|
import com.fr.third.org.objectweb.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); |
||||||
|
} |
||||||
|
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue