1
16 package org.modelmapper.internal;
17
18 import java.lang.annotation.Annotation;
19 import java.lang.reflect.Field;
20 import java.lang.reflect.Member;
21 import java.lang.reflect.Method;
22 import java.lang.reflect.Type;
23 import net.jodah.typetools.TypeResolver;
24 import org.modelmapper.spi.PropertyInfo;
25 import org.modelmapper.spi.PropertyType;
26 import org.modelmapper.spi.ValueReader;
27 import org.modelmapper.spi.ValueWriter;
28
29
35 abstract class PropertyInfoImpl<M extends Member> implements PropertyInfo {
36 protected final Class<?> initialType;
37 protected final M member;
38 protected final Class<?> type;
39 protected final String name;
40 private final PropertyType propertyType;
41
42 static abstract class AbstractMethodInfo extends PropertyInfoImpl<Method> {
43 private AbstractMethodInfo(Class<?> initialType, Method method, String name) {
44 super(initialType, method, PropertyType.METHOD, name);
45 method.setAccessible(true);
46 }
47
48 public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
49 return member.getAnnotation(annotationClass);
50 }
51 }
52
53 static class FieldPropertyInfo extends PropertyInfoImpl<Field> implements Accessor, Mutator {
54 FieldPropertyInfo(Class<?> initialType, Field field, String name) {
55 super(initialType, field, PropertyType.FIELD, name);
56 field.setAccessible(true);
57 }
58
59 public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
60 return member.getAnnotation(annotationClass);
61 }
62
63 public Type getGenericType() {
64 return member.getGenericType();
65 }
66
67 public Object getValue(Object subject) {
68 try {
69 return member.get(subject);
70 } catch (Exception e) {
71 throw new Errors().errorGettingValue(member, e).toMappingException();
72 }
73 }
74
75 public void setValue(Object subject, Object value) {
76 try {
77 member.set(subject, value);
78 } catch (Exception e) {
79 throw new Errors().errorSettingValue(member, value, e).toMappingException();
80 }
81 }
82
83 public TypeInfo<?> getTypeInfo(InheritingConfiguration configuration) {
84 return TypeInfoRegistry.typeInfoFor(this, configuration);
85 }
86 }
87
88 static class MethodAccessor extends AbstractMethodInfo implements Accessor {
89 MethodAccessor(Class<?> initialType, Method method, String name) {
90 super(initialType, method, name);
91 }
92
93 public Type getGenericType() {
94 return member.getGenericReturnType();
95 }
96
97 public Object getValue(Object subject) {
98 try {
99 return member.invoke(subject);
100 } catch (IllegalAccessException e) {
101 new Errors().errorAccessingProperty(this).throwMappingExceptionIfErrorsExist();
102 return null;
103 } catch (Exception e) {
104 throw new Errors().errorGettingValue(member, e).toMappingException();
105 }
106 }
107
108 public TypeInfo<?> getTypeInfo(InheritingConfiguration configuration) {
109 return TypeInfoRegistry.typeInfoFor(this, configuration);
110 }
111 }
112
113 static class MethodMutator extends AbstractMethodInfo implements Mutator {
114 MethodMutator(Class<?> initialType, Method method, String name) {
115 super(initialType, method, name);
116 }
117
118 public Type getGenericType() {
119 return member.getGenericParameterTypes()[0];
120 }
121
122 public void setValue(Object subject, Object value) {
123 try {
124 member.invoke(subject, value);
125 } catch (Exception e) {
126 throw new Errors().errorSettingValue(member, value, e).toMappingException();
127 }
128 }
129
130 public TypeInfo<?> getTypeInfo(InheritingConfiguration configuration) {
131 return TypeInfoRegistry.typeInfoFor(type, configuration);
132 }
133 }
134
135 static class ValueReaderPropertyInfo extends PropertyInfoImpl<Member> implements Accessor {
136 private ValueReader.Member<Object> valueReaderMember;
137
138 @SuppressWarnings("unchecked")
139 ValueReaderPropertyInfo(ValueReader.Member<?> valueReaderMember, Class<?> initialType, String name) {
140 super(initialType, null, PropertyType.GENERIC, name);
141 this.valueReaderMember = (ValueReader.Member<Object>) valueReaderMember;
142 }
143
144 @Override
145 public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
146 return null;
147 }
148
149 @Override
150 public Type getGenericType() {
151 return type;
152 }
153
154 @Override
155 @SuppressWarnings("unchecked")
156 public Object getValue(Object subject) {
157 return valueReaderMember.get(subject, name);
158 }
159
160 @Override
161 public TypeInfo<?> getTypeInfo(InheritingConfiguration configuration) {
162 return TypeInfoRegistry.typeInfoFor(type, configuration);
163 }
164
165 static ValueReaderPropertyInfo fromMember(final ValueReader.Member<?> valueReaderMember, String memberName) {
166 if (valueReaderMember.getOrigin() != null) {
167 return new ValueReaderPropertyInfo(valueReaderMember, valueReaderMember.getValueType(), memberName) {
168 @Override
169 public TypeInfo<?> getTypeInfo(InheritingConfiguration configuration) {
170 return TypeInfoRegistry.typeInfoFor(valueReaderMember.getOrigin(),
171 valueReaderMember.getValueType(), configuration);
172 }
173 };
174 }
175 return new ValueReaderPropertyInfo(valueReaderMember, valueReaderMember.getValueType(), memberName);
176 }
177
178 @SuppressWarnings("unchecked")
179 static ValueReaderPropertyInfo create(final ValueReader<?> valueReader, String memberName) {
180 final ValueReader<Object> uncheckedValueReader = (ValueReader<Object>) valueReader;
181 ValueReader.Member<?> valueReaderMember = new ValueReader.Member<Object>(Object.class) {
182 @Override
183 public Object get(Object source, String memberName) {
184 return uncheckedValueReader.get(source, memberName);
185 }
186 };
187 return new ValueReaderPropertyInfo(valueReaderMember, valueReaderMember.getValueType(), memberName);
188 }
189 }
190 static class ValueWriterPropertyInfo extends PropertyInfoImpl<Member> implements Mutator {
191 private ValueWriter.Member<Object> valueWriterMember;
192
193 @SuppressWarnings("unchecked")
194 ValueWriterPropertyInfo(ValueWriter.Member<?> valueWriterMember, Class<?> initialType, String name) {
195 super(initialType, null, PropertyType.GENERIC, name);
196 this.valueWriterMember = (ValueWriter.Member<Object>) valueWriterMember;
197 }
198
199 @Override
200 public <T extends Annotation> T getAnnotation(Class<T> annotationClass) {
201 return null;
202 }
203
204 @Override
205 public Type getGenericType() {
206 return type;
207 }
208
209 @Override
210 public TypeInfo<?> getTypeInfo(InheritingConfiguration configuration) {
211 return TypeInfoRegistry.typeInfoFor(type, configuration);
212 }
213
214 @Override
215 public void setValue(Object subject, Object value) {
216 valueWriterMember.setValue(subject, value);
217 }
218
219 static ValueWriterPropertyInfo fromMember(final ValueWriter.Member<?> valueWriterMember, String memberName) {
220 if (valueWriterMember.getOrigin() != null) {
221 return new ValueWriterPropertyInfo(valueWriterMember, valueWriterMember.getValueType(), memberName) {
222 @Override
223 public TypeInfo<?> getTypeInfo(InheritingConfiguration configuration) {
224 return TypeInfoRegistry.typeInfoFor(valueWriterMember.getOrigin(),
225 valueWriterMember.getValueType(), configuration);
226 }
227 };
228 }
229 return new ValueWriterPropertyInfo(valueWriterMember, valueWriterMember.getValueType(), memberName);
230 }
231
232 @SuppressWarnings("unchecked")
233 static ValueWriterPropertyInfo create(final ValueWriter<?> valueWriter, final String memberName) {
234 final ValueWriter<Object> uncheckedValueWriter = (ValueWriter<Object>) valueWriter;
235 ValueWriter.Member<?> valueWriterMember = new ValueWriter.Member<Object>(Object.class) {
236 @Override
237 public void setValue(Object source, Object value) {
238 uncheckedValueWriter.setValue(source, value, memberName);
239 }
240 };
241 return new ValueWriterPropertyInfo(valueWriterMember, valueWriterMember.getValueType(), memberName);
242 }
243 }
244
245 private PropertyInfoImpl(Class<?> initialType, M member, PropertyType propertyType, String name) {
246 this.initialType = initialType;
247 this.member = member;
248 this.propertyType = propertyType;
249 Type genericType = getGenericType();
250 this.type = genericType == null ? initialType : TypeResolver.resolveRawClass(genericType,
251 initialType);
252 this.name = name;
253 }
254
255 @Override
256 public boolean equals(Object o) {
257 if (this == o) {
258 return true;
259 }
260 if (o == null || getClass() != o.getClass()) {
261 return false;
262 }
263 PropertyInfoImpl<?> that = (PropertyInfoImpl<?>) o;
264 if (member != null ? !member.equals(that.member) : that.member != null) {
265 return false;
266 }
267 return name.equals(that.name);
268 }
269
270 public Class<?> getInitialType() {
271 return initialType;
272 }
273
274 public M getMember() {
275 return member;
276 }
277
278 public String getName() {
279 return name;
280 }
281
282 public PropertyType getPropertyType() {
283 return propertyType;
284 }
285
286 public Class<?> getType() {
287 return type;
288 }
289
290 @Override
291 public int hashCode() {
292 return (member == null ? 1 : member.getDeclaringClass().hashCode()) * 31 + name.hashCode();
293 }
294
295 @Override
296 public String toString() {
297 return member == null ? name : member.getDeclaringClass().getSimpleName() + "." + name;
298 }
299 }