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