BeanCopier sets name prefix for public classes as well

Includes consistent formatting of Spring-patched files.

Closes gh-28699
This commit is contained in:
Juergen Hoeller 2023-10-15 16:09:17 +02:00
parent da95542d8f
commit 7a60e2024b
5 changed files with 634 additions and 636 deletions

View File

@ -16,7 +16,6 @@
package org.springframework.cglib.beans; package org.springframework.cglib.beans;
import java.beans.PropertyDescriptor; import java.beans.PropertyDescriptor;
import java.lang.reflect.Modifier;
import java.security.ProtectionDomain; import java.security.ProtectionDomain;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
@ -42,155 +41,154 @@ import org.springframework.cglib.core.TypeUtils;
@SuppressWarnings({"rawtypes", "unchecked"}) @SuppressWarnings({"rawtypes", "unchecked"})
abstract public class BeanCopier abstract public class BeanCopier
{ {
private static final BeanCopierKey KEY_FACTORY = private static final BeanCopierKey KEY_FACTORY =
(BeanCopierKey)KeyFactory.create(BeanCopierKey.class); (BeanCopierKey)KeyFactory.create(BeanCopierKey.class);
private static final Type CONVERTER = private static final Type CONVERTER =
TypeUtils.parseType("org.springframework.cglib.core.Converter"); TypeUtils.parseType("org.springframework.cglib.core.Converter");
private static final Type BEAN_COPIER = private static final Type BEAN_COPIER =
TypeUtils.parseType("org.springframework.cglib.beans.BeanCopier"); TypeUtils.parseType("org.springframework.cglib.beans.BeanCopier");
private static final Signature COPY = private static final Signature COPY =
new Signature("copy", Type.VOID_TYPE, new Type[]{ Constants.TYPE_OBJECT, Constants.TYPE_OBJECT, CONVERTER }); new Signature("copy", Type.VOID_TYPE, new Type[]{ Constants.TYPE_OBJECT, Constants.TYPE_OBJECT, CONVERTER });
private static final Signature CONVERT = private static final Signature CONVERT =
TypeUtils.parseSignature("Object convert(Object, Class, Object)"); TypeUtils.parseSignature("Object convert(Object, Class, Object)");
interface BeanCopierKey { interface BeanCopierKey {
public Object newInstance(String source, String target, boolean useConverter); public Object newInstance(String source, String target, boolean useConverter);
} }
public static BeanCopier create(Class source, Class target, boolean useConverter) { public static BeanCopier create(Class source, Class target, boolean useConverter) {
Generator gen = new Generator(); Generator gen = new Generator();
gen.setSource(source); gen.setSource(source);
gen.setTarget(target); gen.setTarget(target);
gen.setUseConverter(useConverter); gen.setUseConverter(useConverter);
return gen.create(); return gen.create();
} }
abstract public void copy(Object from, Object to, Converter converter); abstract public void copy(Object from, Object to, Converter converter);
public static class Generator extends AbstractClassGenerator { public static class Generator extends AbstractClassGenerator {
private static final Source SOURCE = new Source(BeanCopier.class.getName()); private static final Source SOURCE = new Source(BeanCopier.class.getName());
private Class source; private Class source;
private Class target; private Class target;
private boolean useConverter; private boolean useConverter;
public Generator() { public Generator() {
super(SOURCE); super(SOURCE);
} }
public void setSource(Class source) { public void setSource(Class source) {
if(!Modifier.isPublic(source.getModifiers())){ this.source = source;
setNamePrefix(source.getName()); // SPRING PATCH BEGIN
} setContextClass(source);
this.source = source; setNamePrefix(source.getName());
} // SPRING PATCH END
}
public void setTarget(Class target) { public void setTarget(Class target) {
if(!Modifier.isPublic(target.getModifiers())){ this.target = target;
setNamePrefix(target.getName());
}
this.target = target;
// SPRING PATCH BEGIN // SPRING PATCH BEGIN
setContextClass(target); setContextClass(target);
setNamePrefix(target.getName());
// SPRING PATCH END // SPRING PATCH END
} }
public void setUseConverter(boolean useConverter) { public void setUseConverter(boolean useConverter) {
this.useConverter = useConverter; this.useConverter = useConverter;
} }
@Override @Override
protected ClassLoader getDefaultClassLoader() { protected ClassLoader getDefaultClassLoader() {
return source.getClassLoader(); return source.getClassLoader();
} }
@Override @Override
protected ProtectionDomain getProtectionDomain() { protected ProtectionDomain getProtectionDomain() {
return ReflectUtils.getProtectionDomain(source); return ReflectUtils.getProtectionDomain(source);
} }
public BeanCopier create() { public BeanCopier create() {
Object key = KEY_FACTORY.newInstance(source.getName(), target.getName(), useConverter); Object key = KEY_FACTORY.newInstance(source.getName(), target.getName(), useConverter);
return (BeanCopier)super.create(key); return (BeanCopier)super.create(key);
} }
@Override @Override
public void generateClass(ClassVisitor v) { public void generateClass(ClassVisitor v) {
Type sourceType = Type.getType(source); Type sourceType = Type.getType(source);
Type targetType = Type.getType(target); Type targetType = Type.getType(target);
ClassEmitter ce = new ClassEmitter(v); ClassEmitter ce = new ClassEmitter(v);
ce.begin_class(Constants.V1_8, ce.begin_class(Constants.V1_8,
Constants.ACC_PUBLIC, Constants.ACC_PUBLIC,
getClassName(), getClassName(),
BEAN_COPIER, BEAN_COPIER,
null, null,
Constants.SOURCE_FILE); Constants.SOURCE_FILE);
EmitUtils.null_constructor(ce); EmitUtils.null_constructor(ce);
CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, COPY, null); CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, COPY, null);
PropertyDescriptor[] getters = ReflectUtils.getBeanGetters(source); PropertyDescriptor[] getters = ReflectUtils.getBeanGetters(source);
PropertyDescriptor[] setters = ReflectUtils.getBeanSetters(target); PropertyDescriptor[] setters = ReflectUtils.getBeanSetters(target);
Map names = new HashMap(); Map names = new HashMap();
for (PropertyDescriptor getter : getters) { for (PropertyDescriptor getter : getters) {
names.put(getter.getName(), getter); names.put(getter.getName(), getter);
} }
Local targetLocal = e.make_local(); Local targetLocal = e.make_local();
Local sourceLocal = e.make_local(); Local sourceLocal = e.make_local();
if (useConverter) { if (useConverter) {
e.load_arg(1); e.load_arg(1);
e.checkcast(targetType); e.checkcast(targetType);
e.store_local(targetLocal); e.store_local(targetLocal);
e.load_arg(0); e.load_arg(0);
e.checkcast(sourceType); e.checkcast(sourceType);
e.store_local(sourceLocal); e.store_local(sourceLocal);
} else { } else {
e.load_arg(1); e.load_arg(1);
e.checkcast(targetType); e.checkcast(targetType);
e.load_arg(0); e.load_arg(0);
e.checkcast(sourceType); e.checkcast(sourceType);
} }
for (PropertyDescriptor setter : setters) { for (PropertyDescriptor setter : setters) {
PropertyDescriptor getter = (PropertyDescriptor)names.get(setter.getName()); PropertyDescriptor getter = (PropertyDescriptor)names.get(setter.getName());
if (getter != null) { if (getter != null) {
MethodInfo read = ReflectUtils.getMethodInfo(getter.getReadMethod()); MethodInfo read = ReflectUtils.getMethodInfo(getter.getReadMethod());
MethodInfo write = ReflectUtils.getMethodInfo(setter.getWriteMethod()); MethodInfo write = ReflectUtils.getMethodInfo(setter.getWriteMethod());
if (useConverter) { if (useConverter) {
Type setterType = write.getSignature().getArgumentTypes()[0]; Type setterType = write.getSignature().getArgumentTypes()[0];
e.load_local(targetLocal); e.load_local(targetLocal);
e.load_arg(2); e.load_arg(2);
e.load_local(sourceLocal); e.load_local(sourceLocal);
e.invoke(read); e.invoke(read);
e.box(read.getSignature().getReturnType()); e.box(read.getSignature().getReturnType());
EmitUtils.load_class(e, setterType); EmitUtils.load_class(e, setterType);
e.push(write.getSignature().getName()); e.push(write.getSignature().getName());
e.invoke_interface(CONVERTER, CONVERT); e.invoke_interface(CONVERTER, CONVERT);
e.unbox_or_zero(setterType); e.unbox_or_zero(setterType);
e.invoke(write); e.invoke(write);
} else if (compatible(getter, setter)) { } else if (compatible(getter, setter)) {
e.dup2(); e.dup2();
e.invoke(read); e.invoke(read);
e.invoke(write); e.invoke(write);
} }
} }
} }
e.return_value(); e.return_value();
e.end_method(); e.end_method();
ce.end_class(); ce.end_class();
} }
private static boolean compatible(PropertyDescriptor getter, PropertyDescriptor setter) { private static boolean compatible(PropertyDescriptor getter, PropertyDescriptor setter) {
// TODO: allow automatic widening conversions? // TODO: allow automatic widening conversions?
return setter.getPropertyType().isAssignableFrom(getter.getPropertyType()); return setter.getPropertyType().isAssignableFrom(getter.getPropertyType());
} }
@Override @Override
protected Object firstInstance(Class type) { protected Object firstInstance(Class type) {
return ReflectUtils.newInstance(type); return ReflectUtils.newInstance(type);
} }
@Override @Override
protected Object nextInstance(Object instance) { protected Object nextInstance(Object instance) {
return instance; return instance;
} }
} }
} }

View File

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

View File

@ -41,309 +41,309 @@ import org.springframework.cglib.core.ReflectUtils;
*/ */
@SuppressWarnings({"rawtypes", "unchecked"}) @SuppressWarnings({"rawtypes", "unchecked"})
abstract public class BeanMap implements Map { abstract public class BeanMap implements Map {
/** /**
* Limit the properties reflected in the key set of the map * Limit the properties reflected in the key set of the map
* to readable properties. * to readable properties.
* @see BeanMap.Generator#setRequire * @see BeanMap.Generator#setRequire
*/ */
public static final int REQUIRE_GETTER = 1; public static final int REQUIRE_GETTER = 1;
/** /**
* Limit the properties reflected in the key set of the map * Limit the properties reflected in the key set of the map
* to writable properties. * to writable properties.
* @see BeanMap.Generator#setRequire * @see BeanMap.Generator#setRequire
*/ */
public static final int REQUIRE_SETTER = 2; public static final int REQUIRE_SETTER = 2;
/** /**
* Helper method to create a new <code>BeanMap</code>. For finer * Helper method to create a new <code>BeanMap</code>. For finer
* control over the generated instance, use a new instance of * control over the generated instance, use a new instance of
* <code>BeanMap.Generator</code> instead of this static method. * <code>BeanMap.Generator</code> instead of this static method.
* @param bean the JavaBean underlying the map * @param bean the JavaBean underlying the map
* @return a new <code>BeanMap</code> instance * @return a new <code>BeanMap</code> instance
*/ */
public static BeanMap create(Object bean) { public static BeanMap create(Object bean) {
Generator gen = new Generator(); Generator gen = new Generator();
gen.setBean(bean); gen.setBean(bean);
return gen.create(); return gen.create();
} }
public static class Generator extends AbstractClassGenerator { public static class Generator extends AbstractClassGenerator {
private static final Source SOURCE = new Source(BeanMap.class.getName()); private static final Source SOURCE = new Source(BeanMap.class.getName());
private static final BeanMapKey KEY_FACTORY = private static final BeanMapKey KEY_FACTORY =
(BeanMapKey)KeyFactory.create(BeanMapKey.class, KeyFactory.CLASS_BY_NAME); (BeanMapKey)KeyFactory.create(BeanMapKey.class, KeyFactory.CLASS_BY_NAME);
interface BeanMapKey { interface BeanMapKey {
public Object newInstance(Class type, int require); public Object newInstance(Class type, int require);
} }
private Object bean; private Object bean;
private Class beanClass; private Class beanClass;
private int require; private int require;
public Generator() { public Generator() {
super(SOURCE); super(SOURCE);
} }
/** /**
* Set the bean that the generated map should reflect. The bean may be swapped * Set the bean that the generated map should reflect. The bean may be swapped
* out for another bean of the same type using {@link #setBean}. * out for another bean of the same type using {@link #setBean}.
* Calling this method overrides any value previously set using {@link #setBeanClass}. * Calling this method overrides any value previously set using {@link #setBeanClass}.
* You must call either this method or {@link #setBeanClass} before {@link #create}. * You must call either this method or {@link #setBeanClass} before {@link #create}.
* @param bean the initial bean * @param bean the initial bean
*/ */
public void setBean(Object bean) { public void setBean(Object bean) {
this.bean = bean; this.bean = bean;
if (bean != null) { if (bean != null) {
beanClass = bean.getClass(); beanClass = bean.getClass();
// SPRING PATCH BEGIN // SPRING PATCH BEGIN
setContextClass(beanClass); setContextClass(beanClass);
// SPRING PATCH END // SPRING PATCH END
} }
} }
/** /**
* Set the class of the bean that the generated map should support. * Set the class of the bean that the generated map should support.
* You must call either this method or {@link #setBeanClass} before {@link #create}. * You must call either this method or {@link #setBeanClass} before {@link #create}.
* @param beanClass the class of the bean * @param beanClass the class of the bean
*/ */
public void setBeanClass(Class beanClass) { public void setBeanClass(Class beanClass) {
this.beanClass = beanClass; this.beanClass = beanClass;
} }
/** /**
* Limit the properties reflected by the generated map. * Limit the properties reflected by the generated map.
* @param require any combination of {@link #REQUIRE_GETTER} and * @param require any combination of {@link #REQUIRE_GETTER} and
* {@link #REQUIRE_SETTER}; default is zero (any property allowed) * {@link #REQUIRE_SETTER}; default is zero (any property allowed)
*/ */
public void setRequire(int require) { public void setRequire(int require) {
this.require = require; this.require = require;
} }
@Override @Override
protected ClassLoader getDefaultClassLoader() { protected ClassLoader getDefaultClassLoader() {
return beanClass.getClassLoader(); return beanClass.getClassLoader();
} }
@Override @Override
protected ProtectionDomain getProtectionDomain() { protected ProtectionDomain getProtectionDomain() {
return ReflectUtils.getProtectionDomain(beanClass); return ReflectUtils.getProtectionDomain(beanClass);
} }
/** /**
* Create a new instance of the <code>BeanMap</code>. An existing * Create a new instance of the <code>BeanMap</code>. An existing
* generated class will be reused if possible. * generated class will be reused if possible.
*/ */
public BeanMap create() { public BeanMap create() {
if (beanClass == null) { if (beanClass == null) {
throw new IllegalArgumentException("Class of bean unknown"); throw new IllegalArgumentException("Class of bean unknown");
} }
setNamePrefix(beanClass.getName()); setNamePrefix(beanClass.getName());
return (BeanMap)super.create(KEY_FACTORY.newInstance(beanClass, require)); return (BeanMap)super.create(KEY_FACTORY.newInstance(beanClass, require));
} }
@Override @Override
public void generateClass(ClassVisitor v) throws Exception { public void generateClass(ClassVisitor v) throws Exception {
new BeanMapEmitter(v, getClassName(), beanClass, require); new BeanMapEmitter(v, getClassName(), beanClass, require);
} }
@Override @Override
protected Object firstInstance(Class type) { protected Object firstInstance(Class type) {
return ((BeanMap)ReflectUtils.newInstance(type)).newInstance(bean); return ((BeanMap)ReflectUtils.newInstance(type)).newInstance(bean);
} }
@Override @Override
protected Object nextInstance(Object instance) { protected Object nextInstance(Object instance) {
return ((BeanMap)instance).newInstance(bean); return ((BeanMap)instance).newInstance(bean);
} }
} }
/** /**
* Create a new <code>BeanMap</code> instance using the specified bean. * Create a new <code>BeanMap</code> instance using the specified bean.
* This is faster than using the {@link #create} static method. * This is faster than using the {@link #create} static method.
* @param bean the JavaBean underlying the map * @param bean the JavaBean underlying the map
* @return a new <code>BeanMap</code> instance * @return a new <code>BeanMap</code> instance
*/ */
abstract public BeanMap newInstance(Object bean); abstract public BeanMap newInstance(Object bean);
/** /**
* Get the type of a property. * Get the type of a property.
* @param name the name of the JavaBean property * @param name the name of the JavaBean property
* @return the type of the property, or null if the property does not exist * @return the type of the property, or null if the property does not exist
*/ */
abstract public Class getPropertyType(String name); abstract public Class getPropertyType(String name);
protected Object bean; protected Object bean;
protected BeanMap() { protected BeanMap() {
} }
protected BeanMap(Object bean) { protected BeanMap(Object bean) {
setBean(bean); setBean(bean);
} }
@Override @Override
public Object get(Object key) { public Object get(Object key) {
return get(bean, key); return get(bean, key);
} }
@Override @Override
public Object put(Object key, Object value) { public Object put(Object key, Object value) {
return put(bean, key, value); return put(bean, key, value);
} }
/** /**
* Get the property of a bean. This allows a <code>BeanMap</code> * Get the property of a bean. This allows a <code>BeanMap</code>
* to be used statically for multiple beans--the bean instance tied to the * to be used statically for multiple beans--the bean instance tied to the
* map is ignored and the bean passed to this method is used instead. * map is ignored and the bean passed to this method is used instead.
* @param bean the bean to query; must be compatible with the type of * @param bean the bean to query; must be compatible with the type of
* this <code>BeanMap</code> * this <code>BeanMap</code>
* @param key must be a String * @param key must be a String
* @return the current value, or null if there is no matching property * @return the current value, or null if there is no matching property
*/ */
abstract public Object get(Object bean, Object key); abstract public Object get(Object bean, Object key);
/** /**
* Set the property of a bean. This allows a <code>BeanMap</code> * Set the property of a bean. This allows a <code>BeanMap</code>
* to be used statically for multiple beans--the bean instance tied to the * to be used statically for multiple beans--the bean instance tied to the
* map is ignored and the bean passed to this method is used instead. * map is ignored and the bean passed to this method is used instead.
* @param key must be a String * @param key must be a String
* @return the old value, if there was one, or null * @return the old value, if there was one, or null
*/ */
abstract public Object put(Object bean, Object key, Object value); abstract public Object put(Object bean, Object key, Object value);
/** /**
* Change the underlying bean this map should use. * Change the underlying bean this map should use.
* @param bean the new JavaBean * @param bean the new JavaBean
* @see #getBean * @see #getBean
*/ */
public void setBean(Object bean) { public void setBean(Object bean) {
this.bean = bean; this.bean = bean;
} }
/** /**
* Return the bean currently in use by this map. * Return the bean currently in use by this map.
* @return the current JavaBean * @return the current JavaBean
* @see #setBean * @see #setBean
*/ */
public Object getBean() { public Object getBean() {
return bean; return bean;
} }
@Override @Override
public void clear() { public void clear() {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override @Override
public boolean containsKey(Object key) { public boolean containsKey(Object key) {
return keySet().contains(key); return keySet().contains(key);
} }
@Override @Override
public boolean containsValue(Object value) { public boolean containsValue(Object value) {
for (Iterator it = keySet().iterator(); it.hasNext();) { for (Iterator it = keySet().iterator(); it.hasNext();) {
Object v = get(it.next()); Object v = get(it.next());
if (((value == null) && (v == null)) || (value != null && value.equals(v))) { if (((value == null) && (v == null)) || (value != null && value.equals(v))) {
return true; return true;
} }
} }
return false; return false;
} }
@Override @Override
public int size() { public int size() {
return keySet().size(); return keySet().size();
} }
@Override @Override
public boolean isEmpty() { public boolean isEmpty() {
return size() == 0; return size() == 0;
} }
@Override @Override
public Object remove(Object key) { public Object remove(Object key) {
throw new UnsupportedOperationException(); throw new UnsupportedOperationException();
} }
@Override @Override
public void putAll(Map t) { public void putAll(Map t) {
for (Object key : t.keySet()) { for (Object key : t.keySet()) {
put(key, t.get(key)); put(key, t.get(key));
} }
} }
@Override @Override
public boolean equals(Object o) { public boolean equals(Object o) {
if (o == null || !(o instanceof Map other)) { if (o == null || !(o instanceof Map other)) {
return false; return false;
} }
if (size() != other.size()) { if (size() != other.size()) {
return false; return false;
} }
for (Object key : keySet()) { for (Object key : keySet()) {
if (!other.containsKey(key)) { if (!other.containsKey(key)) {
return false; return false;
} }
Object v1 = get(key); Object v1 = get(key);
Object v2 = other.get(key); Object v2 = other.get(key);
if (!((v1 == null) ? v2 == null : v1.equals(v2))) { if (!((v1 == null) ? v2 == null : v1.equals(v2))) {
return false; return false;
} }
} }
return true; return true;
} }
@Override @Override
public int hashCode() { public int hashCode() {
int code = 0; int code = 0;
for (Object key : keySet()) { for (Object key : keySet()) {
Object value = get(key); Object value = get(key);
code += ((key == null) ? 0 : key.hashCode()) ^ code += ((key == null) ? 0 : key.hashCode()) ^
((value == null) ? 0 : value.hashCode()); ((value == null) ? 0 : value.hashCode());
} }
return code; return code;
} }
// TODO: optimize // TODO: optimize
@Override @Override
public Set entrySet() { public Set entrySet() {
HashMap copy = new HashMap(); HashMap copy = new HashMap();
for (Object key : keySet()) { for (Object key : keySet()) {
copy.put(key, get(key)); copy.put(key, get(key));
} }
return Collections.unmodifiableMap(copy).entrySet(); return Collections.unmodifiableMap(copy).entrySet();
} }
@Override @Override
public Collection values() { public Collection values() {
Set keys = keySet(); Set keys = keySet();
List values = new ArrayList(keys.size()); List values = new ArrayList(keys.size());
for (Iterator it = keys.iterator(); it.hasNext();) { for (Iterator it = keys.iterator(); it.hasNext();) {
values.add(get(it.next())); values.add(get(it.next()));
} }
return Collections.unmodifiableCollection(values); return Collections.unmodifiableCollection(values);
} }
/* /*
* @see java.util.AbstractMap#toString * @see java.util.AbstractMap#toString
*/ */
@Override @Override
public String toString() public String toString()
{ {
StringBuilder sb = new StringBuilder(); StringBuilder sb = new StringBuilder();
sb.append('{'); sb.append('{');
for (Iterator it = keySet().iterator(); it.hasNext();) { for (Iterator it = keySet().iterator(); it.hasNext();) {
Object key = it.next(); Object key = it.next();
sb.append(key); sb.append(key);
sb.append('='); sb.append('=');
sb.append(get(key)); sb.append(get(key));
if (it.hasNext()) { if (it.hasNext()) {
sb.append(", "); sb.append(", ");
} }
} }
sb.append('}'); sb.append('}');
return sb.toString(); return sb.toString();
} }
} }

View File

@ -28,123 +28,123 @@ import org.springframework.cglib.core.ReflectUtils;
@SuppressWarnings({"rawtypes", "unchecked"}) @SuppressWarnings({"rawtypes", "unchecked"})
abstract public class BulkBean abstract public class BulkBean
{ {
private static final BulkBeanKey KEY_FACTORY = private static final BulkBeanKey KEY_FACTORY =
(BulkBeanKey)KeyFactory.create(BulkBeanKey.class); (BulkBeanKey)KeyFactory.create(BulkBeanKey.class);
interface BulkBeanKey { interface BulkBeanKey {
public Object newInstance(String target, String[] getters, String[] setters, String[] types); public Object newInstance(String target, String[] getters, String[] setters, String[] types);
} }
protected Class target; protected Class target;
protected String[] getters, setters; protected String[] getters, setters;
protected Class[] types; protected Class[] types;
protected BulkBean() { } protected BulkBean() { }
abstract public void getPropertyValues(Object bean, Object[] values); abstract public void getPropertyValues(Object bean, Object[] values);
abstract public void setPropertyValues(Object bean, Object[] values); abstract public void setPropertyValues(Object bean, Object[] values);
public Object[] getPropertyValues(Object bean) { public Object[] getPropertyValues(Object bean) {
Object[] values = new Object[getters.length]; Object[] values = new Object[getters.length];
getPropertyValues(bean, values); getPropertyValues(bean, values);
return values; return values;
} }
public Class[] getPropertyTypes() { public Class[] getPropertyTypes() {
return types.clone(); return types.clone();
} }
public String[] getGetters() { public String[] getGetters() {
return getters.clone(); return getters.clone();
} }
public String[] getSetters() { public String[] getSetters() {
return setters.clone(); return setters.clone();
} }
public static BulkBean create(Class target, String[] getters, String[] setters, Class[] types) { public static BulkBean create(Class target, String[] getters, String[] setters, Class[] types) {
Generator gen = new Generator(); Generator gen = new Generator();
gen.setTarget(target); gen.setTarget(target);
gen.setGetters(getters); gen.setGetters(getters);
gen.setSetters(setters); gen.setSetters(setters);
gen.setTypes(types); gen.setTypes(types);
return gen.create(); return gen.create();
} }
public static class Generator extends AbstractClassGenerator { public static class Generator extends AbstractClassGenerator {
private static final Source SOURCE = new Source(BulkBean.class.getName()); private static final Source SOURCE = new Source(BulkBean.class.getName());
private Class target; private Class target;
private String[] getters; private String[] getters;
private String[] setters; private String[] setters;
private Class[] types; private Class[] types;
public Generator() { public Generator() {
super(SOURCE); super(SOURCE);
} }
public void setTarget(Class target) { public void setTarget(Class target) {
this.target = target; this.target = target;
// SPRING PATCH BEGIN // SPRING PATCH BEGIN
setContextClass(target); setContextClass(target);
// SPRING PATCH END // SPRING PATCH END
} }
public void setGetters(String[] getters) { public void setGetters(String[] getters) {
this.getters = getters; this.getters = getters;
} }
public void setSetters(String[] setters) { public void setSetters(String[] setters) {
this.setters = setters; this.setters = setters;
} }
public void setTypes(Class[] types) { public void setTypes(Class[] types) {
this.types = types; this.types = types;
} }
@Override @Override
protected ClassLoader getDefaultClassLoader() { protected ClassLoader getDefaultClassLoader() {
return target.getClassLoader(); return target.getClassLoader();
} }
@Override @Override
protected ProtectionDomain getProtectionDomain() { protected ProtectionDomain getProtectionDomain() {
return ReflectUtils.getProtectionDomain(target); return ReflectUtils.getProtectionDomain(target);
} }
public BulkBean create() { public BulkBean create() {
setNamePrefix(target.getName()); setNamePrefix(target.getName());
String targetClassName = target.getName(); String targetClassName = target.getName();
String[] typeClassNames = ReflectUtils.getNames(types); String[] typeClassNames = ReflectUtils.getNames(types);
Object key = KEY_FACTORY.newInstance(targetClassName, getters, setters, typeClassNames); Object key = KEY_FACTORY.newInstance(targetClassName, getters, setters, typeClassNames);
return (BulkBean)super.create(key); return (BulkBean)super.create(key);
} }
@Override @Override
public void generateClass(ClassVisitor v) throws Exception { public void generateClass(ClassVisitor v) throws Exception {
new BulkBeanEmitter(v, getClassName(), target, getters, setters, types); new BulkBeanEmitter(v, getClassName(), target, getters, setters, types);
} }
@Override @Override
protected Object firstInstance(Class type) { protected Object firstInstance(Class type) {
BulkBean instance = (BulkBean)ReflectUtils.newInstance(type); BulkBean instance = (BulkBean)ReflectUtils.newInstance(type);
instance.target = target; instance.target = target;
int length = getters.length; int length = getters.length;
instance.getters = new String[length]; instance.getters = new String[length];
System.arraycopy(getters, 0, instance.getters, 0, length); System.arraycopy(getters, 0, instance.getters, 0, length);
instance.setters = new String[length]; instance.setters = new String[length];
System.arraycopy(setters, 0, instance.setters, 0, length); System.arraycopy(setters, 0, instance.setters, 0, length);
instance.types = new Class[types.length]; instance.types = new Class[types.length];
System.arraycopy(types, 0, instance.types, 0, types.length); System.arraycopy(types, 0, instance.types, 0, types.length);
return instance; return instance;
} }
@Override @Override
protected Object nextInstance(Object instance) { protected Object nextInstance(Object instance) {
return instance; return instance;
} }
} }
} }

View File

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