Skip to content

Commit e8e7d4b

Browse files
committed
Changes DeployCreateProperties to allow processing of inheritance hierarchies with generics
1 parent d977e74 commit e8e7d4b

File tree

1 file changed

+73
-18
lines changed

1 file changed

+73
-18
lines changed

ebean-core/src/main/java/io/ebeaninternal/server/deploy/parse/DeployCreateProperties.java

Lines changed: 73 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@
1111

1212
import jakarta.persistence.*;
1313
import java.lang.reflect.*;
14+
import java.util.HashMap;
15+
import java.util.Map;
1416

1517
import static java.lang.System.Logger.Level.*;
1618

@@ -35,7 +37,7 @@ public DeployCreateProperties(TypeManager typeManager) {
3537
* Create the appropriate properties for a bean.
3638
*/
3739
public void createProperties(DeployBeanDescriptor<?> desc) {
38-
createProperties(desc, desc.getBeanType(), 0);
40+
createProperties(desc, desc.getBeanType(), 0, new HashMap<>());
3941
desc.sortProperties();
4042
}
4143

@@ -56,15 +58,20 @@ private boolean ignoreFieldByName(String fieldName) {
5658

5759
private boolean ignoreField(Field field) {
5860
return Modifier.isStatic(field.getModifiers())
59-
|| Modifier.isTransient(field.getModifiers())
60-
|| ignoreFieldByName(field.getName());
61+
|| Modifier.isTransient(field.getModifiers())
62+
|| ignoreFieldByName(field.getName());
6163
}
6264

6365
/**
64-
* properties the bean properties from Class. Some of these properties may not map to database
66+
* properties the bean properties from Class. Some of these properties may not
67+
* map to database
6568
* columns.
6669
*/
67-
private void createProperties(DeployBeanDescriptor<?> desc, Class<?> beanType, int level) {
70+
private void createProperties(
71+
DeployBeanDescriptor<?> desc,
72+
Class<?> beanType,
73+
int level,
74+
Map<TypeVariable<?>, Class<?>> genericTypeMap) {
6875
if (beanType.equals(Model.class)) {
6976
// ignore all fields on model (_$dbName)
7077
return;
@@ -74,7 +81,7 @@ private void createProperties(DeployBeanDescriptor<?> desc, Class<?> beanType, i
7481
for (int i = 0; i < fields.length; i++) {
7582
Field field = fields[i];
7683
if (!ignoreField(field)) {
77-
DeployBeanProperty prop = createProp(desc, field, beanType);
84+
DeployBeanProperty prop = createProp(desc, field, beanType, genericTypeMap);
7885
if (prop != null) {
7986
// set a order that gives priority to inherited properties
8087
// push Id/EmbeddedId up and CreatedTimestamp/UpdatedTimestamp down
@@ -95,7 +102,7 @@ private void createProperties(DeployBeanDescriptor<?> desc, Class<?> beanType, i
95102
if (!superClass.equals(Object.class)) {
96103
// recursively add any properties in the inheritance hierarchy
97104
// up to the Object.class level...
98-
createProperties(desc, superClass, level + 1);
105+
createProperties(desc, superClass, level + 1, mapGenerics(beanType));
99106
}
100107
} catch (PersistenceException ex) {
101108
throw ex;
@@ -116,8 +123,13 @@ private DeployBeanProperty createManyType(DeployBeanDescriptor<?> desc, Class<?>
116123
return new DeployBeanPropertyAssocMany<>(desc, targetType, manyType);
117124
}
118125

119-
private DeployBeanProperty createProp(DeployBeanDescriptor<?> desc, Field field) {
120-
Class<?> propertyType = field.getType();
126+
private DeployBeanProperty createProp(
127+
DeployBeanDescriptor<?> desc,
128+
Field field,
129+
Map<TypeVariable<?>, Class<?>> genericTypeMap) {
130+
Class<?> propertyType = field.getGenericType() instanceof TypeVariable<?>
131+
? genericTypeMap.get(field.getGenericType())
132+
: field.getType();
121133
if (isSpecialScalarType(field)) {
122134
return new DeployBeanProperty(desc, propertyType, field.getGenericType());
123135
}
@@ -131,7 +143,8 @@ private DeployBeanProperty createProp(DeployBeanDescriptor<?> desc, Field field)
131143
// not supporting this field (generic type used)
132144
return null;
133145
}
134-
CoreLog.internal.log(WARNING, "Could not find parameter type (via reflection) on " + desc.getFullName() + " " + field.getName());
146+
CoreLog.internal.log(WARNING,
147+
"Could not find parameter type (via reflection) on " + desc.getFullName() + " " + field.getName());
135148
}
136149
return createManyType(desc, targetType, manyType);
137150
}
@@ -147,7 +160,8 @@ private DeployBeanProperty createProp(DeployBeanDescriptor<?> desc, Field field)
147160
return new DeployBeanProperty(desc, propertyType, null, null);
148161
}
149162
if (AnnotationUtil.has(field, Convert.class)) {
150-
throw new IllegalStateException("No AttributeConverter registered for type " + propertyType + " at " + desc.getFullName() + "." + field.getName());
163+
throw new IllegalStateException("No AttributeConverter registered for type " + propertyType + " at "
164+
+ desc.getFullName() + "." + field.getName());
151165
}
152166
try {
153167
return new DeployBeanPropertyAssocOne<>(desc, propertyType);
@@ -162,18 +176,22 @@ private DeployBeanProperty createProp(DeployBeanDescriptor<?> desc, Field field)
162176
*/
163177
private boolean isSpecialScalarType(Field field) {
164178
return (AnnotationUtil.has(field, DbJson.class))
165-
|| (AnnotationUtil.has(field, DbJsonB.class))
166-
|| (AnnotationUtil.has(field, DbArray.class))
167-
|| (AnnotationUtil.has(field, DbMap.class))
168-
|| (AnnotationUtil.has(field, UnmappedJson.class));
179+
|| (AnnotationUtil.has(field, DbJsonB.class))
180+
|| (AnnotationUtil.has(field, DbArray.class))
181+
|| (AnnotationUtil.has(field, DbMap.class))
182+
|| (AnnotationUtil.has(field, UnmappedJson.class));
169183
}
170184

171185
private boolean isTransientField(Field field) {
172186
return AnnotationUtil.has(field, Transient.class);
173187
}
174188

175-
private DeployBeanProperty createProp(DeployBeanDescriptor<?> desc, Field field, Class<?> beanType) {
176-
DeployBeanProperty prop = createProp(desc, field);
189+
private DeployBeanProperty createProp(
190+
DeployBeanDescriptor<?> desc,
191+
Field field,
192+
Class<?> beanType,
193+
Map<TypeVariable<?>, Class<?>> genericTypeMap) {
194+
DeployBeanProperty prop = createProp(desc, field, genericTypeMap);
177195
if (prop == null) {
178196
// transient annotation on unsupported type
179197
return null;
@@ -186,7 +204,8 @@ private DeployBeanProperty createProp(DeployBeanDescriptor<?> desc, Field field,
186204
}
187205

188206
/**
189-
* Determine the type of the List,Set or Map. Not been set explicitly so determine this from
207+
* Determine the type of the List,Set or Map. Not been set explicitly so
208+
* determine this from
190209
* ParameterizedType.
191210
*/
192211
private Class<?> determineTargetType(Field field) {
@@ -224,4 +243,40 @@ private Class<?> determineTargetType(Field field) {
224243
// if targetType is null, then must be set in annotations
225244
return null;
226245
}
246+
247+
private Map<TypeVariable<?>, Class<?>> mapGenerics(Class<?> clazz) {
248+
Type genericSuperclass = clazz.getGenericSuperclass();
249+
if (!(genericSuperclass instanceof ParameterizedType)) {
250+
return new HashMap<>();
251+
}
252+
253+
ParameterizedType parameterized = (ParameterizedType) genericSuperclass;
254+
TypeVariable<?>[] typeVars = ((Class<?>) parameterized.getRawType()).getTypeParameters();
255+
Type[] actualTypes = parameterized.getActualTypeArguments();
256+
257+
Map<TypeVariable<?>, Class<?>> typeMap = new HashMap<>();
258+
for (int i = 0; i < typeVars.length; i++) {
259+
Type actual = actualTypes[i];
260+
Class<?> resolvedClass = resolveToClass(actual);
261+
if (resolvedClass != null) {
262+
typeMap.put(typeVars[i], resolvedClass);
263+
} else {
264+
// ignore
265+
}
266+
}
267+
return typeMap;
268+
}
269+
270+
private static Class<?> resolveToClass(Type type) {
271+
if (type instanceof Class<?>) {
272+
return (Class<?>) type;
273+
} else if (type instanceof ParameterizedType) {
274+
ParameterizedType pType = (ParameterizedType) type;
275+
Type raw = pType.getRawType();
276+
if (raw instanceof Class<?>) {
277+
return (Class<?>) raw;
278+
}
279+
}
280+
return null;
281+
}
227282
}

0 commit comments

Comments
 (0)