Skip to content

Commit 1420cb4

Browse files
zhangyinyueAuthorlove
authored andcommitted
增加MethodValidated注解的测试用例 及对MethodValidated使用场景和用法的说明注释 (#784)
* 增加MethodValidated注解的测试用例 及对MethodValidated使用场景和用法的说明注释 * 将需要检查的分组维护到List<Class<?>> groups中,包括当前接口类及Default.class两个默认的分组 * 修改接口级别为jdk1.6; 按javadoc规范修改注释
1 parent 50d4ddd commit 1420cb4

File tree

6 files changed

+114
-16
lines changed

6 files changed

+114
-16
lines changed

dubbo-config/dubbo-config-api/src/test/java/com/alibaba/dubbo/config/validation/ValidationParameter.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ public class ValidationParameter implements Serializable {
3434

3535
private static final long serialVersionUID = 7158911668568000392L;
3636

37+
@NotNull(groups = ValidationService.Update.class)
38+
private Integer id;
39+
3740
@NotNull // 不允许为空
3841
@Size(min = 2, max = 20) // 长度或大小范围
3942
private String name;
@@ -52,6 +55,14 @@ public class ValidationParameter implements Serializable {
5255
@Future // 必须为一个未来的时间
5356
private Date expiryDate;
5457

58+
public Integer getId() {
59+
return id;
60+
}
61+
62+
public void setId(Integer id) {
63+
this.id = id;
64+
}
65+
5566
public String getName() {
5667
return name;
5768
}

dubbo-config/dubbo-config-api/src/test/java/com/alibaba/dubbo/config/validation/ValidationService.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
*/
1616
package com.alibaba.dubbo.config.validation;
1717

18+
import com.alibaba.dubbo.validation.MethodValidated;
19+
1820
import javax.validation.constraints.Min;
1921
import javax.validation.constraints.NotNull;
2022
import javax.validation.constraints.Pattern;
@@ -28,16 +30,31 @@
2830
*/
2931
public interface ValidationService { // 缺省可按服务接口区分验证场景,如:@NotNull(groups = ValidationService.class)
3032

33+
/**
34+
* 没有加上“@MethodValidated(ValidationService.Save.class)”这句代码时,
35+
* 现在的检查逻辑不会去检验groups = ValidationService.Save.class这个分组
36+
*
37+
* @param parameter
38+
*/
39+
@MethodValidated(Save.class)
3140
void save(ValidationParameter parameter);
3241

3342
void update(ValidationParameter parameter);
3443

3544
void delete(@Min(1) long id, @NotNull @Size(min = 2, max = 16) @Pattern(regexp = "^[a-zA-Z]+$") String operator);
3645

46+
/**
47+
* 假设关联查询的时候需要同时传id和email的值。这时需要检查Sava分组和Update分组。
48+
* @param parameter
49+
*/
50+
@MethodValidated({Save.class, Update.class})
51+
void relatedQuery(ValidationParameter parameter);
52+
3753
@interface Save {
3854
} // 与方法同名接口,首字母大写,用于区分验证场景,如:@NotNull(groups = ValidationService.Save.class),可选
3955

4056
@interface Update {
4157
} // 与方法同名接口,首字母大写,用于区分验证场景,如:@NotNull(groups = ValidationService.Update.class),可选
4258

59+
4360
}

dubbo-config/dubbo-config-api/src/test/java/com/alibaba/dubbo/config/validation/ValidationServiceImpl.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,4 +31,8 @@ public void update(ValidationParameter parameter) {
3131
public void delete(long id, String operator) {
3232
}
3333

34+
public void relatedQuery(ValidationParameter parameter){
35+
36+
}
37+
3438
}

dubbo-config/dubbo-config-api/src/test/java/com/alibaba/dubbo/config/validation/ValidationTest.java

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,36 @@ public void testValidation() {
8181
Assert.assertNotNull(violations);
8282
}
8383

84+
//检查Save分组 save error
85+
try {
86+
parameter = new ValidationParameter();
87+
parameter.setName("liangfei");
88+
parameter.setAge(50);
89+
parameter.setLoginDate(new Date(System.currentTimeMillis() - 1000000));
90+
parameter.setExpiryDate(new Date(System.currentTimeMillis() + 1000000));
91+
validationService.save(parameter);
92+
Assert.fail();
93+
} catch (RpcException e) {
94+
ConstraintViolationException ve = (ConstraintViolationException) e.getCause();
95+
Set<ConstraintViolation<?>> violations = ve.getConstraintViolations();
96+
Assert.assertNotNull(violations);
97+
}
98+
99+
// relatedQuery error 不传id和email的值,触发Save和Update的检查异常
100+
try {
101+
parameter = new ValidationParameter();
102+
parameter.setName("liangfei");
103+
parameter.setAge(50);
104+
parameter.setLoginDate(new Date(System.currentTimeMillis() - 1000000));
105+
parameter.setExpiryDate(new Date(System.currentTimeMillis() + 1000000));
106+
validationService.relatedQuery(parameter);
107+
Assert.fail();
108+
} catch (RpcException e) {
109+
ConstraintViolationException ve = (ConstraintViolationException) e.getCause();
110+
Set<ConstraintViolation<?>> violations = ve.getConstraintViolations();
111+
Assert.assertEquals(violations.size(),2);
112+
}
113+
84114
// Save Error
85115
try {
86116
parameter = new ValidationParameter();
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.alibaba.dubbo.validation;
2+
3+
import java.lang.annotation.Documented;
4+
import java.lang.annotation.ElementType;
5+
import java.lang.annotation.Retention;
6+
import java.lang.annotation.RetentionPolicy;
7+
import java.lang.annotation.Target;
8+
9+
/**
10+
* 方法分组验证注解
11+
* <p>使用场景:当调用某个方法时,需要检查多个分组,可以在接口方法上加上该注解</p><br>
12+
* 用法:<pre> @MethodValidated({Save.class, Update.class})
13+
* void relatedQuery(ValidationParameter parameter);</pre>
14+
* 在接口方法上增加注解,表示relatedQuery这个方法需要同时检查Save和Update这两个分组
15+
*
16+
* @author: zhangyinyue
17+
*/
18+
@Target({ElementType.METHOD})
19+
@Retention(RetentionPolicy.RUNTIME)
20+
@Documented
21+
public @interface MethodValidated {
22+
Class<?>[] value() default {};
23+
}

dubbo-filter/dubbo-filter-validation/src/main/java/com/alibaba/dubbo/validation/support/jvalidation/JValidator.java

Lines changed: 29 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import com.alibaba.dubbo.common.logger.Logger;
2121
import com.alibaba.dubbo.common.logger.LoggerFactory;
2222
import com.alibaba.dubbo.common.utils.ReflectUtils;
23+
import com.alibaba.dubbo.validation.MethodValidated;
2324
import com.alibaba.dubbo.validation.Validator;
2425

2526
import javassist.ClassPool;
@@ -55,9 +56,12 @@
5556
import java.lang.reflect.Array;
5657
import java.lang.reflect.Field;
5758
import java.lang.reflect.Method;
59+
import java.util.ArrayList;
60+
import java.util.Arrays;
5861
import java.util.Collection;
5962
import java.util.Date;
6063
import java.util.HashSet;
64+
import java.util.List;
6165
import java.util.Map;
6266
import java.util.Set;
6367

@@ -231,51 +235,60 @@ else if (memberValue instanceof ArrayMemberValue) {
231235
}
232236

233237
public void validate(String methodName, Class<?>[] parameterTypes, Object[] arguments) throws Exception {
238+
List<Class<?>> groups = new ArrayList<Class<?>>();
234239
String methodClassName = clazz.getName() + "$" + toUpperMethoName(methodName);
235240
Class<?> methodClass = null;
236241
try {
237242
methodClass = Class.forName(methodClassName, false, Thread.currentThread().getContextClassLoader());
243+
groups.add(methodClass);
238244
} catch (ClassNotFoundException e) {
239245
}
240246
Set<ConstraintViolation<?>> violations = new HashSet<ConstraintViolation<?>>();
241247
Method method = clazz.getMethod(methodName, parameterTypes);
248+
Class<?>[] methodClasses = null;
249+
if (method.isAnnotationPresent(MethodValidated.class)){
250+
methodClasses = method.getAnnotation(MethodValidated.class).value();
251+
groups.addAll(Arrays.asList(methodClasses));
252+
}
253+
//加入默认分组
254+
groups.add(0, Default.class);
255+
groups.add(1, clazz);
256+
257+
//将list转换为数组
258+
Class<?>[] classgroups = groups.toArray(new Class[0]);
259+
242260
Object parameterBean = getMethodParameterBean(clazz, method, arguments);
243261
if (parameterBean != null) {
244-
if (methodClass != null) {
245-
violations.addAll(validator.validate(parameterBean, Default.class, clazz, methodClass));
246-
} else {
247-
violations.addAll(validator.validate(parameterBean, Default.class, clazz));
248-
}
262+
violations.addAll(validator.validate(parameterBean, classgroups ));
249263
}
264+
250265
for (Object arg : arguments) {
251-
validate(violations, arg, clazz, methodClass);
266+
validate(violations, arg, classgroups);
252267
}
268+
253269
if (violations.size() > 0) {
270+
logger.error("Failed to validate service: " + clazz.getName() + ", method: " + methodName + ", cause: " + violations);
254271
throw new ConstraintViolationException("Failed to validate service: " + clazz.getName() + ", method: " + methodName + ", cause: " + violations, violations);
255272
}
256273
}
257274

258-
private void validate(Set<ConstraintViolation<?>> violations, Object arg, Class<?> clazz, Class<?> methodClass) {
275+
private void validate(Set<ConstraintViolation<?>> violations, Object arg, Class<?>... groups) {
259276
if (arg != null && !isPrimitives(arg.getClass())) {
260277
if (Object[].class.isInstance(arg)) {
261278
for (Object item : (Object[]) arg) {
262-
validate(violations, item, clazz, methodClass);
279+
validate(violations, item, groups);
263280
}
264281
} else if (Collection.class.isInstance(arg)) {
265282
for (Object item : (Collection<?>) arg) {
266-
validate(violations, item, clazz, methodClass);
283+
validate(violations, item, groups);
267284
}
268285
} else if (Map.class.isInstance(arg)) {
269286
for (Map.Entry<?, ?> entry : ((Map<?, ?>) arg).entrySet()) {
270-
validate(violations, entry.getKey(), clazz, methodClass);
271-
validate(violations, entry.getValue(), clazz, methodClass);
287+
validate(violations, entry.getKey(), groups);
288+
validate(violations, entry.getValue(), groups);
272289
}
273290
} else {
274-
if (methodClass != null) {
275-
violations.addAll(validator.validate(arg, Default.class, clazz, methodClass));
276-
} else {
277-
violations.addAll(validator.validate(arg, Default.class, clazz));
278-
}
291+
violations.addAll(validator.validate(arg, groups));
279292
}
280293
}
281294
}

0 commit comments

Comments
 (0)