Turn CGLIB patch into full CGLIB fork in spring-core
Closes gh-28955
This commit is contained in:
parent
a052f9a34e
commit
7fa5b8dcb5
|
@ -30,7 +30,7 @@ eclipse.classpath.file.whenMerged { classpath ->
|
|||
}
|
||||
|
||||
// Remove any remaining direct depencencies on JARs in the build/libs folder
|
||||
// except Spring's spring-cglib-repack and spring-objenesis-repack JARs.
|
||||
// except the repack JARs.
|
||||
classpath.entries.removeAll { entry -> (entry.path =~ /(?!.*?repack.*\.jar).*?\/([^\/]+)\/build\/libs\/[^\/]+\.jar/) }
|
||||
}
|
||||
|
||||
|
|
|
@ -5,43 +5,15 @@ description = "Spring Core"
|
|||
|
||||
apply plugin: "kotlin"
|
||||
|
||||
// spring-core includes asm, javapoet and repackages cglib, inlining all into the
|
||||
// spring-core jar. cglib itself depends on asm and is therefore further transformed by
|
||||
// the ShadowJar task to depend on org.springframework.asm; this avoids including two
|
||||
// different copies of asm.
|
||||
def cglibVersion = "3.3.0"
|
||||
def javapoetVersion = "1.13.0"
|
||||
def objenesisVersion = "3.2"
|
||||
|
||||
configurations {
|
||||
cglib
|
||||
javapoet
|
||||
objenesis
|
||||
graalvm
|
||||
}
|
||||
|
||||
task cglibRepackJar(type: ShadowJar) {
|
||||
archiveBaseName = 'spring-cglib-repack'
|
||||
archiveVersion = cglibVersion
|
||||
configurations = [project.configurations.cglib]
|
||||
relocate('net.sf.cglib', 'org.springframework.cglib')
|
||||
relocate('org.objectweb.asm', 'org.springframework.asm')
|
||||
}
|
||||
|
||||
task cglibSource(type: ShadowSource) {
|
||||
configurations = [project.configurations.cglib]
|
||||
relocate('net.sf.cglib', 'org.springframework.cglib')
|
||||
relocate('org.objectweb.asm', 'org.springframework.asm')
|
||||
outputDirectory = file("build/shadow-source/cglib")
|
||||
}
|
||||
|
||||
task cglibSourceJar(type: Jar) {
|
||||
archiveBaseName = 'spring-cglib-repack'
|
||||
archiveVersion = cglibVersion
|
||||
archiveClassifier = 'sources'
|
||||
from cglibSource
|
||||
}
|
||||
|
||||
task javapoetRepackJar(type: ShadowJar) {
|
||||
archiveBaseName = 'spring-javapoet-repack'
|
||||
archiveVersion = javapoetVersion
|
||||
|
@ -83,11 +55,9 @@ task objenesisSourceJar(type: Jar) {
|
|||
}
|
||||
|
||||
dependencies {
|
||||
cglib("cglib:cglib:${cglibVersion}@jar")
|
||||
javapoet("com.squareup:javapoet:${javapoetVersion}@jar")
|
||||
objenesis("org.objenesis:objenesis:${objenesisVersion}@jar")
|
||||
graalvm(project(path: ":graalvm-feature", configuration: 'classesOnlyElements'))
|
||||
api(files(cglibRepackJar))
|
||||
api(files(javapoetRepackJar))
|
||||
api(files(objenesisRepackJar))
|
||||
api(project(":spring-jcl"))
|
||||
|
@ -126,21 +96,6 @@ jar {
|
|||
preserveFileTimestamps = false // maybe not necessary here, but good for reproducibility
|
||||
manifest.attributes["Dependencies"] = "jdk.unsupported" // for WildFly (-> Objenesis 3.2)
|
||||
|
||||
// Inline repackaged cglib classes directly into spring-core jar
|
||||
dependsOn cglibRepackJar
|
||||
from(zipTree(cglibRepackJar.archivePath)) {
|
||||
include "org/springframework/cglib/**"
|
||||
exclude "org/springframework/cglib/beans/**"
|
||||
exclude "org/springframework/cglib/core/AbstractClassGenerator*.class"
|
||||
exclude "org/springframework/cglib/core/AsmApi*.class"
|
||||
exclude "org/springframework/cglib/core/KeyFactory.class"
|
||||
exclude "org/springframework/cglib/core/KeyFactory\$*.class"
|
||||
exclude "org/springframework/cglib/core/MethodWrapper*.class"
|
||||
exclude "org/springframework/cglib/core/ReflectUtils*.class"
|
||||
exclude "org/springframework/cglib/proxy/Enhancer*.class"
|
||||
exclude "org/springframework/cglib/proxy/MethodProxy*.class"
|
||||
}
|
||||
|
||||
dependsOn javapoetRepackJar
|
||||
from(zipTree(javapoetRepackJar.archivePath)) {
|
||||
include "org/springframework/javapoet/**"
|
||||
|
@ -167,16 +122,14 @@ test {
|
|||
}
|
||||
|
||||
sourcesJar {
|
||||
dependsOn cglibSourceJar
|
||||
dependsOn javapoetSourceJar
|
||||
dependsOn objenesisSourceJar
|
||||
from cglibSource
|
||||
from javapoetSource
|
||||
from objenesisSource
|
||||
}
|
||||
|
||||
eclipse {
|
||||
synchronizationTasks cglibSourceJar, javapoetSourceJar, objenesisSourceJar
|
||||
synchronizationTasks javapoetSourceJar, objenesisSourceJar
|
||||
classpath {
|
||||
file {
|
||||
whenMerged {
|
||||
|
|
|
@ -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
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.core;
|
||||
|
||||
import org.springframework.asm.Label;
|
||||
|
||||
public class Block
|
||||
{
|
||||
private CodeEmitter e;
|
||||
private Label start;
|
||||
private Label end;
|
||||
|
||||
public Block(CodeEmitter e) {
|
||||
this.e = e;
|
||||
start = e.mark();
|
||||
}
|
||||
|
||||
public CodeEmitter getCodeEmitter() {
|
||||
return e;
|
||||
}
|
||||
|
||||
public void end() {
|
||||
if (end != null) {
|
||||
throw new IllegalStateException("end of label already set");
|
||||
}
|
||||
end = e.mark();
|
||||
}
|
||||
|
||||
public Label getStart() {
|
||||
return start;
|
||||
}
|
||||
|
||||
public Label getEnd() {
|
||||
return end;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,282 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.core;
|
||||
|
||||
import org.springframework.cglib.transform.ClassTransformer;
|
||||
|
||||
import org.springframework.asm.ClassVisitor;
|
||||
import org.springframework.asm.FieldVisitor;
|
||||
import org.springframework.asm.MethodVisitor;
|
||||
import org.springframework.asm.Type;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author Juozas Baliuka, Chris Nokleberg
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
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(Constants.ASM_API);
|
||||
}
|
||||
|
||||
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(Constants.ASM_API, v) {
|
||||
public void visitMaxs(int maxStack, int maxLocals) {
|
||||
// ignore
|
||||
}
|
||||
public void visitInsn(int insn) {
|
||||
if (insn != Constants.RETURN) {
|
||||
super.visitInsn(insn);
|
||||
}
|
||||
}
|
||||
};
|
||||
staticInit = new CodeEmitter(this, wrapped, access, sig, exceptions);
|
||||
if (staticHook == null) {
|
||||
// force static hook creation
|
||||
getStaticHook();
|
||||
} else {
|
||||
staticInit.invoke_static_this(staticHookSig);
|
||||
}
|
||||
return staticInit;
|
||||
} else if (sig.equals(staticHookSig)) {
|
||||
return new CodeEmitter(this, v, access, sig, exceptions) {
|
||||
public boolean isStaticHook() {
|
||||
return true;
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return new CodeEmitter(this, v, access, sig, exceptions);
|
||||
}
|
||||
}
|
||||
|
||||
public CodeEmitter begin_static() {
|
||||
return begin_method(Constants.ACC_STATIC, Constants.SIG_STATIC, null);
|
||||
}
|
||||
|
||||
public void declare_field(int access, String name, Type type, Object value) {
|
||||
FieldInfo existing = (FieldInfo)fieldInfo.get(name);
|
||||
FieldInfo info = new FieldInfo(access, name, type, value);
|
||||
if (existing != null) {
|
||||
if (!info.equals(existing)) {
|
||||
throw new IllegalArgumentException("Field \"" + name + "\" has been declared differently");
|
||||
}
|
||||
} else {
|
||||
fieldInfo.put(name, info);
|
||||
cv.visitField(access, name, type.getDescriptor(), null, value);
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: make public?
|
||||
boolean isFieldDeclared(String name) {
|
||||
return fieldInfo.get(name) != null;
|
||||
}
|
||||
|
||||
FieldInfo getFieldInfo(String name) {
|
||||
FieldInfo field = (FieldInfo)fieldInfo.get(name);
|
||||
if (field == null) {
|
||||
throw new IllegalArgumentException("Field " + name + " is not declared in " + getClassType().getClassName());
|
||||
}
|
||||
return field;
|
||||
}
|
||||
|
||||
static class FieldInfo {
|
||||
int access;
|
||||
String name;
|
||||
Type type;
|
||||
Object value;
|
||||
|
||||
public FieldInfo(int access, String name, Type type, Object value) {
|
||||
this.access = access;
|
||||
this.name = name;
|
||||
this.type = type;
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (o == null)
|
||||
return false;
|
||||
if (!(o instanceof FieldInfo))
|
||||
return false;
|
||||
FieldInfo other = (FieldInfo)o;
|
||||
if (access != other.access ||
|
||||
!name.equals(other.name) ||
|
||||
!type.equals(other.type)) {
|
||||
return false;
|
||||
}
|
||||
if ((value == null) ^ (other.value == null))
|
||||
return false;
|
||||
if (value != null && !value.equals(other.value))
|
||||
return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return access ^ name.hashCode() ^ type.hashCode() ^ ((value == null) ? 0 : value.hashCode());
|
||||
}
|
||||
}
|
||||
|
||||
public void visit(int version,
|
||||
int access,
|
||||
String name,
|
||||
String signature,
|
||||
String superName,
|
||||
String[] interfaces) {
|
||||
begin_class(version,
|
||||
access,
|
||||
name.replace('/', '.'),
|
||||
TypeUtils.fromInternalName(superName),
|
||||
TypeUtils.fromInternalNames(interfaces),
|
||||
null); // TODO
|
||||
}
|
||||
|
||||
public void visitEnd() {
|
||||
end_class();
|
||||
}
|
||||
|
||||
public FieldVisitor visitField(int access,
|
||||
String name,
|
||||
String desc,
|
||||
String signature,
|
||||
Object value) {
|
||||
declare_field(access, name, Type.getType(desc), value);
|
||||
return null; // TODO
|
||||
}
|
||||
|
||||
public MethodVisitor visitMethod(int access,
|
||||
String name,
|
||||
String desc,
|
||||
String signature,
|
||||
String[] exceptions) {
|
||||
return begin_method(access,
|
||||
new Signature(name, desc),
|
||||
TypeUtils.fromInternalNames(exceptions));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.core;
|
||||
|
||||
import org.springframework.asm.ClassVisitor;
|
||||
|
||||
public interface ClassGenerator {
|
||||
void generateClass(ClassVisitor v) throws Exception;
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright 2004 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.core;
|
||||
|
||||
import org.springframework.asm.Attribute;
|
||||
import org.springframework.asm.Type;
|
||||
|
||||
abstract public class ClassInfo {
|
||||
|
||||
protected ClassInfo() {
|
||||
}
|
||||
|
||||
abstract public Type getType();
|
||||
abstract public Type getSuperType();
|
||||
abstract public Type[] getInterfaces();
|
||||
abstract public int getModifiers();
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (o == null)
|
||||
return false;
|
||||
if (!(o instanceof ClassInfo))
|
||||
return false;
|
||||
return getType().equals(((ClassInfo)o).getType());
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return getType().hashCode();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
// TODO: include modifiers, superType, interfaces
|
||||
return getType().getClassName();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,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
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.core;
|
||||
|
||||
import org.springframework.asm.ClassReader;
|
||||
import org.springframework.asm.ClassVisitor;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
// TODO: optimize (ClassReader buffers entire class before accept)
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public class ClassNameReader {
|
||||
private ClassNameReader() {
|
||||
}
|
||||
|
||||
private static final EarlyExitException EARLY_EXIT = new EarlyExitException();
|
||||
|
||||
@SuppressWarnings("serial")
|
||||
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(Constants.ASM_API, null) {
|
||||
public void visit(int version,
|
||||
int access,
|
||||
String name,
|
||||
String signature,
|
||||
String superName,
|
||||
String[] interfaces) {
|
||||
array.add( name.replace('/', '.') );
|
||||
if(superName != null){
|
||||
array.add( superName.replace('/', '.') );
|
||||
}
|
||||
for(int i = 0; i < interfaces.length; i++ ){
|
||||
array.add( interfaces[i].replace('/', '.') );
|
||||
}
|
||||
|
||||
throw EARLY_EXIT;
|
||||
}
|
||||
}, ClassReader.SKIP_DEBUG | ClassReader.SKIP_FRAMES);
|
||||
} catch (EarlyExitException e) { }
|
||||
|
||||
return (String[])array.toArray( new String[]{} );
|
||||
}
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.core;
|
||||
|
||||
public class ClassesKey {
|
||||
private static final Key FACTORY = (Key)KeyFactory.create(Key.class);
|
||||
|
||||
interface Key {
|
||||
Object newInstance(Object[] array);
|
||||
}
|
||||
|
||||
private ClassesKey() {
|
||||
}
|
||||
|
||||
public static Object create(Object[] array) {
|
||||
return FACTORY.newInstance(classNames(array));
|
||||
}
|
||||
|
||||
private static String[] classNames(Object[] objects) {
|
||||
if (objects == null) {
|
||||
return null;
|
||||
}
|
||||
String[] classNames = new String[objects.length];
|
||||
for (int i = 0; i < objects.length; i++) {
|
||||
Object object = objects[i];
|
||||
if (object != null) {
|
||||
Class<?> aClass = object.getClass();
|
||||
classNames[i] = aClass == null ? null : aClass.getName();
|
||||
}
|
||||
}
|
||||
return classNames;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,870 @@
|
|||
/*
|
||||
* Copyright 2003,2004 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.core;
|
||||
|
||||
import java.io.*;
|
||||
import java.util.*;
|
||||
import org.springframework.asm.*;
|
||||
|
||||
/**
|
||||
* @author Juozas Baliuka, Chris Nokleberg
|
||||
*/
|
||||
@SuppressWarnings("fallthrough")
|
||||
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(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(i);
|
||||
}
|
||||
}
|
||||
|
||||
public void push(long value) {
|
||||
if (value == 0L || value == 1L) {
|
||||
mv.visitInsn(TypeUtils.LCONST(value));
|
||||
} else {
|
||||
mv.visitLdcInsn(value);
|
||||
}
|
||||
}
|
||||
|
||||
public void push(float value) {
|
||||
if (value == 0f || value == 1f || value == 2f) {
|
||||
mv.visitInsn(TypeUtils.FCONST(value));
|
||||
} else {
|
||||
mv.visitLdcInsn(value);
|
||||
}
|
||||
}
|
||||
public void push(double value) {
|
||||
if (value == 0d || value == 1d) {
|
||||
mv.visitInsn(TypeUtils.DCONST(value));
|
||||
} else {
|
||||
mv.visitLdcInsn(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, false);
|
||||
}
|
||||
|
||||
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, boolean isInterface) {
|
||||
if (sig.getName().equals(Constants.CONSTRUCTOR_NAME) &&
|
||||
((opcode == Constants.INVOKEVIRTUAL) ||
|
||||
(opcode == Constants.INVOKESTATIC))) {
|
||||
// TODO: error
|
||||
}
|
||||
mv.visitMethodInsn(opcode,
|
||||
type.getInternalName(),
|
||||
sig.getName(),
|
||||
sig.getDescriptor(),
|
||||
isInterface);
|
||||
}
|
||||
|
||||
public void invoke_interface(Type owner, Signature sig) {
|
||||
emit_invoke(Constants.INVOKEINTERFACE, owner, sig, true);
|
||||
}
|
||||
|
||||
public void invoke_virtual(Type owner, Signature sig) {
|
||||
emit_invoke(Constants.INVOKEVIRTUAL, owner, sig, false);
|
||||
}
|
||||
|
||||
@Deprecated
|
||||
public void invoke_static(Type owner, Signature sig) {
|
||||
invoke_static(owner, sig, false);
|
||||
}
|
||||
|
||||
public void invoke_static(Type owner, Signature sig, boolean isInterface) {
|
||||
emit_invoke(Constants.INVOKESTATIC, owner, sig, isInterface);
|
||||
}
|
||||
|
||||
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, false);
|
||||
}
|
||||
|
||||
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.isStatic(method.getModifiers())) {
|
||||
invoke_static(type, sig, TypeUtils.isInterface(classInfo.getModifiers()));
|
||||
} else if (TypeUtils.isInterface(classInfo.getModifiers())) {
|
||||
invoke_interface(type, sig);
|
||||
} else {
|
||||
invoke_virtual(virtualType, sig);
|
||||
}
|
||||
}
|
||||
|
||||
public void invoke(MethodInfo method) {
|
||||
invoke(method, method.getClassInfo().getType());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.core;
|
||||
|
||||
/**
|
||||
* @version $Id: CodeGenerationException.java,v 1.3 2004/06/24 21:15:21 herbyderby Exp $
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class CodeGenerationException extends RuntimeException {
|
||||
private Throwable cause;
|
||||
|
||||
public CodeGenerationException(Throwable cause) {
|
||||
super(cause.getClass().getName() + "-->" + cause.getMessage());
|
||||
this.cause = cause;
|
||||
}
|
||||
|
||||
public Throwable getCause() {
|
||||
return cause;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
/*
|
||||
* Copyright 2003,2004 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.core;
|
||||
|
||||
import java.util.*;
|
||||
import java.lang.reflect.Array;
|
||||
|
||||
/**
|
||||
* @author Chris Nokleberg
|
||||
* @version $Id: CollectionUtils.java,v 1.7 2004/06/24 21:15:21 herbyderby Exp $
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
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 = 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(), index++);
|
||||
}
|
||||
return indexes;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.core;
|
||||
|
||||
import org.springframework.asm.Type;
|
||||
|
||||
/**
|
||||
* @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 $
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public interface Constants extends org.springframework.asm.Opcodes {
|
||||
|
||||
/* Indicates the ASM API version that is used throughout cglib */
|
||||
public static final int ASM_API = AsmApi.value();
|
||||
|
||||
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("org.springframework.cglib.core.Signature");
|
||||
public static final Type TYPE_TYPE = Type.getType(Type.class);
|
||||
|
||||
public static final String CONSTRUCTOR_NAME = "<init>";
|
||||
public static final String STATIC_NAME = "<clinit>";
|
||||
public static final String SOURCE_FILE = "<generated>";
|
||||
public static final String SUID_FIELD_NAME = "serialVersionUID";
|
||||
|
||||
public static final int PRIVATE_FINAL_STATIC = ACC_PRIVATE | ACC_FINAL | ACC_STATIC;
|
||||
|
||||
public static final int SWITCH_STYLE_TRIE = 0;
|
||||
public static final int SWITCH_STYLE_HASH = 1;
|
||||
public static final int SWITCH_STYLE_HASHONLY = 2;
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.core;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public interface Converter {
|
||||
Object convert(Object value, Class target, Object context);
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.core;
|
||||
|
||||
import org.springframework.asm.Type;
|
||||
|
||||
/**
|
||||
* Customizes key types for {@link KeyFactory} when building equals, hashCode, and toString.
|
||||
* For customization of field types, use {@link FieldTypeCustomizer}
|
||||
*
|
||||
* @see KeyFactory#CLASS_BY_NAME
|
||||
*/
|
||||
public interface Customizer extends KeyFactoryCustomizer {
|
||||
void customize(CodeEmitter e, Type type);
|
||||
}
|
|
@ -0,0 +1,108 @@
|
|||
/*
|
||||
* Copyright 2003,2004 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.core;
|
||||
|
||||
import org.springframework.asm.ClassWriter;
|
||||
import org.springframework.asm.ClassReader;
|
||||
import org.springframework.asm.ClassVisitor;
|
||||
import org.springframework.asm.Opcodes;
|
||||
|
||||
import java.io.*;
|
||||
import java.lang.reflect.Constructor;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
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("org.springframework.asm.util.TraceClassVisitor");
|
||||
traceCtor = clazz.getConstructor(new Class[]{ClassVisitor.class, PrintWriter.class});
|
||||
} catch (Throwable ignore) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public DebuggingClassWriter(int flags) {
|
||||
super(Constants.ASM_API, 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() {
|
||||
|
||||
byte[] b = ((ClassWriter) DebuggingClassWriter.super.cv).toByteArray();
|
||||
if (debugLocation != null) {
|
||||
String dirs = className.replace('.', File.separatorChar);
|
||||
try {
|
||||
new File(debugLocation + File.separatorChar + dirs).getParentFile().mkdirs();
|
||||
|
||||
File file = new File(new File(debugLocation), dirs + ".class");
|
||||
OutputStream out = new BufferedOutputStream(new FileOutputStream(file));
|
||||
try {
|
||||
out.write(b);
|
||||
} finally {
|
||||
out.close();
|
||||
}
|
||||
|
||||
if (traceCtor != null) {
|
||||
file = new File(new File(debugLocation), dirs + ".asm");
|
||||
out = new BufferedOutputStream(new FileOutputStream(file));
|
||||
try {
|
||||
ClassReader cr = new ClassReader(b);
|
||||
PrintWriter pw = new PrintWriter(new OutputStreamWriter(out));
|
||||
ClassVisitor tcv = (ClassVisitor)traceCtor.newInstance(new Object[]{null, pw});
|
||||
cr.accept(tcv, 0);
|
||||
pw.flush();
|
||||
} finally {
|
||||
out.close();
|
||||
}
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new CodeGenerationException(e);
|
||||
}
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.core;
|
||||
|
||||
import org.springframework.asm.ClassWriter;
|
||||
|
||||
public class DefaultGeneratorStrategy implements GeneratorStrategy {
|
||||
public static final DefaultGeneratorStrategy INSTANCE = new DefaultGeneratorStrategy();
|
||||
|
||||
public byte[] generate(ClassGenerator cg) throws Exception {
|
||||
DebuggingClassWriter cw = getClassVisitor();
|
||||
transform(cg).generateClass(cw);
|
||||
return transform(cw.toByteArray());
|
||||
}
|
||||
|
||||
protected DebuggingClassWriter getClassVisitor() throws Exception {
|
||||
return new DebuggingClassWriter(ClassWriter.COMPUTE_FRAMES);
|
||||
}
|
||||
|
||||
protected final ClassWriter getClassWriter() {
|
||||
// Cause compile / runtime errors for people who implemented the old
|
||||
// interface without using @Override
|
||||
throw new UnsupportedOperationException("You are calling " +
|
||||
"getClassWriter, which no longer exists in this cglib version.");
|
||||
}
|
||||
|
||||
protected byte[] transform(byte[] b) throws Exception {
|
||||
return b;
|
||||
}
|
||||
|
||||
protected ClassGenerator transform(ClassGenerator cg) throws Exception {
|
||||
return cg;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
* Copyright 2003,2004 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.core;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* The default policy used by {@link AbstractClassGenerator}.
|
||||
* Generates names such as
|
||||
* <p><code>org.springframework.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("org.springframework.cglib.test.stressHashCodes");
|
||||
|
||||
public String getClassName(String prefix, String source, Object key, Predicate names) {
|
||||
if (prefix == null) {
|
||||
prefix = "org.springframework.cglib.empty.Object";
|
||||
} else if (prefix.startsWith("java")) {
|
||||
prefix = "$" + prefix;
|
||||
}
|
||||
String base =
|
||||
prefix + "$$" +
|
||||
source.substring(source.lastIndexOf('.') + 1) +
|
||||
getTag() + "$$" +
|
||||
Integer.toHexString(STRESS_HASH_CODE ? 0 : key.hashCode());
|
||||
String attempt = base;
|
||||
int index = 2;
|
||||
while (names.evaluate(attempt))
|
||||
attempt = base + "_" + index++;
|
||||
return attempt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string which is incorporated into every generated class name.
|
||||
* By default returns "ByCGLIB"
|
||||
*/
|
||||
protected String getTag() {
|
||||
return "ByCGLIB";
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return getTag().hashCode();
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
return (o instanceof DefaultNamingPolicy) && ((DefaultNamingPolicy) o).getTag().equals(getTag());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,165 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.core;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.springframework.asm.ClassReader;
|
||||
import org.springframework.asm.ClassVisitor;
|
||||
import org.springframework.asm.MethodVisitor;
|
||||
import org.springframework.asm.Opcodes;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public class DuplicatesPredicate implements Predicate {
|
||||
private final Set unique;
|
||||
private final Set rejected;
|
||||
|
||||
/**
|
||||
* Constructs a DuplicatesPredicate that will allow subclass bridge methods to be preferred over
|
||||
* superclass non-bridge methods.
|
||||
*/
|
||||
public DuplicatesPredicate() {
|
||||
unique = new HashSet();
|
||||
rejected = Collections.emptySet();
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a DuplicatesPredicate that prefers using superclass non-bridge methods despite a
|
||||
* subclass method with the same signtaure existing (if the subclass is a bridge method).
|
||||
*/
|
||||
public DuplicatesPredicate(List allMethods) {
|
||||
rejected = new HashSet();
|
||||
unique = new HashSet();
|
||||
|
||||
// Traverse through the methods and capture ones that are bridge
|
||||
// methods when a subsequent method (from a non-interface superclass)
|
||||
// has the same signature but isn't a bridge. Record these so that
|
||||
// we avoid using them when filtering duplicates.
|
||||
Map scanned = new HashMap();
|
||||
Map suspects = new HashMap();
|
||||
for (Object o : allMethods) {
|
||||
Method method = (Method) o;
|
||||
Object sig = MethodWrapper.create(method);
|
||||
Method existing = (Method) scanned.get(sig);
|
||||
if (existing == null) {
|
||||
scanned.put(sig, method);
|
||||
} else if (!suspects.containsKey(sig) && existing.isBridge() && !method.isBridge()) {
|
||||
// TODO: this currently only will capture a single bridge. it will not work
|
||||
// if there's Child.bridge1 Middle.bridge2 Parent.concrete. (we'd offer the 2nd bridge).
|
||||
// no idea if that's even possible tho...
|
||||
suspects.put(sig, existing);
|
||||
}
|
||||
}
|
||||
|
||||
if (!suspects.isEmpty()) {
|
||||
Set classes = new HashSet();
|
||||
UnnecessaryBridgeFinder finder = new UnnecessaryBridgeFinder(rejected);
|
||||
for (Object o : suspects.values()) {
|
||||
Method m = (Method) o;
|
||||
classes.add(m.getDeclaringClass());
|
||||
finder.addSuspectMethod(m);
|
||||
}
|
||||
for (Object o : classes) {
|
||||
Class c = (Class) o;
|
||||
try {
|
||||
ClassLoader cl = getClassLoader(c);
|
||||
if (cl == null) {
|
||||
continue;
|
||||
}
|
||||
InputStream is = cl.getResourceAsStream(c.getName().replace('.', '/') + ".class");
|
||||
if (is == null) {
|
||||
continue;
|
||||
}
|
||||
try {
|
||||
new ClassReader(is).accept(finder, ClassReader.SKIP_FRAMES | ClassReader.SKIP_DEBUG);
|
||||
} finally {
|
||||
is.close();
|
||||
}
|
||||
} catch (IOException ignored) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public boolean evaluate(Object arg) {
|
||||
return !rejected.contains(arg) && unique.add(MethodWrapper.create((Method) arg));
|
||||
}
|
||||
|
||||
private static ClassLoader getClassLoader(Class c) {
|
||||
ClassLoader cl = c.getClassLoader();
|
||||
if (cl == null) {
|
||||
cl = DuplicatesPredicate.class.getClassLoader();
|
||||
}
|
||||
if (cl == null) {
|
||||
cl = Thread.currentThread().getContextClassLoader();
|
||||
}
|
||||
return cl;
|
||||
}
|
||||
|
||||
private static class UnnecessaryBridgeFinder extends ClassVisitor {
|
||||
private final Set rejected;
|
||||
|
||||
private Signature currentMethodSig = null;
|
||||
private Map methods = new HashMap();
|
||||
|
||||
UnnecessaryBridgeFinder(Set rejected) {
|
||||
super(Constants.ASM_API);
|
||||
this.rejected = rejected;
|
||||
}
|
||||
|
||||
void addSuspectMethod(Method m) {
|
||||
methods.put(ReflectUtils.getSignature(m), m);
|
||||
}
|
||||
|
||||
public void visit(
|
||||
int version,
|
||||
int access,
|
||||
String name,
|
||||
String signature,
|
||||
String superName,
|
||||
String[] interfaces) {}
|
||||
|
||||
public MethodVisitor visitMethod(
|
||||
int access, String name, String desc, String signature, String[] exceptions) {
|
||||
Signature sig = new Signature(name, desc);
|
||||
final Method currentMethod = (Method) methods.remove(sig);
|
||||
if (currentMethod != null) {
|
||||
currentMethodSig = sig;
|
||||
return new MethodVisitor(Constants.ASM_API) {
|
||||
public void visitMethodInsn(
|
||||
int opcode, String owner, String name, String desc, boolean itf) {
|
||||
if (opcode == Opcodes.INVOKESPECIAL && currentMethodSig != null) {
|
||||
Signature target = new Signature(name, desc);
|
||||
if (target.equals(currentMethodSig)) {
|
||||
rejected.add(currentMethod);
|
||||
}
|
||||
currentMethodSig = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,961 @@
|
|||
/*
|
||||
* Copyright 2003,2004 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.core;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.BigInteger;
|
||||
import java.util.*;
|
||||
|
||||
import org.springframework.cglib.core.internal.CustomizerRegistry;
|
||||
import org.springframework.asm.Label;
|
||||
import org.springframework.asm.Type;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked", "static", "fallthrough", "deprecation"})
|
||||
public class EmitUtils {
|
||||
private static final Signature CSTRUCT_NULL =
|
||||
TypeUtils.parseConstructor("");
|
||||
private static final Signature CSTRUCT_THROWABLE =
|
||||
TypeUtils.parseConstructor("Throwable");
|
||||
|
||||
private static final Signature GET_NAME =
|
||||
TypeUtils.parseSignature("String getName()");
|
||||
private static final Signature HASH_CODE =
|
||||
TypeUtils.parseSignature("int hashCode()");
|
||||
private static final Signature EQUALS =
|
||||
TypeUtils.parseSignature("boolean equals(Object)");
|
||||
private static final Signature STRING_LENGTH =
|
||||
TypeUtils.parseSignature("int length()");
|
||||
private static final Signature STRING_CHAR_AT =
|
||||
TypeUtils.parseSignature("char charAt(int)");
|
||||
private static final Signature FOR_NAME =
|
||||
TypeUtils.parseSignature("Class forName(String)");
|
||||
private static final Signature DOUBLE_TO_LONG_BITS =
|
||||
TypeUtils.parseSignature("long doubleToLongBits(double)");
|
||||
private static final Signature FLOAT_TO_INT_BITS =
|
||||
TypeUtils.parseSignature("int floatToIntBits(float)");
|
||||
private static final Signature TO_STRING =
|
||||
TypeUtils.parseSignature("String toString()");
|
||||
private static final Signature APPEND_STRING =
|
||||
TypeUtils.parseSignature("StringBuffer append(String)");
|
||||
private static final Signature APPEND_INT =
|
||||
TypeUtils.parseSignature("StringBuffer append(int)");
|
||||
private static final Signature APPEND_DOUBLE =
|
||||
TypeUtils.parseSignature("StringBuffer append(double)");
|
||||
private static final Signature APPEND_FLOAT =
|
||||
TypeUtils.parseSignature("StringBuffer append(float)");
|
||||
private static final Signature APPEND_CHAR =
|
||||
TypeUtils.parseSignature("StringBuffer append(char)");
|
||||
private static final Signature APPEND_LONG =
|
||||
TypeUtils.parseSignature("StringBuffer append(long)");
|
||||
private static final Signature APPEND_BOOLEAN =
|
||||
TypeUtils.parseSignature("StringBuffer append(boolean)");
|
||||
private static final Signature LENGTH =
|
||||
TypeUtils.parseSignature("int length()");
|
||||
private static final Signature SET_LENGTH =
|
||||
TypeUtils.parseSignature("void setLength(int)");
|
||||
private static final Signature GET_DECLARED_METHOD =
|
||||
TypeUtils.parseSignature("java.lang.reflect.Method getDeclaredMethod(String, Class[])");
|
||||
|
||||
|
||||
|
||||
public static final ArrayDelimiters DEFAULT_DELIMITERS = new ArrayDelimiters("{", ", ", "}");
|
||||
|
||||
private EmitUtils() {
|
||||
}
|
||||
|
||||
public static void factory_method(ClassEmitter ce, Signature sig) {
|
||||
CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, sig, null);
|
||||
e.new_instance_this();
|
||||
e.dup();
|
||||
e.load_args();
|
||||
e.invoke_constructor_this(TypeUtils.parseConstructor(sig.getArgumentTypes()));
|
||||
e.return_value();
|
||||
e.end_method();
|
||||
}
|
||||
|
||||
public static void null_constructor(ClassEmitter ce) {
|
||||
CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, CSTRUCT_NULL, null);
|
||||
e.load_this();
|
||||
e.super_invoke_constructor();
|
||||
e.return_value();
|
||||
e.end_method();
|
||||
}
|
||||
|
||||
/**
|
||||
* Process an array on the stack. Assumes the top item on the stack
|
||||
* is an array of the specified type. For each element in the array,
|
||||
* puts the element on the stack and triggers the callback.
|
||||
* @param type the type of the array (type.isArray() must be true)
|
||||
* @param callback the callback triggered for each element
|
||||
*/
|
||||
public static void process_array(CodeEmitter e, Type type, ProcessArrayCallback callback) {
|
||||
Type componentType = TypeUtils.getComponentType(type);
|
||||
Local array = e.make_local();
|
||||
Local loopvar = e.make_local(Type.INT_TYPE);
|
||||
Label loopbody = e.make_label();
|
||||
Label checkloop = e.make_label();
|
||||
e.store_local(array);
|
||||
e.push(0);
|
||||
e.store_local(loopvar);
|
||||
e.goTo(checkloop);
|
||||
|
||||
e.mark(loopbody);
|
||||
e.load_local(array);
|
||||
e.load_local(loopvar);
|
||||
e.array_load(componentType);
|
||||
callback.processElement(componentType);
|
||||
e.iinc(loopvar, 1);
|
||||
|
||||
e.mark(checkloop);
|
||||
e.load_local(loopvar);
|
||||
e.load_local(array);
|
||||
e.arraylength();
|
||||
e.if_icmp(e.LT, loopbody);
|
||||
}
|
||||
|
||||
/**
|
||||
* Process two arrays on the stack in parallel. Assumes the top two items on the stack
|
||||
* are arrays of the specified class. The arrays must be the same length. For each pair
|
||||
* of elements in the arrays, puts the pair on the stack and triggers the callback.
|
||||
* @param type the type of the arrays (type.isArray() must be true)
|
||||
* @param callback the callback triggered for each pair of elements
|
||||
*/
|
||||
public static void process_arrays(CodeEmitter e, Type type, ProcessArrayCallback callback) {
|
||||
Type componentType = TypeUtils.getComponentType(type);
|
||||
Local array1 = e.make_local();
|
||||
Local array2 = e.make_local();
|
||||
Local loopvar = e.make_local(Type.INT_TYPE);
|
||||
Label loopbody = e.make_label();
|
||||
Label checkloop = e.make_label();
|
||||
e.store_local(array1);
|
||||
e.store_local(array2);
|
||||
e.push(0);
|
||||
e.store_local(loopvar);
|
||||
e.goTo(checkloop);
|
||||
|
||||
e.mark(loopbody);
|
||||
e.load_local(array1);
|
||||
e.load_local(loopvar);
|
||||
e.array_load(componentType);
|
||||
e.load_local(array2);
|
||||
e.load_local(loopvar);
|
||||
e.array_load(componentType);
|
||||
callback.processElement(componentType);
|
||||
e.iinc(loopvar, 1);
|
||||
|
||||
e.mark(checkloop);
|
||||
e.load_local(loopvar);
|
||||
e.load_local(array1);
|
||||
e.arraylength();
|
||||
e.if_icmp(e.LT, loopbody);
|
||||
}
|
||||
|
||||
public static void string_switch(CodeEmitter e, String[] strings, int switchStyle, ObjectSwitchCallback callback) {
|
||||
try {
|
||||
switch (switchStyle) {
|
||||
case Constants.SWITCH_STYLE_TRIE:
|
||||
string_switch_trie(e, strings, callback);
|
||||
break;
|
||||
case Constants.SWITCH_STYLE_HASH:
|
||||
string_switch_hash(e, strings, callback, false);
|
||||
break;
|
||||
case Constants.SWITCH_STYLE_HASHONLY:
|
||||
string_switch_hash(e, strings, callback, true);
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("unknown switch style " + switchStyle);
|
||||
}
|
||||
} catch (RuntimeException ex) {
|
||||
throw ex;
|
||||
} catch (Error ex) {
|
||||
throw ex;
|
||||
} catch (Exception ex) {
|
||||
throw new CodeGenerationException(ex);
|
||||
}
|
||||
}
|
||||
|
||||
private static void string_switch_trie(final CodeEmitter e,
|
||||
String[] strings,
|
||||
final ObjectSwitchCallback callback) throws Exception {
|
||||
final Label def = e.make_label();
|
||||
final Label end = e.make_label();
|
||||
final Map buckets = CollectionUtils.bucket(Arrays.asList(strings), new Transformer() {
|
||||
public Object transform(Object value) {
|
||||
return ((String)value).length();
|
||||
}
|
||||
});
|
||||
e.dup();
|
||||
e.invoke_virtual(Constants.TYPE_STRING, STRING_LENGTH);
|
||||
e.process_switch(getSwitchKeys(buckets), new ProcessSwitchCallback() {
|
||||
public void processCase(int key, Label ignore_end) throws Exception {
|
||||
List bucket = (List)buckets.get(key);
|
||||
stringSwitchHelper(e, bucket, callback, def, end, 0);
|
||||
}
|
||||
public void processDefault() {
|
||||
e.goTo(def);
|
||||
}
|
||||
});
|
||||
e.mark(def);
|
||||
e.pop();
|
||||
callback.processDefault();
|
||||
e.mark(end);
|
||||
}
|
||||
|
||||
private static void stringSwitchHelper(final CodeEmitter e,
|
||||
List strings,
|
||||
final ObjectSwitchCallback callback,
|
||||
final Label def,
|
||||
final Label end,
|
||||
final int index) throws Exception {
|
||||
final int len = ((String)strings.get(0)).length();
|
||||
final Map buckets = CollectionUtils.bucket(strings, new Transformer() {
|
||||
public Object transform(Object value) {
|
||||
return ((String)value).charAt(index);
|
||||
}
|
||||
});
|
||||
e.dup();
|
||||
e.push(index);
|
||||
e.invoke_virtual(Constants.TYPE_STRING, STRING_CHAR_AT);
|
||||
e.process_switch(getSwitchKeys(buckets), new ProcessSwitchCallback() {
|
||||
public void processCase(int key, Label ignore_end) throws Exception {
|
||||
List bucket = (List)buckets.get(key);
|
||||
if (index + 1 == len) {
|
||||
e.pop();
|
||||
callback.processCase(bucket.get(0), end);
|
||||
} else {
|
||||
stringSwitchHelper(e, bucket, callback, def, end, index + 1);
|
||||
}
|
||||
}
|
||||
public void processDefault() {
|
||||
e.goTo(def);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
static int[] getSwitchKeys(Map buckets) {
|
||||
int[] keys = new int[buckets.size()];
|
||||
int index = 0;
|
||||
for (Iterator it = buckets.keySet().iterator(); it.hasNext();) {
|
||||
keys[index++] = ((Integer)it.next());
|
||||
}
|
||||
Arrays.sort(keys);
|
||||
return keys;
|
||||
}
|
||||
|
||||
private static void string_switch_hash(final CodeEmitter e,
|
||||
final String[] strings,
|
||||
final ObjectSwitchCallback callback,
|
||||
final boolean skipEquals) throws Exception {
|
||||
final Map buckets = CollectionUtils.bucket(Arrays.asList(strings), new Transformer() {
|
||||
public Object transform(Object value) {
|
||||
return value.hashCode();
|
||||
}
|
||||
});
|
||||
final Label def = e.make_label();
|
||||
final Label end = e.make_label();
|
||||
e.dup();
|
||||
e.invoke_virtual(Constants.TYPE_OBJECT, HASH_CODE);
|
||||
e.process_switch(getSwitchKeys(buckets), new ProcessSwitchCallback() {
|
||||
public void processCase(int key, Label ignore_end) throws Exception {
|
||||
List bucket = (List)buckets.get(key);
|
||||
Label next = null;
|
||||
if (skipEquals && bucket.size() == 1) {
|
||||
if (skipEquals)
|
||||
e.pop();
|
||||
callback.processCase((String)bucket.get(0), end);
|
||||
} else {
|
||||
for (Iterator it = bucket.iterator(); it.hasNext();) {
|
||||
String string = (String)it.next();
|
||||
if (next != null) {
|
||||
e.mark(next);
|
||||
}
|
||||
if (it.hasNext()) {
|
||||
e.dup();
|
||||
}
|
||||
e.push(string);
|
||||
e.invoke_virtual(Constants.TYPE_OBJECT, EQUALS);
|
||||
if (it.hasNext()) {
|
||||
e.if_jump(e.EQ, next = e.make_label());
|
||||
e.pop();
|
||||
} else {
|
||||
e.if_jump(e.EQ, def);
|
||||
}
|
||||
callback.processCase(string, end);
|
||||
}
|
||||
}
|
||||
}
|
||||
public void processDefault() {
|
||||
e.pop();
|
||||
}
|
||||
});
|
||||
e.mark(def);
|
||||
callback.processDefault();
|
||||
e.mark(end);
|
||||
}
|
||||
|
||||
public static void load_class_this(CodeEmitter e) {
|
||||
load_class_helper(e, e.getClassEmitter().getClassType());
|
||||
}
|
||||
|
||||
public static void load_class(CodeEmitter e, Type type) {
|
||||
if (TypeUtils.isPrimitive(type)) {
|
||||
if (type == Type.VOID_TYPE) {
|
||||
throw new IllegalArgumentException("cannot load void type");
|
||||
}
|
||||
e.getstatic(TypeUtils.getBoxedType(type), "TYPE", Constants.TYPE_CLASS);
|
||||
} else {
|
||||
load_class_helper(e, type);
|
||||
}
|
||||
}
|
||||
|
||||
private static void load_class_helper(CodeEmitter e, final Type type) {
|
||||
if (e.isStaticHook()) {
|
||||
// have to fall back on non-optimized load
|
||||
e.push(TypeUtils.emulateClassGetName(type));
|
||||
e.invoke_static(Constants.TYPE_CLASS, FOR_NAME);
|
||||
} else {
|
||||
ClassEmitter ce = e.getClassEmitter();
|
||||
String typeName = TypeUtils.emulateClassGetName(type);
|
||||
|
||||
// TODO: can end up with duplicated field names when using chained transformers; incorporate static hook # somehow
|
||||
String fieldName = "CGLIB$load_class$" + TypeUtils.escapeType(typeName);
|
||||
if (!ce.isFieldDeclared(fieldName)) {
|
||||
ce.declare_field(Constants.PRIVATE_FINAL_STATIC, fieldName, Constants.TYPE_CLASS, null);
|
||||
CodeEmitter hook = ce.getStaticHook();
|
||||
hook.push(typeName);
|
||||
hook.invoke_static(Constants.TYPE_CLASS, FOR_NAME);
|
||||
hook.putstatic(ce.getClassType(), fieldName, Constants.TYPE_CLASS);
|
||||
}
|
||||
e.getfield(fieldName);
|
||||
}
|
||||
}
|
||||
|
||||
public static void push_array(CodeEmitter e, Object[] array) {
|
||||
e.push(array.length);
|
||||
e.newarray(Type.getType(remapComponentType(array.getClass().getComponentType())));
|
||||
for (int i = 0; i < array.length; i++) {
|
||||
e.dup();
|
||||
e.push(i);
|
||||
push_object(e, array[i]);
|
||||
e.aastore();
|
||||
}
|
||||
}
|
||||
|
||||
private static Class remapComponentType(Class componentType) {
|
||||
if (componentType.equals(Type.class))
|
||||
return Class.class;
|
||||
return componentType;
|
||||
}
|
||||
|
||||
public static void push_object(CodeEmitter e, Object obj) {
|
||||
if (obj == null) {
|
||||
e.aconst_null();
|
||||
} else {
|
||||
Class type = obj.getClass();
|
||||
if (type.isArray()) {
|
||||
push_array(e, (Object[])obj);
|
||||
} else if (obj instanceof String) {
|
||||
e.push((String)obj);
|
||||
} else if (obj instanceof Type) {
|
||||
load_class(e, (Type)obj);
|
||||
} else if (obj instanceof Class) {
|
||||
load_class(e, Type.getType((Class)obj));
|
||||
} else if (obj instanceof BigInteger) {
|
||||
e.new_instance(Constants.TYPE_BIG_INTEGER);
|
||||
e.dup();
|
||||
e.push(obj.toString());
|
||||
e.invoke_constructor(Constants.TYPE_BIG_INTEGER);
|
||||
} else if (obj instanceof BigDecimal) {
|
||||
e.new_instance(Constants.TYPE_BIG_DECIMAL);
|
||||
e.dup();
|
||||
e.push(obj.toString());
|
||||
e.invoke_constructor(Constants.TYPE_BIG_DECIMAL);
|
||||
} else {
|
||||
throw new IllegalArgumentException("unknown type: " + obj.getClass());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated use {@link #hash_code(CodeEmitter, Type, int, CustomizerRegistry)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public static void hash_code(CodeEmitter e, Type type, int multiplier, final Customizer customizer) {
|
||||
hash_code(e, type, multiplier, CustomizerRegistry.singleton(customizer));
|
||||
}
|
||||
|
||||
public static void hash_code(CodeEmitter e, Type type, int multiplier, final CustomizerRegistry registry) {
|
||||
if (TypeUtils.isArray(type)) {
|
||||
hash_array(e, type, multiplier, registry);
|
||||
} else {
|
||||
e.swap(Type.INT_TYPE, type);
|
||||
e.push(multiplier);
|
||||
e.math(e.MUL, Type.INT_TYPE);
|
||||
e.swap(type, Type.INT_TYPE);
|
||||
if (TypeUtils.isPrimitive(type)) {
|
||||
hash_primitive(e, type);
|
||||
} else {
|
||||
hash_object(e, type, registry);
|
||||
}
|
||||
e.math(e.ADD, Type.INT_TYPE);
|
||||
}
|
||||
}
|
||||
|
||||
private static void hash_array(final CodeEmitter e, Type type, final int multiplier, final CustomizerRegistry registry) {
|
||||
Label skip = e.make_label();
|
||||
Label end = e.make_label();
|
||||
e.dup();
|
||||
e.ifnull(skip);
|
||||
EmitUtils.process_array(e, type, new ProcessArrayCallback() {
|
||||
public void processElement(Type type) {
|
||||
hash_code(e, type, multiplier, registry);
|
||||
}
|
||||
});
|
||||
e.goTo(end);
|
||||
e.mark(skip);
|
||||
e.pop();
|
||||
e.mark(end);
|
||||
}
|
||||
|
||||
private static void hash_object(CodeEmitter e, Type type, CustomizerRegistry registry) {
|
||||
// (f == null) ? 0 : f.hashCode();
|
||||
Label skip = e.make_label();
|
||||
Label end = e.make_label();
|
||||
e.dup();
|
||||
e.ifnull(skip);
|
||||
boolean customHashCode = false;
|
||||
for (HashCodeCustomizer customizer : registry.get(HashCodeCustomizer.class)) {
|
||||
if (customizer.customize(e, type)) {
|
||||
customHashCode = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!customHashCode) {
|
||||
for (Customizer customizer : registry.get(Customizer.class)) {
|
||||
customizer.customize(e, type);
|
||||
}
|
||||
e.invoke_virtual(Constants.TYPE_OBJECT, HASH_CODE);
|
||||
}
|
||||
e.goTo(end);
|
||||
e.mark(skip);
|
||||
e.pop();
|
||||
e.push(0);
|
||||
e.mark(end);
|
||||
}
|
||||
|
||||
private static void hash_primitive(CodeEmitter e, Type type) {
|
||||
switch (type.getSort()) {
|
||||
case Type.BOOLEAN:
|
||||
// f ? 0 : 1
|
||||
e.push(1);
|
||||
e.math(e.XOR, Type.INT_TYPE);
|
||||
break;
|
||||
case Type.FLOAT:
|
||||
// Float.floatToIntBits(f)
|
||||
e.invoke_static(Constants.TYPE_FLOAT, FLOAT_TO_INT_BITS);
|
||||
break;
|
||||
case Type.DOUBLE:
|
||||
// Double.doubleToLongBits(f), hash_code(Long.TYPE)
|
||||
e.invoke_static(Constants.TYPE_DOUBLE, DOUBLE_TO_LONG_BITS);
|
||||
// fall through
|
||||
case Type.LONG:
|
||||
hash_long(e);
|
||||
}
|
||||
}
|
||||
|
||||
private static void hash_long(CodeEmitter e) {
|
||||
// (int)(f ^ (f >>> 32))
|
||||
e.dup2();
|
||||
e.push(32);
|
||||
e.math(e.USHR, Type.LONG_TYPE);
|
||||
e.math(e.XOR, Type.LONG_TYPE);
|
||||
e.cast_numeric(Type.LONG_TYPE, Type.INT_TYPE);
|
||||
}
|
||||
|
||||
// public static void not_equals(CodeEmitter e, Type type, Label notEquals) {
|
||||
// not_equals(e, type, notEquals, null);
|
||||
// }
|
||||
|
||||
/**
|
||||
* @deprecated use {@link #not_equals(CodeEmitter, Type, Label, CustomizerRegistry)} instead
|
||||
*/
|
||||
@Deprecated
|
||||
public static void not_equals(CodeEmitter e, Type type, final Label notEquals, final Customizer customizer) {
|
||||
not_equals(e, type, notEquals, CustomizerRegistry.singleton(customizer));
|
||||
}
|
||||
|
||||
/**
|
||||
* Branches to the specified label if the top two items on the stack
|
||||
* are not equal. The items must both be of the specified
|
||||
* class. Equality is determined by comparing primitive values
|
||||
* directly and by invoking the <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 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(key);
|
||||
member_helper_type(e, bucket, callback, typer, def, end, new BitSet());
|
||||
}
|
||||
public void processDefault() throws Exception {
|
||||
e.goTo(def);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private static void member_helper_type(final CodeEmitter e,
|
||||
List members,
|
||||
final ObjectSwitchCallback callback,
|
||||
final ParameterTyper typer,
|
||||
final Label def,
|
||||
final Label end,
|
||||
final BitSet checked) throws Exception {
|
||||
if (members.size() == 1) {
|
||||
MethodInfo member = (MethodInfo)members.get(0);
|
||||
Type[] types = typer.getParameterTypes(member);
|
||||
// need to check classes that have not already been checked via switches
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
if (checked == null || !checked.get(i)) {
|
||||
e.dup();
|
||||
e.aaload(i);
|
||||
e.invoke_virtual(Constants.TYPE_CLASS, GET_NAME);
|
||||
e.push(TypeUtils.emulateClassGetName(types[i]));
|
||||
e.invoke_virtual(Constants.TYPE_OBJECT, EQUALS);
|
||||
e.if_jump(e.EQ, def);
|
||||
}
|
||||
}
|
||||
e.pop();
|
||||
callback.processCase(member, end);
|
||||
} else {
|
||||
// choose the index that has the best chance of uniquely identifying member
|
||||
Type[] example = typer.getParameterTypes((MethodInfo)members.get(0));
|
||||
Map buckets = null;
|
||||
int index = -1;
|
||||
for (int i = 0; i < example.length; i++) {
|
||||
final int j = i;
|
||||
Map test = CollectionUtils.bucket(members, new Transformer() {
|
||||
public Object transform(Object value) {
|
||||
return TypeUtils.emulateClassGetName(typer.getParameterTypes((MethodInfo)value)[j]);
|
||||
}
|
||||
});
|
||||
if (buckets == null || test.size() > buckets.size()) {
|
||||
buckets = test;
|
||||
index = i;
|
||||
}
|
||||
}
|
||||
if (buckets == null || buckets.size() == 1) {
|
||||
// TODO: switch by returnType
|
||||
// must have two methods with same name, types, and different return types
|
||||
e.goTo(def);
|
||||
} else {
|
||||
checked.set(index);
|
||||
|
||||
e.dup();
|
||||
e.aaload(index);
|
||||
e.invoke_virtual(Constants.TYPE_CLASS, GET_NAME);
|
||||
|
||||
final Map fbuckets = buckets;
|
||||
String[] names = (String[])buckets.keySet().toArray(new String[buckets.size()]);
|
||||
EmitUtils.string_switch(e, names, Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() {
|
||||
public void processCase(Object key, Label dontUseEnd) throws Exception {
|
||||
member_helper_type(e, (List)fbuckets.get(key), callback, typer, def, end, checked);
|
||||
}
|
||||
public void processDefault() throws Exception {
|
||||
e.goTo(def);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void wrap_throwable(Block block, Type wrapper) {
|
||||
CodeEmitter e = block.getCodeEmitter();
|
||||
e.catch_exception(block, Constants.TYPE_THROWABLE);
|
||||
e.new_instance(wrapper);
|
||||
e.dup_x1();
|
||||
e.swap();
|
||||
e.invoke_constructor(wrapper, CSTRUCT_THROWABLE);
|
||||
e.athrow();
|
||||
}
|
||||
|
||||
public static void add_properties(ClassEmitter ce, String[] names, Type[] types) {
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
String fieldName = "$cglib_prop_" + names[i];
|
||||
ce.declare_field(Constants.ACC_PRIVATE, fieldName, types[i], null);
|
||||
EmitUtils.add_property(ce, names[i], types[i], fieldName);
|
||||
}
|
||||
}
|
||||
|
||||
public static void add_property(ClassEmitter ce, String name, Type type, String fieldName) {
|
||||
String property = TypeUtils.upperFirst(name);
|
||||
CodeEmitter e;
|
||||
e = ce.begin_method(Constants.ACC_PUBLIC,
|
||||
new Signature("get" + property,
|
||||
type,
|
||||
Constants.TYPES_EMPTY),
|
||||
null);
|
||||
e.load_this();
|
||||
e.getfield(fieldName);
|
||||
e.return_value();
|
||||
e.end_method();
|
||||
|
||||
e = ce.begin_method(Constants.ACC_PUBLIC,
|
||||
new Signature("set" + property,
|
||||
Type.VOID_TYPE,
|
||||
new Type[]{ type }),
|
||||
null);
|
||||
e.load_this();
|
||||
e.load_arg(0);
|
||||
e.putfield(fieldName);
|
||||
e.return_value();
|
||||
e.end_method();
|
||||
}
|
||||
|
||||
/* generates:
|
||||
} catch (RuntimeException e) {
|
||||
throw e;
|
||||
} catch (Error e) {
|
||||
throw e;
|
||||
} catch (<DeclaredException> e) {
|
||||
throw e;
|
||||
} catch (Throwable e) {
|
||||
throw new <Wrapper>(e);
|
||||
}
|
||||
*/
|
||||
public static void wrap_undeclared_throwable(CodeEmitter e, Block handler, Type[] exceptions, Type wrapper) {
|
||||
Set set = (exceptions == null) ? Collections.EMPTY_SET : new HashSet(Arrays.asList(exceptions));
|
||||
|
||||
if (set.contains(Constants.TYPE_THROWABLE))
|
||||
return;
|
||||
|
||||
boolean needThrow = exceptions != null;
|
||||
if (!set.contains(Constants.TYPE_RUNTIME_EXCEPTION)) {
|
||||
e.catch_exception(handler, Constants.TYPE_RUNTIME_EXCEPTION);
|
||||
needThrow = true;
|
||||
}
|
||||
if (!set.contains(Constants.TYPE_ERROR)) {
|
||||
e.catch_exception(handler, Constants.TYPE_ERROR);
|
||||
needThrow = true;
|
||||
}
|
||||
if (exceptions != null) {
|
||||
for (int i = 0; i < exceptions.length; i++) {
|
||||
e.catch_exception(handler, exceptions[i]);
|
||||
}
|
||||
}
|
||||
if (needThrow) {
|
||||
e.athrow();
|
||||
}
|
||||
// e -> eo -> oeo -> ooe -> o
|
||||
e.catch_exception(handler, Constants.TYPE_THROWABLE);
|
||||
e.new_instance(wrapper);
|
||||
e.dup_x1();
|
||||
e.swap();
|
||||
e.invoke_constructor(wrapper, CSTRUCT_THROWABLE);
|
||||
e.athrow();
|
||||
}
|
||||
|
||||
public static CodeEmitter begin_method(ClassEmitter e, MethodInfo method) {
|
||||
return begin_method(e, method, method.getModifiers());
|
||||
}
|
||||
|
||||
public static CodeEmitter begin_method(ClassEmitter e, MethodInfo method, int access) {
|
||||
return e.begin_method(access,
|
||||
method.getSignature(),
|
||||
method.getExceptionTypes());
|
||||
}
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
package org.springframework.cglib.core;
|
||||
|
||||
import org.springframework.asm.Type;
|
||||
|
||||
/**
|
||||
* Customizes key types for {@link KeyFactory} right in constructor.
|
||||
*/
|
||||
public interface FieldTypeCustomizer extends KeyFactoryCustomizer {
|
||||
/**
|
||||
* Customizes {@code this.FIELD_0 = ?} assignment in key constructor
|
||||
* @param e code emitter
|
||||
* @param index parameter index
|
||||
* @param type parameter type
|
||||
*/
|
||||
void customize(CodeEmitter e, int index, Type type);
|
||||
|
||||
/**
|
||||
* Computes type of field for storing given parameter
|
||||
* @param index parameter index
|
||||
* @param type parameter type
|
||||
*/
|
||||
Type getOutType(int index, Type type);
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.core;
|
||||
|
||||
/**
|
||||
* The <code>GeneratorStrategy</code. is responsible for taking a
|
||||
* {@link ClassGenerator} and producing a byte array containing the
|
||||
* data for the generated <code>Class</code>. By providing your
|
||||
* own strategy you may examine or modify the generated class before
|
||||
* it is loaded. Typically this will be accomplished by subclassing
|
||||
* {@link DefaultGeneratorStrategy} and overriding the appropriate
|
||||
* protected method.
|
||||
* @see AbstractClassGenerator#setStrategy
|
||||
*/
|
||||
public interface GeneratorStrategy {
|
||||
/**
|
||||
* Generate the class.
|
||||
* @param cg a class generator on which you can call {@link ClassGenerator#generateClass}
|
||||
* @return a byte array containing the bits of a valid Class
|
||||
*/
|
||||
byte[] generate(ClassGenerator cg) throws Exception;
|
||||
|
||||
/**
|
||||
* The <code>GeneratorStrategy</code> in use does not currently, but may
|
||||
* in the future, affect the caching of classes generated by {@link
|
||||
* AbstractClassGenerator}, so this is a reminder that you should
|
||||
* correctly implement <code>equals</code> and <code>hashCode</code>
|
||||
* to avoid generating too many classes.
|
||||
*/
|
||||
boolean equals(Object o);
|
||||
}
|
|
@ -0,0 +1,12 @@
|
|||
package org.springframework.cglib.core;
|
||||
|
||||
import org.springframework.asm.Type;
|
||||
|
||||
public interface HashCodeCustomizer extends KeyFactoryCustomizer {
|
||||
/**
|
||||
* Customizes calculation of hashcode
|
||||
* @param e code emitter
|
||||
* @param type parameter type
|
||||
*/
|
||||
boolean customize(CodeEmitter e, Type type);
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package org.springframework.cglib.core;
|
||||
|
||||
/**
|
||||
* Marker interface for customizers of {@link KeyFactory}
|
||||
*/
|
||||
public interface KeyFactoryCustomizer {
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.core;
|
||||
|
||||
import org.springframework.asm.Type;
|
||||
|
||||
public class Local
|
||||
{
|
||||
private Type type;
|
||||
private int index;
|
||||
|
||||
public Local(int index, Type type) {
|
||||
this.type = type;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
public Type getType() {
|
||||
return type;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,158 @@
|
|||
/***
|
||||
* ASM: a very small and fast Java bytecode manipulation framework
|
||||
* Copyright (c) 2000-2005 INRIA, France Telecom
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of the copyright holders nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
|
||||
* THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
package org.springframework.cglib.core;
|
||||
|
||||
import org.springframework.asm.Label;
|
||||
import org.springframework.asm.MethodVisitor;
|
||||
import org.springframework.asm.Opcodes;
|
||||
import org.springframework.asm.Type;
|
||||
|
||||
/**
|
||||
* A {@link MethodVisitor} that renumbers local variables in their order of
|
||||
* appearance. This adapter allows one to easily add new local variables to a
|
||||
* method.
|
||||
*
|
||||
* @author Chris Nokleberg
|
||||
* @author Eric Bruneton
|
||||
*/
|
||||
public class LocalVariablesSorter extends MethodVisitor {
|
||||
|
||||
/**
|
||||
* Mapping from old to new local variable indexes. A local variable at index
|
||||
* i of size 1 is remapped to 'mapping[2*i]', while a local variable at
|
||||
* index i of size 2 is remapped to 'mapping[2*i+1]'.
|
||||
*/
|
||||
private static class State
|
||||
{
|
||||
int[] mapping = new int[40];
|
||||
int nextLocal;
|
||||
}
|
||||
|
||||
protected final int firstLocal;
|
||||
private final State state;
|
||||
|
||||
public LocalVariablesSorter(
|
||||
final int access,
|
||||
final String desc,
|
||||
final MethodVisitor mv)
|
||||
{
|
||||
super(Constants.ASM_API, mv);
|
||||
state = new State();
|
||||
Type[] args = Type.getArgumentTypes(desc);
|
||||
state.nextLocal = ((Opcodes.ACC_STATIC & access) != 0) ? 0 : 1;
|
||||
for (int i = 0; i < args.length; i++) {
|
||||
state.nextLocal += args[i].getSize();
|
||||
}
|
||||
firstLocal = state.nextLocal;
|
||||
}
|
||||
|
||||
public LocalVariablesSorter(LocalVariablesSorter lvs) {
|
||||
super(Constants.ASM_API, lvs.mv);
|
||||
state = lvs.state;
|
||||
firstLocal = lvs.firstLocal;
|
||||
}
|
||||
|
||||
public void visitVarInsn(final int opcode, final int var) {
|
||||
int size;
|
||||
switch (opcode) {
|
||||
case Opcodes.LLOAD:
|
||||
case Opcodes.LSTORE:
|
||||
case Opcodes.DLOAD:
|
||||
case Opcodes.DSTORE:
|
||||
size = 2;
|
||||
break;
|
||||
default:
|
||||
size = 1;
|
||||
}
|
||||
mv.visitVarInsn(opcode, remap(var, size));
|
||||
}
|
||||
|
||||
public void visitIincInsn(final int var, final int increment) {
|
||||
mv.visitIincInsn(remap(var, 1), increment);
|
||||
}
|
||||
|
||||
public void visitMaxs(final int maxStack, final int maxLocals) {
|
||||
mv.visitMaxs(maxStack, state.nextLocal);
|
||||
}
|
||||
|
||||
public void visitLocalVariable(
|
||||
final String name,
|
||||
final String desc,
|
||||
final String signature,
|
||||
final Label start,
|
||||
final Label end,
|
||||
final int index)
|
||||
{
|
||||
mv.visitLocalVariable(name, desc, signature, start, end, remap(index));
|
||||
}
|
||||
|
||||
// -------------
|
||||
|
||||
protected int newLocal(final int size) {
|
||||
int var = state.nextLocal;
|
||||
state.nextLocal += size;
|
||||
return var;
|
||||
}
|
||||
|
||||
private int remap(final int var, final int size) {
|
||||
if (var < firstLocal) {
|
||||
return var;
|
||||
}
|
||||
int key = 2 * var + size - 1;
|
||||
int length = state.mapping.length;
|
||||
if (key >= length) {
|
||||
int[] newMapping = new int[Math.max(2 * length, key + 1)];
|
||||
System.arraycopy(state.mapping, 0, newMapping, 0, length);
|
||||
state.mapping = newMapping;
|
||||
}
|
||||
int value = state.mapping[key];
|
||||
if (value == 0) {
|
||||
value = state.nextLocal + 1;
|
||||
state.mapping[key] = value;
|
||||
state.nextLocal += size;
|
||||
}
|
||||
return value - 1;
|
||||
}
|
||||
|
||||
private int remap(final int var) {
|
||||
if (var < firstLocal) {
|
||||
return var;
|
||||
}
|
||||
int key = 2 * var;
|
||||
int value = key < state.mapping.length ? state.mapping[key] : 0;
|
||||
if (value == 0) {
|
||||
value = key + 1 < state.mapping.length ? state.mapping[key + 1] : 0;
|
||||
}
|
||||
if (value == 0) {
|
||||
throw new IllegalStateException("Unknown local variable " + var);
|
||||
}
|
||||
return value - 1;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright 2004 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.core;
|
||||
|
||||
import org.springframework.asm.Attribute;
|
||||
import org.springframework.asm.Type;
|
||||
|
||||
abstract public class MethodInfo {
|
||||
|
||||
protected MethodInfo() {
|
||||
}
|
||||
|
||||
abstract public ClassInfo getClassInfo();
|
||||
abstract public int getModifiers();
|
||||
abstract public Signature getSignature();
|
||||
abstract public Type[] getExceptionTypes();
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (o == null)
|
||||
return false;
|
||||
if (!(o instanceof MethodInfo))
|
||||
return false;
|
||||
return getSignature().equals(((MethodInfo)o).getSignature());
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return getSignature().hashCode();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
// TODO: include modifiers, exceptions
|
||||
return getSignature().toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright 2004 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.core;
|
||||
|
||||
import java.lang.reflect.*;
|
||||
|
||||
public class MethodInfoTransformer implements Transformer
|
||||
{
|
||||
private static final MethodInfoTransformer INSTANCE = new MethodInfoTransformer();
|
||||
|
||||
public static MethodInfoTransformer getInstance() {
|
||||
return INSTANCE;
|
||||
}
|
||||
|
||||
public Object transform(Object value) {
|
||||
if (value instanceof Method) {
|
||||
return ReflectUtils.getMethodInfo((Method)value);
|
||||
} else if (value instanceof Constructor) {
|
||||
return ReflectUtils.getMethodInfo((Constructor)value);
|
||||
} else {
|
||||
throw new IllegalArgumentException("cannot get method info for " + value);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.core;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* Customize the generated class name for {@link AbstractClassGenerator}-based utilities.
|
||||
*/
|
||||
public interface NamingPolicy {
|
||||
/**
|
||||
* Choose a name for a generated class.
|
||||
* @param prefix a dotted-name chosen by the generating class (possibly to put the generated class in a particular package)
|
||||
* @param source the fully-qualified class name of the generating class (for example "org.springframework.cglib.Enhancer")
|
||||
* @param key A key object representing the state of the parameters; for caching to work properly, equal keys should result
|
||||
* in the same generated class name. The default policy incorporates <code>key.hashCode()</code> into the class name.
|
||||
* @param names a predicate that returns true if the given classname has already been used in the same ClassLoader.
|
||||
* @return the fully-qualified class name
|
||||
*/
|
||||
String getClassName(String prefix, String source, Object key, Predicate names);
|
||||
|
||||
/**
|
||||
* The <code>NamingPolicy</code> in use does not currently, but may
|
||||
* in the future, affect the caching of classes generated by {@link
|
||||
* AbstractClassGenerator}, so this is a reminder that you should
|
||||
* correctly implement <code>equals</code> and <code>hashCode</code>
|
||||
* to avoid generating too many classes.
|
||||
*/
|
||||
boolean equals(Object o);
|
||||
}
|
|
@ -0,0 +1,24 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.core;
|
||||
|
||||
import org.springframework.asm.Label;
|
||||
|
||||
public interface ObjectSwitchCallback {
|
||||
void processCase(Object key, Label end) throws Exception;
|
||||
void processDefault() throws Exception;
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.core;
|
||||
|
||||
public interface Predicate {
|
||||
boolean evaluate(Object arg);
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.core;
|
||||
|
||||
import org.springframework.asm.Type;
|
||||
|
||||
public interface ProcessArrayCallback {
|
||||
void processElement(Type type);
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.core;
|
||||
|
||||
import org.springframework.asm.Label;
|
||||
|
||||
public interface ProcessSwitchCallback {
|
||||
void processCase(int key, Label end) throws Exception;
|
||||
void processDefault() throws Exception;
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright 2004 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.core;
|
||||
|
||||
import java.lang.reflect.*;
|
||||
|
||||
public class RejectModifierPredicate implements Predicate {
|
||||
private int rejectMask;
|
||||
|
||||
public RejectModifierPredicate(int rejectMask) {
|
||||
this.rejectMask = rejectMask;
|
||||
}
|
||||
|
||||
public boolean evaluate(Object arg) {
|
||||
return (((Member)arg).getModifiers() & rejectMask) == 0;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.core;
|
||||
|
||||
import org.springframework.asm.Type;
|
||||
|
||||
/**
|
||||
* A representation of a method signature, containing the method name,
|
||||
* return type, and parameter types.
|
||||
*/
|
||||
public class Signature {
|
||||
private String name;
|
||||
private String desc;
|
||||
|
||||
public Signature(String name, String desc) {
|
||||
// TODO: better error checking
|
||||
if (name.indexOf('(') >= 0) {
|
||||
throw new IllegalArgumentException("Name '" + name + "' is invalid");
|
||||
}
|
||||
this.name = name;
|
||||
this.desc = desc;
|
||||
}
|
||||
|
||||
public Signature(String name, Type returnType, Type[] argumentTypes) {
|
||||
this(name, Type.getMethodDescriptor(returnType, argumentTypes));
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public String getDescriptor() {
|
||||
return desc;
|
||||
}
|
||||
|
||||
public Type getReturnType() {
|
||||
return Type.getReturnType(desc);
|
||||
}
|
||||
|
||||
public Type[] getArgumentTypes() {
|
||||
return Type.getArgumentTypes(desc);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return name + desc;
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (o == null)
|
||||
return false;
|
||||
if (!(o instanceof Signature))
|
||||
return false;
|
||||
Signature other = (Signature)o;
|
||||
return name.equals(other.name) && desc.equals(other.desc);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return name.hashCode() ^ desc.hashCode();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.core;
|
||||
|
||||
@Deprecated
|
||||
public class TinyBitSet {
|
||||
private static int[] T = new int[256];
|
||||
private int value = 0;
|
||||
|
||||
private static int gcount(int x) {
|
||||
int c = 0;
|
||||
while (x != 0) {
|
||||
c++;
|
||||
x &= (x - 1);
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
static {
|
||||
for (int j = 0; j < 256; j++) {
|
||||
T[j] = gcount(j);
|
||||
}
|
||||
}
|
||||
|
||||
private static int topbit(int i) {
|
||||
int j;
|
||||
for (j = 0; i != 0; i ^= j) {
|
||||
j = i & -i;
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
private static int log2(int i) {
|
||||
int j = 0;
|
||||
for (j = 0; i != 0; i >>= 1) {
|
||||
j++;
|
||||
}
|
||||
return j;
|
||||
}
|
||||
|
||||
public int length() {
|
||||
return log2(topbit(value));
|
||||
}
|
||||
|
||||
/**
|
||||
* If bit 31 is set then this method results in an infinite loop.
|
||||
*
|
||||
* @return the number of bits set to <code>true</code> in this TinyBitSet.
|
||||
*/
|
||||
public int cardinality() {
|
||||
int w = value;
|
||||
int c = 0;
|
||||
while (w != 0) {
|
||||
c += T[w & 255];
|
||||
w >>= 8;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
public boolean get(int index) {
|
||||
return (value & (1 << index)) != 0;
|
||||
}
|
||||
|
||||
public void set(int index) {
|
||||
value |= (1 << index);
|
||||
}
|
||||
|
||||
public void clear(int index) {
|
||||
value &= ~(1 << index);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.core;
|
||||
|
||||
public interface Transformer {
|
||||
Object transform(Object value);
|
||||
}
|
|
@ -0,0 +1,422 @@
|
|||
/*
|
||||
* Copyright 2003,2004 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.core;
|
||||
|
||||
import java.util.*;
|
||||
import org.springframework.asm.Type;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public class TypeUtils {
|
||||
private static final Map transforms = new HashMap();
|
||||
private static final Map rtransforms = new HashMap();
|
||||
|
||||
private TypeUtils() {
|
||||
}
|
||||
|
||||
static {
|
||||
transforms.put("void", "V");
|
||||
transforms.put("byte", "B");
|
||||
transforms.put("char", "C");
|
||||
transforms.put("double", "D");
|
||||
transforms.put("float", "F");
|
||||
transforms.put("int", "I");
|
||||
transforms.put("long", "J");
|
||||
transforms.put("short", "S");
|
||||
transforms.put("boolean", "Z");
|
||||
|
||||
CollectionUtils.reverse(transforms, rtransforms);
|
||||
}
|
||||
|
||||
public static Type getType(String className) {
|
||||
return Type.getType("L" + className.replace('.', '/') + ";");
|
||||
}
|
||||
|
||||
public static boolean isFinal(int access) {
|
||||
return (Constants.ACC_FINAL & access) != 0;
|
||||
}
|
||||
|
||||
public static boolean isStatic(int access) {
|
||||
return (Constants.ACC_STATIC & access) != 0;
|
||||
}
|
||||
|
||||
public static boolean isProtected(int access) {
|
||||
return (Constants.ACC_PROTECTED & access) != 0;
|
||||
}
|
||||
|
||||
public static boolean isPublic(int access) {
|
||||
return (Constants.ACC_PUBLIC & access) != 0;
|
||||
}
|
||||
|
||||
public static boolean isAbstract(int access) {
|
||||
return (Constants.ACC_ABSTRACT & access) != 0;
|
||||
}
|
||||
|
||||
public static boolean isInterface(int access) {
|
||||
return (Constants.ACC_INTERFACE & access) != 0;
|
||||
}
|
||||
|
||||
public static boolean isPrivate(int access) {
|
||||
return (Constants.ACC_PRIVATE & access) != 0;
|
||||
}
|
||||
|
||||
public static boolean isSynthetic(int access) {
|
||||
return (Constants.ACC_SYNTHETIC & access) != 0;
|
||||
}
|
||||
|
||||
public static boolean isBridge(int access) {
|
||||
return (Constants.ACC_BRIDGE & access) != 0;
|
||||
}
|
||||
|
||||
// getPackage returns null on JDK 1.2
|
||||
public static String getPackageName(Type type) {
|
||||
return getPackageName(getClassName(type));
|
||||
}
|
||||
|
||||
public static String getPackageName(String className) {
|
||||
int idx = className.lastIndexOf('.');
|
||||
return (idx < 0) ? "" : className.substring(0, idx);
|
||||
}
|
||||
|
||||
public static String upperFirst(String s) {
|
||||
if (s == null || s.length() == 0) {
|
||||
return s;
|
||||
}
|
||||
return Character.toUpperCase(s.charAt(0)) + s.substring(1);
|
||||
}
|
||||
|
||||
public static String getClassName(Type type) {
|
||||
if (isPrimitive(type)) {
|
||||
return (String)rtransforms.get(type.getDescriptor());
|
||||
} else if (isArray(type)) {
|
||||
return getClassName(getComponentType(type)) + "[]";
|
||||
} else {
|
||||
return type.getClassName();
|
||||
}
|
||||
}
|
||||
|
||||
public static Type[] add(Type[] types, Type extra) {
|
||||
if (types == null) {
|
||||
return new Type[]{ extra };
|
||||
} else {
|
||||
List list = Arrays.asList(types);
|
||||
if (list.contains(extra)) {
|
||||
return types;
|
||||
}
|
||||
Type[] copy = new Type[types.length + 1];
|
||||
System.arraycopy(types, 0, copy, 0, types.length);
|
||||
copy[types.length] = extra;
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
|
||||
public static Type[] add(Type[] t1, Type[] t2) {
|
||||
// TODO: set semantics?
|
||||
Type[] all = new Type[t1.length + t2.length];
|
||||
System.arraycopy(t1, 0, all, 0, t1.length);
|
||||
System.arraycopy(t2, 0, all, t1.length, t2.length);
|
||||
return all;
|
||||
}
|
||||
|
||||
public static Type fromInternalName(String name) {
|
||||
// TODO; primitives?
|
||||
return Type.getType("L" + name + ";");
|
||||
}
|
||||
|
||||
public static Type[] fromInternalNames(String[] names) {
|
||||
if (names == null) {
|
||||
return null;
|
||||
}
|
||||
Type[] types = new Type[names.length];
|
||||
for (int i = 0; i < names.length; i++) {
|
||||
types[i] = fromInternalName(names[i]);
|
||||
}
|
||||
return types;
|
||||
}
|
||||
|
||||
public static int getStackSize(Type[] types) {
|
||||
int size = 0;
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
size += types[i].getSize();
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
public static String[] toInternalNames(Type[] types) {
|
||||
if (types == null) {
|
||||
return null;
|
||||
}
|
||||
String[] names = new String[types.length];
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
names[i] = types[i].getInternalName();
|
||||
}
|
||||
return names;
|
||||
}
|
||||
|
||||
public static Signature parseSignature(String s) {
|
||||
int space = s.indexOf(' ');
|
||||
int lparen = s.indexOf('(', space);
|
||||
int rparen = s.indexOf(')', lparen);
|
||||
String returnType = s.substring(0, space);
|
||||
String methodName = s.substring(space + 1, lparen);
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append('(');
|
||||
for (Iterator it = parseTypes(s, lparen + 1, rparen).iterator(); it.hasNext();) {
|
||||
sb.append(it.next());
|
||||
}
|
||||
sb.append(')');
|
||||
sb.append(map(returnType));
|
||||
return new Signature(methodName, sb.toString());
|
||||
}
|
||||
|
||||
public static Type parseType(String s) {
|
||||
return Type.getType(map(s));
|
||||
}
|
||||
|
||||
public static Type[] parseTypes(String s) {
|
||||
List names = parseTypes(s, 0, s.length());
|
||||
Type[] types = new Type[names.size()];
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
types[i] = Type.getType((String)names.get(i));
|
||||
}
|
||||
return types;
|
||||
}
|
||||
|
||||
public static Signature parseConstructor(Type[] types) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append("(");
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
sb.append(types[i].getDescriptor());
|
||||
}
|
||||
sb.append(")");
|
||||
sb.append("V");
|
||||
return new Signature(Constants.CONSTRUCTOR_NAME, sb.toString());
|
||||
}
|
||||
|
||||
public static Signature parseConstructor(String sig) {
|
||||
return parseSignature("void <init>(" + sig + ")"); // TODO
|
||||
}
|
||||
|
||||
private static List parseTypes(String s, int mark, int end) {
|
||||
List types = new ArrayList(5);
|
||||
for (;;) {
|
||||
int next = s.indexOf(',', mark);
|
||||
if (next < 0) {
|
||||
break;
|
||||
}
|
||||
types.add(map(s.substring(mark, next).trim()));
|
||||
mark = next + 1;
|
||||
}
|
||||
types.add(map(s.substring(mark, end).trim()));
|
||||
return types;
|
||||
}
|
||||
|
||||
private static String map(String type) {
|
||||
if (type.equals("")) {
|
||||
return type;
|
||||
}
|
||||
String t = (String)transforms.get(type);
|
||||
if (t != null) {
|
||||
return t;
|
||||
} else if (type.indexOf('.') < 0) {
|
||||
return map("java.lang." + type);
|
||||
} else {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
int index = 0;
|
||||
while ((index = type.indexOf("[]", index) + 1) > 0) {
|
||||
sb.append('[');
|
||||
}
|
||||
type = type.substring(0, type.length() - sb.length() * 2);
|
||||
sb.append('L').append(type.replace('.', '/')).append(';');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
||||
|
||||
public static Type getBoxedType(Type type) {
|
||||
switch (type.getSort()) {
|
||||
case Type.CHAR:
|
||||
return Constants.TYPE_CHARACTER;
|
||||
case Type.BOOLEAN:
|
||||
return Constants.TYPE_BOOLEAN;
|
||||
case Type.DOUBLE:
|
||||
return Constants.TYPE_DOUBLE;
|
||||
case Type.FLOAT:
|
||||
return Constants.TYPE_FLOAT;
|
||||
case Type.LONG:
|
||||
return Constants.TYPE_LONG;
|
||||
case Type.INT:
|
||||
return Constants.TYPE_INTEGER;
|
||||
case Type.SHORT:
|
||||
return Constants.TYPE_SHORT;
|
||||
case Type.BYTE:
|
||||
return Constants.TYPE_BYTE;
|
||||
default:
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
public static Type getUnboxedType(Type type) {
|
||||
if (Constants.TYPE_INTEGER.equals(type)) {
|
||||
return Type.INT_TYPE;
|
||||
} else if (Constants.TYPE_BOOLEAN.equals(type)) {
|
||||
return Type.BOOLEAN_TYPE;
|
||||
} else if (Constants.TYPE_DOUBLE.equals(type)) {
|
||||
return Type.DOUBLE_TYPE;
|
||||
} else if (Constants.TYPE_LONG.equals(type)) {
|
||||
return Type.LONG_TYPE;
|
||||
} else if (Constants.TYPE_CHARACTER.equals(type)) {
|
||||
return Type.CHAR_TYPE;
|
||||
} else if (Constants.TYPE_BYTE.equals(type)) {
|
||||
return Type.BYTE_TYPE;
|
||||
} else if (Constants.TYPE_FLOAT.equals(type)) {
|
||||
return Type.FLOAT_TYPE;
|
||||
} else if (Constants.TYPE_SHORT.equals(type)) {
|
||||
return Type.SHORT_TYPE;
|
||||
} else {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isArray(Type type) {
|
||||
return type.getSort() == Type.ARRAY;
|
||||
}
|
||||
|
||||
public static Type getComponentType(Type type) {
|
||||
if (!isArray(type)) {
|
||||
throw new IllegalArgumentException("Type " + type + " is not an array");
|
||||
}
|
||||
return Type.getType(type.getDescriptor().substring(1));
|
||||
}
|
||||
|
||||
public static boolean isPrimitive(Type type) {
|
||||
switch (type.getSort()) {
|
||||
case Type.ARRAY:
|
||||
case Type.OBJECT:
|
||||
return false;
|
||||
default:
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static String emulateClassGetName(Type type) {
|
||||
if (isArray(type)) {
|
||||
return type.getDescriptor().replace('/', '.');
|
||||
} else {
|
||||
return getClassName(type);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean isConstructor(MethodInfo method) {
|
||||
return method.getSignature().getName().equals(Constants.CONSTRUCTOR_NAME);
|
||||
}
|
||||
|
||||
public static Type[] getTypes(Class[] classes) {
|
||||
if (classes == null) {
|
||||
return null;
|
||||
}
|
||||
Type[] types = new Type[classes.length];
|
||||
for (int i = 0; i < classes.length; i++) {
|
||||
types[i] = Type.getType(classes[i]);
|
||||
}
|
||||
return types;
|
||||
}
|
||||
|
||||
public static int ICONST(int value) {
|
||||
switch (value) {
|
||||
case -1: return Constants.ICONST_M1;
|
||||
case 0: return Constants.ICONST_0;
|
||||
case 1: return Constants.ICONST_1;
|
||||
case 2: return Constants.ICONST_2;
|
||||
case 3: return Constants.ICONST_3;
|
||||
case 4: return Constants.ICONST_4;
|
||||
case 5: return Constants.ICONST_5;
|
||||
}
|
||||
return -1; // error
|
||||
}
|
||||
|
||||
public static int LCONST(long value) {
|
||||
if (value == 0L) {
|
||||
return Constants.LCONST_0;
|
||||
} else if (value == 1L) {
|
||||
return Constants.LCONST_1;
|
||||
} else {
|
||||
return -1; // error
|
||||
}
|
||||
}
|
||||
|
||||
public static int FCONST(float value) {
|
||||
if (value == 0f) {
|
||||
return Constants.FCONST_0;
|
||||
} else if (value == 1f) {
|
||||
return Constants.FCONST_1;
|
||||
} else if (value == 2f) {
|
||||
return Constants.FCONST_2;
|
||||
} else {
|
||||
return -1; // error
|
||||
}
|
||||
}
|
||||
|
||||
public static int DCONST(double value) {
|
||||
if (value == 0d) {
|
||||
return Constants.DCONST_0;
|
||||
} else if (value == 1d) {
|
||||
return Constants.DCONST_1;
|
||||
} else {
|
||||
return -1; // error
|
||||
}
|
||||
}
|
||||
|
||||
public static int NEWARRAY(Type type) {
|
||||
switch (type.getSort()) {
|
||||
case Type.BYTE:
|
||||
return Constants.T_BYTE;
|
||||
case Type.CHAR:
|
||||
return Constants.T_CHAR;
|
||||
case Type.DOUBLE:
|
||||
return Constants.T_DOUBLE;
|
||||
case Type.FLOAT:
|
||||
return Constants.T_FLOAT;
|
||||
case Type.INT:
|
||||
return Constants.T_INT;
|
||||
case Type.LONG:
|
||||
return Constants.T_LONG;
|
||||
case Type.SHORT:
|
||||
return Constants.T_SHORT;
|
||||
case Type.BOOLEAN:
|
||||
return Constants.T_BOOLEAN;
|
||||
default:
|
||||
return -1; // error
|
||||
}
|
||||
}
|
||||
|
||||
public static String escapeType(String s) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
for (int i = 0, len = s.length(); i < len; i++) {
|
||||
char c = s.charAt(i);
|
||||
switch (c) {
|
||||
case '$': sb.append("$24"); break;
|
||||
case '.': sb.append("$2E"); break;
|
||||
case '[': sb.append("$5B"); break;
|
||||
case ';': sb.append("$3B"); break;
|
||||
case '(': sb.append("$28"); break;
|
||||
case ')': sb.append("$29"); break;
|
||||
case '/': sb.append("$2F"); break;
|
||||
default:
|
||||
sb.append(c);
|
||||
}
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright 2003,2004 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.core;
|
||||
|
||||
import java.lang.reflect.*;
|
||||
import org.springframework.asm.Type;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public class VisibilityPredicate implements Predicate {
|
||||
private boolean protectedOk;
|
||||
private String pkg;
|
||||
private boolean samePackageOk;
|
||||
|
||||
public VisibilityPredicate(Class source, boolean protectedOk) {
|
||||
this.protectedOk = protectedOk;
|
||||
// same package is not ok for the bootstrap loaded classes. In all other cases we are
|
||||
// generating classes in the same classloader
|
||||
this.samePackageOk = source.getClassLoader() != null;
|
||||
pkg = TypeUtils.getPackageName(Type.getType(source));
|
||||
}
|
||||
|
||||
public boolean evaluate(Object arg) {
|
||||
Member member = (Member)arg;
|
||||
int mod = member.getModifiers();
|
||||
if (Modifier.isPrivate(mod)) {
|
||||
return false;
|
||||
} else if (Modifier.isPublic(mod)) {
|
||||
return true;
|
||||
} else if (Modifier.isProtected(mod) && protectedOk) {
|
||||
// protected is fine if 'protectedOk' is true (for subclasses)
|
||||
return true;
|
||||
} else {
|
||||
// protected/package private if the member is in the same package as the source class
|
||||
// and we are generating into the same classloader.
|
||||
return samePackageOk
|
||||
&& pkg.equals(TypeUtils.getPackageName(Type.getType(member.getDeclaringClass())));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
package org.springframework.cglib.core;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
/**
|
||||
* Allows to check for object equality, yet the class does not keep strong reference to the target.
|
||||
* {@link #equals(Object)} returns true if and only if the reference is not yet expired and target
|
||||
* objects are equal in terms of {@link #equals(Object)}.
|
||||
* <p>
|
||||
* This an internal class, thus it might disappear in future cglib releases.
|
||||
*
|
||||
* @param <T> type of the reference
|
||||
*/
|
||||
public class WeakCacheKey<T> extends WeakReference<T> {
|
||||
private final int hash;
|
||||
|
||||
public WeakCacheKey(T referent) {
|
||||
super(referent);
|
||||
this.hash = referent.hashCode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object obj) {
|
||||
if (!(obj instanceof WeakCacheKey)) {
|
||||
return false;
|
||||
}
|
||||
Object ours = get();
|
||||
Object theirs = ((WeakCacheKey) obj).get();
|
||||
return ours != null && theirs != null && ours.equals(theirs);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
return hash;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
T t = get();
|
||||
return t == null ? "Clean WeakIdentityKey, hash: " + hash : t.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package org.springframework.cglib.core.internal;
|
||||
|
||||
import org.springframework.cglib.core.Customizer;
|
||||
import org.springframework.cglib.core.FieldTypeCustomizer;
|
||||
import org.springframework.cglib.core.KeyFactoryCustomizer;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public class CustomizerRegistry {
|
||||
private final Class[] customizerTypes;
|
||||
private Map<Class, List<KeyFactoryCustomizer>> customizers = new HashMap<Class, List<KeyFactoryCustomizer>>();
|
||||
|
||||
public CustomizerRegistry(Class[] customizerTypes) {
|
||||
this.customizerTypes = customizerTypes;
|
||||
}
|
||||
|
||||
public void add(KeyFactoryCustomizer customizer) {
|
||||
Class<? extends KeyFactoryCustomizer> klass = customizer.getClass();
|
||||
for (Class type : customizerTypes) {
|
||||
if (type.isAssignableFrom(klass)) {
|
||||
List<KeyFactoryCustomizer> list = customizers.get(type);
|
||||
if (list == null) {
|
||||
customizers.put(type, list = new ArrayList<KeyFactoryCustomizer>());
|
||||
}
|
||||
list.add(customizer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public <T> List<T> get(Class<T> klass) {
|
||||
List<KeyFactoryCustomizer> list = customizers.get(klass);
|
||||
if (list == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return (List<T>) list;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Only to keep backward compatibility.
|
||||
*/
|
||||
@Deprecated
|
||||
public static CustomizerRegistry singleton(Customizer customizer)
|
||||
{
|
||||
CustomizerRegistry registry = new CustomizerRegistry(new Class[]{Customizer.class});
|
||||
registry.add(customizer);
|
||||
return registry;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package org.springframework.cglib.core.internal;
|
||||
|
||||
public interface Function<K, V> {
|
||||
V apply(K key);
|
||||
}
|
|
@ -0,0 +1,87 @@
|
|||
package org.springframework.cglib.core.internal;
|
||||
|
||||
import java.util.concurrent.*;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public class LoadingCache<K, KK, V> {
|
||||
protected final ConcurrentMap<KK, Object> map;
|
||||
protected final Function<K, V> loader;
|
||||
protected final Function<K, KK> keyMapper;
|
||||
|
||||
public static final Function IDENTITY = new Function() {
|
||||
public Object apply(Object key) {
|
||||
return key;
|
||||
}
|
||||
};
|
||||
|
||||
public LoadingCache(Function<K, KK> keyMapper, Function<K, V> loader) {
|
||||
this.keyMapper = keyMapper;
|
||||
this.loader = loader;
|
||||
this.map = new ConcurrentHashMap<KK, Object>();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public static <K> Function<K, K> identity() {
|
||||
return IDENTITY;
|
||||
}
|
||||
|
||||
public V get(K key) {
|
||||
final KK cacheKey = keyMapper.apply(key);
|
||||
Object v = map.get(cacheKey);
|
||||
if (v != null && !(v instanceof FutureTask)) {
|
||||
return (V) v;
|
||||
}
|
||||
|
||||
return createEntry(key, cacheKey, v);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads entry to the cache.
|
||||
* If entry is missing, put {@link FutureTask} first so other competing thread might wait for the result.
|
||||
* @param key original key that would be used to load the instance
|
||||
* @param cacheKey key that would be used to store the entry in internal map
|
||||
* @param v null or {@link FutureTask<V>}
|
||||
* @return newly created instance
|
||||
*/
|
||||
protected V createEntry(final K key, KK cacheKey, Object v) {
|
||||
FutureTask<V> task;
|
||||
boolean creator = false;
|
||||
if (v != null) {
|
||||
// Another thread is already loading an instance
|
||||
task = (FutureTask<V>) v;
|
||||
} else {
|
||||
task = new FutureTask<V>(new Callable<V>() {
|
||||
public V call() throws Exception {
|
||||
return loader.apply(key);
|
||||
}
|
||||
});
|
||||
Object prevTask = map.putIfAbsent(cacheKey, task);
|
||||
if (prevTask == null) {
|
||||
// creator does the load
|
||||
creator = true;
|
||||
task.run();
|
||||
} else if (prevTask instanceof FutureTask) {
|
||||
task = (FutureTask<V>) prevTask;
|
||||
} else {
|
||||
return (V) prevTask;
|
||||
}
|
||||
}
|
||||
|
||||
V result;
|
||||
try {
|
||||
result = task.get();
|
||||
} catch (InterruptedException e) {
|
||||
throw new IllegalStateException("Interrupted while loading cache item", e);
|
||||
} catch (ExecutionException e) {
|
||||
Throwable cause = e.getCause();
|
||||
if (cause instanceof RuntimeException) {
|
||||
throw ((RuntimeException) cause);
|
||||
}
|
||||
throw new IllegalStateException("Unable to load cache item", cause);
|
||||
}
|
||||
if (creator) {
|
||||
map.put(cacheKey, result);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,127 @@
|
|||
/*
|
||||
* 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
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cglib.proxy;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import org.springframework.cglib.core.Constants;
|
||||
import org.springframework.cglib.core.Signature;
|
||||
import org.springframework.asm.ClassReader;
|
||||
import org.springframework.asm.ClassVisitor;
|
||||
import org.springframework.asm.MethodVisitor;
|
||||
import org.springframework.asm.Opcodes;
|
||||
|
||||
/**
|
||||
* Uses bytecode reflection to figure out the targets of all bridge methods that use invokespecial
|
||||
* and invokeinterface, so that we can later rewrite them to use invokevirtual.
|
||||
*
|
||||
* <p>For interface bridges, using invokesuper will fail since the method being bridged to is in a
|
||||
* superinterface, not a superclass. Starting in Java 8, javac emits default bridge methods in
|
||||
* interfaces, which use invokeinterface to bridge to the target method.
|
||||
*
|
||||
* @author sberlin@gmail.com (Sam Berlin)
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
class BridgeMethodResolver {
|
||||
|
||||
private final Map/* <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(Constants.ASM_API);
|
||||
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(Constants.ASM_API) {
|
||||
public void visitMethodInsn(
|
||||
int opcode, String owner, String name, String desc, boolean itf) {
|
||||
if ((opcode == Opcodes.INVOKESPECIAL
|
||||
|| (itf && opcode == Opcodes.INVOKEINTERFACE))
|
||||
&& currentMethod != null) {
|
||||
Signature target = new Signature(name, desc);
|
||||
// If the target signature is the same as the current,
|
||||
// we shouldn't change our bridge becaues invokespecial
|
||||
// is the only way to make progress (otherwise we'll
|
||||
// get infinite recursion). This would typically
|
||||
// only happen when a bridge method is created to widen
|
||||
// the visibility of a superclass' method.
|
||||
if (!target.equals(currentMethod)) {
|
||||
resolved.put(currentMethod, target);
|
||||
}
|
||||
currentMethod = null;
|
||||
}
|
||||
}
|
||||
};
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.proxy;
|
||||
|
||||
/**
|
||||
* All callback interfaces used by {@link Enhancer} extend this interface.
|
||||
* @see MethodInterceptor
|
||||
* @see NoOp
|
||||
* @see LazyLoader
|
||||
* @see Dispatcher
|
||||
* @see InvocationHandler
|
||||
* @see FixedValue
|
||||
*/
|
||||
public interface Callback
|
||||
{
|
||||
}
|
|
@ -0,0 +1,46 @@
|
|||
/*
|
||||
* Copyright 2003,2004 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.proxy;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* Map methods of subclasses generated by {@link Enhancer} to a particular
|
||||
* callback. The type of the callbacks chosen for each method affects
|
||||
* the bytecode generated for that method in the subclass, and cannot
|
||||
* change for the life of the class.
|
||||
* <p>Note: {@link CallbackFilter} implementations are supposed to be
|
||||
* lightweight as cglib might keep {@link CallbackFilter} objects
|
||||
* alive to enable caching of generated classes. Prefer using {@code static}
|
||||
* classes for implementation of {@link CallbackFilter}.</p>
|
||||
*/
|
||||
public interface CallbackFilter {
|
||||
/**
|
||||
* Map a method to a callback.
|
||||
* @param method the intercepted method
|
||||
* @return the index into the array of callbacks (as specified by {@link Enhancer#setCallbacks}) to use for the method,
|
||||
*/
|
||||
int accept(Method method);
|
||||
|
||||
/**
|
||||
* The <code>CallbackFilter</code> in use affects which cached class
|
||||
* the <code>Enhancer</code> will use, so this is a reminder that
|
||||
* you should correctly implement <code>equals</code> and
|
||||
* <code>hashCode</code> for custom <code>CallbackFilter</code>
|
||||
* implementations in order to improve performance.
|
||||
*/
|
||||
boolean equals(Object o);
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright 2003,2004 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.proxy;
|
||||
|
||||
import java.util.List;
|
||||
import org.springframework.cglib.core.*;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
interface CallbackGenerator
|
||||
{
|
||||
void generate(ClassEmitter ce, Context context, List methods) throws Exception;
|
||||
void generateStatic(CodeEmitter e, Context context, List methods) throws Exception;
|
||||
|
||||
interface Context
|
||||
{
|
||||
ClassLoader getClassLoader();
|
||||
CodeEmitter beginMethod(ClassEmitter ce, MethodInfo method);
|
||||
int getOriginalModifiers(MethodInfo method);
|
||||
int getIndex(MethodInfo method);
|
||||
void emitCallback(CodeEmitter ce, int index);
|
||||
Signature getImplSignature(MethodInfo method);
|
||||
void emitLoadArgsAndInvoke(CodeEmitter e, MethodInfo method);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
/*
|
||||
* Copyright 2004 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.proxy;
|
||||
|
||||
import org.springframework.cglib.core.ReflectUtils;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
|
||||
/**
|
||||
* @version $Id: CallbackHelper.java,v 1.2 2004/06/24 21:15:20 herbyderby Exp $
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
abstract public class CallbackHelper
|
||||
implements CallbackFilter
|
||||
{
|
||||
private Map methodMap = new HashMap();
|
||||
private List callbacks = new ArrayList();
|
||||
|
||||
public CallbackHelper(Class superclass, Class[] interfaces)
|
||||
{
|
||||
List methods = new ArrayList();
|
||||
Enhancer.getMethods(superclass, interfaces, methods);
|
||||
Map indexes = new HashMap();
|
||||
for (int i = 0, size = methods.size(); i < size; i++) {
|
||||
Method method = (Method)methods.get(i);
|
||||
Object callback = getCallback(method);
|
||||
if (callback == null)
|
||||
throw new IllegalStateException("getCallback cannot return null");
|
||||
boolean isCallback = callback instanceof Callback;
|
||||
if (!(isCallback || (callback instanceof Class)))
|
||||
throw new IllegalStateException("getCallback must return a Callback or a Class");
|
||||
if (i > 0 && ((callbacks.get(i - 1) instanceof Callback) ^ isCallback))
|
||||
throw new IllegalStateException("getCallback must return a Callback or a Class consistently for every Method");
|
||||
Integer index = (Integer)indexes.get(callback);
|
||||
if (index == null) {
|
||||
index = callbacks.size();
|
||||
indexes.put(callback, index);
|
||||
}
|
||||
methodMap.put(method, index);
|
||||
callbacks.add(callback);
|
||||
}
|
||||
}
|
||||
|
||||
abstract protected Object getCallback(Method method);
|
||||
|
||||
public Callback[] getCallbacks()
|
||||
{
|
||||
if (callbacks.size() == 0)
|
||||
return new Callback[0];
|
||||
if (callbacks.get(0) instanceof Callback) {
|
||||
return (Callback[])callbacks.toArray(new Callback[callbacks.size()]);
|
||||
} else {
|
||||
throw new IllegalStateException("getCallback returned classes, not callbacks; call getCallbackTypes instead");
|
||||
}
|
||||
}
|
||||
|
||||
public Class[] getCallbackTypes()
|
||||
{
|
||||
if (callbacks.size() == 0)
|
||||
return new Class[0];
|
||||
if (callbacks.get(0) instanceof Callback) {
|
||||
return ReflectUtils.getClasses(getCallbacks());
|
||||
} else {
|
||||
return (Class[])callbacks.toArray(new Class[callbacks.size()]);
|
||||
}
|
||||
}
|
||||
|
||||
public int accept(Method method)
|
||||
{
|
||||
return ((Integer)methodMap.get(method)).intValue();
|
||||
}
|
||||
|
||||
public int hashCode()
|
||||
{
|
||||
return methodMap.hashCode();
|
||||
}
|
||||
|
||||
public boolean equals(Object o)
|
||||
{
|
||||
if (o == null)
|
||||
return false;
|
||||
if (!(o instanceof CallbackHelper))
|
||||
return false;
|
||||
return methodMap.equals(((CallbackHelper)o).methodMap);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,117 @@
|
|||
/*
|
||||
* Copyright 2004 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.proxy;
|
||||
|
||||
import org.springframework.asm.Type;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
class CallbackInfo
|
||||
{
|
||||
public static Type[] determineTypes(Class[] callbackTypes) {
|
||||
return determineTypes(callbackTypes, true);
|
||||
}
|
||||
|
||||
public static Type[] determineTypes(Class[] callbackTypes, boolean checkAll) {
|
||||
Type[] types = new Type[callbackTypes.length];
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
types[i] = determineType(callbackTypes[i], checkAll);
|
||||
}
|
||||
return types;
|
||||
}
|
||||
|
||||
public static Type[] determineTypes(Callback[] callbacks) {
|
||||
return determineTypes(callbacks, true);
|
||||
}
|
||||
|
||||
public static Type[] determineTypes(Callback[] callbacks, boolean checkAll) {
|
||||
Type[] types = new Type[callbacks.length];
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
types[i] = determineType(callbacks[i], checkAll);
|
||||
}
|
||||
return types;
|
||||
}
|
||||
|
||||
public static CallbackGenerator[] getGenerators(Type[] callbackTypes) {
|
||||
CallbackGenerator[] generators = new CallbackGenerator[callbackTypes.length];
|
||||
for (int i = 0; i < generators.length; i++) {
|
||||
generators[i] = getGenerator(callbackTypes[i]);
|
||||
}
|
||||
return generators;
|
||||
}
|
||||
|
||||
//////////////////// PRIVATE ////////////////////
|
||||
|
||||
private Class cls;
|
||||
private CallbackGenerator generator;
|
||||
private Type type;
|
||||
|
||||
private static final CallbackInfo[] CALLBACKS = {
|
||||
new CallbackInfo(NoOp.class, NoOpGenerator.INSTANCE),
|
||||
new CallbackInfo(MethodInterceptor.class, MethodInterceptorGenerator.INSTANCE),
|
||||
new CallbackInfo(InvocationHandler.class, InvocationHandlerGenerator.INSTANCE),
|
||||
new CallbackInfo(LazyLoader.class, LazyLoaderGenerator.INSTANCE),
|
||||
new CallbackInfo(Dispatcher.class, DispatcherGenerator.INSTANCE),
|
||||
new CallbackInfo(FixedValue.class, FixedValueGenerator.INSTANCE),
|
||||
new CallbackInfo(ProxyRefDispatcher.class, DispatcherGenerator.PROXY_REF_INSTANCE),
|
||||
};
|
||||
|
||||
private CallbackInfo(Class cls, CallbackGenerator generator) {
|
||||
this.cls = cls;
|
||||
this.generator = generator;
|
||||
type = Type.getType(cls);
|
||||
}
|
||||
|
||||
private static Type determineType(Callback callback, boolean checkAll) {
|
||||
if (callback == null) {
|
||||
throw new IllegalStateException("Callback is null");
|
||||
}
|
||||
return determineType(callback.getClass(), checkAll);
|
||||
}
|
||||
|
||||
private static Type determineType(Class callbackType, boolean checkAll) {
|
||||
Class cur = null;
|
||||
Type type = null;
|
||||
for (int i = 0; i < CALLBACKS.length; i++) {
|
||||
CallbackInfo info = CALLBACKS[i];
|
||||
if (info.cls.isAssignableFrom(callbackType)) {
|
||||
if (cur != null) {
|
||||
throw new IllegalStateException("Callback implements both " + cur + " and " + info.cls);
|
||||
}
|
||||
cur = info.cls;
|
||||
type = info.type;
|
||||
if (!checkAll) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (cur == null) {
|
||||
throw new IllegalStateException("Unknown callback type " + callbackType);
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
private static CallbackGenerator getGenerator(Type callbackType) {
|
||||
for (int i = 0; i < CALLBACKS.length; i++) {
|
||||
CallbackInfo info = CALLBACKS[i];
|
||||
if (info.type.equals(callbackType)) {
|
||||
return info.generator;
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("Unknown callback type " + callbackType);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.proxy;
|
||||
|
||||
/**
|
||||
* Dispatching {@link Enhancer} callback. This is identical to the
|
||||
* {@link LazyLoader} interface but needs to be separate so that <code>Enhancer</code>
|
||||
* knows which type of code to generate.
|
||||
*/
|
||||
public interface Dispatcher extends Callback {
|
||||
/**
|
||||
* Return the object which the original method invocation should
|
||||
* be dispatched. This method is called for <b>every</b> method invocation.
|
||||
* @return an object that can invoke the method
|
||||
*/
|
||||
Object loadObject() throws Exception;
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright 2003,2004 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.proxy;
|
||||
|
||||
import java.util.*;
|
||||
import org.springframework.cglib.core.*;
|
||||
import org.springframework.asm.Type;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
class DispatcherGenerator implements CallbackGenerator {
|
||||
public static final DispatcherGenerator INSTANCE =
|
||||
new DispatcherGenerator(false);
|
||||
public static final DispatcherGenerator PROXY_REF_INSTANCE =
|
||||
new DispatcherGenerator(true);
|
||||
|
||||
private static final Type DISPATCHER =
|
||||
TypeUtils.parseType("org.springframework.cglib.proxy.Dispatcher");
|
||||
private static final Type PROXY_REF_DISPATCHER =
|
||||
TypeUtils.parseType("org.springframework.cglib.proxy.ProxyRefDispatcher");
|
||||
private static final Signature LOAD_OBJECT =
|
||||
TypeUtils.parseSignature("Object loadObject()");
|
||||
private static final Signature PROXY_REF_LOAD_OBJECT =
|
||||
TypeUtils.parseSignature("Object loadObject(Object)");
|
||||
|
||||
private boolean proxyRef;
|
||||
|
||||
private DispatcherGenerator(boolean proxyRef) {
|
||||
this.proxyRef = proxyRef;
|
||||
}
|
||||
|
||||
public void generate(ClassEmitter ce, Context context, List methods) {
|
||||
for (Iterator it = methods.iterator(); it.hasNext();) {
|
||||
MethodInfo method = (MethodInfo)it.next();
|
||||
if (!TypeUtils.isProtected(method.getModifiers())) {
|
||||
CodeEmitter e = context.beginMethod(ce, method);
|
||||
context.emitCallback(e, context.getIndex(method));
|
||||
if (proxyRef) {
|
||||
e.load_this();
|
||||
e.invoke_interface(PROXY_REF_DISPATCHER, PROXY_REF_LOAD_OBJECT);
|
||||
} else {
|
||||
e.invoke_interface(DISPATCHER, LOAD_OBJECT);
|
||||
}
|
||||
e.checkcast(method.getClassInfo().getType());
|
||||
e.load_args();
|
||||
e.invoke(method);
|
||||
e.return_value();
|
||||
e.end_method();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void generateStatic(CodeEmitter e, Context context, List methods) { }
|
||||
}
|
|
@ -0,0 +1,80 @@
|
|||
/*
|
||||
* Copyright 2002,2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cglib.proxy;
|
||||
|
||||
/**
|
||||
* All enhanced instances returned by the {@link Enhancer} class implement this interface.
|
||||
* Using this interface for new instances is faster than going through the <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 $
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public interface Factory {
|
||||
/**
|
||||
* Creates new instance of the same type, using the no-arg constructor.
|
||||
* The class of this object must have been created using a single Callback type.
|
||||
* If multiple callbacks are required an exception will be thrown.
|
||||
* @param callback the new interceptor to use
|
||||
* @return new instance of the same type
|
||||
*/
|
||||
Object newInstance(Callback callback);
|
||||
|
||||
/**
|
||||
* Creates new instance of the same type, using the no-arg constructor.
|
||||
* @param callbacks the new callbacks(s) to use
|
||||
* @return new instance of the same type
|
||||
*/
|
||||
Object newInstance(Callback[] callbacks);
|
||||
|
||||
/**
|
||||
* Creates a new instance of the same type, using the constructor
|
||||
* matching the given signature.
|
||||
* @param types the constructor argument types
|
||||
* @param args the constructor arguments
|
||||
* @param callbacks the new interceptor(s) to use
|
||||
* @return new instance of the same type
|
||||
*/
|
||||
Object newInstance(Class[] types, Object[] args, Callback[] callbacks);
|
||||
|
||||
/**
|
||||
* Return the <code>Callback</code> implementation at the specified index.
|
||||
* @param index the callback index
|
||||
* @return the callback implementation
|
||||
*/
|
||||
Callback getCallback(int index);
|
||||
|
||||
/**
|
||||
* Set the callback for this object for the given type.
|
||||
* @param index the callback index to replace
|
||||
* @param callback the new callback
|
||||
*/
|
||||
void setCallback(int index, Callback callback);
|
||||
|
||||
/**
|
||||
* Replace all of the callbacks for this object at once.
|
||||
* @param callbacks the new callbacks(s) to use
|
||||
*/
|
||||
void setCallbacks(Callback[] callbacks);
|
||||
|
||||
/**
|
||||
* Get the current set of callbacks for ths object.
|
||||
* @return a new array instance
|
||||
*/
|
||||
Callback[] getCallbacks();
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.proxy;
|
||||
|
||||
/**
|
||||
* {@link Enhancer} callback that simply returns the value to return
|
||||
* from the proxied method. No information about what method
|
||||
* is being called is available to the callback, and the type of
|
||||
* the returned object must be compatible with the return type of
|
||||
* the proxied method. This makes this callback primarily useful
|
||||
* for forcing a particular method (through the use of a {@link CallbackFilter}
|
||||
* to return a fixed value with little overhead.
|
||||
*/
|
||||
public interface FixedValue extends Callback {
|
||||
/**
|
||||
* Return the object which the original method invocation should
|
||||
* return. This method is called for <b>every</b> method invocation.
|
||||
* @return an object matching the type of the return value for every
|
||||
* method this callback is mapped to
|
||||
*/
|
||||
Object loadObject() throws Exception;
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright 2003,2004 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.proxy;
|
||||
|
||||
import java.util.*;
|
||||
import org.springframework.cglib.core.*;
|
||||
import org.springframework.asm.Type;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
class FixedValueGenerator implements CallbackGenerator {
|
||||
public static final FixedValueGenerator INSTANCE = new FixedValueGenerator();
|
||||
private static final Type FIXED_VALUE =
|
||||
TypeUtils.parseType("org.springframework.cglib.proxy.FixedValue");
|
||||
private static final Signature LOAD_OBJECT =
|
||||
TypeUtils.parseSignature("Object loadObject()");
|
||||
|
||||
public void generate(ClassEmitter ce, Context context, List methods) {
|
||||
for (Iterator it = methods.iterator(); it.hasNext();) {
|
||||
MethodInfo method = (MethodInfo)it.next();
|
||||
CodeEmitter e = context.beginMethod(ce, method);
|
||||
context.emitCallback(e, context.getIndex(method));
|
||||
e.invoke_interface(FIXED_VALUE, LOAD_OBJECT);
|
||||
e.unbox_or_zero(e.getReturnType());
|
||||
e.return_value();
|
||||
e.end_method();
|
||||
}
|
||||
}
|
||||
|
||||
public void generateStatic(CodeEmitter e, Context context, List methods) { }
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
* Copyright 2004 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.proxy;
|
||||
|
||||
import java.lang.reflect.*;
|
||||
import java.util.*;
|
||||
import org.springframework.cglib.core.*;
|
||||
import org.springframework.asm.ClassVisitor;
|
||||
import org.springframework.asm.Type;
|
||||
|
||||
/**
|
||||
* Generates new interfaces at runtime.
|
||||
* By passing a generated interface to the Enhancer's list of interfaces to
|
||||
* implement, you can make your enhanced classes handle an arbitrary set
|
||||
* of method signatures.
|
||||
* @author Chris Nokleberg
|
||||
* @version $Id: InterfaceMaker.java,v 1.4 2006/03/05 02:43:19 herbyderby Exp $
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public class InterfaceMaker extends AbstractClassGenerator
|
||||
{
|
||||
private static final Source SOURCE = new Source(InterfaceMaker.class.getName());
|
||||
private Map signatures = new HashMap();
|
||||
|
||||
/**
|
||||
* Create a new <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_8,
|
||||
Constants.ACC_PUBLIC | Constants.ACC_INTERFACE | Constants.ACC_ABSTRACT,
|
||||
getClassName(),
|
||||
null,
|
||||
null,
|
||||
Constants.SOURCE_FILE);
|
||||
for (Iterator it = signatures.keySet().iterator(); it.hasNext();) {
|
||||
Signature sig = (Signature)it.next();
|
||||
Type[] exceptions = (Type[])signatures.get(sig);
|
||||
ce.begin_method(Constants.ACC_PUBLIC | Constants.ACC_ABSTRACT,
|
||||
sig,
|
||||
exceptions).end_method();
|
||||
}
|
||||
ce.end_class();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.proxy;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
/**
|
||||
* {@link java.lang.reflect.InvocationHandler} replacement (unavailable under JDK 1.2).
|
||||
* This callback type is primarily for use by the {@link Proxy} class but
|
||||
* may be used with {@link Enhancer} as well.
|
||||
* @author Neeme Praks <a href="mailto:neeme@apache.org">neeme@apache.org</a>
|
||||
* @version $Id: InvocationHandler.java,v 1.3 2004/06/24 21:15:20 herbyderby Exp $
|
||||
*/
|
||||
public interface InvocationHandler
|
||||
extends Callback
|
||||
{
|
||||
/**
|
||||
* @see java.lang.reflect.InvocationHandler#invoke(java.lang.Object, java.lang.reflect.Method, java.lang.Object)
|
||||
*/
|
||||
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;
|
||||
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
/*
|
||||
* Copyright 2003,2004 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.proxy;
|
||||
|
||||
import org.springframework.cglib.core.*;
|
||||
import java.util.*;
|
||||
import org.springframework.asm.Type;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
class InvocationHandlerGenerator
|
||||
implements CallbackGenerator
|
||||
{
|
||||
public static final InvocationHandlerGenerator INSTANCE = new InvocationHandlerGenerator();
|
||||
|
||||
private static final Type INVOCATION_HANDLER =
|
||||
TypeUtils.parseType("org.springframework.cglib.proxy.InvocationHandler");
|
||||
private static final Type UNDECLARED_THROWABLE_EXCEPTION =
|
||||
TypeUtils.parseType("org.springframework.cglib.proxy.UndeclaredThrowableException");
|
||||
private static final Type METHOD =
|
||||
TypeUtils.parseType("java.lang.reflect.Method");
|
||||
private static final Signature INVOKE =
|
||||
TypeUtils.parseSignature("Object invoke(Object, java.lang.reflect.Method, Object[])");
|
||||
|
||||
public void generate(ClassEmitter ce, Context context, List methods) {
|
||||
for (Iterator it = methods.iterator(); it.hasNext();) {
|
||||
MethodInfo method = (MethodInfo)it.next();
|
||||
Signature impl = context.getImplSignature(method);
|
||||
ce.declare_field(Constants.PRIVATE_FINAL_STATIC, impl.getName(), METHOD, null);
|
||||
|
||||
CodeEmitter e = context.beginMethod(ce, method);
|
||||
Block handler = e.begin_block();
|
||||
context.emitCallback(e, context.getIndex(method));
|
||||
e.load_this();
|
||||
e.getfield(impl.getName());
|
||||
e.create_arg_array();
|
||||
e.invoke_interface(INVOCATION_HANDLER, INVOKE);
|
||||
e.unbox(method.getSignature().getReturnType());
|
||||
e.return_value();
|
||||
handler.end();
|
||||
EmitUtils.wrap_undeclared_throwable(e, handler, method.getExceptionTypes(), UNDECLARED_THROWABLE_EXCEPTION);
|
||||
e.end_method();
|
||||
}
|
||||
}
|
||||
|
||||
public void generateStatic(CodeEmitter e, Context context, List methods) {
|
||||
for (Iterator it = methods.iterator(); it.hasNext();) {
|
||||
MethodInfo method = (MethodInfo)it.next();
|
||||
EmitUtils.load_method(e, method);
|
||||
e.putfield(context.getImplSignature(method).getName());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.proxy;
|
||||
|
||||
/**
|
||||
* Lazy-loading {@link Enhancer} callback.
|
||||
*/
|
||||
public interface LazyLoader extends Callback {
|
||||
/**
|
||||
* Return the object which the original method invocation should be
|
||||
* dispatched. Called as soon as the first lazily-loaded method in
|
||||
* the enhanced instance is invoked. The same object is then used
|
||||
* for every future method call to the proxy instance.
|
||||
* @return an object that can invoke the method
|
||||
*/
|
||||
Object loadObject() throws Exception;
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
/*
|
||||
* Copyright 2003,2004 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.proxy;
|
||||
|
||||
import java.util.*;
|
||||
import org.springframework.cglib.core.*;
|
||||
import org.springframework.asm.Label;
|
||||
import org.springframework.asm.Type;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
class LazyLoaderGenerator implements CallbackGenerator {
|
||||
public static final LazyLoaderGenerator INSTANCE = new LazyLoaderGenerator();
|
||||
|
||||
private static final Signature LOAD_OBJECT =
|
||||
TypeUtils.parseSignature("Object loadObject()");
|
||||
private static final Type LAZY_LOADER =
|
||||
TypeUtils.parseType("org.springframework.cglib.proxy.LazyLoader");
|
||||
|
||||
public void generate(ClassEmitter ce, Context context, List methods) {
|
||||
Set indexes = new HashSet();
|
||||
for (Iterator it = methods.iterator(); it.hasNext();) {
|
||||
MethodInfo method = (MethodInfo)it.next();
|
||||
if (TypeUtils.isProtected(method.getModifiers())) {
|
||||
// ignore protected methods
|
||||
} else {
|
||||
int index = context.getIndex(method);
|
||||
indexes.add(index);
|
||||
CodeEmitter e = context.beginMethod(ce, method);
|
||||
e.load_this();
|
||||
e.dup();
|
||||
e.invoke_virtual_this(loadMethod(index));
|
||||
e.checkcast(method.getClassInfo().getType());
|
||||
e.load_args();
|
||||
e.invoke(method);
|
||||
e.return_value();
|
||||
e.end_method();
|
||||
}
|
||||
}
|
||||
|
||||
for (Iterator it = indexes.iterator(); it.hasNext();) {
|
||||
int index = ((Integer)it.next());
|
||||
|
||||
String delegate = "CGLIB$LAZY_LOADER_" + index;
|
||||
ce.declare_field(Constants.ACC_PRIVATE, delegate, Constants.TYPE_OBJECT, null);
|
||||
|
||||
CodeEmitter e = ce.begin_method(Constants.ACC_PRIVATE |
|
||||
Constants.ACC_SYNCHRONIZED |
|
||||
Constants.ACC_FINAL,
|
||||
loadMethod(index),
|
||||
null);
|
||||
e.load_this();
|
||||
e.getfield(delegate);
|
||||
e.dup();
|
||||
Label end = e.make_label();
|
||||
e.ifnonnull(end);
|
||||
e.pop();
|
||||
e.load_this();
|
||||
context.emitCallback(e, index);
|
||||
e.invoke_interface(LAZY_LOADER, LOAD_OBJECT);
|
||||
e.dup_x1();
|
||||
e.putfield(delegate);
|
||||
e.mark(end);
|
||||
e.return_value();
|
||||
e.end_method();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
private Signature loadMethod(int index) {
|
||||
return new Signature("CGLIB$LOAD_PRIVATE_" + index,
|
||||
Constants.TYPE_OBJECT,
|
||||
Constants.TYPES_EMPTY);
|
||||
}
|
||||
|
||||
public void generateStatic(CodeEmitter e, Context context, List methods) { }
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright 2002,2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.proxy;
|
||||
|
||||
/**
|
||||
* General-purpose {@link Enhancer} callback which provides for "around advice".
|
||||
* @author Juozas Baliuka <a href="mailto:baliuka@mwm.lt">baliuka@mwm.lt</a>
|
||||
* @version $Id: MethodInterceptor.java,v 1.8 2004/06/24 21:15:20 herbyderby Exp $
|
||||
*/
|
||||
public interface MethodInterceptor
|
||||
extends Callback
|
||||
{
|
||||
/**
|
||||
* All generated proxied methods call this method instead of the original method.
|
||||
* The original method may either be invoked by normal reflection using the Method object,
|
||||
* or by using the MethodProxy (faster).
|
||||
* @param obj "this", the enhanced object
|
||||
* @param method intercepted Method
|
||||
* @param args argument array; primitive types are wrapped
|
||||
* @param proxy used to invoke super (non-intercepted method); may be called
|
||||
* as many times as needed
|
||||
* @throws Throwable any exception may be thrown; if so, super method will not be invoked
|
||||
* @return any value compatible with the signature of the proxied method. Method returning void will ignore this value.
|
||||
* @see MethodProxy
|
||||
*/
|
||||
public Object intercept(Object obj, java.lang.reflect.Method method, Object[] args,
|
||||
MethodProxy proxy) throws Throwable;
|
||||
|
||||
}
|
|
@ -0,0 +1,238 @@
|
|||
/*
|
||||
* Copyright 2003,2004 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.proxy;
|
||||
|
||||
import java.util.*;
|
||||
import org.springframework.cglib.core.*;
|
||||
import org.springframework.asm.Label;
|
||||
import org.springframework.asm.Type;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked", "deprecation"})
|
||||
class MethodInterceptorGenerator
|
||||
implements CallbackGenerator
|
||||
{
|
||||
public static final MethodInterceptorGenerator INSTANCE = new MethodInterceptorGenerator();
|
||||
|
||||
static final String EMPTY_ARGS_NAME = "CGLIB$emptyArgs";
|
||||
static final String FIND_PROXY_NAME = "CGLIB$findMethodProxy";
|
||||
static final Class[] FIND_PROXY_TYPES = { Signature.class };
|
||||
|
||||
private static final Type ABSTRACT_METHOD_ERROR =
|
||||
TypeUtils.parseType("AbstractMethodError");
|
||||
private static final Type METHOD =
|
||||
TypeUtils.parseType("java.lang.reflect.Method");
|
||||
private static final Type REFLECT_UTILS =
|
||||
TypeUtils.parseType("org.springframework.cglib.core.ReflectUtils");
|
||||
private static final Type METHOD_PROXY =
|
||||
TypeUtils.parseType("org.springframework.cglib.proxy.MethodProxy");
|
||||
private static final Type METHOD_INTERCEPTOR =
|
||||
TypeUtils.parseType("org.springframework.cglib.proxy.MethodInterceptor");
|
||||
private static final Signature GET_DECLARED_METHODS =
|
||||
TypeUtils.parseSignature("java.lang.reflect.Method[] getDeclaredMethods()");
|
||||
private static final Signature GET_DECLARING_CLASS =
|
||||
TypeUtils.parseSignature("Class getDeclaringClass()");
|
||||
private static final Signature FIND_METHODS =
|
||||
TypeUtils.parseSignature("java.lang.reflect.Method[] findMethods(String[], java.lang.reflect.Method[])");
|
||||
private static final Signature MAKE_PROXY =
|
||||
new Signature("create", METHOD_PROXY, new Type[]{
|
||||
Constants.TYPE_CLASS,
|
||||
Constants.TYPE_CLASS,
|
||||
Constants.TYPE_STRING,
|
||||
Constants.TYPE_STRING,
|
||||
Constants.TYPE_STRING
|
||||
});
|
||||
private static final Signature INTERCEPT =
|
||||
new Signature("intercept", Constants.TYPE_OBJECT, new Type[]{
|
||||
Constants.TYPE_OBJECT,
|
||||
METHOD,
|
||||
Constants.TYPE_OBJECT_ARRAY,
|
||||
METHOD_PROXY
|
||||
});
|
||||
private static final Signature FIND_PROXY =
|
||||
new Signature(FIND_PROXY_NAME, METHOD_PROXY, new Type[]{ Constants.TYPE_SIGNATURE });
|
||||
private static final Signature TO_STRING =
|
||||
TypeUtils.parseSignature("String toString()");
|
||||
private static final Transformer METHOD_TO_CLASS = new Transformer(){
|
||||
public Object transform(Object value) {
|
||||
return ((MethodInfo)value).getClassInfo();
|
||||
}
|
||||
};
|
||||
private static final Signature CSTRUCT_SIGNATURE =
|
||||
TypeUtils.parseConstructor("String, String");
|
||||
|
||||
private String getMethodField(Signature impl) {
|
||||
return impl.getName() + "$Method";
|
||||
}
|
||||
private String getMethodProxyField(Signature impl) {
|
||||
return impl.getName() + "$Proxy";
|
||||
}
|
||||
|
||||
public void generate(ClassEmitter ce, Context context, List methods) {
|
||||
Map sigMap = new HashMap();
|
||||
for (Iterator it = methods.iterator(); it.hasNext();) {
|
||||
MethodInfo method = (MethodInfo)it.next();
|
||||
Signature sig = method.getSignature();
|
||||
Signature impl = context.getImplSignature(method);
|
||||
|
||||
String methodField = getMethodField(impl);
|
||||
String methodProxyField = getMethodProxyField(impl);
|
||||
|
||||
sigMap.put(sig.toString(), methodProxyField);
|
||||
ce.declare_field(Constants.PRIVATE_FINAL_STATIC, methodField, METHOD, null);
|
||||
ce.declare_field(Constants.PRIVATE_FINAL_STATIC, methodProxyField, METHOD_PROXY, null);
|
||||
ce.declare_field(Constants.PRIVATE_FINAL_STATIC, EMPTY_ARGS_NAME, Constants.TYPE_OBJECT_ARRAY, null);
|
||||
CodeEmitter e;
|
||||
|
||||
// access method
|
||||
e = ce.begin_method(Constants.ACC_FINAL,
|
||||
impl,
|
||||
method.getExceptionTypes());
|
||||
superHelper(e, method, context);
|
||||
e.return_value();
|
||||
e.end_method();
|
||||
|
||||
// around method
|
||||
e = context.beginMethod(ce, method);
|
||||
Label nullInterceptor = e.make_label();
|
||||
context.emitCallback(e, context.getIndex(method));
|
||||
e.dup();
|
||||
e.ifnull(nullInterceptor);
|
||||
|
||||
e.load_this();
|
||||
e.getfield(methodField);
|
||||
|
||||
if (sig.getArgumentTypes().length == 0) {
|
||||
e.getfield(EMPTY_ARGS_NAME);
|
||||
} else {
|
||||
e.create_arg_array();
|
||||
}
|
||||
|
||||
e.getfield(methodProxyField);
|
||||
e.invoke_interface(METHOD_INTERCEPTOR, INTERCEPT);
|
||||
e.unbox_or_zero(sig.getReturnType());
|
||||
e.return_value();
|
||||
|
||||
e.mark(nullInterceptor);
|
||||
superHelper(e, method, context);
|
||||
e.return_value();
|
||||
e.end_method();
|
||||
}
|
||||
generateFindProxy(ce, sigMap);
|
||||
}
|
||||
|
||||
private static void superHelper(CodeEmitter e, MethodInfo method, Context context)
|
||||
{
|
||||
if (TypeUtils.isAbstract(method.getModifiers())) {
|
||||
e.throw_exception(ABSTRACT_METHOD_ERROR, method.toString() + " is abstract" );
|
||||
} else {
|
||||
e.load_this();
|
||||
context.emitLoadArgsAndInvoke(e, method);
|
||||
}
|
||||
}
|
||||
|
||||
public void generateStatic(CodeEmitter e, Context context, List methods) throws Exception {
|
||||
/* generates:
|
||||
static {
|
||||
Class thisClass = Class.forName("NameOfThisClass");
|
||||
Class cls = Class.forName("java.lang.Object");
|
||||
String[] sigs = new String[]{ "toString", "()Ljava/lang/String;", ... };
|
||||
Method[] methods = cls.getDeclaredMethods();
|
||||
methods = ReflectUtils.findMethods(sigs, methods);
|
||||
METHOD_0 = methods[0];
|
||||
CGLIB$ACCESS_0 = MethodProxy.create(cls, thisClass, "()Ljava/lang/String;", "toString", "CGLIB$ACCESS_0");
|
||||
...
|
||||
}
|
||||
*/
|
||||
|
||||
e.push(0);
|
||||
e.newarray();
|
||||
e.putfield(EMPTY_ARGS_NAME);
|
||||
|
||||
Local thisclass = e.make_local();
|
||||
Local declaringclass = e.make_local();
|
||||
EmitUtils.load_class_this(e);
|
||||
e.store_local(thisclass);
|
||||
|
||||
Map methodsByClass = CollectionUtils.bucket(methods, METHOD_TO_CLASS);
|
||||
for (Iterator i = methodsByClass.keySet().iterator(); i.hasNext();) {
|
||||
ClassInfo classInfo = (ClassInfo)i.next();
|
||||
|
||||
List classMethods = (List)methodsByClass.get(classInfo);
|
||||
e.push(2 * classMethods.size());
|
||||
e.newarray(Constants.TYPE_STRING);
|
||||
for (int index = 0; index < classMethods.size(); index++) {
|
||||
MethodInfo method = (MethodInfo)classMethods.get(index);
|
||||
Signature sig = method.getSignature();
|
||||
e.dup();
|
||||
e.push(2 * index);
|
||||
e.push(sig.getName());
|
||||
e.aastore();
|
||||
e.dup();
|
||||
e.push(2 * index + 1);
|
||||
e.push(sig.getDescriptor());
|
||||
e.aastore();
|
||||
}
|
||||
|
||||
EmitUtils.load_class(e, classInfo.getType());
|
||||
e.dup();
|
||||
e.store_local(declaringclass);
|
||||
e.invoke_virtual(Constants.TYPE_CLASS, GET_DECLARED_METHODS);
|
||||
e.invoke_static(REFLECT_UTILS, FIND_METHODS);
|
||||
|
||||
for (int index = 0; index < classMethods.size(); index++) {
|
||||
MethodInfo method = (MethodInfo)classMethods.get(index);
|
||||
Signature sig = method.getSignature();
|
||||
Signature impl = context.getImplSignature(method);
|
||||
e.dup();
|
||||
e.push(index);
|
||||
e.array_load(METHOD);
|
||||
e.putfield(getMethodField(impl));
|
||||
|
||||
e.load_local(declaringclass);
|
||||
e.load_local(thisclass);
|
||||
e.push(sig.getDescriptor());
|
||||
e.push(sig.getName());
|
||||
e.push(impl.getName());
|
||||
e.invoke_static(METHOD_PROXY, MAKE_PROXY);
|
||||
e.putfield(getMethodProxyField(impl));
|
||||
}
|
||||
e.pop();
|
||||
}
|
||||
}
|
||||
|
||||
public void generateFindProxy(ClassEmitter ce, final Map sigMap) {
|
||||
final CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC | Constants.ACC_STATIC,
|
||||
FIND_PROXY,
|
||||
null);
|
||||
e.load_arg(0);
|
||||
e.invoke_virtual(Constants.TYPE_OBJECT, TO_STRING);
|
||||
ObjectSwitchCallback callback = new ObjectSwitchCallback() {
|
||||
public void processCase(Object key, Label end) {
|
||||
e.getfield((String)sigMap.get(key));
|
||||
e.return_value();
|
||||
}
|
||||
public void processDefault() {
|
||||
e.aconst_null();
|
||||
e.return_value();
|
||||
}
|
||||
};
|
||||
EmitUtils.string_switch(e,
|
||||
(String[])sigMap.keySet().toArray(new String[0]),
|
||||
Constants.SWITCH_STYLE_HASH,
|
||||
callback);
|
||||
e.end_method();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,243 @@
|
|||
/*
|
||||
* Copyright 2003,2004 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.proxy;
|
||||
|
||||
import java.security.ProtectionDomain;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.*;
|
||||
import org.springframework.cglib.core.*;
|
||||
import org.springframework.asm.ClassVisitor;
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* <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 $
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
abstract public class Mixin {
|
||||
private static final MixinKey KEY_FACTORY =
|
||||
(MixinKey)KeyFactory.create(MixinKey.class, KeyFactory.CLASS_BY_NAME);
|
||||
private static final Map ROUTE_CACHE = Collections.synchronizedMap(new HashMap());
|
||||
|
||||
public static final int STYLE_INTERFACES = 0;
|
||||
public static final int STYLE_BEANS = 1;
|
||||
public static final int STYLE_EVERYTHING = 2;
|
||||
|
||||
interface MixinKey {
|
||||
public Object newInstance(int style, String[] classes, int[] route);
|
||||
}
|
||||
|
||||
abstract public Mixin newInstance(Object[] delegates);
|
||||
|
||||
/**
|
||||
* Helper method to create an interface mixin. For finer control over the
|
||||
* generated instance, use a new instance of <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 route(delegates).classes.clone();
|
||||
}
|
||||
|
||||
// public static int[] getRoute(Object[] delegates) {
|
||||
// return (int[])route(delegates).route.clone();
|
||||
// }
|
||||
|
||||
private static Route route(Object[] delegates) {
|
||||
Object key = ClassesKey.create(delegates);
|
||||
Route route = (Route)ROUTE_CACHE.get(key);
|
||||
if (route == null) {
|
||||
ROUTE_CACHE.put(key, route = new Route(delegates));
|
||||
}
|
||||
return route;
|
||||
}
|
||||
|
||||
private static class Route
|
||||
{
|
||||
private Class[] classes;
|
||||
private int[] route;
|
||||
|
||||
Route(Object[] delegates) {
|
||||
Map map = new HashMap();
|
||||
ArrayList collect = new ArrayList();
|
||||
for (int i = 0; i < delegates.length; i++) {
|
||||
Class delegate = delegates[i].getClass();
|
||||
collect.clear();
|
||||
ReflectUtils.addAllInterfaces(delegate, collect);
|
||||
for (Iterator it = collect.iterator(); it.hasNext();) {
|
||||
Class iface = (Class)it.next();
|
||||
if (!map.containsKey(iface)) {
|
||||
map.put(iface, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
classes = new Class[map.size()];
|
||||
route = new int[map.size()];
|
||||
int index = 0;
|
||||
for (Iterator it = map.keySet().iterator(); it.hasNext();) {
|
||||
Class key = (Class)it.next();
|
||||
classes[index] = key;
|
||||
route[index] = ((Integer)map.get(key));
|
||||
index++;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.proxy;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import org.springframework.cglib.core.ReflectUtils;
|
||||
import org.springframework.asm.ClassVisitor;
|
||||
|
||||
/**
|
||||
* @author Chris Nokleberg
|
||||
* @version $Id: MixinBeanEmitter.java,v 1.2 2004/06/24 21:15:20 herbyderby Exp $
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
class MixinBeanEmitter extends MixinEmitter {
|
||||
public MixinBeanEmitter(ClassVisitor v, String className, Class[] classes) {
|
||||
super(v, className, classes, null);
|
||||
}
|
||||
|
||||
protected Class[] getInterfaces(Class[] classes) {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected Method[] getMethods(Class type) {
|
||||
return ReflectUtils.getPropertyMethods(ReflectUtils.getBeanProperties(type), true, true);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,94 @@
|
|||
/*
|
||||
* Copyright 2003,2004 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.proxy;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.*;
|
||||
import org.springframework.cglib.core.*;
|
||||
import org.springframework.asm.ClassVisitor;
|
||||
import org.springframework.asm.Type;
|
||||
|
||||
/**
|
||||
* @author Chris Nokleberg
|
||||
* @version $Id: MixinEmitter.java,v 1.9 2006/08/27 21:04:37 herbyderby Exp $
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
class MixinEmitter extends ClassEmitter {
|
||||
private static final String FIELD_NAME = "CGLIB$DELEGATES";
|
||||
private static final Signature CSTRUCT_OBJECT_ARRAY =
|
||||
TypeUtils.parseConstructor("Object[]");
|
||||
private static final Type MIXIN =
|
||||
TypeUtils.parseType("org.springframework.cglib.proxy.Mixin");
|
||||
private static final Signature NEW_INSTANCE =
|
||||
new Signature("newInstance", MIXIN, new Type[]{ Constants.TYPE_OBJECT_ARRAY });
|
||||
|
||||
public MixinEmitter(ClassVisitor v, String className, Class[] classes, int[] route) {
|
||||
super(v);
|
||||
|
||||
begin_class(Constants.V1_8,
|
||||
Constants.ACC_PUBLIC,
|
||||
className,
|
||||
MIXIN,
|
||||
TypeUtils.getTypes(getInterfaces(classes)),
|
||||
Constants.SOURCE_FILE);
|
||||
EmitUtils.null_constructor(this);
|
||||
EmitUtils.factory_method(this, NEW_INSTANCE);
|
||||
|
||||
declare_field(Constants.ACC_PRIVATE, FIELD_NAME, Constants.TYPE_OBJECT_ARRAY, null);
|
||||
|
||||
CodeEmitter e = begin_method(Constants.ACC_PUBLIC, CSTRUCT_OBJECT_ARRAY, null);
|
||||
e.load_this();
|
||||
e.super_invoke_constructor();
|
||||
e.load_this();
|
||||
e.load_arg(0);
|
||||
e.putfield(FIELD_NAME);
|
||||
e.return_value();
|
||||
e.end_method();
|
||||
|
||||
Set unique = new HashSet();
|
||||
for (int i = 0; i < classes.length; i++) {
|
||||
Method[] methods = getMethods(classes[i]);
|
||||
for (int j = 0; j < methods.length; j++) {
|
||||
if (unique.add(MethodWrapper.create(methods[j]))) {
|
||||
MethodInfo method = ReflectUtils.getMethodInfo(methods[j]);
|
||||
int modifiers = Constants.ACC_PUBLIC;
|
||||
if ((method.getModifiers() & Constants.ACC_VARARGS) == Constants.ACC_VARARGS) {
|
||||
modifiers |= Constants.ACC_VARARGS;
|
||||
}
|
||||
e = EmitUtils.begin_method(this, method, modifiers);
|
||||
e.load_this();
|
||||
e.getfield(FIELD_NAME);
|
||||
e.aaload((route != null) ? route[i] : i);
|
||||
e.checkcast(method.getClassInfo().getType());
|
||||
e.load_args();
|
||||
e.invoke(method);
|
||||
e.return_value();
|
||||
e.end_method();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
end_class();
|
||||
}
|
||||
|
||||
protected Class[] getInterfaces(Class[] classes) {
|
||||
return classes;
|
||||
}
|
||||
|
||||
protected Method[] getMethods(Class type) {
|
||||
return type.getMethods();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright 2004 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.proxy;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Modifier;
|
||||
import java.util.*;
|
||||
import org.springframework.cglib.core.CollectionUtils;
|
||||
import org.springframework.cglib.core.ReflectUtils;
|
||||
import org.springframework.cglib.core.RejectModifierPredicate;
|
||||
import org.springframework.asm.ClassVisitor;
|
||||
|
||||
/**
|
||||
* @author Chris Nokleberg
|
||||
* @version $Id: MixinEverythingEmitter.java,v 1.3 2004/06/24 21:15:19 herbyderby Exp $
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
class MixinEverythingEmitter extends MixinEmitter {
|
||||
|
||||
public MixinEverythingEmitter(ClassVisitor v, String className, Class[] classes) {
|
||||
super(v, className, classes, null);
|
||||
}
|
||||
|
||||
protected Class[] getInterfaces(Class[] classes) {
|
||||
List list = new ArrayList();
|
||||
for (int i = 0; i < classes.length; i++) {
|
||||
ReflectUtils.addAllInterfaces(classes[i], list);
|
||||
}
|
||||
return (Class[])list.toArray(new Class[list.size()]);
|
||||
}
|
||||
|
||||
protected Method[] getMethods(Class type) {
|
||||
List methods = new ArrayList(Arrays.asList(type.getMethods()));
|
||||
CollectionUtils.filter(methods, new RejectModifierPredicate(Modifier.FINAL | Modifier.STATIC));
|
||||
return (Method[])methods.toArray(new Method[methods.size()]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.proxy;
|
||||
|
||||
/**
|
||||
* Methods using this {@link Enhancer} callback will delegate directly to the
|
||||
* default (super) implementation in the base class.
|
||||
*/
|
||||
public interface NoOp extends Callback
|
||||
{
|
||||
/**
|
||||
* A thread-safe singleton instance of the <code>NoOp</code> callback.
|
||||
*/
|
||||
public static final NoOp INSTANCE = new NoOp() { };
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
/*
|
||||
* Copyright 2003,2004 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.proxy;
|
||||
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import org.springframework.cglib.core.*;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
class NoOpGenerator
|
||||
implements CallbackGenerator
|
||||
{
|
||||
public static final NoOpGenerator INSTANCE = new NoOpGenerator();
|
||||
|
||||
public void generate(ClassEmitter ce, Context context, List methods) {
|
||||
for (Iterator it = methods.iterator(); it.hasNext();) {
|
||||
MethodInfo method = (MethodInfo)it.next();
|
||||
if (TypeUtils.isBridge(method.getModifiers()) || (
|
||||
TypeUtils.isProtected(context.getOriginalModifiers(method)) &&
|
||||
TypeUtils.isPublic(method.getModifiers()))) {
|
||||
CodeEmitter e = EmitUtils.begin_method(ce, method);
|
||||
e.load_this();
|
||||
context.emitLoadArgsAndInvoke(e, method);
|
||||
e.return_value();
|
||||
e.end_method();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void generateStatic(CodeEmitter e, Context context, List methods) { }
|
||||
}
|
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
* Copyright 2003,2004 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.proxy;
|
||||
|
||||
import java.io.Serializable;
|
||||
import java.lang.reflect.Method;
|
||||
import java.lang.reflect.Member;
|
||||
import org.springframework.cglib.core.CodeGenerationException;
|
||||
|
||||
/**
|
||||
* This class is meant to be used as replacement for
|
||||
* <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 $
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked", "serial"})
|
||||
public class Proxy implements Serializable {
|
||||
protected InvocationHandler h;
|
||||
|
||||
private static final CallbackFilter BAD_OBJECT_METHOD_FILTER = new CallbackFilter() {
|
||||
public int accept(Method method) {
|
||||
if (method.getDeclaringClass().getName().equals("java.lang.Object")) {
|
||||
String name = method.getName();
|
||||
if (!(name.equals("hashCode") ||
|
||||
name.equals("equals") ||
|
||||
name.equals("toString"))) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
protected Proxy(InvocationHandler h) {
|
||||
Enhancer.registerCallbacks(getClass(), new Callback[]{ h, null });
|
||||
this.h = h;
|
||||
}
|
||||
|
||||
// private for security of isProxyClass
|
||||
private static class ProxyImpl extends Proxy {
|
||||
protected ProxyImpl(InvocationHandler h) {
|
||||
super(h);
|
||||
}
|
||||
}
|
||||
|
||||
public static InvocationHandler getInvocationHandler(Object proxy) {
|
||||
if (!(proxy instanceof ProxyImpl)) {
|
||||
throw new IllegalArgumentException("Object is not a proxy");
|
||||
}
|
||||
return ((Proxy)proxy).h;
|
||||
}
|
||||
|
||||
public static Class getProxyClass(ClassLoader loader, Class[] interfaces) {
|
||||
Enhancer e = new Enhancer();
|
||||
e.setSuperclass(ProxyImpl.class);
|
||||
e.setInterfaces(interfaces);
|
||||
e.setCallbackTypes(new Class[]{
|
||||
InvocationHandler.class,
|
||||
NoOp.class,
|
||||
});
|
||||
e.setCallbackFilter(BAD_OBJECT_METHOD_FILTER);
|
||||
e.setUseFactory(false);
|
||||
return e.createClass();
|
||||
}
|
||||
|
||||
public static boolean isProxyClass(Class cl) {
|
||||
return cl.getSuperclass().equals(ProxyImpl.class);
|
||||
}
|
||||
|
||||
public static Object newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h) {
|
||||
try {
|
||||
Class clazz = getProxyClass(loader, interfaces);
|
||||
return clazz.getConstructor(new Class[]{ InvocationHandler.class }).newInstance(new Object[]{ h });
|
||||
} catch (RuntimeException e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new CodeGenerationException(e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.proxy;
|
||||
|
||||
/**
|
||||
* Dispatching {@link Enhancer} callback. This is the same as the
|
||||
* {@link Dispatcher} except for the addition of an argument
|
||||
* which references the proxy object.
|
||||
*/
|
||||
public interface ProxyRefDispatcher extends Callback {
|
||||
/**
|
||||
* Return the object which the original method invocation should
|
||||
* be dispatched. This method is called for <b>every</b> method invocation.
|
||||
* @param proxy a reference to the proxy (generated) object
|
||||
* @return an object that can invoke the method
|
||||
*/
|
||||
Object loadObject(Object proxy) throws Exception;
|
||||
}
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright 2002,2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cglib.proxy;
|
||||
|
||||
import org.springframework.cglib.core.CodeGenerationException;
|
||||
|
||||
/**
|
||||
* Used by {@link Proxy} as a replacement for <code>java.lang.reflect.UndeclaredThrowableException</code>.
|
||||
* @author Juozas Baliuka
|
||||
*/
|
||||
@SuppressWarnings("serial")
|
||||
public class UndeclaredThrowableException extends CodeGenerationException {
|
||||
/**
|
||||
* Creates a new instance of <code>UndeclaredThrowableException</code> without detail message.
|
||||
*/
|
||||
public UndeclaredThrowableException(Throwable t) {
|
||||
super(t);
|
||||
}
|
||||
|
||||
public Throwable getUndeclaredThrowable() {
|
||||
return getCause();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.reflect;
|
||||
|
||||
import java.lang.reflect.*;
|
||||
import java.security.ProtectionDomain;
|
||||
import org.springframework.cglib.core.*;
|
||||
import org.springframework.asm.ClassVisitor;
|
||||
import org.springframework.asm.Type;
|
||||
|
||||
/**
|
||||
* @author Chris Nokleberg
|
||||
* @version $Id: ConstructorDelegate.java,v 1.20 2006/03/05 02:43:19 herbyderby Exp $
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
abstract public class ConstructorDelegate {
|
||||
private static final ConstructorKey KEY_FACTORY =
|
||||
(ConstructorKey)KeyFactory.create(ConstructorKey.class, KeyFactory.CLASS_BY_NAME);
|
||||
|
||||
interface ConstructorKey {
|
||||
public Object newInstance(String declaring, String iface);
|
||||
}
|
||||
|
||||
protected ConstructorDelegate() {
|
||||
}
|
||||
|
||||
public static ConstructorDelegate create(Class targetClass, Class iface) {
|
||||
Generator gen = new Generator();
|
||||
gen.setTargetClass(targetClass);
|
||||
gen.setInterface(iface);
|
||||
return gen.create();
|
||||
}
|
||||
|
||||
public static class Generator extends AbstractClassGenerator {
|
||||
private static final Source SOURCE = new Source(ConstructorDelegate.class.getName());
|
||||
private static final Type CONSTRUCTOR_DELEGATE =
|
||||
TypeUtils.parseType("org.springframework.cglib.reflect.ConstructorDelegate");
|
||||
|
||||
private Class iface;
|
||||
private Class targetClass;
|
||||
|
||||
public Generator() {
|
||||
super(SOURCE);
|
||||
}
|
||||
|
||||
public void setInterface(Class iface) {
|
||||
this.iface = iface;
|
||||
}
|
||||
|
||||
public void setTargetClass(Class targetClass) {
|
||||
this.targetClass = targetClass;
|
||||
}
|
||||
|
||||
public ConstructorDelegate create() {
|
||||
setNamePrefix(targetClass.getName());
|
||||
Object key = KEY_FACTORY.newInstance(iface.getName(), targetClass.getName());
|
||||
return (ConstructorDelegate)super.create(key);
|
||||
}
|
||||
|
||||
protected ClassLoader getDefaultClassLoader() {
|
||||
return targetClass.getClassLoader();
|
||||
}
|
||||
|
||||
protected ProtectionDomain getProtectionDomain() {
|
||||
return ReflectUtils.getProtectionDomain(targetClass);
|
||||
}
|
||||
|
||||
public void generateClass(ClassVisitor v) {
|
||||
setNamePrefix(targetClass.getName());
|
||||
|
||||
final Method newInstance = ReflectUtils.findNewInstance(iface);
|
||||
if (!newInstance.getReturnType().isAssignableFrom(targetClass)) {
|
||||
throw new IllegalArgumentException("incompatible return type");
|
||||
}
|
||||
final Constructor constructor;
|
||||
try {
|
||||
constructor = targetClass.getDeclaredConstructor(newInstance.getParameterTypes());
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new IllegalArgumentException("interface does not match any known constructor");
|
||||
}
|
||||
|
||||
ClassEmitter ce = new ClassEmitter(v);
|
||||
ce.begin_class(Constants.V1_8,
|
||||
Constants.ACC_PUBLIC,
|
||||
getClassName(),
|
||||
CONSTRUCTOR_DELEGATE,
|
||||
new Type[]{ Type.getType(iface) },
|
||||
Constants.SOURCE_FILE);
|
||||
Type declaring = Type.getType(constructor.getDeclaringClass());
|
||||
EmitUtils.null_constructor(ce);
|
||||
CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC,
|
||||
ReflectUtils.getSignature(newInstance),
|
||||
ReflectUtils.getExceptionTypes(newInstance));
|
||||
e.new_instance(declaring);
|
||||
e.dup();
|
||||
e.load_args();
|
||||
e.invoke_constructor(declaring, ReflectUtils.getSignature(constructor));
|
||||
e.return_value();
|
||||
e.end_method();
|
||||
ce.end_class();
|
||||
}
|
||||
|
||||
protected Object firstInstance(Class type) {
|
||||
return ReflectUtils.newInstance(type);
|
||||
}
|
||||
|
||||
protected Object nextInstance(Object instance) {
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,208 @@
|
|||
/*
|
||||
* Copyright 2003,2004 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.reflect;
|
||||
|
||||
import org.springframework.cglib.core.*;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.security.ProtectionDomain;
|
||||
import org.springframework.asm.ClassVisitor;
|
||||
import org.springframework.asm.Type;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
abstract public class FastClass
|
||||
{
|
||||
private Class type;
|
||||
|
||||
protected FastClass() {
|
||||
throw new Error("Using the FastClass empty constructor--please report to the cglib-devel mailing list");
|
||||
}
|
||||
|
||||
protected FastClass(Class type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public static FastClass create(Class type) {
|
||||
|
||||
return create(type.getClassLoader(),type);
|
||||
|
||||
}
|
||||
public static FastClass create(ClassLoader loader, Class type) {
|
||||
Generator gen = new Generator();
|
||||
gen.setType(type);
|
||||
gen.setClassLoader(loader);
|
||||
return gen.create();
|
||||
}
|
||||
|
||||
public static class Generator extends AbstractClassGenerator
|
||||
{
|
||||
private static final Source SOURCE = new Source(FastClass.class.getName());
|
||||
private Class type;
|
||||
|
||||
public Generator() {
|
||||
super(SOURCE);
|
||||
}
|
||||
|
||||
public void setType(Class type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public FastClass create() {
|
||||
setNamePrefix(type.getName());
|
||||
return (FastClass)super.create(type.getName());
|
||||
}
|
||||
|
||||
protected ClassLoader getDefaultClassLoader() {
|
||||
return type.getClassLoader();
|
||||
}
|
||||
|
||||
protected ProtectionDomain getProtectionDomain() {
|
||||
return ReflectUtils.getProtectionDomain(type);
|
||||
}
|
||||
|
||||
public void generateClass(ClassVisitor v) throws Exception {
|
||||
new FastClassEmitter(v, getClassName(), type);
|
||||
}
|
||||
|
||||
protected Object firstInstance(Class type) {
|
||||
return ReflectUtils.newInstance(type,
|
||||
new Class[]{ Class.class },
|
||||
new Object[]{ this.type });
|
||||
}
|
||||
|
||||
protected Object nextInstance(Object instance) {
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
|
||||
public Object invoke(String name, Class[] parameterTypes, Object obj, Object[] args) throws InvocationTargetException {
|
||||
return invoke(getIndex(name, parameterTypes), obj, args);
|
||||
}
|
||||
|
||||
public Object newInstance() throws InvocationTargetException {
|
||||
return newInstance(getIndex(Constants.EMPTY_CLASS_ARRAY), null);
|
||||
}
|
||||
|
||||
public Object newInstance(Class[] parameterTypes, Object[] args) throws InvocationTargetException {
|
||||
return newInstance(getIndex(parameterTypes), args);
|
||||
}
|
||||
|
||||
public FastMethod getMethod(Method method) {
|
||||
return new FastMethod(this, method);
|
||||
}
|
||||
|
||||
public FastConstructor getConstructor(Constructor constructor) {
|
||||
return new FastConstructor(this, constructor);
|
||||
}
|
||||
|
||||
public FastMethod getMethod(String name, Class[] parameterTypes) {
|
||||
try {
|
||||
return getMethod(type.getMethod(name, parameterTypes));
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new NoSuchMethodError(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public FastConstructor getConstructor(Class[] parameterTypes) {
|
||||
try {
|
||||
return getConstructor(type.getConstructor(parameterTypes));
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new NoSuchMethodError(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return type.getName();
|
||||
}
|
||||
|
||||
public Class getJavaClass() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return type.toString();
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return type.hashCode();
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (o == null || !(o instanceof FastClass)) {
|
||||
return false;
|
||||
}
|
||||
return type.equals(((FastClass)o).type);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the index of the matching method. The index may be used
|
||||
* later to invoke the method with less overhead. If more than one
|
||||
* method matches (i.e. they differ by return type only), one is
|
||||
* chosen arbitrarily.
|
||||
* @see #invoke(int, Object, Object[])
|
||||
* @param name the method name
|
||||
* @param parameterTypes the parameter array
|
||||
* @return the index, or <code>-1</code> if none is found.
|
||||
*/
|
||||
abstract public int getIndex(String name, Class[] parameterTypes);
|
||||
|
||||
/**
|
||||
* Return the index of the matching constructor. The index may be used
|
||||
* later to create a new instance with less overhead.
|
||||
* @see #newInstance(int, Object[])
|
||||
* @param parameterTypes the parameter array
|
||||
* @return the constructor index, or <code>-1</code> if none is found.
|
||||
*/
|
||||
abstract public int getIndex(Class[] parameterTypes);
|
||||
|
||||
/**
|
||||
* Invoke the method with the specified index.
|
||||
* @see getIndex(name, Class[])
|
||||
* @param index the method index
|
||||
* @param obj the object the underlying method is invoked from
|
||||
* @param args the arguments used for the method call
|
||||
* @throws java.lang.reflect.InvocationTargetException if the underlying method throws an exception
|
||||
*/
|
||||
abstract public Object invoke(int index, Object obj, Object[] args) throws InvocationTargetException;
|
||||
|
||||
/**
|
||||
* Create a new instance using the specified constructor index and arguments.
|
||||
* @see getIndex(Class[])
|
||||
* @param index the constructor index
|
||||
* @param args the arguments passed to the constructor
|
||||
* @throws java.lang.reflect.InvocationTargetException if the constructor throws an exception
|
||||
*/
|
||||
abstract public Object newInstance(int index, Object[] args) throws InvocationTargetException;
|
||||
|
||||
abstract public int getIndex(Signature sig);
|
||||
|
||||
/**
|
||||
* Returns the maximum method index for this class.
|
||||
*/
|
||||
abstract public int getMaxIndex();
|
||||
|
||||
protected static String getSignatureWithoutReturnType(String name, Class[] parameterTypes) {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append(name);
|
||||
sb.append('(');
|
||||
for (int i = 0; i < parameterTypes.length; i++) {
|
||||
sb.append(Type.getDescriptor(parameterTypes[i]));
|
||||
}
|
||||
sb.append(')');
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,227 @@
|
|||
/*
|
||||
* Copyright 2003,2004 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.reflect;
|
||||
|
||||
import java.lang.reflect.*;
|
||||
import java.util.*;
|
||||
import org.springframework.cglib.core.*;
|
||||
import org.springframework.asm.ClassVisitor;
|
||||
import org.springframework.asm.Label;
|
||||
import org.springframework.asm.Type;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked", "deprecation"})
|
||||
class FastClassEmitter extends ClassEmitter {
|
||||
private static final Signature CSTRUCT_CLASS =
|
||||
TypeUtils.parseConstructor("Class");
|
||||
private static final Signature METHOD_GET_INDEX =
|
||||
TypeUtils.parseSignature("int getIndex(String, Class[])");
|
||||
private static final Signature SIGNATURE_GET_INDEX =
|
||||
new Signature("getIndex", Type.INT_TYPE, new Type[]{ Constants.TYPE_SIGNATURE });
|
||||
private static final Signature TO_STRING =
|
||||
TypeUtils.parseSignature("String toString()");
|
||||
private static final Signature CONSTRUCTOR_GET_INDEX =
|
||||
TypeUtils.parseSignature("int getIndex(Class[])");
|
||||
private static final Signature INVOKE =
|
||||
TypeUtils.parseSignature("Object invoke(int, Object, Object[])");
|
||||
private static final Signature NEW_INSTANCE =
|
||||
TypeUtils.parseSignature("Object newInstance(int, Object[])");
|
||||
private static final Signature GET_MAX_INDEX =
|
||||
TypeUtils.parseSignature("int getMaxIndex()");
|
||||
private static final Signature GET_SIGNATURE_WITHOUT_RETURN_TYPE =
|
||||
TypeUtils.parseSignature("String getSignatureWithoutReturnType(String, Class[])");
|
||||
private static final Type FAST_CLASS =
|
||||
TypeUtils.parseType("org.springframework.cglib.reflect.FastClass");
|
||||
private static final Type ILLEGAL_ARGUMENT_EXCEPTION =
|
||||
TypeUtils.parseType("IllegalArgumentException");
|
||||
private static final Type INVOCATION_TARGET_EXCEPTION =
|
||||
TypeUtils.parseType("java.lang.reflect.InvocationTargetException");
|
||||
private static final Type[] INVOCATION_TARGET_EXCEPTION_ARRAY = { INVOCATION_TARGET_EXCEPTION };
|
||||
|
||||
public FastClassEmitter(ClassVisitor v, String className, Class type) {
|
||||
super(v);
|
||||
|
||||
Type base = Type.getType(type);
|
||||
begin_class(Constants.V1_8, Constants.ACC_PUBLIC, className, FAST_CLASS, null, Constants.SOURCE_FILE);
|
||||
|
||||
// constructor
|
||||
CodeEmitter e = begin_method(Constants.ACC_PUBLIC, CSTRUCT_CLASS, null);
|
||||
e.load_this();
|
||||
e.load_args();
|
||||
e.super_invoke_constructor(CSTRUCT_CLASS);
|
||||
e.return_value();
|
||||
e.end_method();
|
||||
|
||||
VisibilityPredicate vp = new VisibilityPredicate(type, false);
|
||||
List methods = ReflectUtils.addAllMethods(type, new ArrayList());
|
||||
CollectionUtils.filter(methods, vp);
|
||||
CollectionUtils.filter(methods, new DuplicatesPredicate());
|
||||
List constructors = new ArrayList(Arrays.asList(type.getDeclaredConstructors()));
|
||||
CollectionUtils.filter(constructors, vp);
|
||||
|
||||
// getIndex(String)
|
||||
emitIndexBySignature(methods);
|
||||
|
||||
// getIndex(String, Class[])
|
||||
emitIndexByClassArray(methods);
|
||||
|
||||
// getIndex(Class[])
|
||||
e = begin_method(Constants.ACC_PUBLIC, CONSTRUCTOR_GET_INDEX, null);
|
||||
e.load_args();
|
||||
List info = CollectionUtils.transform(constructors, MethodInfoTransformer.getInstance());
|
||||
EmitUtils.constructor_switch(e, info, new GetIndexCallback(e, info));
|
||||
e.end_method();
|
||||
|
||||
// invoke(int, Object, Object[])
|
||||
e = begin_method(Constants.ACC_PUBLIC, INVOKE, INVOCATION_TARGET_EXCEPTION_ARRAY);
|
||||
e.load_arg(1);
|
||||
e.checkcast(base);
|
||||
e.load_arg(0);
|
||||
invokeSwitchHelper(e, methods, 2, base);
|
||||
e.end_method();
|
||||
|
||||
// newInstance(int, Object[])
|
||||
e = begin_method(Constants.ACC_PUBLIC, NEW_INSTANCE, INVOCATION_TARGET_EXCEPTION_ARRAY);
|
||||
e.new_instance(base);
|
||||
e.dup();
|
||||
e.load_arg(0);
|
||||
invokeSwitchHelper(e, constructors, 1, base);
|
||||
e.end_method();
|
||||
|
||||
// getMaxIndex()
|
||||
e = begin_method(Constants.ACC_PUBLIC, GET_MAX_INDEX, null);
|
||||
e.push(methods.size() - 1);
|
||||
e.return_value();
|
||||
e.end_method();
|
||||
|
||||
end_class();
|
||||
}
|
||||
|
||||
// TODO: support constructor indices ("<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(), index++);
|
||||
}
|
||||
}
|
||||
|
||||
public void processCase(Object key, Label end) {
|
||||
e.push(((Integer)indexes.get(key)));
|
||||
e.return_value();
|
||||
}
|
||||
|
||||
public void processDefault() {
|
||||
e.push(-1);
|
||||
e.return_value();
|
||||
}
|
||||
}
|
||||
|
||||
private static int[] getIntRange(int length) {
|
||||
int[] range = new int[length];
|
||||
for (int i = 0; i < length; i++) {
|
||||
range[i] = i;
|
||||
}
|
||||
return range;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,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
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.reflect;
|
||||
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public class FastConstructor extends FastMember
|
||||
{
|
||||
FastConstructor(FastClass fc, Constructor constructor) {
|
||||
super(fc, constructor, fc.getIndex(constructor.getParameterTypes()));
|
||||
}
|
||||
|
||||
public Class[] getParameterTypes() {
|
||||
return ((Constructor)member).getParameterTypes();
|
||||
}
|
||||
|
||||
public Class[] getExceptionTypes() {
|
||||
return ((Constructor)member).getExceptionTypes();
|
||||
}
|
||||
|
||||
public Object newInstance() throws InvocationTargetException {
|
||||
return fc.newInstance(index, null);
|
||||
}
|
||||
|
||||
public Object newInstance(Object[] args) throws InvocationTargetException {
|
||||
return fc.newInstance(index, args);
|
||||
}
|
||||
|
||||
public Constructor getJavaConstructor() {
|
||||
return (Constructor)member;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,66 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.reflect;
|
||||
|
||||
import java.lang.reflect.Member;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
abstract public class FastMember
|
||||
{
|
||||
protected FastClass fc;
|
||||
protected Member member;
|
||||
protected int index;
|
||||
|
||||
protected FastMember(FastClass fc, Member member, int index) {
|
||||
this.fc = fc;
|
||||
this.member = member;
|
||||
this.index = index;
|
||||
}
|
||||
|
||||
abstract public Class[] getParameterTypes();
|
||||
abstract public Class[] getExceptionTypes();
|
||||
|
||||
public int getIndex() {
|
||||
return index;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return member.getName();
|
||||
}
|
||||
|
||||
public Class getDeclaringClass() {
|
||||
return fc.getJavaClass();
|
||||
}
|
||||
|
||||
public int getModifiers() {
|
||||
return member.getModifiers();
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
return member.toString();
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return member.hashCode();
|
||||
}
|
||||
|
||||
public boolean equals(Object o) {
|
||||
if (o == null || !(o instanceof FastMember)) {
|
||||
return false;
|
||||
}
|
||||
return member.equals(((FastMember)o).member);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,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
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.reflect;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.cglib.core.Signature;
|
||||
|
||||
import org.springframework.asm.Type;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public class FastMethod extends FastMember
|
||||
{
|
||||
FastMethod(FastClass fc, Method method) {
|
||||
super(fc, method, helper(fc, method));
|
||||
}
|
||||
|
||||
private static int helper(FastClass fc, Method method) {
|
||||
int index = fc.getIndex(new Signature(method.getName(), Type.getMethodDescriptor(method)));
|
||||
if (index < 0) {
|
||||
Class[] types = method.getParameterTypes();
|
||||
System.err.println("hash=" + method.getName().hashCode() + " size=" + types.length);
|
||||
for (int i = 0; i < types.length; i++) {
|
||||
System.err.println(" types[" + i + "]=" + types[i].getName());
|
||||
}
|
||||
throw new IllegalArgumentException("Cannot find method " + method);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
public Class getReturnType() {
|
||||
return ((Method)member).getReturnType();
|
||||
}
|
||||
|
||||
public Class[] getParameterTypes() {
|
||||
return ((Method)member).getParameterTypes();
|
||||
}
|
||||
|
||||
public Class[] getExceptionTypes() {
|
||||
return ((Method)member).getExceptionTypes();
|
||||
}
|
||||
|
||||
public Object invoke(Object obj, Object[] args) throws InvocationTargetException {
|
||||
return fc.invoke(index, obj, args);
|
||||
}
|
||||
|
||||
public Method getJavaMethod() {
|
||||
return (Method)member;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,269 @@
|
|||
/*
|
||||
* Copyright 2003,2004 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.reflect;
|
||||
|
||||
import java.lang.reflect.*;
|
||||
import java.security.ProtectionDomain;
|
||||
import org.springframework.cglib.*;
|
||||
import org.springframework.cglib.core.*;
|
||||
import org.springframework.asm.ClassVisitor;
|
||||
import org.springframework.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 $
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
abstract public class MethodDelegate {
|
||||
private static final MethodDelegateKey KEY_FACTORY =
|
||||
(MethodDelegateKey)KeyFactory.create(MethodDelegateKey.class, KeyFactory.CLASS_BY_NAME);
|
||||
|
||||
protected Object target;
|
||||
protected String eqMethod;
|
||||
|
||||
interface MethodDelegateKey {
|
||||
Object newInstance(Class delegateClass, String methodName, Class iface);
|
||||
}
|
||||
|
||||
public static MethodDelegate createStatic(Class targetClass, String methodName, Class iface) {
|
||||
Generator gen = new Generator();
|
||||
gen.setTargetClass(targetClass);
|
||||
gen.setMethodName(methodName);
|
||||
gen.setInterface(iface);
|
||||
return gen.create();
|
||||
}
|
||||
|
||||
public static MethodDelegate create(Object target, String methodName, Class iface) {
|
||||
Generator gen = new Generator();
|
||||
gen.setTarget(target);
|
||||
gen.setMethodName(methodName);
|
||||
gen.setInterface(iface);
|
||||
return gen.create();
|
||||
}
|
||||
|
||||
public boolean equals(Object obj) {
|
||||
MethodDelegate other = (MethodDelegate)obj;
|
||||
return (other != null && target == other.target) && eqMethod.equals(other.eqMethod);
|
||||
}
|
||||
|
||||
public int hashCode() {
|
||||
return target.hashCode() ^ eqMethod.hashCode();
|
||||
}
|
||||
|
||||
public Object getTarget() {
|
||||
return target;
|
||||
}
|
||||
|
||||
abstract public MethodDelegate newInstance(Object target);
|
||||
|
||||
public static class Generator extends AbstractClassGenerator {
|
||||
private static final Source SOURCE = new Source(MethodDelegate.class.getName());
|
||||
private static final Type METHOD_DELEGATE =
|
||||
TypeUtils.parseType("org.springframework.cglib.reflect.MethodDelegate");
|
||||
private static final Signature NEW_INSTANCE =
|
||||
new Signature("newInstance", METHOD_DELEGATE, new Type[]{ Constants.TYPE_OBJECT });
|
||||
|
||||
private Object target;
|
||||
private Class targetClass;
|
||||
private String methodName;
|
||||
private Class iface;
|
||||
|
||||
public Generator() {
|
||||
super(SOURCE);
|
||||
}
|
||||
|
||||
public void setTarget(Object target) {
|
||||
this.target = target;
|
||||
this.targetClass = target.getClass();
|
||||
}
|
||||
|
||||
public void setTargetClass(Class targetClass) {
|
||||
this.targetClass = targetClass;
|
||||
}
|
||||
|
||||
public void setMethodName(String methodName) {
|
||||
this.methodName = methodName;
|
||||
}
|
||||
|
||||
public void setInterface(Class iface) {
|
||||
this.iface = iface;
|
||||
}
|
||||
|
||||
protected ClassLoader getDefaultClassLoader() {
|
||||
return targetClass.getClassLoader();
|
||||
}
|
||||
|
||||
protected ProtectionDomain getProtectionDomain() {
|
||||
return ReflectUtils.getProtectionDomain(targetClass);
|
||||
}
|
||||
|
||||
public MethodDelegate create() {
|
||||
setNamePrefix(targetClass.getName());
|
||||
Object key = KEY_FACTORY.newInstance(targetClass, methodName, iface);
|
||||
return (MethodDelegate)super.create(key);
|
||||
}
|
||||
|
||||
protected Object firstInstance(Class type) {
|
||||
return ((MethodDelegate)ReflectUtils.newInstance(type)).newInstance(target);
|
||||
}
|
||||
|
||||
protected Object nextInstance(Object instance) {
|
||||
return ((MethodDelegate)instance).newInstance(target);
|
||||
}
|
||||
|
||||
public void generateClass(ClassVisitor v) throws NoSuchMethodException {
|
||||
Method proxy = ReflectUtils.findInterfaceMethod(iface);
|
||||
final Method method = targetClass.getMethod(methodName, proxy.getParameterTypes());
|
||||
if (!proxy.getReturnType().isAssignableFrom(method.getReturnType())) {
|
||||
throw new IllegalArgumentException("incompatible return types");
|
||||
}
|
||||
|
||||
MethodInfo methodInfo = ReflectUtils.getMethodInfo(method);
|
||||
|
||||
boolean isStatic = TypeUtils.isStatic(methodInfo.getModifiers());
|
||||
if ((target == null) ^ isStatic) {
|
||||
throw new IllegalArgumentException("Static method " + (isStatic ? "not " : "") + "expected");
|
||||
}
|
||||
|
||||
ClassEmitter ce = new ClassEmitter(v);
|
||||
CodeEmitter e;
|
||||
ce.begin_class(Constants.V1_8,
|
||||
Constants.ACC_PUBLIC,
|
||||
getClassName(),
|
||||
METHOD_DELEGATE,
|
||||
new Type[]{ Type.getType(iface) },
|
||||
Constants.SOURCE_FILE);
|
||||
ce.declare_field(Constants.PRIVATE_FINAL_STATIC, "eqMethod", Constants.TYPE_STRING, null);
|
||||
EmitUtils.null_constructor(ce);
|
||||
|
||||
// generate proxied method
|
||||
MethodInfo proxied = ReflectUtils.getMethodInfo(iface.getDeclaredMethods()[0]);
|
||||
int modifiers = Constants.ACC_PUBLIC;
|
||||
if ((proxied.getModifiers() & Constants.ACC_VARARGS) == Constants.ACC_VARARGS) {
|
||||
modifiers |= Constants.ACC_VARARGS;
|
||||
}
|
||||
e = EmitUtils.begin_method(ce, proxied, modifiers);
|
||||
e.load_this();
|
||||
e.super_getfield("target", Constants.TYPE_OBJECT);
|
||||
e.checkcast(methodInfo.getClassInfo().getType());
|
||||
e.load_args();
|
||||
e.invoke(methodInfo);
|
||||
e.return_value();
|
||||
e.end_method();
|
||||
|
||||
// newInstance
|
||||
e = ce.begin_method(Constants.ACC_PUBLIC, NEW_INSTANCE, null);
|
||||
e.new_instance_this();
|
||||
e.dup();
|
||||
e.dup2();
|
||||
e.invoke_constructor_this();
|
||||
e.getfield("eqMethod");
|
||||
e.super_putfield("eqMethod", Constants.TYPE_STRING);
|
||||
e.load_arg(0);
|
||||
e.super_putfield("target", Constants.TYPE_OBJECT);
|
||||
e.return_value();
|
||||
e.end_method();
|
||||
|
||||
// static initializer
|
||||
e = ce.begin_static();
|
||||
e.push(methodInfo.getSignature().toString());
|
||||
e.putfield("eqMethod");
|
||||
e.return_value();
|
||||
e.end_method();
|
||||
|
||||
ce.end_class();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,180 @@
|
|||
/*
|
||||
* Copyright 2003,2004 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.reflect;
|
||||
|
||||
import java.lang.reflect.*;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.util.*;
|
||||
import org.springframework.cglib.core.*;
|
||||
import org.springframework.asm.ClassVisitor;
|
||||
import org.springframework.asm.MethodVisitor;
|
||||
import org.springframework.asm.Type;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
abstract public class MulticastDelegate implements Cloneable {
|
||||
protected Object[] targets = {};
|
||||
|
||||
protected MulticastDelegate() {
|
||||
}
|
||||
|
||||
public List getTargets() {
|
||||
return new ArrayList(Arrays.asList(targets));
|
||||
}
|
||||
|
||||
abstract public MulticastDelegate add(Object target);
|
||||
|
||||
protected MulticastDelegate addHelper(Object target) {
|
||||
MulticastDelegate copy = newInstance();
|
||||
copy.targets = new Object[targets.length + 1];
|
||||
System.arraycopy(targets, 0, copy.targets, 0, targets.length);
|
||||
copy.targets[targets.length] = target;
|
||||
return copy;
|
||||
}
|
||||
|
||||
public MulticastDelegate remove(Object target) {
|
||||
for (int i = targets.length - 1; i >= 0; i--) {
|
||||
if (targets[i].equals(target)) {
|
||||
MulticastDelegate copy = newInstance();
|
||||
copy.targets = new Object[targets.length - 1];
|
||||
System.arraycopy(targets, 0, copy.targets, 0, i);
|
||||
System.arraycopy(targets, i + 1, copy.targets, i, targets.length - i - 1);
|
||||
return copy;
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
abstract public MulticastDelegate newInstance();
|
||||
|
||||
public static MulticastDelegate create(Class iface) {
|
||||
Generator gen = new Generator();
|
||||
gen.setInterface(iface);
|
||||
return gen.create();
|
||||
}
|
||||
|
||||
public static class Generator extends AbstractClassGenerator {
|
||||
private static final Source SOURCE = new Source(MulticastDelegate.class.getName());
|
||||
private static final Type MULTICAST_DELEGATE =
|
||||
TypeUtils.parseType("org.springframework.cglib.reflect.MulticastDelegate");
|
||||
private static final Signature NEW_INSTANCE =
|
||||
new Signature("newInstance", MULTICAST_DELEGATE, new Type[0]);
|
||||
private static final Signature ADD_DELEGATE =
|
||||
new Signature("add", MULTICAST_DELEGATE, new Type[]{ Constants.TYPE_OBJECT });
|
||||
private static final Signature ADD_HELPER =
|
||||
new Signature("addHelper", MULTICAST_DELEGATE, new Type[]{ Constants.TYPE_OBJECT });
|
||||
|
||||
private Class iface;
|
||||
|
||||
public Generator() {
|
||||
super(SOURCE);
|
||||
}
|
||||
|
||||
protected ClassLoader getDefaultClassLoader() {
|
||||
return iface.getClassLoader();
|
||||
}
|
||||
|
||||
protected ProtectionDomain getProtectionDomain() {
|
||||
return ReflectUtils.getProtectionDomain(iface);
|
||||
}
|
||||
|
||||
public void setInterface(Class iface) {
|
||||
this.iface = iface;
|
||||
}
|
||||
|
||||
public MulticastDelegate create() {
|
||||
setNamePrefix(MulticastDelegate.class.getName());
|
||||
return (MulticastDelegate)super.create(iface.getName());
|
||||
}
|
||||
|
||||
public void generateClass(ClassVisitor cv) {
|
||||
final MethodInfo method = ReflectUtils.getMethodInfo(ReflectUtils.findInterfaceMethod(iface));
|
||||
|
||||
ClassEmitter ce = new ClassEmitter(cv);
|
||||
ce.begin_class(Constants.V1_8,
|
||||
Constants.ACC_PUBLIC,
|
||||
getClassName(),
|
||||
MULTICAST_DELEGATE,
|
||||
new Type[]{ Type.getType(iface) },
|
||||
Constants.SOURCE_FILE);
|
||||
EmitUtils.null_constructor(ce);
|
||||
|
||||
// generate proxied method
|
||||
emitProxy(ce, method);
|
||||
|
||||
// newInstance
|
||||
CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, NEW_INSTANCE, null);
|
||||
e.new_instance_this();
|
||||
e.dup();
|
||||
e.invoke_constructor_this();
|
||||
e.return_value();
|
||||
e.end_method();
|
||||
|
||||
// add
|
||||
e = ce.begin_method(Constants.ACC_PUBLIC, ADD_DELEGATE, null);
|
||||
e.load_this();
|
||||
e.load_arg(0);
|
||||
e.checkcast(Type.getType(iface));
|
||||
e.invoke_virtual_this(ADD_HELPER);
|
||||
e.return_value();
|
||||
e.end_method();
|
||||
|
||||
ce.end_class();
|
||||
}
|
||||
|
||||
private void emitProxy(ClassEmitter ce, final MethodInfo method) {
|
||||
int modifiers = Constants.ACC_PUBLIC;
|
||||
if ((method.getModifiers() & Constants.ACC_VARARGS) == Constants.ACC_VARARGS) {
|
||||
modifiers |= Constants.ACC_VARARGS;
|
||||
}
|
||||
final CodeEmitter e = EmitUtils.begin_method(ce, method, modifiers);
|
||||
Type returnType = method.getSignature().getReturnType();
|
||||
final boolean returns = returnType != Type.VOID_TYPE;
|
||||
Local result = null;
|
||||
if (returns) {
|
||||
result = e.make_local(returnType);
|
||||
e.zero_or_null(returnType);
|
||||
e.store_local(result);
|
||||
}
|
||||
e.load_this();
|
||||
e.super_getfield("targets", Constants.TYPE_OBJECT_ARRAY);
|
||||
final Local result2 = result;
|
||||
EmitUtils.process_array(e, Constants.TYPE_OBJECT_ARRAY, new ProcessArrayCallback() {
|
||||
public void processElement(Type type) {
|
||||
e.checkcast(Type.getType(iface));
|
||||
e.load_args();
|
||||
e.invoke(method);
|
||||
if (returns) {
|
||||
e.store_local(result2);
|
||||
}
|
||||
}
|
||||
});
|
||||
if (returns) {
|
||||
e.load_local(result);
|
||||
}
|
||||
e.return_value();
|
||||
e.end_method();
|
||||
}
|
||||
|
||||
protected Object firstInstance(Class type) {
|
||||
// make a new instance in case first object is used with a long list of targets
|
||||
return ((MulticastDelegate)ReflectUtils.newInstance(type)).newInstance();
|
||||
}
|
||||
|
||||
protected Object nextInstance(Object instance) {
|
||||
return ((MulticastDelegate)instance).newInstance();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
/*
|
||||
* Copyright 2004 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.transform;
|
||||
|
||||
import org.springframework.asm.*;
|
||||
|
||||
abstract public class AbstractClassFilterTransformer extends AbstractClassTransformer {
|
||||
private ClassTransformer pass;
|
||||
private ClassVisitor target;
|
||||
|
||||
public void setTarget(ClassVisitor target) {
|
||||
super.setTarget(target);
|
||||
pass.setTarget(target);
|
||||
}
|
||||
|
||||
protected AbstractClassFilterTransformer(ClassTransformer pass) {
|
||||
this.pass = pass;
|
||||
}
|
||||
|
||||
abstract protected boolean accept(int version, int access, String name, String signature, String superName, String[] interfaces);
|
||||
|
||||
public void visit(int version,
|
||||
int access,
|
||||
String name,
|
||||
String signature,
|
||||
String superName,
|
||||
String[] interfaces) {
|
||||
target = accept(version, access, name, signature, superName, interfaces) ? pass : cv;
|
||||
target.visit(version, access, name, signature, superName, interfaces);
|
||||
}
|
||||
|
||||
public void visitSource(String source, String debug) {
|
||||
target.visitSource(source, debug);
|
||||
}
|
||||
|
||||
public void visitOuterClass(String owner, String name, String desc) {
|
||||
target.visitOuterClass(owner, name, desc);
|
||||
}
|
||||
|
||||
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
|
||||
return target.visitAnnotation(desc, visible);
|
||||
}
|
||||
|
||||
public void visitAttribute(Attribute attr) {
|
||||
target.visitAttribute(attr);
|
||||
}
|
||||
|
||||
public void visitInnerClass(String name, String outerName, String innerName, int access) {
|
||||
target.visitInnerClass(name, outerName, innerName, access);
|
||||
}
|
||||
|
||||
public FieldVisitor visitField(int access,
|
||||
String name,
|
||||
String desc,
|
||||
String signature,
|
||||
Object value) {
|
||||
return target.visitField(access, name, desc, signature, value);
|
||||
}
|
||||
|
||||
public MethodVisitor visitMethod(int access,
|
||||
String name,
|
||||
String desc,
|
||||
String signature,
|
||||
String[] exceptions) {
|
||||
return target.visitMethod(access, name, desc, signature, exceptions);
|
||||
}
|
||||
|
||||
public void visitEnd() {
|
||||
target.visitEnd();
|
||||
target = null; // just to be safe
|
||||
}
|
||||
}
|
|
@ -0,0 +1,112 @@
|
|||
/*
|
||||
* Copyright 2003,2004 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.transform;
|
||||
|
||||
import org.springframework.cglib.core.CodeGenerationException;
|
||||
import org.springframework.cglib.core.ClassGenerator;
|
||||
import org.springframework.cglib.core.DebuggingClassWriter;
|
||||
import org.springframework.asm.ClassReader;
|
||||
import org.springframework.asm.ClassWriter;
|
||||
import org.springframework.asm.Attribute;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
abstract public class AbstractClassLoader extends ClassLoader {
|
||||
private ClassFilter filter;
|
||||
private ClassLoader classPath;
|
||||
private static java.security.ProtectionDomain DOMAIN ;
|
||||
|
||||
static{
|
||||
DOMAIN = AbstractClassLoader.class.getProtectionDomain();
|
||||
}
|
||||
|
||||
protected AbstractClassLoader(ClassLoader parent, ClassLoader classPath, ClassFilter filter) {
|
||||
super(parent);
|
||||
this.filter = filter;
|
||||
this.classPath = classPath;
|
||||
}
|
||||
|
||||
public Class loadClass(String name) throws ClassNotFoundException {
|
||||
|
||||
Class loaded = findLoadedClass(name);
|
||||
|
||||
if( loaded != null ){
|
||||
if( loaded.getClassLoader() == this ){
|
||||
return loaded;
|
||||
}//else reload with this class loader
|
||||
}
|
||||
|
||||
if (!filter.accept(name)) {
|
||||
return super.loadClass(name);
|
||||
}
|
||||
ClassReader r;
|
||||
try {
|
||||
|
||||
java.io.InputStream is = classPath.getResourceAsStream(
|
||||
name.replace('.','/') + ".class"
|
||||
);
|
||||
|
||||
if (is == null) {
|
||||
|
||||
throw new ClassNotFoundException(name);
|
||||
|
||||
}
|
||||
try {
|
||||
|
||||
r = new ClassReader(is);
|
||||
|
||||
} finally {
|
||||
|
||||
is.close();
|
||||
|
||||
}
|
||||
} catch (IOException e) {
|
||||
throw new ClassNotFoundException(name + ":" + e.getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
DebuggingClassWriter w =
|
||||
new DebuggingClassWriter(ClassWriter.COMPUTE_FRAMES);
|
||||
getGenerator(r).generateClass(w);
|
||||
byte[] b = w.toByteArray();
|
||||
Class c = super.defineClass(name, b, 0, b.length, DOMAIN);
|
||||
postProcess(c);
|
||||
return c;
|
||||
} catch (RuntimeException e) {
|
||||
throw e;
|
||||
} catch (Error e) {
|
||||
throw e;
|
||||
} catch (Exception e) {
|
||||
throw new CodeGenerationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
protected ClassGenerator getGenerator(ClassReader r) {
|
||||
return new ClassReaderGenerator(r, attributes(), getFlags());
|
||||
}
|
||||
|
||||
protected int getFlags() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
protected Attribute[] attributes() {
|
||||
return null;
|
||||
}
|
||||
|
||||
protected void postProcess(Class c) {
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.transform;
|
||||
|
||||
import org.springframework.cglib.core.Constants;
|
||||
import org.springframework.asm.ClassVisitor;
|
||||
|
||||
abstract public class AbstractClassTransformer extends ClassTransformer {
|
||||
protected AbstractClassTransformer() {
|
||||
super(Constants.ASM_API);
|
||||
}
|
||||
|
||||
public void setTarget(ClassVisitor target) {
|
||||
cv = target;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.transform;
|
||||
|
||||
import org.springframework.cglib.core.Constants;
|
||||
import org.springframework.asm.AnnotationVisitor;
|
||||
|
||||
public class AnnotationVisitorTee extends AnnotationVisitor {
|
||||
private AnnotationVisitor av1, av2;
|
||||
|
||||
public static AnnotationVisitor getInstance(AnnotationVisitor av1, AnnotationVisitor av2) {
|
||||
if (av1 == null)
|
||||
return av2;
|
||||
if (av2 == null)
|
||||
return av1;
|
||||
return new AnnotationVisitorTee(av1, av2);
|
||||
}
|
||||
|
||||
public AnnotationVisitorTee(AnnotationVisitor av1, AnnotationVisitor av2) {
|
||||
super(Constants.ASM_API);
|
||||
this.av1 = av1;
|
||||
this.av2 = av2;
|
||||
}
|
||||
|
||||
public void visit(String name, Object value) {
|
||||
av2.visit(name, value);
|
||||
av2.visit(name, value);
|
||||
}
|
||||
|
||||
public void visitEnum(String name, String desc, String value) {
|
||||
av1.visitEnum(name, desc, value);
|
||||
av2.visitEnum(name, desc, value);
|
||||
}
|
||||
|
||||
public AnnotationVisitor visitAnnotation(String name, String desc) {
|
||||
return getInstance(av1.visitAnnotation(name, desc),
|
||||
av2.visitAnnotation(name, desc));
|
||||
}
|
||||
|
||||
public AnnotationVisitor visitArray(String name) {
|
||||
return getInstance(av1.visitArray(name), av2.visitArray(name));
|
||||
}
|
||||
|
||||
public void visitEnd() {
|
||||
av1.visitEnd();
|
||||
av2.visitEnd();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.transform;
|
||||
|
||||
import org.springframework.cglib.core.ClassEmitter;
|
||||
|
||||
abstract public class ClassEmitterTransformer extends ClassEmitter {
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.springframework.cglib.transform;
|
||||
|
||||
/**
|
||||
*
|
||||
* @author baliuka
|
||||
*/
|
||||
public interface ClassFilter {
|
||||
|
||||
boolean accept(String className);
|
||||
|
||||
}
|
|
@ -0,0 +1,31 @@
|
|||
/*
|
||||
* Copyright 2003,2004 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.transform;
|
||||
|
||||
import org.springframework.asm.*;
|
||||
|
||||
public class ClassFilterTransformer extends AbstractClassFilterTransformer {
|
||||
private ClassFilter filter;
|
||||
|
||||
public ClassFilterTransformer(ClassFilter filter, ClassTransformer pass) {
|
||||
super(pass);
|
||||
this.filter = filter;
|
||||
}
|
||||
|
||||
protected boolean accept(int version, int access, String name, String signature, String superName, String[] interfaces) {
|
||||
return filter.accept(name.replace('/', '.'));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.transform;
|
||||
|
||||
import org.springframework.cglib.core.ClassGenerator;
|
||||
import org.springframework.asm.Attribute;
|
||||
import org.springframework.asm.ClassReader;
|
||||
import org.springframework.asm.ClassVisitor;
|
||||
|
||||
public class ClassReaderGenerator implements ClassGenerator {
|
||||
private final ClassReader r;
|
||||
private final Attribute[] attrs;
|
||||
private final int flags;
|
||||
|
||||
public ClassReaderGenerator(ClassReader r, int flags) {
|
||||
this(r, null, flags);
|
||||
}
|
||||
|
||||
public ClassReaderGenerator(ClassReader r, Attribute[] attrs, int flags) {
|
||||
this.r = r;
|
||||
this.attrs = (attrs != null) ? attrs : new Attribute[0];
|
||||
this.flags = flags;
|
||||
}
|
||||
|
||||
public void generateClass(ClassVisitor v) {
|
||||
r.accept(v, attrs, flags);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.transform;
|
||||
|
||||
import org.springframework.cglib.core.Constants;
|
||||
import org.springframework.asm.ClassVisitor;
|
||||
|
||||
public abstract class ClassTransformer extends ClassVisitor {
|
||||
public ClassTransformer() {
|
||||
super(Constants.ASM_API);
|
||||
}
|
||||
public ClassTransformer(int opcode) {
|
||||
super(opcode);
|
||||
}
|
||||
public abstract void setTarget(ClassVisitor target);
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
/*
|
||||
* Copyright 2003,2004 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.transform;
|
||||
|
||||
import org.springframework.asm.*;
|
||||
|
||||
public class ClassTransformerChain extends AbstractClassTransformer {
|
||||
private ClassTransformer[] chain;
|
||||
|
||||
public ClassTransformerChain(ClassTransformer[] chain) {
|
||||
this.chain = chain.clone();
|
||||
}
|
||||
|
||||
public void setTarget(ClassVisitor v) {
|
||||
super.setTarget(chain[0]);
|
||||
ClassVisitor next = v;
|
||||
for (int i = chain.length - 1; i >= 0; i--) {
|
||||
chain[i].setTarget(next);
|
||||
next = chain[i];
|
||||
}
|
||||
}
|
||||
|
||||
public MethodVisitor visitMethod(int access,
|
||||
String name,
|
||||
String desc,
|
||||
String signature,
|
||||
String[] exceptions) {
|
||||
return cv.visitMethod(access, name, desc, signature, exceptions);
|
||||
}
|
||||
|
||||
public String toString() {
|
||||
StringBuffer sb = new StringBuffer();
|
||||
sb.append("ClassTransformerChain{");
|
||||
for (int i = 0; i < chain.length; i++) {
|
||||
if (i > 0) {
|
||||
sb.append(", ");
|
||||
}
|
||||
sb.append(chain[i].toString());
|
||||
}
|
||||
sb.append("}");
|
||||
return sb.toString();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,20 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.transform;
|
||||
|
||||
public interface ClassTransformerFactory {
|
||||
ClassTransformer newInstance();
|
||||
}
|
|
@ -0,0 +1,32 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.transform;
|
||||
|
||||
import org.springframework.cglib.core.Constants;
|
||||
import org.springframework.asm.ClassVisitor;
|
||||
|
||||
public class ClassTransformerTee extends ClassTransformer {
|
||||
private ClassVisitor branch;
|
||||
|
||||
public ClassTransformerTee(ClassVisitor branch) {
|
||||
super(Constants.ASM_API);
|
||||
this.branch = branch;
|
||||
}
|
||||
|
||||
public void setTarget(ClassVisitor target) {
|
||||
cv = new ClassVisitorTee(branch, target);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.transform;
|
||||
|
||||
import org.springframework.cglib.core.Constants;
|
||||
import org.springframework.asm.*;
|
||||
|
||||
public class ClassVisitorTee extends ClassVisitor {
|
||||
private ClassVisitor cv1, cv2;
|
||||
|
||||
public ClassVisitorTee(ClassVisitor cv1, ClassVisitor cv2) {
|
||||
super(Constants.ASM_API);
|
||||
this.cv1 = cv1;
|
||||
this.cv2 = cv2;
|
||||
}
|
||||
|
||||
public void visit(int version,
|
||||
int access,
|
||||
String name,
|
||||
String signature,
|
||||
String superName,
|
||||
String[] interfaces) {
|
||||
cv1.visit(version, access, name, signature, superName, interfaces);
|
||||
cv2.visit(version, access, name, signature, superName, interfaces);
|
||||
}
|
||||
|
||||
public void visitEnd() {
|
||||
cv1.visitEnd();
|
||||
cv2.visitEnd();
|
||||
cv1 = cv2 = null;
|
||||
}
|
||||
|
||||
public void visitInnerClass(String name, String outerName, String innerName, int access) {
|
||||
cv1.visitInnerClass(name, outerName, innerName, access);
|
||||
cv2.visitInnerClass(name, outerName, innerName, access);
|
||||
}
|
||||
|
||||
public FieldVisitor visitField(int access,
|
||||
String name,
|
||||
String desc,
|
||||
String signature,
|
||||
Object value) {
|
||||
FieldVisitor fv1 = cv1.visitField(access, name, desc, signature, value);
|
||||
FieldVisitor fv2 = cv2.visitField(access, name, desc, signature, value);
|
||||
if (fv1 == null)
|
||||
return fv2;
|
||||
if (fv2 == null)
|
||||
return fv1;
|
||||
return new FieldVisitorTee(fv1, fv2);
|
||||
}
|
||||
|
||||
|
||||
public MethodVisitor visitMethod(int access,
|
||||
String name,
|
||||
String desc,
|
||||
String signature,
|
||||
String[] exceptions) {
|
||||
MethodVisitor mv1 = cv1.visitMethod(access, name, desc, signature, exceptions);
|
||||
MethodVisitor mv2 = cv2.visitMethod(access, name, desc, signature, exceptions);
|
||||
if (mv1 == null)
|
||||
return mv2;
|
||||
if (mv2 == null)
|
||||
return mv1;
|
||||
return new MethodVisitorTee(mv1, mv2);
|
||||
}
|
||||
|
||||
public void visitSource(String source, String debug) {
|
||||
cv1.visitSource(source, debug);
|
||||
cv2.visitSource(source, debug);
|
||||
}
|
||||
|
||||
public void visitOuterClass(String owner, String name, String desc) {
|
||||
cv1.visitOuterClass(owner, name, desc);
|
||||
cv2.visitOuterClass(owner, name, desc);
|
||||
}
|
||||
|
||||
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
|
||||
return AnnotationVisitorTee.getInstance(cv1.visitAnnotation(desc, visible),
|
||||
cv2.visitAnnotation(desc, visible));
|
||||
}
|
||||
|
||||
public void visitAttribute(Attribute attrs) {
|
||||
cv1.visitAttribute(attrs);
|
||||
cv2.visitAttribute(attrs);
|
||||
}
|
||||
|
||||
public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
|
||||
return AnnotationVisitorTee.getInstance(cv1.visitTypeAnnotation(typeRef, typePath, desc, visible),
|
||||
cv2.visitTypeAnnotation(typeRef, typePath, desc, visible));
|
||||
}
|
||||
}
|
|
@ -0,0 +1,53 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.transform;
|
||||
|
||||
import org.springframework.cglib.core.Constants;
|
||||
import org.springframework.asm.AnnotationVisitor;
|
||||
import org.springframework.asm.Attribute;
|
||||
import org.springframework.asm.FieldVisitor;
|
||||
import org.springframework.asm.TypePath;
|
||||
|
||||
public class FieldVisitorTee extends FieldVisitor {
|
||||
private FieldVisitor fv1, fv2;
|
||||
|
||||
public FieldVisitorTee(FieldVisitor fv1, FieldVisitor fv2) {
|
||||
super(Constants.ASM_API);
|
||||
this.fv1 = fv1;
|
||||
this.fv2 = fv2;
|
||||
}
|
||||
|
||||
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
|
||||
return AnnotationVisitorTee.getInstance(fv1.visitAnnotation(desc, visible),
|
||||
fv2.visitAnnotation(desc, visible));
|
||||
}
|
||||
|
||||
public void visitAttribute(Attribute attr) {
|
||||
fv1.visitAttribute(attr);
|
||||
fv2.visitAttribute(attr);
|
||||
}
|
||||
|
||||
public void visitEnd() {
|
||||
fv1.visitEnd();
|
||||
fv2.visitEnd();
|
||||
}
|
||||
|
||||
public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
|
||||
return AnnotationVisitorTee.getInstance(fv1.visitTypeAnnotation(typeRef, typePath, desc, visible),
|
||||
fv2.visitTypeAnnotation(typeRef, typePath, desc, visible));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.transform;
|
||||
|
||||
import org.springframework.asm.Attribute;
|
||||
|
||||
public interface MethodFilter {
|
||||
// TODO: pass class name too?
|
||||
boolean accept(int access, String name, String desc, String signature, String[] exceptions);
|
||||
}
|
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.transform;
|
||||
|
||||
import org.springframework.asm.*;
|
||||
|
||||
public class MethodFilterTransformer extends AbstractClassTransformer {
|
||||
private MethodFilter filter;
|
||||
private ClassTransformer pass;
|
||||
private ClassVisitor direct;
|
||||
|
||||
public MethodFilterTransformer(MethodFilter filter, ClassTransformer pass) {
|
||||
this.filter = filter;
|
||||
this.pass = pass;
|
||||
super.setTarget(pass);
|
||||
}
|
||||
|
||||
public MethodVisitor visitMethod(int access,
|
||||
String name,
|
||||
String desc,
|
||||
String signature,
|
||||
String[] exceptions) {
|
||||
return (filter.accept(access, name, desc, signature, exceptions) ? pass : direct).visitMethod(access, name, desc, signature, exceptions);
|
||||
}
|
||||
|
||||
public void setTarget(ClassVisitor target) {
|
||||
pass.setTarget(target);
|
||||
direct = target;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,189 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.transform;
|
||||
|
||||
import org.springframework.cglib.core.Constants;
|
||||
import org.springframework.asm.*;
|
||||
|
||||
@SuppressWarnings("deprecation")
|
||||
public class MethodVisitorTee extends MethodVisitor {
|
||||
private final MethodVisitor mv1;
|
||||
private final MethodVisitor mv2;
|
||||
|
||||
public MethodVisitorTee(MethodVisitor mv1, MethodVisitor mv2) {
|
||||
super(Constants.ASM_API);
|
||||
this.mv1 = mv1;
|
||||
this.mv2 = mv2;
|
||||
}
|
||||
|
||||
public void visitFrame(int type, int nLocal, Object[] local, int nStack, Object[] stack) {
|
||||
mv1.visitFrame(type, nLocal, local, nStack, stack);
|
||||
mv2.visitFrame(type, nLocal, local, nStack, stack);
|
||||
}
|
||||
|
||||
public AnnotationVisitor visitAnnotationDefault() {
|
||||
return AnnotationVisitorTee.getInstance(mv1.visitAnnotationDefault(),
|
||||
mv2.visitAnnotationDefault());
|
||||
}
|
||||
|
||||
public AnnotationVisitor visitAnnotation(String desc, boolean visible) {
|
||||
return AnnotationVisitorTee.getInstance(mv1.visitAnnotation(desc, visible),
|
||||
mv2.visitAnnotation(desc, visible));
|
||||
}
|
||||
|
||||
public AnnotationVisitor visitParameterAnnotation(int parameter,
|
||||
String desc,
|
||||
boolean visible) {
|
||||
return AnnotationVisitorTee.getInstance(mv1.visitParameterAnnotation(parameter, desc, visible),
|
||||
mv2.visitParameterAnnotation(parameter, desc, visible));
|
||||
}
|
||||
|
||||
public void visitAttribute(Attribute attr) {
|
||||
mv1.visitAttribute(attr);
|
||||
mv2.visitAttribute(attr);
|
||||
}
|
||||
|
||||
public void visitCode() {
|
||||
mv1.visitCode();
|
||||
mv2.visitCode();
|
||||
}
|
||||
|
||||
public void visitInsn(int opcode) {
|
||||
mv1.visitInsn(opcode);
|
||||
mv2.visitInsn(opcode);
|
||||
}
|
||||
|
||||
public void visitIntInsn(int opcode, int operand) {
|
||||
mv1.visitIntInsn(opcode, operand);
|
||||
mv2.visitIntInsn(opcode, operand);
|
||||
}
|
||||
|
||||
public void visitVarInsn(int opcode, int var) {
|
||||
mv1.visitVarInsn(opcode, var);
|
||||
mv2.visitVarInsn(opcode, var);
|
||||
}
|
||||
|
||||
public void visitTypeInsn(int opcode, String desc) {
|
||||
mv1.visitTypeInsn(opcode, desc);
|
||||
mv2.visitTypeInsn(opcode, desc);
|
||||
}
|
||||
|
||||
public void visitFieldInsn(int opcode, String owner, String name, String desc) {
|
||||
mv1.visitFieldInsn(opcode, owner, name, desc);
|
||||
mv2.visitFieldInsn(opcode, owner, name, desc);
|
||||
}
|
||||
|
||||
public void visitMethodInsn(int opcode, String owner, String name, String desc) {
|
||||
mv1.visitMethodInsn(opcode, owner, name, desc);
|
||||
mv2.visitMethodInsn(opcode, owner, name, desc);
|
||||
}
|
||||
|
||||
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
|
||||
mv1.visitMethodInsn(opcode, owner, name, desc, itf);
|
||||
mv2.visitMethodInsn(opcode, owner, name, desc, itf);
|
||||
}
|
||||
|
||||
public void visitJumpInsn(int opcode, Label label) {
|
||||
mv1.visitJumpInsn(opcode, label);
|
||||
mv2.visitJumpInsn(opcode, label);
|
||||
}
|
||||
|
||||
public void visitLabel(Label label) {
|
||||
mv1.visitLabel(label);
|
||||
mv2.visitLabel(label);
|
||||
}
|
||||
|
||||
public void visitLdcInsn(Object cst) {
|
||||
mv1.visitLdcInsn(cst);
|
||||
mv2.visitLdcInsn(cst);
|
||||
}
|
||||
|
||||
public void visitIincInsn(int var, int increment) {
|
||||
mv1.visitIincInsn(var, increment);
|
||||
mv2.visitIincInsn(var, increment);
|
||||
}
|
||||
|
||||
public void visitTableSwitchInsn(int min, int max, Label dflt, Label... labels) {
|
||||
mv1.visitTableSwitchInsn(min, max, dflt, labels);
|
||||
mv2.visitTableSwitchInsn(min, max, dflt, labels);
|
||||
}
|
||||
|
||||
public void visitLookupSwitchInsn(Label dflt, int[] keys, Label[] labels) {
|
||||
mv1.visitLookupSwitchInsn(dflt, keys, labels);
|
||||
mv2.visitLookupSwitchInsn(dflt, keys, labels);
|
||||
}
|
||||
|
||||
public void visitMultiANewArrayInsn(String desc, int dims) {
|
||||
mv1.visitMultiANewArrayInsn(desc, dims);
|
||||
mv2.visitMultiANewArrayInsn(desc, dims);
|
||||
}
|
||||
|
||||
public void visitTryCatchBlock(Label start, Label end, Label handler, String type) {
|
||||
mv1.visitTryCatchBlock(start, end, handler, type);
|
||||
mv2.visitTryCatchBlock(start, end, handler, type);
|
||||
}
|
||||
|
||||
public void visitLocalVariable(String name, String desc, String signature, Label start, Label end, int index) {
|
||||
mv1.visitLocalVariable(name, desc, signature, start, end, index);
|
||||
mv2.visitLocalVariable(name, desc, signature, start, end, index);
|
||||
}
|
||||
|
||||
public void visitLineNumber(int line, Label start) {
|
||||
mv1.visitLineNumber(line, start);
|
||||
mv2.visitLineNumber(line, start);
|
||||
}
|
||||
|
||||
public void visitMaxs(int maxStack, int maxLocals) {
|
||||
mv1.visitMaxs(maxStack, maxLocals);
|
||||
mv2.visitMaxs(maxStack, maxLocals);
|
||||
}
|
||||
|
||||
public void visitEnd() {
|
||||
mv1.visitEnd();
|
||||
mv2.visitEnd();
|
||||
}
|
||||
|
||||
public void visitParameter(String name, int access) {
|
||||
mv1.visitParameter(name, access);
|
||||
mv2.visitParameter(name, access);
|
||||
}
|
||||
|
||||
public AnnotationVisitor visitTypeAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
|
||||
return AnnotationVisitorTee.getInstance(mv1.visitTypeAnnotation(typeRef, typePath, desc, visible),
|
||||
mv2.visitTypeAnnotation(typeRef, typePath, desc, visible));
|
||||
}
|
||||
|
||||
public void visitInvokeDynamicInsn(String name, String desc, Handle bsm, Object... bsmArgs) {
|
||||
mv1.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
|
||||
mv2.visitInvokeDynamicInsn(name, desc, bsm, bsmArgs);
|
||||
}
|
||||
|
||||
public AnnotationVisitor visitInsnAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
|
||||
return AnnotationVisitorTee.getInstance(mv1.visitInsnAnnotation(typeRef, typePath, desc, visible),
|
||||
mv2.visitInsnAnnotation(typeRef, typePath, desc, visible));
|
||||
}
|
||||
|
||||
public AnnotationVisitor visitTryCatchAnnotation(int typeRef, TypePath typePath, String desc, boolean visible) {
|
||||
return AnnotationVisitorTee.getInstance(mv1.visitTryCatchAnnotation(typeRef, typePath, desc, visible),
|
||||
mv2.visitTryCatchAnnotation(typeRef, typePath, desc, visible));
|
||||
}
|
||||
|
||||
public AnnotationVisitor visitLocalVariableAnnotation(int typeRef, TypePath typePath, Label[] start, Label[] end, int[] index, String desc, boolean visible) {
|
||||
return AnnotationVisitorTee.getInstance(mv1.visitLocalVariableAnnotation(typeRef, typePath, start, end, index, desc, visible),
|
||||
mv2.visitLocalVariableAnnotation(typeRef, typePath, start, end, index, desc, visible));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.transform;
|
||||
|
||||
import org.springframework.cglib.core.ClassGenerator;
|
||||
import org.springframework.cglib.core.Transformer;
|
||||
import org.springframework.asm.ClassVisitor;
|
||||
|
||||
public class TransformingClassGenerator implements ClassGenerator {
|
||||
private ClassGenerator gen;
|
||||
private ClassTransformer t;
|
||||
|
||||
public TransformingClassGenerator(ClassGenerator gen, ClassTransformer t) {
|
||||
this.gen = gen;
|
||||
this.t = t;
|
||||
}
|
||||
|
||||
public void generateClass(ClassVisitor v) throws Exception {
|
||||
t.setTarget(v);
|
||||
gen.generateClass(t);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,34 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.transform;
|
||||
|
||||
import java.util.*;
|
||||
import org.springframework.cglib.core.ClassGenerator;
|
||||
import org.springframework.asm.*;
|
||||
|
||||
public class TransformingClassLoader extends AbstractClassLoader {
|
||||
private ClassTransformerFactory t;
|
||||
|
||||
public TransformingClassLoader(ClassLoader parent, ClassFilter filter, ClassTransformerFactory t) {
|
||||
super(parent, parent, filter);
|
||||
this.t = t;
|
||||
}
|
||||
|
||||
protected ClassGenerator getGenerator(ClassReader r) {
|
||||
ClassTransformer t2 = t.newInstance();
|
||||
return new TransformingClassGenerator(super.getGenerator(r), t2);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,42 @@
|
|||
/*
|
||||
* Copyright 2004 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.transform.impl;
|
||||
|
||||
/**
|
||||
* @author Chris Nokleberg
|
||||
*/
|
||||
public class AbstractInterceptFieldCallback implements InterceptFieldCallback {
|
||||
|
||||
public int writeInt(Object obj, String name, int oldValue, int newValue) { return newValue; }
|
||||
public char writeChar(Object obj, String name, char oldValue, char newValue) { return newValue; }
|
||||
public byte writeByte(Object obj, String name, byte oldValue, byte newValue) { return newValue; }
|
||||
public boolean writeBoolean(Object obj, String name, boolean oldValue, boolean newValue) { return newValue; }
|
||||
public short writeShort(Object obj, String name, short oldValue, short newValue) { return newValue; }
|
||||
public float writeFloat(Object obj, String name, float oldValue, float newValue) { return newValue; }
|
||||
public double writeDouble(Object obj, String name, double oldValue, double newValue) { return newValue; }
|
||||
public long writeLong(Object obj, String name, long oldValue, long newValue) { return newValue; }
|
||||
public Object writeObject(Object obj, String name, Object oldValue, Object newValue) { return newValue; }
|
||||
|
||||
public int readInt(Object obj, String name, int oldValue) { return oldValue; }
|
||||
public char readChar(Object obj, String name, char oldValue) { return oldValue; }
|
||||
public byte readByte(Object obj, String name, byte oldValue) { return oldValue; }
|
||||
public boolean readBoolean(Object obj, String name, boolean oldValue) { return oldValue; }
|
||||
public short readShort(Object obj, String name, short oldValue) { return oldValue; }
|
||||
public float readFloat(Object obj, String name, float oldValue) { return oldValue; }
|
||||
public double readDouble(Object obj, String name, double oldValue) { return oldValue; }
|
||||
public long readLong(Object obj, String name, long oldValue) { return oldValue; }
|
||||
public Object readObject(Object obj, String name, Object oldValue) { return oldValue; }
|
||||
}
|
|
@ -0,0 +1,64 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.transform.impl;
|
||||
|
||||
import org.springframework.cglib.transform.*;
|
||||
import org.springframework.cglib.core.*;
|
||||
import org.springframework.asm.ClassVisitor;
|
||||
import org.springframework.asm.MethodVisitor;
|
||||
import org.springframework.asm.Attribute;
|
||||
import org.springframework.asm.Type;
|
||||
|
||||
public class AccessFieldTransformer extends ClassEmitterTransformer {
|
||||
private Callback callback;
|
||||
|
||||
public AccessFieldTransformer(Callback callback) {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
public interface Callback {
|
||||
String getPropertyName(Type owner, String fieldName);
|
||||
}
|
||||
|
||||
public void declare_field(int access, final String name, Type type, Object value) {
|
||||
super.declare_field(access, name, type, value);
|
||||
|
||||
String property = TypeUtils.upperFirst(callback.getPropertyName(getClassType(), name));
|
||||
if (property != null) {
|
||||
CodeEmitter e;
|
||||
e = begin_method(Constants.ACC_PUBLIC,
|
||||
new Signature("get" + property,
|
||||
type,
|
||||
Constants.TYPES_EMPTY),
|
||||
null);
|
||||
e.load_this();
|
||||
e.getfield(name);
|
||||
e.return_value();
|
||||
e.end_method();
|
||||
|
||||
e = begin_method(Constants.ACC_PUBLIC,
|
||||
new Signature("set" + property,
|
||||
Type.VOID_TYPE,
|
||||
new Type[]{ type }),
|
||||
null);
|
||||
e.load_this();
|
||||
e.load_arg(0);
|
||||
e.putfield(name);
|
||||
e.return_value();
|
||||
e.end_method();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
/*
|
||||
* Copyright 2003 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.transform.impl;
|
||||
|
||||
import org.springframework.cglib.transform.*;
|
||||
import java.lang.reflect.*;
|
||||
import java.util.*;
|
||||
import org.springframework.cglib.core.*;
|
||||
import org.springframework.asm.Attribute;
|
||||
import org.springframework.asm.Type;
|
||||
|
||||
/**
|
||||
* @author Juozas Baliuka
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
public class AddDelegateTransformer extends ClassEmitterTransformer {
|
||||
private static final String DELEGATE = "$CGLIB_DELEGATE";
|
||||
private static final Signature CSTRUCT_OBJECT =
|
||||
TypeUtils.parseSignature("void <init>(Object)");
|
||||
|
||||
private Class[] delegateIf;
|
||||
private Class delegateImpl;
|
||||
private Type delegateType;
|
||||
|
||||
/** Creates a new instance of AddDelegateTransformer */
|
||||
public AddDelegateTransformer(Class delegateIf[], Class delegateImpl) {
|
||||
try {
|
||||
delegateImpl.getConstructor(new Class[]{ Object.class });
|
||||
this.delegateIf = delegateIf;
|
||||
this.delegateImpl = delegateImpl;
|
||||
delegateType = Type.getType(delegateImpl);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new CodeGenerationException(e);
|
||||
}
|
||||
}
|
||||
|
||||
public void begin_class(int version, int access, String className, Type superType, Type[] interfaces, String sourceFile) {
|
||||
|
||||
if(!TypeUtils.isInterface(access)){
|
||||
|
||||
Type[] all = TypeUtils.add(interfaces, TypeUtils.getTypes(delegateIf));
|
||||
super.begin_class(version, access, className, superType, all, sourceFile);
|
||||
|
||||
declare_field(Constants.ACC_PRIVATE | Constants.ACC_TRANSIENT,
|
||||
DELEGATE,
|
||||
delegateType,
|
||||
null);
|
||||
for (int i = 0; i < delegateIf.length; i++) {
|
||||
Method[] methods = delegateIf[i].getMethods();
|
||||
for (int j = 0; j < methods.length; j++) {
|
||||
if (Modifier.isAbstract(methods[j].getModifiers())) {
|
||||
addDelegate(methods[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}else{
|
||||
super.begin_class(version, access, className, superType, interfaces, sourceFile);
|
||||
}
|
||||
}
|
||||
|
||||
public CodeEmitter begin_method(int access, Signature sig, Type[] exceptions) {
|
||||
final CodeEmitter e = super.begin_method(access, sig, exceptions);
|
||||
if (sig.getName().equals(Constants.CONSTRUCTOR_NAME)) {
|
||||
return new CodeEmitter(e) {
|
||||
private boolean transformInit = true;
|
||||
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
|
||||
super.visitMethodInsn(opcode, owner, name, desc, itf);
|
||||
if (transformInit && opcode == Constants.INVOKESPECIAL) {
|
||||
load_this();
|
||||
new_instance(delegateType);
|
||||
dup();
|
||||
load_this();
|
||||
invoke_constructor(delegateType, CSTRUCT_OBJECT);
|
||||
putfield(DELEGATE);
|
||||
transformInit = false;
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
return e;
|
||||
}
|
||||
|
||||
private void addDelegate(Method m) {
|
||||
Method delegate;
|
||||
try {
|
||||
delegate = delegateImpl.getMethod(m.getName(), m.getParameterTypes());
|
||||
if (!delegate.getReturnType().getName().equals(m.getReturnType().getName())){
|
||||
throw new IllegalArgumentException("Invalid delegate signature " + delegate);
|
||||
}
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new CodeGenerationException(e);
|
||||
}
|
||||
|
||||
final Signature sig = ReflectUtils.getSignature(m);
|
||||
Type[] exceptions = TypeUtils.getTypes(m.getExceptionTypes());
|
||||
CodeEmitter e = super.begin_method(Constants.ACC_PUBLIC, sig, exceptions);
|
||||
e.load_this();
|
||||
e.getfield(DELEGATE);
|
||||
e.load_args();
|
||||
e.invoke_virtual(delegateType, sig);
|
||||
e.return_value();
|
||||
e.end_method();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright 2004 The Apache Software Foundation
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.springframework.cglib.transform.impl;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
import org.springframework.cglib.core.CodeEmitter;
|
||||
import org.springframework.cglib.core.Constants;
|
||||
import org.springframework.cglib.core.MethodInfo;
|
||||
import org.springframework.cglib.core.ReflectUtils;
|
||||
import org.springframework.cglib.core.Signature;
|
||||
import org.springframework.cglib.transform.ClassEmitterTransformer;
|
||||
|
||||
import org.springframework.asm.Attribute;
|
||||
import org.springframework.asm.Type;
|
||||
|
||||
/**
|
||||
* @author Mark Hobson
|
||||
*/
|
||||
public class AddInitTransformer extends ClassEmitterTransformer {
|
||||
private MethodInfo info;
|
||||
|
||||
public AddInitTransformer(Method method) {
|
||||
info = ReflectUtils.getMethodInfo(method);
|
||||
|
||||
Type[] types = info.getSignature().getArgumentTypes();
|
||||
if (types.length != 1 ||
|
||||
!types[0].equals(Constants.TYPE_OBJECT) ||
|
||||
!info.getSignature().getReturnType().equals(Type.VOID_TYPE)) {
|
||||
throw new IllegalArgumentException(method + " illegal signature");
|
||||
}
|
||||
}
|
||||
|
||||
public CodeEmitter begin_method(int access, Signature sig, Type[] exceptions) {
|
||||
final CodeEmitter emitter = super.begin_method(access, sig, exceptions);
|
||||
if (sig.getName().equals(Constants.CONSTRUCTOR_NAME)) {
|
||||
return new CodeEmitter(emitter) {
|
||||
public void visitInsn(int opcode) {
|
||||
if (opcode == Constants.RETURN) {
|
||||
load_this();
|
||||
invoke(info);
|
||||
}
|
||||
super.visitInsn(opcode);
|
||||
}
|
||||
};
|
||||
}
|
||||
return emitter;
|
||||
}
|
||||
}
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue