Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@

import jakarta.persistence.*;
import java.lang.reflect.*;
import java.util.HashMap;
import java.util.Map;

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

Expand All @@ -35,7 +37,7 @@ public DeployCreateProperties(TypeManager typeManager) {
* Create the appropriate properties for a bean.
*/
public void createProperties(DeployBeanDescriptor<?> desc) {
createProperties(desc, desc.getBeanType(), 0);
createProperties(desc, desc.getBeanType(), 0, new HashMap<>());
desc.sortProperties();
}

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

private boolean ignoreField(Field field) {
return Modifier.isStatic(field.getModifiers())
|| Modifier.isTransient(field.getModifiers())
|| ignoreFieldByName(field.getName());
|| Modifier.isTransient(field.getModifiers())
|| ignoreFieldByName(field.getName());
}

/**
* properties the bean properties from Class. Some of these properties may not map to database
* properties the bean properties from Class. Some of these properties may not
* map to database
* columns.
*/
private void createProperties(DeployBeanDescriptor<?> desc, Class<?> beanType, int level) {
private void createProperties(
DeployBeanDescriptor<?> desc,
Class<?> beanType,
int level,
Map<TypeVariable<?>, Class<?>> genericTypeMap) {
if (beanType.equals(Model.class)) {
// ignore all fields on model (_$dbName)
return;
Expand All @@ -74,7 +81,7 @@ private void createProperties(DeployBeanDescriptor<?> desc, Class<?> beanType, i
for (int i = 0; i < fields.length; i++) {
Field field = fields[i];
if (!ignoreField(field)) {
DeployBeanProperty prop = createProp(desc, field, beanType);
DeployBeanProperty prop = createProp(desc, field, beanType, genericTypeMap);
if (prop != null) {
// set a order that gives priority to inherited properties
// push Id/EmbeddedId up and CreatedTimestamp/UpdatedTimestamp down
Expand All @@ -95,7 +102,7 @@ private void createProperties(DeployBeanDescriptor<?> desc, Class<?> beanType, i
if (!superClass.equals(Object.class)) {
// recursively add any properties in the inheritance hierarchy
// up to the Object.class level...
createProperties(desc, superClass, level + 1);
createProperties(desc, superClass, level + 1, mapGenerics(beanType));
}
} catch (PersistenceException ex) {
throw ex;
Expand All @@ -116,8 +123,13 @@ private DeployBeanProperty createManyType(DeployBeanDescriptor<?> desc, Class<?>
return new DeployBeanPropertyAssocMany<>(desc, targetType, manyType);
}

private DeployBeanProperty createProp(DeployBeanDescriptor<?> desc, Field field) {
Class<?> propertyType = field.getType();
private DeployBeanProperty createProp(
DeployBeanDescriptor<?> desc,
Field field,
Map<TypeVariable<?>, Class<?>> genericTypeMap) {
Class<?> propertyType = field.getGenericType() instanceof TypeVariable<?>
? genericTypeMap.get(field.getGenericType())
: field.getType();
if (isSpecialScalarType(field)) {
return new DeployBeanProperty(desc, propertyType, field.getGenericType());
}
Expand All @@ -131,7 +143,8 @@ private DeployBeanProperty createProp(DeployBeanDescriptor<?> desc, Field field)
// not supporting this field (generic type used)
return null;
}
CoreLog.internal.log(WARNING, "Could not find parameter type (via reflection) on " + desc.getFullName() + " " + field.getName());
CoreLog.internal.log(WARNING,
"Could not find parameter type (via reflection) on " + desc.getFullName() + " " + field.getName());
}
return createManyType(desc, targetType, manyType);
}
Expand All @@ -147,7 +160,8 @@ private DeployBeanProperty createProp(DeployBeanDescriptor<?> desc, Field field)
return new DeployBeanProperty(desc, propertyType, null, null);
}
if (AnnotationUtil.has(field, Convert.class)) {
throw new IllegalStateException("No AttributeConverter registered for type " + propertyType + " at " + desc.getFullName() + "." + field.getName());
throw new IllegalStateException("No AttributeConverter registered for type " + propertyType + " at "
+ desc.getFullName() + "." + field.getName());
}
try {
return new DeployBeanPropertyAssocOne<>(desc, propertyType);
Expand All @@ -162,18 +176,22 @@ private DeployBeanProperty createProp(DeployBeanDescriptor<?> desc, Field field)
*/
private boolean isSpecialScalarType(Field field) {
return (AnnotationUtil.has(field, DbJson.class))
|| (AnnotationUtil.has(field, DbJsonB.class))
|| (AnnotationUtil.has(field, DbArray.class))
|| (AnnotationUtil.has(field, DbMap.class))
|| (AnnotationUtil.has(field, UnmappedJson.class));
|| (AnnotationUtil.has(field, DbJsonB.class))
|| (AnnotationUtil.has(field, DbArray.class))
|| (AnnotationUtil.has(field, DbMap.class))
|| (AnnotationUtil.has(field, UnmappedJson.class));
}

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

private DeployBeanProperty createProp(DeployBeanDescriptor<?> desc, Field field, Class<?> beanType) {
DeployBeanProperty prop = createProp(desc, field);
private DeployBeanProperty createProp(
DeployBeanDescriptor<?> desc,
Field field,
Class<?> beanType,
Map<TypeVariable<?>, Class<?>> genericTypeMap) {
DeployBeanProperty prop = createProp(desc, field, genericTypeMap);
if (prop == null) {
// transient annotation on unsupported type
return null;
Expand All @@ -186,7 +204,8 @@ private DeployBeanProperty createProp(DeployBeanDescriptor<?> desc, Field field,
}

/**
* Determine the type of the List,Set or Map. Not been set explicitly so determine this from
* Determine the type of the List,Set or Map. Not been set explicitly so
* determine this from
* ParameterizedType.
*/
private Class<?> determineTargetType(Field field) {
Expand Down Expand Up @@ -224,4 +243,40 @@ private Class<?> determineTargetType(Field field) {
// if targetType is null, then must be set in annotations
return null;
}

private Map<TypeVariable<?>, Class<?>> mapGenerics(Class<?> clazz) {
Type genericSuperclass = clazz.getGenericSuperclass();
if (!(genericSuperclass instanceof ParameterizedType)) {
return new HashMap<>();
}

ParameterizedType parameterized = (ParameterizedType) genericSuperclass;
TypeVariable<?>[] typeVars = ((Class<?>) parameterized.getRawType()).getTypeParameters();
Type[] actualTypes = parameterized.getActualTypeArguments();

Map<TypeVariable<?>, Class<?>> typeMap = new HashMap<>();
for (int i = 0; i < typeVars.length; i++) {
Type actual = actualTypes[i];
Class<?> resolvedClass = resolveToClass(actual);
if (resolvedClass != null) {
typeMap.put(typeVars[i], resolvedClass);
} else {
// ignore
}
}
return typeMap;
}

private static Class<?> resolveToClass(Type type) {
if (type instanceof Class<?>) {
return (Class<?>) type;
} else if (type instanceof ParameterizedType) {
ParameterizedType pType = (ParameterizedType) type;
Type raw = pType.getRawType();
if (raw instanceof Class<?>) {
return (Class<?>) raw;
}
}
return null;
}
}
Loading