1111
1212import jakarta .persistence .*;
1313import java .lang .reflect .*;
14+ import java .util .HashMap ;
15+ import java .util .Map ;
1416
1517import 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