Consistent support for setContextClass in CGLIB beans package

Closes gh-28530
This commit is contained in:
Juergen Hoeller 2022-06-14 15:08:44 +02:00
parent 8c777111fa
commit f8b41c1ad2
13 changed files with 1047 additions and 5 deletions

View File

@ -76,8 +76,7 @@ jar {
dependsOn cglibRepackJar
from(zipTree(cglibRepackJar.archivePath)) {
include "org/springframework/cglib/**"
exclude "org/springframework/cglib/beans/BeanMap.class"
exclude "org/springframework/cglib/beans/BeanMap\$*.class"
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"

View File

@ -0,0 +1,179 @@
/*
* Copyright 2003,2004 The Apache Software Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* 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.beans;
import java.beans.PropertyDescriptor;
import java.lang.reflect.*;
import java.security.ProtectionDomain;
import org.springframework.cglib.core.*;
import org.springframework.asm.ClassVisitor;
import org.springframework.asm.Type;
import java.util.*;
/**
* @author Chris Nokleberg
*/
@SuppressWarnings({"rawtypes", "unchecked"})
abstract public class BeanCopier
{
private static final BeanCopierKey KEY_FACTORY =
(BeanCopierKey)KeyFactory.create(BeanCopierKey.class);
private static final Type CONVERTER =
TypeUtils.parseType("org.springframework.cglib.core.Converter");
private static final Type BEAN_COPIER =
TypeUtils.parseType("org.springframework.cglib.beans.BeanCopier");
private static final Signature COPY =
new Signature("copy", Type.VOID_TYPE, new Type[]{ Constants.TYPE_OBJECT, Constants.TYPE_OBJECT, CONVERTER });
private static final Signature CONVERT =
TypeUtils.parseSignature("Object convert(Object, Class, Object)");
interface BeanCopierKey {
public Object newInstance(String source, String target, boolean useConverter);
}
public static BeanCopier create(Class source, Class target, boolean useConverter) {
Generator gen = new Generator();
gen.setSource(source);
gen.setTarget(target);
gen.setUseConverter(useConverter);
return gen.create();
}
abstract public void copy(Object from, Object to, Converter converter);
public static class Generator extends AbstractClassGenerator {
private static final Source SOURCE = new Source(BeanCopier.class.getName());
private Class source;
private Class target;
private boolean useConverter;
public Generator() {
super(SOURCE);
}
public void setSource(Class source) {
if(!Modifier.isPublic(source.getModifiers())){
setNamePrefix(source.getName());
}
this.source = source;
}
public void setTarget(Class target) {
if(!Modifier.isPublic(target.getModifiers())){
setNamePrefix(target.getName());
}
this.target = target;
// SPRING PATCH BEGIN
setContextClass(target);
// SPRING PATCH END
}
public void setUseConverter(boolean useConverter) {
this.useConverter = useConverter;
}
protected ClassLoader getDefaultClassLoader() {
return source.getClassLoader();
}
protected ProtectionDomain getProtectionDomain() {
return ReflectUtils.getProtectionDomain(source);
}
public BeanCopier create() {
Object key = KEY_FACTORY.newInstance(source.getName(), target.getName(), useConverter);
return (BeanCopier)super.create(key);
}
public void generateClass(ClassVisitor v) {
Type sourceType = Type.getType(source);
Type targetType = Type.getType(target);
ClassEmitter ce = new ClassEmitter(v);
ce.begin_class(Constants.V1_8,
Constants.ACC_PUBLIC,
getClassName(),
BEAN_COPIER,
null,
Constants.SOURCE_FILE);
EmitUtils.null_constructor(ce);
CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, COPY, null);
PropertyDescriptor[] getters = ReflectUtils.getBeanGetters(source);
PropertyDescriptor[] setters = ReflectUtils.getBeanSetters(target);
Map names = new HashMap();
for (int i = 0; i < getters.length; i++) {
names.put(getters[i].getName(), getters[i]);
}
Local targetLocal = e.make_local();
Local sourceLocal = e.make_local();
if (useConverter) {
e.load_arg(1);
e.checkcast(targetType);
e.store_local(targetLocal);
e.load_arg(0);
e.checkcast(sourceType);
e.store_local(sourceLocal);
} else {
e.load_arg(1);
e.checkcast(targetType);
e.load_arg(0);
e.checkcast(sourceType);
}
for (int i = 0; i < setters.length; i++) {
PropertyDescriptor setter = setters[i];
PropertyDescriptor getter = (PropertyDescriptor)names.get(setter.getName());
if (getter != null) {
MethodInfo read = ReflectUtils.getMethodInfo(getter.getReadMethod());
MethodInfo write = ReflectUtils.getMethodInfo(setter.getWriteMethod());
if (useConverter) {
Type setterType = write.getSignature().getArgumentTypes()[0];
e.load_local(targetLocal);
e.load_arg(2);
e.load_local(sourceLocal);
e.invoke(read);
e.box(read.getSignature().getReturnType());
EmitUtils.load_class(e, setterType);
e.push(write.getSignature().getName());
e.invoke_interface(CONVERTER, CONVERT);
e.unbox_or_zero(setterType);
e.invoke(write);
} else if (compatible(getter, setter)) {
e.dup2();
e.invoke(read);
e.invoke(write);
}
}
}
e.return_value();
e.end_method();
ce.end_class();
}
private static boolean compatible(PropertyDescriptor getter, PropertyDescriptor setter) {
// TODO: allow automatic widening conversions?
return setter.getPropertyType().isAssignableFrom(getter.getPropertyType());
}
protected Object firstInstance(Class type) {
return ReflectUtils.newInstance(type);
}
protected Object nextInstance(Object instance) {
return instance;
}
}
}

View File

@ -0,0 +1,153 @@
/*
* 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.beans;
import java.beans.PropertyDescriptor;
import java.security.ProtectionDomain;
import java.util.*;
import org.springframework.cglib.core.*;
import org.springframework.asm.ClassVisitor;
import org.springframework.asm.Type;
/**
* @author Juozas Baliuka, Chris Nokleberg
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public class BeanGenerator extends AbstractClassGenerator
{
private static final Source SOURCE = new Source(BeanGenerator.class.getName());
private static final BeanGeneratorKey KEY_FACTORY =
(BeanGeneratorKey)KeyFactory.create(BeanGeneratorKey.class);
interface BeanGeneratorKey {
public Object newInstance(String superclass, Map props);
}
private Class superclass;
private Map props = new HashMap();
private boolean classOnly;
public BeanGenerator() {
super(SOURCE);
}
/**
* Set the class which the generated class will extend. The class
* must not be declared as final, and must have a non-private
* no-argument constructor.
* @param superclass class to extend, or null to extend Object
*/
public void setSuperclass(Class superclass) {
if (superclass != null && superclass.equals(Object.class)) {
superclass = null;
}
this.superclass = superclass;
// SPRING PATCH BEGIN
setContextClass(superclass);
// SPRING PATCH END
}
public void addProperty(String name, Class type) {
if (props.containsKey(name)) {
throw new IllegalArgumentException("Duplicate property name \"" + name + "\"");
}
props.put(name, Type.getType(type));
}
protected ClassLoader getDefaultClassLoader() {
if (superclass != null) {
return superclass.getClassLoader();
} else {
return null;
}
}
protected ProtectionDomain getProtectionDomain() {
return ReflectUtils.getProtectionDomain(superclass);
}
public Object create() {
classOnly = false;
return createHelper();
}
public Object createClass() {
classOnly = true;
return createHelper();
}
private Object createHelper() {
if (superclass != null) {
setNamePrefix(superclass.getName());
}
String superName = (superclass != null) ? superclass.getName() : "java.lang.Object";
Object key = KEY_FACTORY.newInstance(superName, props);
return super.create(key);
}
public void generateClass(ClassVisitor v) throws Exception {
int size = props.size();
String[] names = (String[])props.keySet().toArray(new String[size]);
Type[] types = new Type[size];
for (int i = 0; i < size; i++) {
types[i] = (Type)props.get(names[i]);
}
ClassEmitter ce = new ClassEmitter(v);
ce.begin_class(Constants.V1_8,
Constants.ACC_PUBLIC,
getClassName(),
superclass != null ? Type.getType(superclass) : Constants.TYPE_OBJECT,
null,
null);
EmitUtils.null_constructor(ce);
EmitUtils.add_properties(ce, names, types);
ce.end_class();
}
protected Object firstInstance(Class type) {
if (classOnly) {
return type;
} else {
return ReflectUtils.newInstance(type);
}
}
protected Object nextInstance(Object instance) {
Class protoclass = (instance instanceof Class) ? (Class)instance : instance.getClass();
if (classOnly) {
return protoclass;
} else {
return ReflectUtils.newInstance(protoclass);
}
}
public static void addProperties(BeanGenerator gen, Map props) {
for (Iterator it = props.keySet().iterator(); it.hasNext();) {
String name = (String)it.next();
gen.addProperty(name, (Class)props.get(name));
}
}
public static void addProperties(BeanGenerator gen, Class type) {
addProperties(gen, ReflectUtils.getBeanProperties(type));
}
public static void addProperties(BeanGenerator gen, PropertyDescriptor[] descriptors) {
for (int i = 0; i < descriptors.length; i++) {
gen.addProperty(descriptors[i].getName(), descriptors[i].getPropertyType());
}
}
}

View File

@ -97,7 +97,9 @@ abstract public class BeanMap implements Map {
this.bean = bean;
if (bean != null) {
beanClass = bean.getClass();
// SPRING PATCH BEGIN
setContextClass(beanClass);
// SPRING PATCH END
}
}

View File

@ -0,0 +1,193 @@
/*
* 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.beans;
import java.beans.*;
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"})
class BeanMapEmitter extends ClassEmitter {
private static final Type BEAN_MAP =
TypeUtils.parseType("org.springframework.cglib.beans.BeanMap");
private static final Type FIXED_KEY_SET =
TypeUtils.parseType("org.springframework.cglib.beans.FixedKeySet");
private static final Signature CSTRUCT_OBJECT =
TypeUtils.parseConstructor("Object");
private static final Signature CSTRUCT_STRING_ARRAY =
TypeUtils.parseConstructor("String[]");
private static final Signature BEAN_MAP_GET =
TypeUtils.parseSignature("Object get(Object, Object)");
private static final Signature BEAN_MAP_PUT =
TypeUtils.parseSignature("Object put(Object, Object, Object)");
private static final Signature KEY_SET =
TypeUtils.parseSignature("java.util.Set keySet()");
private static final Signature NEW_INSTANCE =
new Signature("newInstance", BEAN_MAP, new Type[]{ Constants.TYPE_OBJECT });
private static final Signature GET_PROPERTY_TYPE =
TypeUtils.parseSignature("Class getPropertyType(String)");
public BeanMapEmitter(ClassVisitor v, String className, Class type, int require) {
super(v);
begin_class(Constants.V1_8, Constants.ACC_PUBLIC, className, BEAN_MAP, null, Constants.SOURCE_FILE);
EmitUtils.null_constructor(this);
EmitUtils.factory_method(this, NEW_INSTANCE);
generateConstructor();
Map getters = makePropertyMap(ReflectUtils.getBeanGetters(type));
Map setters = makePropertyMap(ReflectUtils.getBeanSetters(type));
Map allProps = new HashMap();
allProps.putAll(getters);
allProps.putAll(setters);
if (require != 0) {
for (Iterator it = allProps.keySet().iterator(); it.hasNext();) {
String name = (String)it.next();
if ((((require & BeanMap.REQUIRE_GETTER) != 0) && !getters.containsKey(name)) ||
(((require & BeanMap.REQUIRE_SETTER) != 0) && !setters.containsKey(name))) {
it.remove();
getters.remove(name);
setters.remove(name);
}
}
}
generateGet(type, getters);
generatePut(type, setters);
String[] allNames = getNames(allProps);
generateKeySet(allNames);
generateGetPropertyType(allProps, allNames);
end_class();
}
private Map makePropertyMap(PropertyDescriptor[] props) {
Map names = new HashMap();
for (int i = 0; i < props.length; i++) {
names.put(props[i].getName(), props[i]);
}
return names;
}
private String[] getNames(Map propertyMap) {
return (String[])propertyMap.keySet().toArray(new String[propertyMap.size()]);
}
private void generateConstructor() {
CodeEmitter e = begin_method(Constants.ACC_PUBLIC, CSTRUCT_OBJECT, null);
e.load_this();
e.load_arg(0);
e.super_invoke_constructor(CSTRUCT_OBJECT);
e.return_value();
e.end_method();
}
private void generateGet(Class type, final Map getters) {
final CodeEmitter e = begin_method(Constants.ACC_PUBLIC, BEAN_MAP_GET, null);
e.load_arg(0);
e.checkcast(Type.getType(type));
e.load_arg(1);
e.checkcast(Constants.TYPE_STRING);
EmitUtils.string_switch(e, getNames(getters), Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() {
public void processCase(Object key, Label end) {
PropertyDescriptor pd = (PropertyDescriptor)getters.get(key);
MethodInfo method = ReflectUtils.getMethodInfo(pd.getReadMethod());
e.invoke(method);
e.box(method.getSignature().getReturnType());
e.return_value();
}
public void processDefault() {
e.aconst_null();
e.return_value();
}
});
e.end_method();
}
private void generatePut(Class type, final Map setters) {
final CodeEmitter e = begin_method(Constants.ACC_PUBLIC, BEAN_MAP_PUT, null);
e.load_arg(0);
e.checkcast(Type.getType(type));
e.load_arg(1);
e.checkcast(Constants.TYPE_STRING);
EmitUtils.string_switch(e, getNames(setters), Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() {
public void processCase(Object key, Label end) {
PropertyDescriptor pd = (PropertyDescriptor)setters.get(key);
if (pd.getReadMethod() == null) {
e.aconst_null();
} else {
MethodInfo read = ReflectUtils.getMethodInfo(pd.getReadMethod());
e.dup();
e.invoke(read);
e.box(read.getSignature().getReturnType());
}
e.swap(); // move old value behind bean
e.load_arg(2); // new value
MethodInfo write = ReflectUtils.getMethodInfo(pd.getWriteMethod());
e.unbox(write.getSignature().getArgumentTypes()[0]);
e.invoke(write);
e.return_value();
}
public void processDefault() {
// fall-through
}
});
e.aconst_null();
e.return_value();
e.end_method();
}
private void generateKeySet(String[] allNames) {
// static initializer
declare_field(Constants.ACC_STATIC | Constants.ACC_PRIVATE, "keys", FIXED_KEY_SET, null);
CodeEmitter e = begin_static();
e.new_instance(FIXED_KEY_SET);
e.dup();
EmitUtils.push_array(e, allNames);
e.invoke_constructor(FIXED_KEY_SET, CSTRUCT_STRING_ARRAY);
e.putfield("keys");
e.return_value();
e.end_method();
// keySet
e = begin_method(Constants.ACC_PUBLIC, KEY_SET, null);
e.load_this();
e.getfield("keys");
e.return_value();
e.end_method();
}
private void generateGetPropertyType(final Map allProps, String[] allNames) {
final CodeEmitter e = begin_method(Constants.ACC_PUBLIC, GET_PROPERTY_TYPE, null);
e.load_arg(0);
EmitUtils.string_switch(e, allNames, Constants.SWITCH_STYLE_HASH, new ObjectSwitchCallback() {
public void processCase(Object key, Label end) {
PropertyDescriptor pd = (PropertyDescriptor)allProps.get(key);
EmitUtils.load_class(e, Type.getType(pd.getPropertyType()));
e.return_value();
}
public void processDefault() {
e.aconst_null();
e.return_value();
}
});
e.end_method();
}
}

View File

@ -0,0 +1,146 @@
/*
* 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.beans;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.security.ProtectionDomain;
import java.util.*;
import org.springframework.cglib.core.*;
import org.springframework.asm.ClassVisitor;
/**
* @author Juozas Baliuka
*/
@SuppressWarnings({"rawtypes", "unchecked"})
abstract public class BulkBean
{
private static final BulkBeanKey KEY_FACTORY =
(BulkBeanKey)KeyFactory.create(BulkBeanKey.class);
interface BulkBeanKey {
public Object newInstance(String target, String[] getters, String[] setters, String[] types);
}
protected Class target;
protected String[] getters, setters;
protected Class[] types;
protected BulkBean() { }
abstract public void getPropertyValues(Object bean, Object[] values);
abstract public void setPropertyValues(Object bean, Object[] values);
public Object[] getPropertyValues(Object bean) {
Object[] values = new Object[getters.length];
getPropertyValues(bean, values);
return values;
}
public Class[] getPropertyTypes() {
return types.clone();
}
public String[] getGetters() {
return getters.clone();
}
public String[] getSetters() {
return setters.clone();
}
public static BulkBean create(Class target, String[] getters, String[] setters, Class[] types) {
Generator gen = new Generator();
gen.setTarget(target);
gen.setGetters(getters);
gen.setSetters(setters);
gen.setTypes(types);
return gen.create();
}
public static class Generator extends AbstractClassGenerator {
private static final Source SOURCE = new Source(BulkBean.class.getName());
private Class target;
private String[] getters;
private String[] setters;
private Class[] types;
public Generator() {
super(SOURCE);
}
public void setTarget(Class target) {
this.target = target;
// SPRING PATCH BEGIN
setContextClass(target);
// SPRING PATCH END
}
public void setGetters(String[] getters) {
this.getters = getters;
}
public void setSetters(String[] setters) {
this.setters = setters;
}
public void setTypes(Class[] types) {
this.types = types;
}
protected ClassLoader getDefaultClassLoader() {
return target.getClassLoader();
}
protected ProtectionDomain getProtectionDomain() {
return ReflectUtils.getProtectionDomain(target);
}
public BulkBean create() {
setNamePrefix(target.getName());
String targetClassName = target.getName();
String[] typeClassNames = ReflectUtils.getNames(types);
Object key = KEY_FACTORY.newInstance(targetClassName, getters, setters, typeClassNames);
return (BulkBean)super.create(key);
}
public void generateClass(ClassVisitor v) throws Exception {
new BulkBeanEmitter(v, getClassName(), target, getters, setters, types);
}
protected Object firstInstance(Class type) {
BulkBean instance = (BulkBean)ReflectUtils.newInstance(type);
instance.target = target;
int length = getters.length;
instance.getters = new String[length];
System.arraycopy(getters, 0, instance.getters, 0, length);
instance.setters = new String[length];
System.arraycopy(setters, 0, instance.setters, 0, length);
instance.types = new Class[types.length];
System.arraycopy(types, 0, instance.types, 0, types.length);
return instance;
}
protected Object nextInstance(Object instance) {
return instance;
}
}
}

View File

@ -0,0 +1,157 @@
/*
* 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.beans;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
import org.springframework.cglib.core.*;
import org.springframework.asm.ClassVisitor;
import org.springframework.asm.Type;
@SuppressWarnings({"rawtypes", "unchecked"})
class BulkBeanEmitter extends ClassEmitter {
private static final Signature GET_PROPERTY_VALUES =
TypeUtils.parseSignature("void getPropertyValues(Object, Object[])");
private static final Signature SET_PROPERTY_VALUES =
TypeUtils.parseSignature("void setPropertyValues(Object, Object[])");
private static final Signature CSTRUCT_EXCEPTION =
TypeUtils.parseConstructor("Throwable, int");
private static final Type BULK_BEAN =
TypeUtils.parseType("org.springframework.cglib.beans.BulkBean");
private static final Type BULK_BEAN_EXCEPTION =
TypeUtils.parseType("org.springframework.cglib.beans.BulkBeanException");
public BulkBeanEmitter(ClassVisitor v,
String className,
Class target,
String[] getterNames,
String[] setterNames,
Class[] types) {
super(v);
Method[] getters = new Method[getterNames.length];
Method[] setters = new Method[setterNames.length];
validate(target, getterNames, setterNames, types, getters, setters);
begin_class(Constants.V1_8, Constants.ACC_PUBLIC, className, BULK_BEAN, null, Constants.SOURCE_FILE);
EmitUtils.null_constructor(this);
generateGet(target, getters);
generateSet(target, setters);
end_class();
}
private void generateGet(final Class target, final Method[] getters) {
CodeEmitter e = begin_method(Constants.ACC_PUBLIC, GET_PROPERTY_VALUES, null);
if (getters.length > 0) {
e.load_arg(0);
e.checkcast(Type.getType(target));
Local bean = e.make_local();
e.store_local(bean);
for (int i = 0; i < getters.length; i++) {
if (getters[i] != null) {
MethodInfo getter = ReflectUtils.getMethodInfo(getters[i]);
e.load_arg(1);
e.push(i);
e.load_local(bean);
e.invoke(getter);
e.box(getter.getSignature().getReturnType());
e.aastore();
}
}
}
e.return_value();
e.end_method();
}
private void generateSet(final Class target, final Method[] setters) {
// setPropertyValues
CodeEmitter e = begin_method(Constants.ACC_PUBLIC, SET_PROPERTY_VALUES, null);
if (setters.length > 0) {
Local index = e.make_local(Type.INT_TYPE);
e.push(0);
e.store_local(index);
e.load_arg(0);
e.checkcast(Type.getType(target));
e.load_arg(1);
Block handler = e.begin_block();
int lastIndex = 0;
for (int i = 0; i < setters.length; i++) {
if (setters[i] != null) {
MethodInfo setter = ReflectUtils.getMethodInfo(setters[i]);
int diff = i - lastIndex;
if (diff > 0) {
e.iinc(index, diff);
lastIndex = i;
}
e.dup2();
e.aaload(i);
e.unbox(setter.getSignature().getArgumentTypes()[0]);
e.invoke(setter);
}
}
handler.end();
e.return_value();
e.catch_exception(handler, Constants.TYPE_THROWABLE);
e.new_instance(BULK_BEAN_EXCEPTION);
e.dup_x1();
e.swap();
e.load_local(index);
e.invoke_constructor(BULK_BEAN_EXCEPTION, CSTRUCT_EXCEPTION);
e.athrow();
} else {
e.return_value();
}
e.end_method();
}
private static void validate(Class target,
String[] getters,
String[] setters,
Class[] types,
Method[] getters_out,
Method[] setters_out) {
int i = -1;
if (setters.length != types.length || getters.length != types.length) {
throw new BulkBeanException("accessor array length must be equal type array length", i);
}
try {
for (i = 0; i < types.length; i++) {
if (getters[i] != null) {
Method method = ReflectUtils.findDeclaredMethod(target, getters[i], null);
if (method.getReturnType() != types[i]) {
throw new BulkBeanException("Specified type " + types[i] +
" does not match declared type " + method.getReturnType(), i);
}
if (Modifier.isPrivate(method.getModifiers())) {
throw new BulkBeanException("Property is private", i);
}
getters_out[i] = method;
}
if (setters[i] != null) {
Method method = ReflectUtils.findDeclaredMethod(target, setters[i], new Class[]{ types[i] });
if (Modifier.isPrivate(method.getModifiers()) ){
throw new BulkBeanException("Property is private", i);
}
setters_out[i] = method;
}
}
} catch (NoSuchMethodException e) {
throw new BulkBeanException("Cannot find specified property", i);
}
}
}

View File

@ -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.beans;
import org.springframework.cglib.core.CodeGenerationException;
@SuppressWarnings({"rawtypes", "unchecked", "serial"})
public class BulkBeanException extends RuntimeException
{
private int index;
private Throwable cause;
public BulkBeanException(String message, int index) {
super(message);
this.index = index;
}
public BulkBeanException(Throwable cause, int index) {
super(cause.getMessage());
this.index = index;
this.cause = cause;
}
public int getIndex() {
return index;
}
public Throwable getCause() {
return cause;
}
}

View File

@ -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.beans;
import java.util.*;
@SuppressWarnings({"rawtypes", "unchecked"})
public /* need it for class loading */ class FixedKeySet extends AbstractSet {
private Set set;
private int size;
public FixedKeySet(String[] keys) {
size = keys.length;
set = Collections.unmodifiableSet(new HashSet(Arrays.asList(keys)));
}
public Iterator iterator() {
return set.iterator();
}
public int size() {
return size;
}
}

View File

@ -0,0 +1,132 @@
/*
* 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.beans;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.security.ProtectionDomain;
import org.springframework.cglib.core.*;
import org.springframework.asm.ClassVisitor;
import org.springframework.asm.Type;
/**
* @author Chris Nokleberg
*/
@SuppressWarnings({"rawtypes", "unchecked"})
public class ImmutableBean
{
private static final Type ILLEGAL_STATE_EXCEPTION =
TypeUtils.parseType("IllegalStateException");
private static final Signature CSTRUCT_OBJECT =
TypeUtils.parseConstructor("Object");
private static final Class[] OBJECT_CLASSES = { Object.class };
private static final String FIELD_NAME = "CGLIB$RWBean";
private ImmutableBean() {
}
public static Object create(Object bean) {
Generator gen = new Generator();
gen.setBean(bean);
return gen.create();
}
public static class Generator extends AbstractClassGenerator {
private static final Source SOURCE = new Source(ImmutableBean.class.getName());
private Object bean;
private Class target;
public Generator() {
super(SOURCE);
}
public void setBean(Object bean) {
this.bean = bean;
target = bean.getClass();
// SPRING PATCH BEGIN
setContextClass(target);
// SPRING PATCH END
}
protected ClassLoader getDefaultClassLoader() {
return target.getClassLoader();
}
protected ProtectionDomain getProtectionDomain() {
return ReflectUtils.getProtectionDomain(target);
}
public Object create() {
String name = target.getName();
setNamePrefix(name);
return super.create(name);
}
public void generateClass(ClassVisitor v) {
Type targetType = Type.getType(target);
ClassEmitter ce = new ClassEmitter(v);
ce.begin_class(Constants.V1_8,
Constants.ACC_PUBLIC,
getClassName(),
targetType,
null,
Constants.SOURCE_FILE);
ce.declare_field(Constants.ACC_FINAL | Constants.ACC_PRIVATE, FIELD_NAME, targetType, null);
CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, CSTRUCT_OBJECT, null);
e.load_this();
e.super_invoke_constructor();
e.load_this();
e.load_arg(0);
e.checkcast(targetType);
e.putfield(FIELD_NAME);
e.return_value();
e.end_method();
PropertyDescriptor[] descriptors = ReflectUtils.getBeanProperties(target);
Method[] getters = ReflectUtils.getPropertyMethods(descriptors, true, false);
Method[] setters = ReflectUtils.getPropertyMethods(descriptors, false, true);
for (int i = 0; i < getters.length; i++) {
MethodInfo getter = ReflectUtils.getMethodInfo(getters[i]);
e = EmitUtils.begin_method(ce, getter, Constants.ACC_PUBLIC);
e.load_this();
e.getfield(FIELD_NAME);
e.invoke(getter);
e.return_value();
e.end_method();
}
for (int i = 0; i < setters.length; i++) {
MethodInfo setter = ReflectUtils.getMethodInfo(setters[i]);
e = EmitUtils.begin_method(ce, setter, Constants.ACC_PUBLIC);
e.throw_exception(ILLEGAL_STATE_EXCEPTION, "Bean is immutable");
e.end_method();
}
ce.end_class();
}
protected Object firstInstance(Class type) {
return ReflectUtils.newInstance(type, OBJECT_CLASSES, new Object[]{ bean });
}
// TODO: optimize
protected Object nextInstance(Object instance) {
return firstInstance(instance.getClass());
}
}
}

View File

@ -1,6 +1,6 @@
/**
* Spring's repackaging of the
* <a href="http://cglib.sourceforge.net">CGLIB</a> beans package
* <a href="https://github.com/cglib/cglib">CGLIB</a> beans package
* (for internal use only).
*
* <p>As this repackaging happens at the class file level, sources

View File

@ -1,6 +1,6 @@
/**
* Spring's repackaging of the
* <a href="http://cglib.sourceforge.net">CGLIB</a> core package
* <a href="https://github.com/cglib/cglib">CGLIB</a> core package
* (for internal use only).
*
* <p>As this repackaging happens at the class file level, sources

View File

@ -1,6 +1,6 @@
/**
* Spring's repackaging of the
* <a href="http://cglib.sourceforge.net">CGLIB</a> proxy package
* <a href="https://github.com/cglib/cglib">CGLIB</a> proxy package
* (for internal use only).
*
* <p>As this repackaging happens at the class file level, sources