All Downloads are FREE. Search and download functionalities are using the official Maven repository.

io.ebeaninternal.server.deploy.parse.DeployCreateProperties Maven / Gradle / Ivy

There is a newer version: 15.8.0
Show newest version
package io.ebeaninternal.server.deploy.parse;

import io.ebean.Model;
import io.ebean.annotation.*;
import io.ebean.core.type.ScalarType;
import io.ebean.util.AnnotationUtil;
import io.ebeaninternal.api.CoreLog;
import io.ebeaninternal.server.deploy.ManyType;
import io.ebeaninternal.server.deploy.meta.*;
import io.ebeaninternal.server.type.TypeManager;

import jakarta.persistence.*;
import java.lang.reflect.*;

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

/**
 * Create the properties for a bean.
 * 

* This also needs to determine if the property is a associated many, associated * one or normal scalar property. *

*/ public final class DeployCreateProperties { private final DetermineManyType determineManyType; private final TypeManager typeManager; public DeployCreateProperties(TypeManager typeManager) { this.typeManager = typeManager; this.determineManyType = new DetermineManyType(); } /** * Create the appropriate properties for a bean. */ public void createProperties(DeployBeanDescriptor desc) { createProperties(desc, desc.getBeanType(), 0); desc.sortProperties(); } /** * Return true if we should ignore this field. *

* We want to ignore ebean internal fields and some others as well. *

*/ private boolean ignoreFieldByName(String fieldName) { if (fieldName.startsWith("_ebean_")) { // ignore Ebean internal fields return true; } // ignore AspectJ internal fields return fieldName.startsWith("ajc$instance$"); } private boolean ignoreField(Field field) { return Modifier.isStatic(field.getModifiers()) || Modifier.isTransient(field.getModifiers()) || ignoreFieldByName(field.getName()); } /** * 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) { if (beanType.equals(Model.class)) { // ignore all fields on model (_$dbName) return; } try { Field[] fields = beanType.getDeclaredFields(); for (int i = 0; i < fields.length; i++) { Field field = fields[i]; if (!ignoreField(field)) { DeployBeanProperty prop = createProp(desc, field, beanType); if (prop != null) { // set a order that gives priority to inherited properties // push Id/EmbeddedId up and CreatedTimestamp/UpdatedTimestamp down int sortOverride = prop.getSortOverride(); prop.setSortOrder((level * 10000 + 100 - i + sortOverride)); DeployBeanProperty replaced = desc.addBeanProperty(prop); if (replaced != null && !replaced.isTransient()) { String msg = "Huh??? property " + prop + " being defined twice"; msg += " but replaced property was not transient? This is not expected?"; CoreLog.log.log(WARNING, msg); } } } } Class superClass = beanType.getSuperclass(); if (!superClass.equals(Object.class)) { // recursively add any properties in the inheritance hierarchy // up to the Object.class level... createProperties(desc, superClass, level + 1); } } catch (PersistenceException ex) { throw ex; } catch (Exception ex) { throw new PersistenceException(ex); } } private DeployBeanProperty createManyType(DeployBeanDescriptor desc, Class targetType, ManyType manyType) { try { ScalarType scalarType = typeManager.type(targetType); if (scalarType != null) { return new DeployBeanPropertySimpleCollection<>(desc, targetType, manyType); } } catch (NullPointerException e) { CoreLog.internal.log(DEBUG, "expected non-scalar type {0}", e.getMessage()); } return new DeployBeanPropertyAssocMany<>(desc, targetType, manyType); } private DeployBeanProperty createProp(DeployBeanDescriptor desc, Field field) { Class propertyType = field.getType(); if (isSpecialScalarType(field)) { return new DeployBeanProperty(desc, propertyType, field.getGenericType()); } // check for Collection type (list, set or map) ManyType manyType = determineManyType.getManyType(propertyType); if (manyType != null) { // List, Set or Map based object Class targetType = determineTargetType(field); if (targetType == null) { if (AnnotationUtil.has(field, Transient.class)) { // 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()); } return createManyType(desc, targetType, manyType); } if (propertyType.isEnum() || propertyType.isPrimitive()) { return new DeployBeanProperty(desc, propertyType, null, null); } ScalarType scalarType = typeManager.type(propertyType); if (scalarType != null) { return new DeployBeanProperty(desc, propertyType, scalarType, null); } if (isTransientField(field)) { // return with no ScalarType (still support JSON features) 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()); } try { return new DeployBeanPropertyAssocOne<>(desc, propertyType); } catch (Exception e) { CoreLog.log.log(ERROR, "Error with " + desc + " field:" + field.getName(), e); return null; } } /** * Return true if the field has one of the special mappings. */ 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)); } 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); if (prop == null) { // transient annotation on unsupported type return null; } else { prop.setOwningType(beanType); prop.setName(field.getName()); prop.setField(field); return prop; } } /** * Determine the type of the List,Set or Map. Not been set explicitly so determine this from * ParameterizedType. */ private Class determineTargetType(Field field) { Type genType = field.getGenericType(); if (genType instanceof ParameterizedType) { ParameterizedType ptype = (ParameterizedType) genType; Type[] typeArgs = ptype.getActualTypeArguments(); if (typeArgs.length == 1) { // expecting set or list if (typeArgs[0] instanceof Class) { return (Class) typeArgs[0]; } if (typeArgs[0] instanceof WildcardType) { final Type[] upperBounds = ((WildcardType) typeArgs[0]).getUpperBounds(); if (upperBounds.length == 1 && upperBounds[0] instanceof Class) { // kotlin generated wildcard type return (Class) upperBounds[0]; } } // throw new RuntimeException("Unexpected Parameterised Type? "+typeArgs[0]); return null; } if (typeArgs.length == 2) { // this is probably a Map if (typeArgs[1] instanceof ParameterizedType) { // not supporting ParameterizedType on Map. return null; } if (typeArgs[1] instanceof WildcardType) { return Object.class; } return (Class) typeArgs[1]; } } // if targetType is null, then must be set in annotations return null; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy