Skip to content

Commit c40ab67

Browse files
committed
bean bind
1 parent 3a123e1 commit c40ab67

File tree

45 files changed

+2051
-391
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+2051
-391
lines changed

dubbo-plugin/dubbo-rest-jaxrs/pom.xml

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,5 +62,45 @@
6262
<artifactId>jaxb-runtime</artifactId>
6363
<scope>test</scope>
6464
</dependency>
65+
<dependency>
66+
<groupId>org.yaml</groupId>
67+
<artifactId>snakeyaml</artifactId>
68+
<scope>test</scope>
69+
</dependency>
70+
<dependency>
71+
<groupId>org.apache.dubbo</groupId>
72+
<artifactId>dubbo-rpc-triple</artifactId>
73+
<version>${project.version}</version>
74+
<type>test-jar</type>
75+
<scope>test</scope>
76+
</dependency>
77+
<dependency>
78+
<groupId>org.spockframework</groupId>
79+
<artifactId>spock-core</artifactId>
80+
<scope>test</scope>
81+
</dependency>
6582
</dependencies>
83+
84+
<build>
85+
<plugins>
86+
<plugin>
87+
<groupId>org.codehaus.gmavenplus</groupId>
88+
<artifactId>gmavenplus-plugin</artifactId>
89+
</plugin>
90+
</plugins>
91+
</build>
92+
93+
<profiles>
94+
<profile>
95+
<id>rpc-rest-test</id>
96+
<dependencies>
97+
<dependency>
98+
<groupId>org.apache.dubbo</groupId>
99+
<artifactId>dubbo-rpc-rest</artifactId>
100+
<version>3.3.0-beta.2</version>
101+
<scope>test</scope>
102+
</dependency>
103+
</dependencies>
104+
</profile>
105+
</profiles>
66106
</project>

dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/BeanArgumentBinder.java

Lines changed: 56 additions & 220 deletions
Original file line numberDiff line numberDiff line change
@@ -27,254 +27,90 @@
2727
import org.apache.dubbo.rpc.protocol.tri.rest.argument.ArgumentResolver;
2828
import org.apache.dubbo.rpc.protocol.tri.rest.argument.CompositeArgumentResolver;
2929
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.AnnotationMeta;
30+
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta;
31+
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta.ConstructorMeta;
32+
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta.FieldMeta;
33+
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.BeanMeta.SetMethodMeta;
3034
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;
31-
import org.apache.dubbo.rpc.protocol.tri.rest.util.RestToolKit;
35+
import org.apache.dubbo.rpc.protocol.tri.rest.util.TypeUtils;
3236

33-
import java.lang.reflect.AnnotatedElement;
34-
import java.lang.reflect.Constructor;
35-
import java.lang.reflect.Field;
36-
import java.lang.reflect.Method;
37-
import java.lang.reflect.Modifier;
38-
import java.lang.reflect.Parameter;
39-
import java.lang.reflect.Type;
40-
import java.util.ArrayList;
41-
import java.util.List;
37+
import java.util.HashSet;
4238
import java.util.Map;
39+
import java.util.Set;
4340

4441
final class BeanArgumentBinder {
4542

46-
private final ArgumentResolver argumentResolver;
43+
private static final ThreadLocal<Set<Class<?>>> LOCAL = new ThreadLocal<>();
4744

4845
private final Map<Pair<Class<?>, String>, BeanMeta> cache = CollectionUtils.newConcurrentHashMap();
46+
private final ArgumentResolver argumentResolver;
4947

5048
BeanArgumentBinder(FrameworkModel frameworkModel) {
5149
ScopeBeanFactory beanFactory = frameworkModel.getBeanFactory();
5250
argumentResolver = beanFactory.getOrRegisterBean(CompositeArgumentResolver.class);
5351
}
5452

55-
public Object bind(ParameterMeta parameter, HttpRequest request, HttpResponse response) {
53+
public Object bind(ParameterMeta paramMeta, HttpRequest request, HttpResponse response) {
54+
Set<Class<?>> walked = LOCAL.get();
55+
if (walked == null) {
56+
LOCAL.set(new HashSet<>());
57+
}
5658
try {
57-
return resolveArgument(parameter, request, response);
59+
return resolveArgument(paramMeta, request, response);
5860
} catch (Exception e) {
59-
throw new RestException(Messages.ARGUMENT_BIND_ERROR, parameter.getName(), parameter.getType(), e);
60-
}
61-
}
62-
63-
private Object resolveArgument(ParameterMeta param, HttpRequest request, HttpResponse response) throws Exception {
64-
AnnotationMeta<?> form = param.findAnnotation(Annotations.Form);
65-
if (form != null || param.isHierarchyAnnotated(Annotations.BeanParam)) {
66-
String prefix = form == null ? null : form.getString("prefix");
67-
BeanMeta beanMeta = cache.computeIfAbsent(
68-
Pair.of(param.getActualType(), prefix),
69-
k -> new BeanMeta(param.getToolKit(), k.getValue(), k.getKey()));
70-
71-
ConstructorMeta constructor = beanMeta.constructor;
72-
ParameterMeta[] parameters = constructor.parameters;
73-
int len = parameters.length;
74-
Object[] args = new Object[len];
75-
for (int i = 0; i < len; i++) {
76-
args[i] = resolveArgument(parameters[i], request, response);
77-
}
78-
Object bean = constructor.newInstance(args);
79-
80-
for (FieldMeta fieldMeta : beanMeta.fields) {
81-
fieldMeta.set(bean, resolveArgument(fieldMeta, request, response));
82-
}
83-
84-
for (SetMethodMeta methodMeta : beanMeta.methods) {
85-
methodMeta.invoke(bean, resolveArgument(methodMeta, request, response));
61+
throw new RestException(e, Messages.ARGUMENT_BIND_ERROR, paramMeta.getName(), paramMeta.getType());
62+
} finally {
63+
if (walked == null) {
64+
LOCAL.remove();
8665
}
87-
return bean;
8866
}
89-
90-
return argumentResolver.resolve(param, request, response);
9167
}
9268

93-
private static class BeanMeta {
94-
95-
private final List<FieldMeta> fields = new ArrayList<>();
96-
private final List<SetMethodMeta> methods = new ArrayList<>();
97-
private final ConstructorMeta constructor;
98-
99-
BeanMeta(RestToolKit toolKit, String prefix, Class<?> type) {
100-
constructor = resolveConstructor(toolKit, prefix, type);
101-
resolveFieldAndMethod(toolKit, prefix, type);
102-
}
103-
104-
private ConstructorMeta resolveConstructor(RestToolKit toolKit, String prefix, Class<?> type) {
105-
Constructor<?>[] constructors = type.getConstructors();
106-
Constructor<?> ct = null;
107-
if (constructors.length == 1) {
108-
ct = constructors[0];
109-
} else {
110-
try {
111-
ct = type.getDeclaredConstructor();
112-
} catch (NoSuchMethodException ignored) {
69+
private Object resolveArgument(ParameterMeta paramMeta, HttpRequest request, HttpResponse response) {
70+
if (paramMeta.isSimple()) {
71+
return argumentResolver.resolve(paramMeta, request, response);
72+
}
73+
74+
// Prevent infinite loops
75+
if (LOCAL.get().add(paramMeta.getActualType())) {
76+
AnnotationMeta<?> form = paramMeta.findAnnotation(Annotations.Form);
77+
if (form != null || paramMeta.isHierarchyAnnotated(Annotations.BeanParam)) {
78+
String prefix = form == null ? null : form.getString("prefix");
79+
BeanMeta beanMeta = cache.computeIfAbsent(
80+
Pair.of(paramMeta.getActualType(), prefix),
81+
k -> new BeanMeta(paramMeta.getToolKit(), k.getValue(), k.getKey()));
82+
83+
ConstructorMeta constructor = beanMeta.getConstructor();
84+
ParameterMeta[] parameters = constructor.getParameters();
85+
Object bean;
86+
int len = parameters.length;
87+
if (len == 0) {
88+
bean = constructor.newInstance();
89+
} else {
90+
Object[] args = new Object[len];
91+
for (int i = 0; i < len; i++) {
92+
args[i] = resolveArgument(parameters[i], request, response);
93+
}
94+
bean = constructor.newInstance(args);
11395
}
114-
}
115-
if (ct == null) {
116-
throw new IllegalArgumentException("No available default constructor found in " + type);
117-
}
118-
return new ConstructorMeta(toolKit, prefix, ct);
119-
}
12096

121-
private void resolveFieldAndMethod(RestToolKit toolKit, String prefix, Class<?> type) {
122-
if (type == Object.class) {
123-
return;
124-
}
125-
for (Field field : type.getDeclaredFields()) {
126-
int modifiers = field.getModifiers();
127-
if (Modifier.isStatic(modifiers) || Modifier.isFinal(modifiers)) {
128-
continue;
129-
}
130-
if (field.getAnnotations().length == 0) {
131-
continue;
132-
}
133-
if (!field.isAccessible()) {
134-
field.setAccessible(true);
135-
}
136-
fields.add(new FieldMeta(toolKit, prefix, field));
137-
}
138-
for (Method method : type.getDeclaredMethods()) {
139-
if (method.getParameterCount() != 1) {
140-
continue;
97+
Set<String> resolved = new HashSet<>();
98+
for (FieldMeta fieldMeta : beanMeta.getFields()) {
99+
resolved.add(fieldMeta.getName());
100+
fieldMeta.setValue(bean, resolveArgument(fieldMeta, request, response));
141101
}
142-
int modifiers = method.getModifiers();
143-
if ((modifiers & (Modifier.PUBLIC | Modifier.ABSTRACT | Modifier.STATIC)) == Modifier.PUBLIC) {
144-
Parameter parameter = method.getParameters()[0];
145-
String name = method.getName();
146-
if (name.length() > 3 && name.startsWith("set")) {
147-
name = Character.toLowerCase(name.charAt(3)) + name.substring(4);
148-
methods.add(new SetMethodMeta(toolKit, method, parameter, prefix, name));
102+
103+
for (SetMethodMeta methodMeta : beanMeta.getMethods()) {
104+
if (resolved.contains(methodMeta.getName())) {
105+
continue;
149106
}
107+
methodMeta.setValue(bean, resolveArgument(methodMeta, request, response));
150108
}
151-
}
152-
resolveFieldAndMethod(toolKit, prefix, type.getSuperclass());
153-
}
154-
}
155-
156-
private static final class ConstructorMeta {
157109

158-
private final Constructor<?> constructor;
159-
private final ConstructorParameterMeta[] parameters;
160-
161-
ConstructorMeta(RestToolKit toolKit, String prefix, Constructor<?> constructor) {
162-
this.constructor = constructor;
163-
parameters = initParameters(toolKit, prefix, constructor);
164-
}
165-
166-
private ConstructorParameterMeta[] initParameters(RestToolKit toolKit, String prefix, Constructor<?> ct) {
167-
Parameter[] cps = ct.getParameters();
168-
int len = cps.length;
169-
ConstructorParameterMeta[] parameters = new ConstructorParameterMeta[len];
170-
for (int i = 0; i < len; i++) {
171-
parameters[i] = new ConstructorParameterMeta(toolKit, cps[i], prefix);
110+
return bean;
172111
}
173-
return parameters;
174112
}
175113

176-
Object newInstance(Object[] args) throws Exception {
177-
return constructor.newInstance(args);
178-
}
179-
}
180-
181-
public static final class ConstructorParameterMeta extends ParameterMeta {
182-
183-
private final Parameter parameter;
184-
185-
ConstructorParameterMeta(RestToolKit toolKit, Parameter parameter, String prefix) {
186-
super(toolKit, prefix, parameter.isNamePresent() ? parameter.getName() : null);
187-
this.parameter = parameter;
188-
}
189-
190-
@Override
191-
protected AnnotatedElement getAnnotatedElement() {
192-
return parameter;
193-
}
194-
195-
@Override
196-
public Class<?> getType() {
197-
return parameter.getType();
198-
}
199-
200-
@Override
201-
public Type getGenericType() {
202-
return parameter.getParameterizedType();
203-
}
204-
205-
@Override
206-
public String getDescription() {
207-
return "ConstructorParameter{" + parameter + '}';
208-
}
209-
}
210-
211-
private static final class FieldMeta extends ParameterMeta {
212-
213-
private final Field field;
214-
215-
FieldMeta(RestToolKit toolKit, String prefix, Field field) {
216-
super(toolKit, prefix, field.getName());
217-
this.field = field;
218-
}
219-
220-
@Override
221-
public Class<?> getType() {
222-
return field.getType();
223-
}
224-
225-
@Override
226-
public Type getGenericType() {
227-
return field.getGenericType();
228-
}
229-
230-
@Override
231-
protected AnnotatedElement getAnnotatedElement() {
232-
return field;
233-
}
234-
235-
public void set(Object bean, Object value) throws Exception {
236-
field.set(bean, value);
237-
}
238-
239-
@Override
240-
public String getDescription() {
241-
return "FieldParameter{" + field + '}';
242-
}
243-
}
244-
245-
private static final class SetMethodMeta extends ParameterMeta {
246-
247-
private final Method method;
248-
private final Parameter parameter;
249-
250-
SetMethodMeta(RestToolKit toolKit, Method method, Parameter parameter, String prefix, String name) {
251-
super(toolKit, prefix, name);
252-
this.method = method;
253-
this.parameter = parameter;
254-
}
255-
256-
@Override
257-
public Class<?> getType() {
258-
return parameter.getType();
259-
}
260-
261-
@Override
262-
public Type getGenericType() {
263-
return parameter.getParameterizedType();
264-
}
265-
266-
@Override
267-
protected AnnotatedElement getAnnotatedElement() {
268-
return parameter;
269-
}
270-
271-
public void invoke(Object bean, Object value) throws Exception {
272-
method.invoke(bean, value);
273-
}
274-
275-
@Override
276-
public String getDescription() {
277-
return "SetMethodParameter{" + method + '}';
278-
}
114+
return TypeUtils.nullDefault(paramMeta.getType());
279115
}
280116
}

dubbo-plugin/dubbo-rest-jaxrs/src/main/java/org/apache/dubbo/rpc/protocol/tri/rest/support/jaxrs/JaxrsRestToolKit.java

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,12 +21,12 @@
2121
import org.apache.dubbo.rpc.model.FrameworkModel;
2222
import org.apache.dubbo.rpc.protocol.tri.rest.RestConstants;
2323
import org.apache.dubbo.rpc.protocol.tri.rest.mapping.meta.ParameterMeta;
24-
import org.apache.dubbo.rpc.protocol.tri.rest.util.DefaultRestToolKit;
24+
import org.apache.dubbo.rpc.protocol.tri.rest.util.AbstractRestToolKit;
2525

2626
import javax.ws.rs.core.MultivaluedHashMap;
2727
import javax.ws.rs.core.MultivaluedMap;
2828

29-
final class JaxrsRestToolKit extends DefaultRestToolKit {
29+
final class JaxrsRestToolKit extends AbstractRestToolKit {
3030

3131
private final BeanArgumentBinder binder;
3232

@@ -35,6 +35,11 @@ public JaxrsRestToolKit(FrameworkModel frameworkModel) {
3535
binder = new BeanArgumentBinder(frameworkModel);
3636
}
3737

38+
@Override
39+
public int getDialect() {
40+
return RestConstants.DIALECT_JAXRS;
41+
}
42+
3843
@Override
3944
public Object convert(Object value, ParameterMeta parameter) {
4045
if (MultivaluedMap.class.isAssignableFrom(parameter.getType())) {
@@ -46,11 +51,6 @@ public Object convert(Object value, ParameterMeta parameter) {
4651
return super.convert(value, parameter);
4752
}
4853

49-
@Override
50-
public int getDialect() {
51-
return RestConstants.DIALECT_JAXRS;
52-
}
53-
5454
@Override
5555
public Object bind(ParameterMeta parameter, HttpRequest request, HttpResponse response) {
5656
return binder.bind(parameter, request, response);

0 commit comments

Comments
 (0)