反射、自定义注解、Lambda 结合练习

Reflect、Annotation and Lambda

Posted by Mr.Vincent on 2020-08-21
Estimated Reading Time 14 Minutes
Words 2.5k In Total
Viewed Times

比较同一类型,两个对象中不同的属性值

1
2
3
4
5
6
7
8
/**
* @author vincent
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface TransferETC {
String name();
boolean required() default true;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
/**
* @author vincent
*/
public class ReflectExerciseDemo {

@Data
public static class PersonalInfoDto {

@TransferETC(name = "姓名")
private String name;

@TransferETC(name = "年纪")
private Integer age;

@TransferETC(name = "性别")
private String gender;

@TransferETC(name = "住址")
private String address;

private String hobby;
}


@Data
private static class Desc {
private String fieldName;

private String newOne;

private String oldOne;
}

/**
* 比较两个对象中不同的属性值
*
* @param t1
* @param t2
* @param <T>
* @return
*/
private <T> List<Desc> compareTo(T t1, T t2) {
return Arrays.stream(t1.getClass().getDeclaredFields())
.filter(field -> {
try {
field.setAccessible(true);
return !Objects.equals(field.get(t1), field.get(t2));
} catch (IllegalAccessException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
})
.filter(item -> item.isAnnotationPresent(TransferETC.class))
.map(field -> {
try {
Desc desc = new Desc();
desc.setFieldName(field.getName());
desc.setNewOne(field.get(t1).toString());
desc.setOldOne(field.get(t2).toString());
TransferETC annotation = field.getAnnotation(TransferETC.class);
Optional.ofNullable(annotation).map(TransferETC::name).filter(StringUtils::isNotEmpty).ifPresent(desc::setFieldName);
return desc;
} catch (IllegalAccessException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}).collect(Collectors.toList());
}


@Test
public void t() {
PersonalInfoDto infoDto = new PersonalInfoDto();
infoDto.setName("小囧");
infoDto.setAge(20);
infoDto.setGender("男");
infoDto.setAddress("上海");
infoDto.setHobby("篮球");

PersonalInfoDto infoDto2 = new PersonalInfoDto();
infoDto2.setName("小乐");
infoDto2.setAge(21);
infoDto2.setGender("男");
infoDto2.setAddress("北京");
infoDto2.setHobby("足球");

List<Desc> descs = compareTo(infoDto, infoDto2);
System.out.println(JSON.toJSONString(descs, SerializerFeature.PrettyFormat));
}
}

显示结果:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
[
{
"fieldName":"姓名",
"newOne":"小囧",
"oldOne":"小乐"
},
{
"fieldName":"年纪",
"newOne":"20",
"oldOne":"21"
},
{
"fieldName":"住址",
"newOne":"上海",
"oldOne":"北京"
}
]

把对象的属性名转化成中文展示

1
2
3
4
5
6
7
8
/**
* @author vincent
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface TransferETC {
String name();
boolean required() default true;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
/**
* @author vincent
*/
public class ReflectExerciseDemo {

@Data
public static class PersonalInfoDto {

@TransferETC(name = "姓名")
private String name;

@TransferETC(name = "年纪")
private Integer age;

@TransferETC(name = "性别")
private String gender;

@TransferETC(name = "住址")
private String address;

private String hobby;
}

/**
* 把对象的属性名转化成中文展示
*
* @param t
* @param <T>
* @return
*/
private <T> String transferFields(T t) {
return Arrays.stream(t.getClass().getDeclaredFields())
.filter(item -> item.isAnnotationPresent(TransferETC.class))
.map(field -> {
try {
field.setAccessible(true);
return String.format("%s:%s", field.getAnnotation(TransferETC.class).name(), field.get(t));
} catch (IllegalAccessException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}).collect(Collectors.joining(";"));
}

@Test
public void t2() {
PersonalInfoDto infoDto = new PersonalInfoDto();
infoDto.setName("小草");
infoDto.setAge(18);
infoDto.setGender("女");
infoDto.setAddress("上海");
infoDto.setHobby("跑步");

String transferFields = transferFields(infoDto);
System.out.println(transferFields);
}
}

显示结果:

1
姓名:小草;年纪:18;性别:女;住址:上海

自定义对象属性非空验证

未引用 vavr 依赖的写法

1
2
3
4
5
6
7
/**
* @author vincent
*/
@FunctionalInterface
public interface CheckedFunction<T, R> {
R apply(T t) throws Exception;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* @author vincent
*/
public class CheckedWrapFunction {
static <T, R> Function<T, R> wrap(CheckedFunction<T, R> checkedFunction) {
return t -> {
try {
return checkedFunction.apply(t);
} catch (Exception e) {
throw new RuntimeException(e);
}
};
}
}
1
2
3
4
5
6
7
/**
* @author vincent
*/
@FunctionalInterface
public interface CheckedPredicate<T> {
boolean test(T t) throws Exception;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
/**
* @author vincent
*/
public class CheckedWrapPredicate {
static <T> Predicate<T> wrap(CheckedPredicate<T> checkedPredicate) {
return t -> {
try {
return checkedPredicate.test(t);
} catch (Exception e) {
throw new RuntimeException(e);
}
};
}
}
1
2
3
4
5
6
7
8
/**
* @author vincent
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface NotBlank {
String message() default "";
IntegrationResultCode resultCode() default IntegrationResultCode.UNKNOWN;
}
1
2
3
4
5
6
7
8
9
/**
* @author vincent
*/
@Data
public class FieldError {
private String fieldName;
private String errorMsg;
private IntegrationResultCode resultCode;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/**
* @author vincent
*/
public enum IntegrationResultCode {

UNKNOWN("-1", "未知异常"),

PARAM_NOT_NULL_ERROR("191099", "参数不能为空"),

PARTNER_CODE_NOT_EMPTY("191097", "企业编码不能为空"),

ORDERIDS_NOT_EMPTY("191096", "订单号不能为空"),

INVOICE_TITLE_NOT_EMPTY("191095", "发票抬头不能为空"),

SOCIAL_CREDIT_CODE_NOT_EMPTY("191094", "社会信用代码不能为空"),

ORDERS_NOT_EMPTY("191092", "需要开具发票的订单不能为空"),

USERNAME_NOT_EMPTY("191091", "用户姓名不能为空"),

DATETIME_NOT_EMPTY("191089", "开票时间不能为空");

private String code;

private String msg;

IntegrationResultCode(String code, String msg) {
this.code = code;
this.msg = msg;
}

public String getCode() {
return code;
}

public String getMsg() {
return msg;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
/**
* @author vincent
*/
@Data
public class InvoiceRequestQueryApiDto implements Serializable {

private Long partnerId;

/**
* 企业编码
*/
@NotBlank(resultCode = IntegrationResultCode.PARTNER_CODE_NOT_EMPTY)
private String partnerCode;

/**
* 发票抬头
*/
@NotBlank(resultCode = IntegrationResultCode.INVOICE_TITLE_NOT_EMPTY)
private String invoiceTitle;

/**
* 社会信用代码
*/
@NotBlank(resultCode = IntegrationResultCode.SOCIAL_CREDIT_CODE_NOT_EMPTY)
private String socialCreditCode;

/**
* 开票类型
*/
private String type;

@NotBlank(resultCode = IntegrationResultCode.ORDERS_NOT_EMPTY)
private List<Orders> orders;

@Data
public static class Orders implements Serializable {
/**
* 需要开具发票的订单号
*/
@NotBlank(resultCode = IntegrationResultCode.ORDERIDS_NOT_EMPTY)
private Long orderId;
private Travellers travellers;
}

@Data
public static class Travellers implements Serializable {
private String userName;
private String email;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
/**
* @author vincent
*/
public class Validate {
public static <T> List<FieldError> check(T t) {
// 获取类中的所以属性
List<Field> allFields = getAllFields(t.getClass());
return allFields.stream()
.filter(field -> field.isAnnotationPresent(NotBlank.class))
.peek(field -> field.setAccessible(true))
.filter(CheckedWrapPredicate.wrap(field -> Objects.isNull(field.get(t)) || Objects.equals(field.get(t), "")
|| (field.get(t) instanceof List) || (field.get(t) instanceof String && StringUtils.isBlank(field.get(t).toString()))))
.map(CheckedWrapFunction.wrap(field -> {
if (field.getType().isAssignableFrom(List.class) && CollectionUtils.isNotEmpty((List) field.get(t))) {
List<?> list = (List) field.get(t);
List<FieldError> fieldErrors = list.stream()
.map(Validate::check)
.flatMap(Collection::stream)
.collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(fieldErrors)) {
return fieldErrors.get(0);
}
} else {
FieldError fieldError = new FieldError();
fieldError.setFieldName(field.getName());
NotBlank annotation = field.getAnnotation(NotBlank.class);
String message = StringUtils.isEmpty(annotation.message()) ? annotation.resultCode().getMsg() : annotation.message();
IntegrationResultCode resultCode = StringUtils.isEmpty(annotation.message()) ? annotation.resultCode() : null;
fieldError.setErrorMsg(message);
fieldError.setResultCode(resultCode);
return fieldError;
}
return null;
}))
.filter(Objects::nonNull)
.collect(Collectors.toList());
}

private static List<Field> getAllFields(Class<?> clazz) {
return getAllFields(clazz, Lists.newArrayList());
}

private static List<Field> getAllFields(Class<?> clazz, List<Field> fields) {
List<Field> fieldList = Arrays.stream(clazz.getDeclaredFields()).collect(Collectors.toList());
fields.addAll(fieldList);
Class<?> superclass = clazz.getSuperclass();
if (Objects.isNull(superclass)) {
return fields;
} else {
return getAllFields(superclass, fields);
}
}
}

引用 vavr 依赖的写法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<!-- lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.10</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.13</version>
</dependency>

<!-- commons-lang3 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.9</version>
</dependency>

<!-- commons-collections4 -->
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-collections4</artifactId>
<version>4.4</version>
</dependency>

<!-- guava -->
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>29.0-jre</version>
</dependency>

<!-- vavr -->
<dependency>
<groupId>io.vavr</groupId>
<artifactId>vavr</artifactId>
<version>0.10.2</version>
</dependency>
1
2
3
4
5
6
7
8
/**
* @author vincent
*/
@Retention(RetentionPolicy.RUNTIME)
public @interface NotBlank {
String message() default "";
IntegrationResultCode resultCode() default IntegrationResultCode.UNKNOWN;
}
1
2
3
4
5
6
7
8
9
/**
* @author vincent
*/
@Data
public class FieldError {
private String fieldName;
private String errorMsg;
private IntegrationResultCode resultCode;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
/**
* @author vincent
*/
public enum IntegrationResultCode {

UNKNOWN("-1", "未知异常"),

PARAM_NOT_NULL_ERROR("191099", "参数不能为空"),

PARTNER_CODE_NOT_EMPTY("191097", "企业编码不能为空"),

ORDERIDS_NOT_EMPTY("191096", "订单号不能为空"),

INVOICE_TITLE_NOT_EMPTY("191095", "发票抬头不能为空"),

SOCIAL_CREDIT_CODE_NOT_EMPTY("191094", "社会信用代码不能为空"),

ORDERS_NOT_EMPTY("191092", "需要开具发票的订单不能为空"),

USERNAME_NOT_EMPTY("191091", "用户姓名不能为空"),

DATETIME_NOT_EMPTY("191089", "开票时间不能为空");

private String code;

private String msg;

IntegrationResultCode(String code, String msg) {
this.code = code;
this.msg = msg;
}

public String getCode() {
return code;
}

public String getMsg() {
return msg;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
/**
* @author vincent
*/
@Data
public class InvoiceRequestQueryApiDto implements Serializable {

private Long partnerId;

/**
* 企业编码
*/
@NotBlank(resultCode = IntegrationResultCode.PARTNER_CODE_NOT_EMPTY)
private String partnerCode;

/**
* 发票抬头
*/
@NotBlank(resultCode = IntegrationResultCode.INVOICE_TITLE_NOT_EMPTY)
private String invoiceTitle;

/**
* 社会信用代码
*/
@NotBlank(resultCode = IntegrationResultCode.SOCIAL_CREDIT_CODE_NOT_EMPTY)
private String socialCreditCode;

/**
* 开票类型
*/
private String type;

@NotBlank(resultCode = IntegrationResultCode.ORDERS_NOT_EMPTY)
private List<Orders> orders;

@Data
public static class Orders implements Serializable {
/**
* 需要开具发票的订单号
*/
@NotBlank(resultCode = IntegrationResultCode.ORDERIDS_NOT_EMPTY)
private Long orderId;
private Travellers travellers;
}

@Data
public static class Travellers implements Serializable {
private String userName;
private String email;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
/**
* @author vincent
*/
public class VavrValidate {
public static <T> List<FieldError> check(T t) {
Field[] allFields = FieldUtils.getAllFields(t.getClass());
return Arrays.stream(allFields)
.filter(field -> field.isAnnotationPresent(NotBlank.class))
.peek(field -> field.setAccessible(true))
.filter(CheckedPredicate.<Field>of(
field -> Objects.isNull(field.get(t)) || Objects.equals(field.get(t), "") || (field.get(t) instanceof List) ||
(field.get(t) instanceof String && StringUtils.isBlank(field.get(t).toString()))
).unchecked()
)
.map(CheckedFunction1.<Field, FieldError>of(
field -> {
if (field.getType().isAssignableFrom(List.class) && CollectionUtils.isNotEmpty((List) field.get(t))) {
List<?> list = (List) field.get(t);
List<FieldError> fieldErrors = list.stream()
.map(Validate::check)
.flatMap(Collection::stream)
.collect(Collectors.toList());
if (CollectionUtils.isNotEmpty(fieldErrors)) {
return fieldErrors.get(0);
}
} else {
FieldError fieldError = new FieldError();
fieldError.setFieldName(field.getName());
NotBlank annotation = field.getAnnotation(NotBlank.class);
String message = StringUtils.isEmpty(annotation.message()) ? annotation.resultCode().getMsg() : annotation.message();
IntegrationResultCode resultCode = StringUtils.isEmpty(annotation.message()) ? annotation.resultCode() : null;
fieldError.setErrorMsg(message);
fieldError.setResultCode(resultCode);
return fieldError;
}
return null;
})
.unchecked()
)
.filter(Objects::nonNull)
.collect(Collectors.toList());
}
}

测试

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
/**
* @author vincent
*/
public class ValidateTest {

@Test
public void t() {
InvoiceRequestQueryApiDto queryApiDto = new InvoiceRequestQueryApiDto();
InvoiceRequestQueryApiDto.Orders orders = new InvoiceRequestQueryApiDto.Orders();
queryApiDto.setOrders(Lists.newArrayList(orders));

List<FieldError> check = Validate.check(queryApiDto);
check.forEach(System.out::println);
}

@Test
public void t2(){
InvoiceRequestQueryApiDto queryApiDto = new InvoiceRequestQueryApiDto();
InvoiceRequestQueryApiDto.Orders orders = new InvoiceRequestQueryApiDto.Orders();
queryApiDto.setOrders(Lists.newArrayList(orders));

List<FieldError> check = VavrValidate.check(queryApiDto);
check.forEach(System.out::println);
}
}

结果显示相同

1
2
3
4
FieldError(fieldName=partnerCode, errorMsg=企业编码不能为空, resultCode=PARTNER_CODE_NOT_EMPTY)
FieldError(fieldName=invoiceTitle, errorMsg=发票抬头不能为空, resultCode=INVOICE_TITLE_NOT_EMPTY)
FieldError(fieldName=socialCreditCode, errorMsg=社会信用代码不能为空, resultCode=SOCIAL_CREDIT_CODE_NOT_EMPTY)
FieldError(fieldName=orderId, errorMsg=订单号不能为空, resultCode=ORDERIDS_NOT_EMPTY)

补充断言比较两个集合是否相同

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
/**
* @author vincent
* <p>
* 补充断言比较两个集合是否相同
*/
public class AssertEqualsUtils {

public static <T> Boolean assertEqualsList(Collection<T> expected, Collection<T> actual) {
if (expected == null && actual == null) {
return true;
}
if (expected == null) {
return false;
}
if (actual == null) {
return false;
}
if (expected.size() == 0 && actual.size() == 0) {
return true;
}
if (expected.size() != actual.size()) {
return false;
}
Iterator<T> iterator1 = expected.iterator();
Iterator<T> iterator2 = actual.iterator();
while (iterator1.hasNext() && iterator2.hasNext()) {
T next1 = iterator1.next();
T next2 = iterator2.next();
if (!assertEqualsObject(next1, next2)) {
return false;
}
}
return true;
}

public static <T> Boolean assertEqualsObject(T expected, T actual) {
if (Objects.isNull(expected) && Objects.isNull(actual)) {
return true;
}
if (Objects.isNull(expected)) {
return false;
}
if (Objects.isNull(actual)) {
return false;
}
return Arrays.stream(FieldUtils.getAllFields(expected.getClass()))
.allMatch(f -> {
f.setAccessible(true);
Class<?> type = f.getType();
Object o1 = get(f, expected);
Object o2 = get(f, actual);
if (Collection.class.isAssignableFrom(type)) {
return assertEqualsList(cast(o1), cast(o2));
} else if (ClassUtils.isPrimitiveOrWrapper(type) || type.getClassLoader() == null) {
return Objects.equals(o1, o2);
}
return assertEqualsObject(o1, o2);
});
}

@SneakyThrows
private static Object get(Field f, Object obj) {
return f.get(obj);
}

@SuppressWarnings("unchecked")
private static <T> T cast(Object obj) {
return (T) obj;
}
}

案例源码:https://github.com/V-Vincen/reflect


If you like this blog or find it useful for you, you are welcome to comment on it. You are also welcome to share this blog, so that more people can participate in it. If the images used in the blog infringe your copyright, please contact the author to delete them. Thank you !