BeanCopier sets name prefix for public classes as well
Includes consistent formatting of Spring-patched files. Closes gh-28699
This commit is contained in:
parent
da95542d8f
commit
7a60e2024b
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue