Browse Source

Merge pull request #17 in CORE/base-third from ~ABEL.CHEN/base-third:feature/10.0 to feature/10.0

* commit 'e580103a3e1f9449df57ed0c2f5e82471b040a57':
  修改代理方式,采用cglib代理
10.0
superman 7 years ago
parent
commit
70688b3624
  1. 4
      build.third_step6.gradle
  2. 50
      fine-cglib/resources/com/fr/third/net/sf/cglib/util/words.txt
  3. 176
      fine-cglib/src/com/fr/third/net/sf/cglib/beans/BeanCopier.java
  4. 149
      fine-cglib/src/com/fr/third/net/sf/cglib/beans/BeanGenerator.java
  5. 320
      fine-cglib/src/com/fr/third/net/sf/cglib/beans/BeanMap.java
  6. 192
      fine-cglib/src/com/fr/third/net/sf/cglib/beans/BeanMapEmitter.java
  7. 142
      fine-cglib/src/com/fr/third/net/sf/cglib/beans/BulkBean.java
  8. 156
      fine-cglib/src/com/fr/third/net/sf/cglib/beans/BulkBeanEmitter.java
  9. 43
      fine-cglib/src/com/fr/third/net/sf/cglib/beans/BulkBeanException.java
  10. 36
      fine-cglib/src/com/fr/third/net/sf/cglib/beans/FixedKeySet.java
  11. 128
      fine-cglib/src/com/fr/third/net/sf/cglib/beans/ImmutableBean.java
  12. 353
      fine-cglib/src/com/fr/third/net/sf/cglib/core/AbstractClassGenerator.java
  13. 49
      fine-cglib/src/com/fr/third/net/sf/cglib/core/Block.java
  14. 282
      fine-cglib/src/com/fr/third/net/sf/cglib/core/ClassEmitter.java
  15. 22
      fine-cglib/src/com/fr/third/net/sf/cglib/core/ClassGenerator.java
  16. 47
      fine-cglib/src/com/fr/third/net/sf/cglib/core/ClassInfo.java
  17. 63
      fine-cglib/src/com/fr/third/net/sf/cglib/core/ClassNameReader.java
  18. 46
      fine-cglib/src/com/fr/third/net/sf/cglib/core/ClassesKey.java
  19. 864
      fine-cglib/src/com/fr/third/net/sf/cglib/core/CodeEmitter.java
  20. 32
      fine-cglib/src/com/fr/third/net/sf/cglib/core/CodeGenerationException.java
  21. 76
      fine-cglib/src/com/fr/third/net/sf/cglib/core/CollectionUtils.java
  22. 68
      fine-cglib/src/com/fr/third/net/sf/cglib/core/Constants.java
  23. 20
      fine-cglib/src/com/fr/third/net/sf/cglib/core/Converter.java
  24. 28
      fine-cglib/src/com/fr/third/net/sf/cglib/core/Customizer.java
  25. 114
      fine-cglib/src/com/fr/third/net/sf/cglib/core/DebuggingClassWriter.java
  26. 47
      fine-cglib/src/com/fr/third/net/sf/cglib/core/DefaultGeneratorStrategy.java
  27. 71
      fine-cglib/src/com/fr/third/net/sf/cglib/core/DefaultNamingPolicy.java
  28. 27
      fine-cglib/src/com/fr/third/net/sf/cglib/core/DuplicatesPredicate.java
  29. 960
      fine-cglib/src/com/fr/third/net/sf/cglib/core/EmitUtils.java
  30. 23
      fine-cglib/src/com/fr/third/net/sf/cglib/core/FieldTypeCustomizer.java
  31. 44
      fine-cglib/src/com/fr/third/net/sf/cglib/core/GeneratorStrategy.java
  32. 12
      fine-cglib/src/com/fr/third/net/sf/cglib/core/HashCodeCustomizer.java
  33. 346
      fine-cglib/src/com/fr/third/net/sf/cglib/core/KeyFactory.java
  34. 7
      fine-cglib/src/com/fr/third/net/sf/cglib/core/KeyFactoryCustomizer.java
  35. 37
      fine-cglib/src/com/fr/third/net/sf/cglib/core/Local.java
  36. 158
      fine-cglib/src/com/fr/third/net/sf/cglib/core/LocalVariablesSorter.java
  37. 47
      fine-cglib/src/com/fr/third/net/sf/cglib/core/MethodInfo.java
  38. 37
      fine-cglib/src/com/fr/third/net/sf/cglib/core/MethodInfoTransformer.java
  39. 46
      fine-cglib/src/com/fr/third/net/sf/cglib/core/MethodWrapper.java
  40. 43
      fine-cglib/src/com/fr/third/net/sf/cglib/core/NamingPolicy.java
  41. 24
      fine-cglib/src/com/fr/third/net/sf/cglib/core/ObjectSwitchCallback.java
  42. 21
      fine-cglib/src/com/fr/third/net/sf/cglib/core/Predicate.java
  43. 22
      fine-cglib/src/com/fr/third/net/sf/cglib/core/ProcessArrayCallback.java
  44. 23
      fine-cglib/src/com/fr/third/net/sf/cglib/core/ProcessSwitchCallback.java
  45. 544
      fine-cglib/src/com/fr/third/net/sf/cglib/core/ReflectUtils.java
  46. 30
      fine-cglib/src/com/fr/third/net/sf/cglib/core/RejectModifierPredicate.java
  47. 73
      fine-cglib/src/com/fr/third/net/sf/cglib/core/Signature.java
  48. 84
      fine-cglib/src/com/fr/third/net/sf/cglib/core/TinyBitSet.java
  49. 20
      fine-cglib/src/com/fr/third/net/sf/cglib/core/Transformer.java
  50. 421
      fine-cglib/src/com/fr/third/net/sf/cglib/core/TypeUtils.java
  51. 52
      fine-cglib/src/com/fr/third/net/sf/cglib/core/VisibilityPredicate.java
  52. 42
      fine-cglib/src/com/fr/third/net/sf/cglib/core/WeakCacheKey.java
  53. 48
      fine-cglib/src/com/fr/third/net/sf/cglib/core/internal/CustomizerRegistry.java
  54. 5
      fine-cglib/src/com/fr/third/net/sf/cglib/core/internal/Function.java
  55. 86
      fine-cglib/src/com/fr/third/net/sf/cglib/core/internal/LoadingCache.java
  56. 125
      fine-cglib/src/com/fr/third/net/sf/cglib/proxy/BridgeMethodResolver.java
  57. 29
      fine-cglib/src/com/fr/third/net/sf/cglib/proxy/Callback.java
  58. 46
      fine-cglib/src/com/fr/third/net/sf/cglib/proxy/CallbackFilter.java
  59. 36
      fine-cglib/src/com/fr/third/net/sf/cglib/proxy/CallbackGenerator.java
  60. 98
      fine-cglib/src/com/fr/third/net/sf/cglib/proxy/CallbackHelper.java
  61. 116
      fine-cglib/src/com/fr/third/net/sf/cglib/proxy/CallbackInfo.java
  62. 30
      fine-cglib/src/com/fr/third/net/sf/cglib/proxy/Dispatcher.java
  63. 65
      fine-cglib/src/com/fr/third/net/sf/cglib/proxy/DispatcherGenerator.java
  64. 1319
      fine-cglib/src/com/fr/third/net/sf/cglib/proxy/Enhancer.java
  65. 79
      fine-cglib/src/com/fr/third/net/sf/cglib/proxy/Factory.java
  66. 35
      fine-cglib/src/com/fr/third/net/sf/cglib/proxy/FixedValue.java
  67. 42
      fine-cglib/src/com/fr/third/net/sf/cglib/proxy/FixedValueGenerator.java
  68. 118
      fine-cglib/src/com/fr/third/net/sf/cglib/proxy/InterfaceMaker.java
  69. 35
      fine-cglib/src/com/fr/third/net/sf/cglib/proxy/InvocationHandler.java
  70. 64
      fine-cglib/src/com/fr/third/net/sf/cglib/proxy/InvocationHandlerGenerator.java
  71. 30
      fine-cglib/src/com/fr/third/net/sf/cglib/proxy/LazyLoader.java
  72. 88
      fine-cglib/src/com/fr/third/net/sf/cglib/proxy/LazyLoaderGenerator.java
  73. 42
      fine-cglib/src/com/fr/third/net/sf/cglib/proxy/MethodInterceptor.java
  74. 238
      fine-cglib/src/com/fr/third/net/sf/cglib/proxy/MethodInterceptorGenerator.java
  75. 233
      fine-cglib/src/com/fr/third/net/sf/cglib/proxy/MethodProxy.java
  76. 242
      fine-cglib/src/com/fr/third/net/sf/cglib/proxy/Mixin.java
  77. 38
      fine-cglib/src/com/fr/third/net/sf/cglib/proxy/MixinBeanEmitter.java
  78. 93
      fine-cglib/src/com/fr/third/net/sf/cglib/proxy/MixinEmitter.java
  79. 49
      fine-cglib/src/com/fr/third/net/sf/cglib/proxy/MixinEverythingEmitter.java
  80. 28
      fine-cglib/src/com/fr/third/net/sf/cglib/proxy/NoOp.java
  81. 43
      fine-cglib/src/com/fr/third/net/sf/cglib/proxy/NoOpGenerator.java
  82. 101
      fine-cglib/src/com/fr/third/net/sf/cglib/proxy/Proxy.java
  83. 31
      fine-cglib/src/com/fr/third/net/sf/cglib/proxy/ProxyRefDispatcher.java
  84. 36
      fine-cglib/src/com/fr/third/net/sf/cglib/proxy/UndeclaredThrowableException.java
  85. 123
      fine-cglib/src/com/fr/third/net/sf/cglib/reflect/ConstructorDelegate.java
  86. 207
      fine-cglib/src/com/fr/third/net/sf/cglib/reflect/FastClass.java
  87. 226
      fine-cglib/src/com/fr/third/net/sf/cglib/reflect/FastClassEmitter.java
  88. 46
      fine-cglib/src/com/fr/third/net/sf/cglib/reflect/FastConstructor.java
  89. 65
      fine-cglib/src/com/fr/third/net/sf/cglib/reflect/FastMember.java
  90. 63
      fine-cglib/src/com/fr/third/net/sf/cglib/reflect/FastMethod.java
  91. 268
      fine-cglib/src/com/fr/third/net/sf/cglib/reflect/MethodDelegate.java
  92. 179
      fine-cglib/src/com/fr/third/net/sf/cglib/reflect/MulticastDelegate.java
  93. 85
      fine-cglib/src/com/fr/third/net/sf/cglib/transform/AbstractClassFilterTransformer.java
  94. 118
      fine-cglib/src/com/fr/third/net/sf/cglib/transform/AbstractClassLoader.java
  95. 29
      fine-cglib/src/com/fr/third/net/sf/cglib/transform/AbstractClassTransformer.java
  96. 61
      fine-cglib/src/com/fr/third/net/sf/cglib/transform/AnnotationVisitorTee.java
  97. 21
      fine-cglib/src/com/fr/third/net/sf/cglib/transform/ClassEmitterTransformer.java
  98. 27
      fine-cglib/src/com/fr/third/net/sf/cglib/transform/ClassFilter.java
  99. 31
      fine-cglib/src/com/fr/third/net/sf/cglib/transform/ClassFilterTransformer.java
  100. 41
      fine-cglib/src/com/fr/third/net/sf/cglib/transform/ClassReaderGenerator.java
  101. Some files were not shown because too many files have changed in this diff Show More

4
build.third_step6.gradle

@ -28,6 +28,8 @@ sourceSets{
"${srcDir}/fine-guava/src", "${srcDir}/fine-guava/src",
"${srcDir}/fine-lucene/src", "${srcDir}/fine-lucene/src",
"${srcDir}/fine-lucene/resources", "${srcDir}/fine-lucene/resources",
"${srcDir}/fine-cglib/src",
"${srcDir}/fine-cglib/resources",
] ]
} }
} }
@ -76,6 +78,8 @@ task copyFiles(type:Copy,dependsOn:'compileJava'){
with dataContent.call("${srcDir}/fine-guava/src") with dataContent.call("${srcDir}/fine-guava/src")
with dataContent.call("${srcDir}/fine-lucene/src") with dataContent.call("${srcDir}/fine-lucene/src")
with dataContent.call("${srcDir}/fine-lucene/resources") with dataContent.call("${srcDir}/fine-lucene/resources")
with dataContent.call("${srcDir}/fine-cglib/src")
with dataContent.call("${srcDir}/fine-cglib/resources")
into "${classesDir}" into "${classesDir}"
} }
} }

50
fine-cglib/resources/com/fr/third/net/sf/cglib/util/words.txt

@ -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

176
fine-cglib/src/com/fr/third/net/sf/cglib/beans/BeanCopier.java

@ -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;
}
}
}

149
fine-cglib/src/com/fr/third/net/sf/cglib/beans/BeanGenerator.java

@ -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());
}
}
}

320
fine-cglib/src/com/fr/third/net/sf/cglib/beans/BeanMap.java

@ -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();
}
}

192
fine-cglib/src/com/fr/third/net/sf/cglib/beans/BeanMapEmitter.java

@ -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();
}
}

142
fine-cglib/src/com/fr/third/net/sf/cglib/beans/BulkBean.java

@ -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;
}
}
}

156
fine-cglib/src/com/fr/third/net/sf/cglib/beans/BulkBeanEmitter.java

@ -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);
}
}
}

43
fine-cglib/src/com/fr/third/net/sf/cglib/beans/BulkBeanException.java

@ -0,0 +1,43 @@
/*
* Copyright 2003 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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;
}
}

36
fine-cglib/src/com/fr/third/net/sf/cglib/beans/FixedKeySet.java

@ -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;
}
}

128
fine-cglib/src/com/fr/third/net/sf/cglib/beans/ImmutableBean.java

@ -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());
}
}
}

353
fine-cglib/src/com/fr/third/net/sf/cglib/core/AbstractClassGenerator.java

@ -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;
}

49
fine-cglib/src/com/fr/third/net/sf/cglib/core/Block.java

@ -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;
}
}

282
fine-cglib/src/com/fr/third/net/sf/cglib/core/ClassEmitter.java

@ -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));
}
}

22
fine-cglib/src/com/fr/third/net/sf/cglib/core/ClassGenerator.java

@ -0,0 +1,22 @@
/*
* Copyright 2003 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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;
}

47
fine-cglib/src/com/fr/third/net/sf/cglib/core/ClassInfo.java

@ -0,0 +1,47 @@
/*
* Copyright 2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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();
}
}

63
fine-cglib/src/com/fr/third/net/sf/cglib/core/ClassNameReader.java

@ -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[]{} );
}
}

46
fine-cglib/src/com/fr/third/net/sf/cglib/core/ClassesKey.java

@ -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;
}
}

864
fine-cglib/src/com/fr/third/net/sf/cglib/core/CodeEmitter.java

@ -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());
}
}

32
fine-cglib/src/com/fr/third/net/sf/cglib/core/CodeGenerationException.java

@ -0,0 +1,32 @@
/*
* Copyright 2003 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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;
}
}

76
fine-cglib/src/com/fr/third/net/sf/cglib/core/CollectionUtils.java

@ -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;
}
}

68
fine-cglib/src/com/fr/third/net/sf/cglib/core/Constants.java

@ -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;
}

20
fine-cglib/src/com/fr/third/net/sf/cglib/core/Converter.java

@ -0,0 +1,20 @@
/*
* Copyright 2003 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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);
}

28
fine-cglib/src/com/fr/third/net/sf/cglib/core/Customizer.java

@ -0,0 +1,28 @@
/*
* Copyright 2003 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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);
}

114
fine-cglib/src/com/fr/third/net/sf/cglib/core/DebuggingClassWriter.java

@ -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;
}
});
}
}

47
fine-cglib/src/com/fr/third/net/sf/cglib/core/DefaultGeneratorStrategy.java

@ -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;
}
}

71
fine-cglib/src/com/fr/third/net/sf/cglib/core/DefaultNamingPolicy.java

@ -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());
}
}

27
fine-cglib/src/com/fr/third/net/sf/cglib/core/DuplicatesPredicate.java

@ -0,0 +1,27 @@
/*
* Copyright 2003 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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));
}
}

960
fine-cglib/src/com/fr/third/net/sf/cglib/core/EmitUtils.java

@ -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());
}
}

23
fine-cglib/src/com/fr/third/net/sf/cglib/core/FieldTypeCustomizer.java

@ -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);
}

44
fine-cglib/src/com/fr/third/net/sf/cglib/core/GeneratorStrategy.java

@ -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);
}

12
fine-cglib/src/com/fr/third/net/sf/cglib/core/HashCodeCustomizer.java

@ -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);
}

346
fine-cglib/src/com/fr/third/net/sf/cglib/core/KeyFactory.java

@ -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;
}
}
}

7
fine-cglib/src/com/fr/third/net/sf/cglib/core/KeyFactoryCustomizer.java

@ -0,0 +1,7 @@
package com.fr.third.net.sf.cglib.core;
/**
* Marker interface for customizers of {@link KeyFactory}
*/
public interface KeyFactoryCustomizer {
}

37
fine-cglib/src/com/fr/third/net/sf/cglib/core/Local.java

@ -0,0 +1,37 @@
/*
* Copyright 2003 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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;
}
}

158
fine-cglib/src/com/fr/third/net/sf/cglib/core/LocalVariablesSorter.java

@ -0,0 +1,158 @@
/***
* ASM: a very small and fast Java bytecode manipulation framework
* Copyright (c) 2000-2005 INRIA, France Telecom
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
* 3. Neither the name of the copyright holders nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
* THE POSSIBILITY OF SUCH DAMAGE.
*/
package 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;
}
}

47
fine-cglib/src/com/fr/third/net/sf/cglib/core/MethodInfo.java

@ -0,0 +1,47 @@
/*
* Copyright 2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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();
}
}

37
fine-cglib/src/com/fr/third/net/sf/cglib/core/MethodInfoTransformer.java

@ -0,0 +1,37 @@
/*
* Copyright 2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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);
}
}
}

46
fine-cglib/src/com/fr/third/net/sf/cglib/core/MethodWrapper.java

@ -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;
}
}

43
fine-cglib/src/com/fr/third/net/sf/cglib/core/NamingPolicy.java

@ -0,0 +1,43 @@
/*
* Copyright 2003 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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);
}

24
fine-cglib/src/com/fr/third/net/sf/cglib/core/ObjectSwitchCallback.java

@ -0,0 +1,24 @@
/*
* Copyright 2003 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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;
}

21
fine-cglib/src/com/fr/third/net/sf/cglib/core/Predicate.java

@ -0,0 +1,21 @@
/*
* Copyright 2003 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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);
}

22
fine-cglib/src/com/fr/third/net/sf/cglib/core/ProcessArrayCallback.java

@ -0,0 +1,22 @@
/*
* Copyright 2003 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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);
}

23
fine-cglib/src/com/fr/third/net/sf/cglib/core/ProcessSwitchCallback.java

@ -0,0 +1,23 @@
/*
* Copyright 2003 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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;
}

544
fine-cglib/src/com/fr/third/net/sf/cglib/core/ReflectUtils.java

@ -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;
}
}

30
fine-cglib/src/com/fr/third/net/sf/cglib/core/RejectModifierPredicate.java

@ -0,0 +1,30 @@
/*
* Copyright 2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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;
}
}

73
fine-cglib/src/com/fr/third/net/sf/cglib/core/Signature.java

@ -0,0 +1,73 @@
/*
* Copyright 2003 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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();
}
}

84
fine-cglib/src/com/fr/third/net/sf/cglib/core/TinyBitSet.java

@ -0,0 +1,84 @@
/*
* Copyright 2003 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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);
}
}

20
fine-cglib/src/com/fr/third/net/sf/cglib/core/Transformer.java

@ -0,0 +1,20 @@
/*
* Copyright 2003 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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);
}

421
fine-cglib/src/com/fr/third/net/sf/cglib/core/TypeUtils.java

@ -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();
}
}

52
fine-cglib/src/com/fr/third/net/sf/cglib/core/VisibilityPredicate.java

@ -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())));
}
}
}

42
fine-cglib/src/com/fr/third/net/sf/cglib/core/WeakCacheKey.java

@ -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();
}
}

48
fine-cglib/src/com/fr/third/net/sf/cglib/core/internal/CustomizerRegistry.java

@ -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;
}
}

5
fine-cglib/src/com/fr/third/net/sf/cglib/core/internal/Function.java

@ -0,0 +1,5 @@
package com.fr.third.net.sf.cglib.core.internal;
public interface Function<K, V> {
V apply(K key);
}

86
fine-cglib/src/com/fr/third/net/sf/cglib/core/internal/LoadingCache.java

@ -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;
}
}

125
fine-cglib/src/com/fr/third/net/sf/cglib/proxy/BridgeMethodResolver.java

@ -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;
}
}
}
}

29
fine-cglib/src/com/fr/third/net/sf/cglib/proxy/Callback.java

@ -0,0 +1,29 @@
/*
* Copyright 2003 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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
{
}

46
fine-cglib/src/com/fr/third/net/sf/cglib/proxy/CallbackFilter.java

@ -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);
}

36
fine-cglib/src/com/fr/third/net/sf/cglib/proxy/CallbackGenerator.java

@ -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);
}
}

98
fine-cglib/src/com/fr/third/net/sf/cglib/proxy/CallbackHelper.java

@ -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);
}
}

116
fine-cglib/src/com/fr/third/net/sf/cglib/proxy/CallbackInfo.java

@ -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);
}
}

30
fine-cglib/src/com/fr/third/net/sf/cglib/proxy/Dispatcher.java

@ -0,0 +1,30 @@
/*
* Copyright 2003 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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;
}

65
fine-cglib/src/com/fr/third/net/sf/cglib/proxy/DispatcherGenerator.java

@ -0,0 +1,65 @@
/*
* Copyright 2003,2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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) { }
}

1319
fine-cglib/src/com/fr/third/net/sf/cglib/proxy/Enhancer.java

File diff suppressed because it is too large Load Diff

79
fine-cglib/src/com/fr/third/net/sf/cglib/proxy/Factory.java

@ -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();
}

35
fine-cglib/src/com/fr/third/net/sf/cglib/proxy/FixedValue.java

@ -0,0 +1,35 @@
/*
* Copyright 2003 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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;
}

42
fine-cglib/src/com/fr/third/net/sf/cglib/proxy/FixedValueGenerator.java

@ -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) { }
}

118
fine-cglib/src/com/fr/third/net/sf/cglib/proxy/InterfaceMaker.java

@ -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();
}
}

35
fine-cglib/src/com/fr/third/net/sf/cglib/proxy/InvocationHandler.java

@ -0,0 +1,35 @@
/*
* Copyright 2003 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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;
}

64
fine-cglib/src/com/fr/third/net/sf/cglib/proxy/InvocationHandlerGenerator.java

@ -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());
}
}
}

30
fine-cglib/src/com/fr/third/net/sf/cglib/proxy/LazyLoader.java

@ -0,0 +1,30 @@
/*
* Copyright 2003 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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;
}

88
fine-cglib/src/com/fr/third/net/sf/cglib/proxy/LazyLoaderGenerator.java

@ -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) { }
}

42
fine-cglib/src/com/fr/third/net/sf/cglib/proxy/MethodInterceptor.java

@ -0,0 +1,42 @@
/*
* Copyright 2002,2003 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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;
}

238
fine-cglib/src/com/fr/third/net/sf/cglib/proxy/MethodInterceptorGenerator.java

@ -0,0 +1,238 @@
/*
* Copyright 2003,2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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();
}
}

233
fine-cglib/src/com/fr/third/net/sf/cglib/proxy/MethodProxy.java

@ -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();
}
}
}

242
fine-cglib/src/com/fr/third/net/sf/cglib/proxy/Mixin.java

@ -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++;
}
}
}
}

38
fine-cglib/src/com/fr/third/net/sf/cglib/proxy/MixinBeanEmitter.java

@ -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);
}
}

93
fine-cglib/src/com/fr/third/net/sf/cglib/proxy/MixinEmitter.java

@ -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();
}
}

49
fine-cglib/src/com/fr/third/net/sf/cglib/proxy/MixinEverythingEmitter.java

@ -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()]);
}
}

28
fine-cglib/src/com/fr/third/net/sf/cglib/proxy/NoOp.java

@ -0,0 +1,28 @@
/*
* Copyright 2003 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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() { };
}

43
fine-cglib/src/com/fr/third/net/sf/cglib/proxy/NoOpGenerator.java

@ -0,0 +1,43 @@
/*
* Copyright 2003,2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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) { }
}

101
fine-cglib/src/com/fr/third/net/sf/cglib/proxy/Proxy.java

@ -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);
}
}
}

31
fine-cglib/src/com/fr/third/net/sf/cglib/proxy/ProxyRefDispatcher.java

@ -0,0 +1,31 @@
/*
* Copyright 2003 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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;
}

36
fine-cglib/src/com/fr/third/net/sf/cglib/proxy/UndeclaredThrowableException.java

@ -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();
}
}

123
fine-cglib/src/com/fr/third/net/sf/cglib/reflect/ConstructorDelegate.java

@ -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;
}
}
}

207
fine-cglib/src/com/fr/third/net/sf/cglib/reflect/FastClass.java

@ -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();
}
}

226
fine-cglib/src/com/fr/third/net/sf/cglib/reflect/FastClassEmitter.java

@ -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;
}
}

46
fine-cglib/src/com/fr/third/net/sf/cglib/reflect/FastConstructor.java

@ -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;
}
}

65
fine-cglib/src/com/fr/third/net/sf/cglib/reflect/FastMember.java

@ -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);
}
}

63
fine-cglib/src/com/fr/third/net/sf/cglib/reflect/FastMethod.java

@ -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;
}
}

268
fine-cglib/src/com/fr/third/net/sf/cglib/reflect/MethodDelegate.java

@ -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();
}
}
}

179
fine-cglib/src/com/fr/third/net/sf/cglib/reflect/MulticastDelegate.java

@ -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();
}
}
}

85
fine-cglib/src/com/fr/third/net/sf/cglib/transform/AbstractClassFilterTransformer.java

@ -0,0 +1,85 @@
/*
* Copyright 2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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
}
}

118
fine-cglib/src/com/fr/third/net/sf/cglib/transform/AbstractClassLoader.java

@ -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) {
}
}

29
fine-cglib/src/com/fr/third/net/sf/cglib/transform/AbstractClassTransformer.java

@ -0,0 +1,29 @@
/*
* Copyright 2003 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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;
}
}

61
fine-cglib/src/com/fr/third/net/sf/cglib/transform/AnnotationVisitorTee.java

@ -0,0 +1,61 @@
/*
* Copyright 2003 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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();
}
}

21
fine-cglib/src/com/fr/third/net/sf/cglib/transform/ClassEmitterTransformer.java

@ -0,0 +1,21 @@
/*
* Copyright 2003 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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 {
}

27
fine-cglib/src/com/fr/third/net/sf/cglib/transform/ClassFilter.java

@ -0,0 +1,27 @@
/*
* Copyright 2003 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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);
}

31
fine-cglib/src/com/fr/third/net/sf/cglib/transform/ClassFilterTransformer.java

@ -0,0 +1,31 @@
/*
* Copyright 2003,2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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('/', '.'));
}
}

41
fine-cglib/src/com/fr/third/net/sf/cglib/transform/ClassReaderGenerator.java

@ -0,0 +1,41 @@
/*
* Copyright 2003 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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…
Cancel
Save