1
2
3
4
5
6
7
8
9 package com.codebox.bean;
10
11 import com.codebox.util.LombokBuilderUtil;
12
13 import java.lang.reflect.Modifier;
14
15 import net.bytebuddy.ByteBuddy;
16 import net.bytebuddy.NamingStrategy;
17 import net.bytebuddy.description.NamedElement;
18 import net.bytebuddy.description.modifier.Visibility;
19 import net.bytebuddy.description.type.TypeDescription;
20 import net.bytebuddy.dynamic.loading.ClassLoadingStrategy;
21 import net.bytebuddy.implementation.HashCodeMethod;
22 import net.bytebuddy.implementation.MethodDelegation;
23 import net.bytebuddy.implementation.ToStringMethod;
24 import net.bytebuddy.implementation.bind.annotation.Argument;
25 import net.bytebuddy.implementation.bind.annotation.This;
26 import net.bytebuddy.matcher.ElementMatchers;
27
28
29
30
31
32 public enum JavaBeanTester {
33
34
35 ;
36
37
38
39
40
41
42
43
44
45
46
47 public static <T> JavaBeanTesterBuilder<T, ?> builder(final Class<T> clazz) {
48
49 if (Modifier.isFinal(clazz.getModifiers())) {
50 return new JavaBeanTesterBuilder<>(clazz, Object.class);
51 }
52
53
54 if (LombokBuilderUtil.getLombokBuilderMethod(clazz) != null) {
55 return builder(clazz, null);
56 }
57
58
59 Class<? extends T> loaded = new ByteBuddy().with(new NamingStrategy.AbstractBase() {
60 @Override
61 protected String name(TypeDescription superClass) {
62 return clazz.getPackageName() + ".ByteBuddyExt" + superClass.getSimpleName();
63 }
64 }).subclass(clazz).method(ElementMatchers.isEquals())
65 .intercept(MethodDelegation.to(InstanceOfEqualsInterceptor.class)).method(ElementMatchers.isHashCode())
66 .intercept(HashCodeMethod.usingSuperClassOffset()).method(ElementMatchers.isToString())
67 .intercept(ToStringMethod.prefixedBySimpleClassName()).method(ElementMatchers.named("canEqual"))
68 .intercept(MethodDelegation.to(CanEqualInterceptor.class))
69 .defineField("javabeanExtension", String.class, Visibility.PACKAGE_PRIVATE).make()
70 .load(clazz.getClassLoader(), ClassLoadingStrategy.Default.WRAPPER).getLoaded();
71
72
73 return builder(clazz, loaded);
74 }
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90 public static <T, E> JavaBeanTesterBuilder<T, E> builder(final Class<T> clazz, final Class<E> extension) {
91 return new JavaBeanTesterBuilder<>(clazz, extension);
92 }
93
94
95
96
97 public static final class CanEqualInterceptor {
98
99
100
101
102 CanEqualInterceptor() {
103
104 }
105
106
107
108
109
110
111
112
113 public static boolean canEqual(final Object object) {
114 return object instanceof NamedElement.WithRuntimeName;
115 }
116
117 }
118
119
120
121
122 public static final class InstanceOfEqualsInterceptor {
123
124
125
126
127 InstanceOfEqualsInterceptor() {
128
129 }
130
131
132
133
134
135
136
137
138
139
140 public static boolean equals(@This Object self, @Argument(0) Object other) {
141 if (self == other) {
142 return true;
143 }
144 if ((other == null) || (!self.getClass().isInstance(other) && !other.getClass().isInstance(self))) {
145 return false;
146 }
147 return self.hashCode() == other.hashCode();
148 }
149 }
150
151 }