Skip to content

Commit f8b41c1

Browse files
committed
Consistent support for setContextClass in CGLIB beans package
Closes gh-28530
1 parent 8c77711 commit f8b41c1

File tree

13 files changed

+1047
-5
lines changed

13 files changed

+1047
-5
lines changed

spring-core/spring-core.gradle

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,8 +76,7 @@ jar {
7676
dependsOn cglibRepackJar
7777
from(zipTree(cglibRepackJar.archivePath)) {
7878
include "org/springframework/cglib/**"
79-
exclude "org/springframework/cglib/beans/BeanMap.class"
80-
exclude "org/springframework/cglib/beans/BeanMap\$*.class"
79+
exclude "org/springframework/cglib/beans/**"
8180
exclude "org/springframework/cglib/core/AbstractClassGenerator*.class"
8281
exclude "org/springframework/cglib/core/AsmApi*.class"
8382
exclude "org/springframework/cglib/core/KeyFactory.class"
Lines changed: 179 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,179 @@
1+
/*
2+
* Copyright 2003,2004 The Apache Software Foundation
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.cglib.beans;
17+
18+
import java.beans.PropertyDescriptor;
19+
import java.lang.reflect.*;
20+
import java.security.ProtectionDomain;
21+
import org.springframework.cglib.core.*;
22+
import org.springframework.asm.ClassVisitor;
23+
import org.springframework.asm.Type;
24+
import java.util.*;
25+
26+
/**
27+
* @author Chris Nokleberg
28+
*/
29+
@SuppressWarnings({"rawtypes", "unchecked"})
30+
abstract public class BeanCopier
31+
{
32+
private static final BeanCopierKey KEY_FACTORY =
33+
(BeanCopierKey)KeyFactory.create(BeanCopierKey.class);
34+
private static final Type CONVERTER =
35+
TypeUtils.parseType("org.springframework.cglib.core.Converter");
36+
private static final Type BEAN_COPIER =
37+
TypeUtils.parseType("org.springframework.cglib.beans.BeanCopier");
38+
private static final Signature COPY =
39+
new Signature("copy", Type.VOID_TYPE, new Type[]{ Constants.TYPE_OBJECT, Constants.TYPE_OBJECT, CONVERTER });
40+
private static final Signature CONVERT =
41+
TypeUtils.parseSignature("Object convert(Object, Class, Object)");
42+
43+
interface BeanCopierKey {
44+
public Object newInstance(String source, String target, boolean useConverter);
45+
}
46+
47+
public static BeanCopier create(Class source, Class target, boolean useConverter) {
48+
Generator gen = new Generator();
49+
gen.setSource(source);
50+
gen.setTarget(target);
51+
gen.setUseConverter(useConverter);
52+
return gen.create();
53+
}
54+
55+
abstract public void copy(Object from, Object to, Converter converter);
56+
57+
public static class Generator extends AbstractClassGenerator {
58+
private static final Source SOURCE = new Source(BeanCopier.class.getName());
59+
private Class source;
60+
private Class target;
61+
private boolean useConverter;
62+
63+
public Generator() {
64+
super(SOURCE);
65+
}
66+
67+
public void setSource(Class source) {
68+
if(!Modifier.isPublic(source.getModifiers())){
69+
setNamePrefix(source.getName());
70+
}
71+
this.source = source;
72+
}
73+
74+
public void setTarget(Class target) {
75+
if(!Modifier.isPublic(target.getModifiers())){
76+
setNamePrefix(target.getName());
77+
}
78+
this.target = target;
79+
// SPRING PATCH BEGIN
80+
setContextClass(target);
81+
// SPRING PATCH END
82+
}
83+
84+
public void setUseConverter(boolean useConverter) {
85+
this.useConverter = useConverter;
86+
}
87+
88+
protected ClassLoader getDefaultClassLoader() {
89+
return source.getClassLoader();
90+
}
91+
92+
protected ProtectionDomain getProtectionDomain() {
93+
return ReflectUtils.getProtectionDomain(source);
94+
}
95+
96+
public BeanCopier create() {
97+
Object key = KEY_FACTORY.newInstance(source.getName(), target.getName(), useConverter);
98+
return (BeanCopier)super.create(key);
99+
}
100+
101+
public void generateClass(ClassVisitor v) {
102+
Type sourceType = Type.getType(source);
103+
Type targetType = Type.getType(target);
104+
ClassEmitter ce = new ClassEmitter(v);
105+
ce.begin_class(Constants.V1_8,
106+
Constants.ACC_PUBLIC,
107+
getClassName(),
108+
BEAN_COPIER,
109+
null,
110+
Constants.SOURCE_FILE);
111+
112+
EmitUtils.null_constructor(ce);
113+
CodeEmitter e = ce.begin_method(Constants.ACC_PUBLIC, COPY, null);
114+
PropertyDescriptor[] getters = ReflectUtils.getBeanGetters(source);
115+
PropertyDescriptor[] setters = ReflectUtils.getBeanSetters(target);
116+
117+
Map names = new HashMap();
118+
for (int i = 0; i < getters.length; i++) {
119+
names.put(getters[i].getName(), getters[i]);
120+
}
121+
Local targetLocal = e.make_local();
122+
Local sourceLocal = e.make_local();
123+
if (useConverter) {
124+
e.load_arg(1);
125+
e.checkcast(targetType);
126+
e.store_local(targetLocal);
127+
e.load_arg(0);
128+
e.checkcast(sourceType);
129+
e.store_local(sourceLocal);
130+
} else {
131+
e.load_arg(1);
132+
e.checkcast(targetType);
133+
e.load_arg(0);
134+
e.checkcast(sourceType);
135+
}
136+
for (int i = 0; i < setters.length; i++) {
137+
PropertyDescriptor setter = setters[i];
138+
PropertyDescriptor getter = (PropertyDescriptor)names.get(setter.getName());
139+
if (getter != null) {
140+
MethodInfo read = ReflectUtils.getMethodInfo(getter.getReadMethod());
141+
MethodInfo write = ReflectUtils.getMethodInfo(setter.getWriteMethod());
142+
if (useConverter) {
143+
Type setterType = write.getSignature().getArgumentTypes()[0];
144+
e.load_local(targetLocal);
145+
e.load_arg(2);
146+
e.load_local(sourceLocal);
147+
e.invoke(read);
148+
e.box(read.getSignature().getReturnType());
149+
EmitUtils.load_class(e, setterType);
150+
e.push(write.getSignature().getName());
151+
e.invoke_interface(CONVERTER, CONVERT);
152+
e.unbox_or_zero(setterType);
153+
e.invoke(write);
154+
} else if (compatible(getter, setter)) {
155+
e.dup2();
156+
e.invoke(read);
157+
e.invoke(write);
158+
}
159+
}
160+
}
161+
e.return_value();
162+
e.end_method();
163+
ce.end_class();
164+
}
165+
166+
private static boolean compatible(PropertyDescriptor getter, PropertyDescriptor setter) {
167+
// TODO: allow automatic widening conversions?
168+
return setter.getPropertyType().isAssignableFrom(getter.getPropertyType());
169+
}
170+
171+
protected Object firstInstance(Class type) {
172+
return ReflectUtils.newInstance(type);
173+
}
174+
175+
protected Object nextInstance(Object instance) {
176+
return instance;
177+
}
178+
}
179+
}
Lines changed: 153 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,153 @@
1+
/*
2+
* Copyright 2003 The Apache Software Foundation
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.cglib.beans;
17+
18+
import java.beans.PropertyDescriptor;
19+
import java.security.ProtectionDomain;
20+
import java.util.*;
21+
import org.springframework.cglib.core.*;
22+
import org.springframework.asm.ClassVisitor;
23+
import org.springframework.asm.Type;
24+
25+
/**
26+
* @author Juozas Baliuka, Chris Nokleberg
27+
*/
28+
@SuppressWarnings({"rawtypes", "unchecked"})
29+
public class BeanGenerator extends AbstractClassGenerator
30+
{
31+
private static final Source SOURCE = new Source(BeanGenerator.class.getName());
32+
private static final BeanGeneratorKey KEY_FACTORY =
33+
(BeanGeneratorKey)KeyFactory.create(BeanGeneratorKey.class);
34+
35+
interface BeanGeneratorKey {
36+
public Object newInstance(String superclass, Map props);
37+
}
38+
39+
private Class superclass;
40+
private Map props = new HashMap();
41+
private boolean classOnly;
42+
43+
public BeanGenerator() {
44+
super(SOURCE);
45+
}
46+
47+
/**
48+
* Set the class which the generated class will extend. The class
49+
* must not be declared as final, and must have a non-private
50+
* no-argument constructor.
51+
* @param superclass class to extend, or null to extend Object
52+
*/
53+
public void setSuperclass(Class superclass) {
54+
if (superclass != null && superclass.equals(Object.class)) {
55+
superclass = null;
56+
}
57+
this.superclass = superclass;
58+
// SPRING PATCH BEGIN
59+
setContextClass(superclass);
60+
// SPRING PATCH END
61+
}
62+
63+
public void addProperty(String name, Class type) {
64+
if (props.containsKey(name)) {
65+
throw new IllegalArgumentException("Duplicate property name \"" + name + "\"");
66+
}
67+
props.put(name, Type.getType(type));
68+
}
69+
70+
protected ClassLoader getDefaultClassLoader() {
71+
if (superclass != null) {
72+
return superclass.getClassLoader();
73+
} else {
74+
return null;
75+
}
76+
}
77+
78+
protected ProtectionDomain getProtectionDomain() {
79+
return ReflectUtils.getProtectionDomain(superclass);
80+
}
81+
82+
public Object create() {
83+
classOnly = false;
84+
return createHelper();
85+
}
86+
87+
public Object createClass() {
88+
classOnly = true;
89+
return createHelper();
90+
}
91+
92+
private Object createHelper() {
93+
if (superclass != null) {
94+
setNamePrefix(superclass.getName());
95+
}
96+
String superName = (superclass != null) ? superclass.getName() : "java.lang.Object";
97+
Object key = KEY_FACTORY.newInstance(superName, props);
98+
return super.create(key);
99+
}
100+
101+
public void generateClass(ClassVisitor v) throws Exception {
102+
int size = props.size();
103+
String[] names = (String[])props.keySet().toArray(new String[size]);
104+
Type[] types = new Type[size];
105+
for (int i = 0; i < size; i++) {
106+
types[i] = (Type)props.get(names[i]);
107+
}
108+
ClassEmitter ce = new ClassEmitter(v);
109+
ce.begin_class(Constants.V1_8,
110+
Constants.ACC_PUBLIC,
111+
getClassName(),
112+
superclass != null ? Type.getType(superclass) : Constants.TYPE_OBJECT,
113+
null,
114+
null);
115+
EmitUtils.null_constructor(ce);
116+
EmitUtils.add_properties(ce, names, types);
117+
ce.end_class();
118+
}
119+
120+
protected Object firstInstance(Class type) {
121+
if (classOnly) {
122+
return type;
123+
} else {
124+
return ReflectUtils.newInstance(type);
125+
}
126+
}
127+
128+
protected Object nextInstance(Object instance) {
129+
Class protoclass = (instance instanceof Class) ? (Class)instance : instance.getClass();
130+
if (classOnly) {
131+
return protoclass;
132+
} else {
133+
return ReflectUtils.newInstance(protoclass);
134+
}
135+
}
136+
137+
public static void addProperties(BeanGenerator gen, Map props) {
138+
for (Iterator it = props.keySet().iterator(); it.hasNext();) {
139+
String name = (String)it.next();
140+
gen.addProperty(name, (Class)props.get(name));
141+
}
142+
}
143+
144+
public static void addProperties(BeanGenerator gen, Class type) {
145+
addProperties(gen, ReflectUtils.getBeanProperties(type));
146+
}
147+
148+
public static void addProperties(BeanGenerator gen, PropertyDescriptor[] descriptors) {
149+
for (int i = 0; i < descriptors.length; i++) {
150+
gen.addProperty(descriptors[i].getName(), descriptors[i].getPropertyType());
151+
}
152+
}
153+
}

spring-core/src/main/java/org/springframework/cglib/beans/BeanMap.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,7 +97,9 @@ public void setBean(Object bean) {
9797
this.bean = bean;
9898
if (bean != null) {
9999
beanClass = bean.getClass();
100+
// SPRING PATCH BEGIN
100101
setContextClass(beanClass);
102+
// SPRING PATCH END
101103
}
102104
}
103105

0 commit comments

Comments
 (0)