Search in sources :

Example 1 with Relation

use of io.micronaut.data.annotation.Relation in project micronaut-data by micronaut-projects.

the class AbstractCascadeOperations method cascade.

/**
 * Cascade on the entity instance and collect cascade operations.
 *
 * @param annotationMetadata The annotationMetadata
 * @param repositoryType     The repositoryType
 * @param fkOnly             Is FK only
 * @param cascadeType        The cascadeType
 * @param ctx                The cascade context
 * @param persistentEntity   The persistent entity
 * @param entity             The entity instance
 * @param cascadeOps         The cascade operations
 * @param <T>                The entity type
 */
protected <T> void cascade(AnnotationMetadata annotationMetadata, Class<?> repositoryType, boolean fkOnly, Relation.Cascade cascadeType, CascadeContext ctx, RuntimePersistentEntity<T> persistentEntity, T entity, List<CascadeOp> cascadeOps) {
    for (RuntimeAssociation<T> association : persistentEntity.getAssociations()) {
        BeanProperty<T, Object> beanProperty = (BeanProperty<T, Object>) association.getProperty();
        Object child = beanProperty.get(entity);
        if (child == null) {
            continue;
        }
        if (association instanceof Embedded) {
            cascade(annotationMetadata, repositoryType, fkOnly, cascadeType, ctx.embedded(association), (RuntimePersistentEntity) association.getAssociatedEntity(), child, cascadeOps);
            continue;
        }
        if (association.doesCascade(cascadeType) && (fkOnly || !association.isForeignKey())) {
            if (association.getInverseSide().map(assoc -> ctx.rootAssociations.contains(assoc) || ctx.associations.contains(assoc)).orElse(false)) {
                continue;
            }
            final RuntimePersistentEntity<Object> associatedEntity = (RuntimePersistentEntity<Object>) association.getAssociatedEntity();
            switch(association.getKind()) {
                case ONE_TO_ONE:
                case MANY_TO_ONE:
                    cascadeOps.add(new CascadeOneOp(annotationMetadata, repositoryType, ctx.relation(association), cascadeType, associatedEntity, child));
                    continue;
                case ONE_TO_MANY:
                case MANY_TO_MANY:
                    final PersistentAssociationPath inverse = association.getInversePathSide().orElse(null);
                    Iterable<Object> children = (Iterable<Object>) association.getProperty().get(entity);
                    if (children == null || !children.iterator().hasNext()) {
                        continue;
                    }
                    if (inverse != null && inverse.getAssociation().getKind() == Relation.Kind.MANY_TO_ONE) {
                        List<Object> entities = new ArrayList<>(CollectionUtils.iterableToList(children));
                        for (ListIterator<Object> iterator = entities.listIterator(); iterator.hasNext(); ) {
                            Object c = iterator.next();
                            Object newC = inverse.setPropertyValue(c, entity);
                            if (c != newC) {
                                iterator.set(newC);
                            }
                        }
                        children = entities;
                    }
                    cascadeOps.add(new CascadeManyOp(annotationMetadata, repositoryType, ctx.relation(association), cascadeType, associatedEntity, children));
                    continue;
                default:
                    throw new IllegalArgumentException("Cannot cascade for relation: " + association.getKind());
            }
        }
    }
}
Also used : ListIterator(java.util.ListIterator) BeanProperty(io.micronaut.core.beans.BeanProperty) ArgumentConversionContext(io.micronaut.core.convert.ArgumentConversionContext) ConversionErrorException(io.micronaut.core.convert.exceptions.ConversionErrorException) Internal(io.micronaut.core.annotation.Internal) ArrayList(java.util.ArrayList) Embedded(io.micronaut.data.model.Embedded) List(java.util.List) ConversionContext(io.micronaut.core.convert.ConversionContext) Association(io.micronaut.data.model.Association) CollectionUtils(io.micronaut.core.util.CollectionUtils) AnnotationMetadata(io.micronaut.core.annotation.AnnotationMetadata) Argument(io.micronaut.core.type.Argument) RuntimeAssociation(io.micronaut.data.model.runtime.RuntimeAssociation) RuntimePersistentEntity(io.micronaut.data.model.runtime.RuntimePersistentEntity) ConversionService(io.micronaut.core.convert.ConversionService) Collections(java.util.Collections) Relation(io.micronaut.data.annotation.Relation) PersistentAssociationPath(io.micronaut.data.model.PersistentAssociationPath) RuntimePersistentEntity(io.micronaut.data.model.runtime.RuntimePersistentEntity) ArrayList(java.util.ArrayList) BeanProperty(io.micronaut.core.beans.BeanProperty) Embedded(io.micronaut.data.model.Embedded) PersistentAssociationPath(io.micronaut.data.model.PersistentAssociationPath)

Example 2 with Relation

use of io.micronaut.data.annotation.Relation in project micronaut-data by micronaut-projects.

the class MappedEntityVisitor method computeMappingDefaults.

private void computeMappingDefaults(NamingStrategy namingStrategy, PersistentProperty property, Map<String, DataType> dataTypes, Map<String, String> dataConverters, VisitorContext context) {
    AnnotationMetadata annotationMetadata = property.getAnnotationMetadata();
    SourcePersistentProperty spp = (SourcePersistentProperty) property;
    PropertyElement propertyElement = spp.getPropertyElement();
    boolean isRelation = propertyElement.hasStereotype(Relation.class);
    DataType dataType = annotationMetadata.getValue(TypeDef.class, "type", DataType.class).orElse(null);
    String converter = annotationMetadata.stringValue(MappedProperty.class, "converter").orElseGet(() -> annotationMetadata.stringValue(TypeDef.class, "converter").orElse(null));
    if (Objects.equals(converter, Object.class.getName())) {
        converter = null;
    }
    if (converter == null) {
        ClassElement type = propertyElement.getGenericType();
        converter = TypeUtils.resolveDataConverter(type, dataConverters);
    }
    if (converter != null) {
        if (isRelation) {
            context.fail("Relation cannot have converter specified", propertyElement);
            return;
        }
        ClassElement persistedClassFromConverter = getPersistedClassFromConverter(converter, context);
        if (persistedClassFromConverter != null) {
            propertyElement.annotate(MappedProperty.class, builder -> {
                builder.member("converterPersistedType", new AnnotationClassValue<>(persistedClassFromConverter.getCanonicalName()));
            });
        }
        if (dataType == null) {
            dataType = getDataTypeFromConverter(propertyElement.getGenericType(), converter, dataTypes, context);
            if (dataType == null) {
                context.fail("Cannot recognize proper data type. Please use @TypeDef to specify one", propertyElement);
                return;
            }
        }
    } else {
        if (dataType == null && spp.getType().isEnum()) {
            if (spp.getOwner().getAnnotationMetadata().hasAnnotation("javax.persistence.Entity") || spp.getOwner().getAnnotationMetadata().hasAnnotation("jakarta.persistence.Entity")) {
                // JPA enums have default ORDINAL mapping for enums
                dataType = DataType.INTEGER;
            }
        }
        if (dataType == null) {
            ClassElement type = propertyElement.getGenericType();
            dataType = TypeUtils.resolveDataType(type, dataTypes);
        }
    }
    if (dataType == DataType.ENTITY && !isRelation) {
        propertyElement = (PropertyElement) propertyElement.annotate(Relation.class, builder -> builder.value(Relation.Kind.MANY_TO_ONE));
    } else if (isRelation) {
        Relation.Kind kind = propertyElement.enumValue(Relation.class, Relation.Kind.class).orElse(Relation.Kind.MANY_TO_ONE);
        if (kind == Relation.Kind.EMBEDDED || kind == Relation.Kind.MANY_TO_ONE) {
            if (propertyElement.stringValue(Relation.class, "mappedBy").isPresent()) {
                context.fail("Relation " + kind + " doesn't support 'mappedBy'.", propertyElement);
            }
        }
        if (kind == Relation.Kind.EMBEDDED) {
            // handled embedded
            SourcePersistentEntity embeddedEntity = entityResolver.apply(propertyElement.getType());
            List<SourcePersistentProperty> persistentProperties = embeddedEntity.getPersistentProperties();
            List<AnnotationValue<Property>> embeddedProperties = new ArrayList<>(persistentProperties.size());
            for (SourcePersistentProperty embeddedProperty : persistentProperties) {
                if (!(embeddedProperty instanceof Association)) {
                    String mappedName = embeddedProperty.stringValue(MappedProperty.class).orElseGet(() -> namingStrategy.mappedName(property.getName() + embeddedProperty.getCapitilizedName()));
                    AnnotationValue<Property> av = AnnotationValue.builder(Property.class).value(mappedName).member("name", embeddedProperty.getName()).build();
                    embeddedProperties.add(av);
                }
            // else {
            // // TODO: handle nested embedded
            // }
            }
            propertyElement.annotate(MappedProperty.class, builder -> builder.member(MappedProperty.EMBEDDED_PROPERTIES, embeddedProperties.toArray(new AnnotationValue[0])));
        }
    }
    Optional<String> mapping = annotationMetadata.stringValue(MappedProperty.class);
    if (mappedEntity && !mapping.isPresent()) {
        propertyElement.annotate(MappedProperty.class, builder -> builder.value(namingStrategy.mappedName(spp)));
    }
    if (dataType != DataType.OBJECT) {
        DataType finalDataType = dataType;
        propertyElement.annotate(MappedProperty.class, builder -> builder.member("type", finalDataType));
    }
    if (converter != null) {
        String finalConverter = converter;
        propertyElement.annotate(MappedProperty.class, builder -> builder.member("converter", new AnnotationClassValue<>(finalConverter)));
    }
}
Also used : DataType(io.micronaut.data.model.DataType) MappedEntity(io.micronaut.data.annotation.MappedEntity) SourcePersistentProperty(io.micronaut.data.processor.model.SourcePersistentProperty) ClassElement(io.micronaut.inject.ast.ClassElement) HashMap(java.util.HashMap) TypeDef(io.micronaut.data.annotation.TypeDef) Function(java.util.function.Function) ArrayList(java.util.ArrayList) Utils.getConfiguredDataTypes(io.micronaut.data.processor.visitors.Utils.getConfiguredDataTypes) Utils.getConfiguredDataConverters(io.micronaut.data.processor.visitors.Utils.getConfiguredDataConverters) TypeElementVisitor(io.micronaut.inject.visitor.TypeElementVisitor) MappedProperty(io.micronaut.data.annotation.MappedProperty) PropertyElement(io.micronaut.inject.ast.PropertyElement) InstantiationUtils(io.micronaut.core.reflect.InstantiationUtils) Map(java.util.Map) TypeUtils(io.micronaut.data.processor.visitors.finders.TypeUtils) AnnotationClassValue(io.micronaut.core.annotation.AnnotationClassValue) NamingStrategies(io.micronaut.data.model.naming.NamingStrategies) PersistentProperty(io.micronaut.data.model.PersistentProperty) Property(io.micronaut.context.annotation.Property) Index(io.micronaut.data.annotation.Index) NamingStrategy(io.micronaut.data.model.naming.NamingStrategy) SourcePersistentEntity(io.micronaut.data.processor.model.SourcePersistentEntity) Collectors(java.util.stream.Collectors) Indexes(io.micronaut.data.annotation.Indexes) Objects(java.util.Objects) NonNull(io.micronaut.core.annotation.NonNull) VisitorContext(io.micronaut.inject.visitor.VisitorContext) List(java.util.List) Association(io.micronaut.data.model.Association) Stream(java.util.stream.Stream) AnnotationValue(io.micronaut.core.annotation.AnnotationValue) Optional(java.util.Optional) AnnotationMetadata(io.micronaut.core.annotation.AnnotationMetadata) AttributeConverter(io.micronaut.data.model.runtime.convert.AttributeConverter) Relation(io.micronaut.data.annotation.Relation) SourcePersistentEntity(io.micronaut.data.processor.model.SourcePersistentEntity) ClassElement(io.micronaut.inject.ast.ClassElement) AnnotationClassValue(io.micronaut.core.annotation.AnnotationClassValue) AnnotationMetadata(io.micronaut.core.annotation.AnnotationMetadata) Relation(io.micronaut.data.annotation.Relation) Association(io.micronaut.data.model.Association) SourcePersistentProperty(io.micronaut.data.processor.model.SourcePersistentProperty) TypeDef(io.micronaut.data.annotation.TypeDef) MappedProperty(io.micronaut.data.annotation.MappedProperty) DataType(io.micronaut.data.model.DataType) AnnotationValue(io.micronaut.core.annotation.AnnotationValue) ArrayList(java.util.ArrayList) List(java.util.List) SourcePersistentProperty(io.micronaut.data.processor.model.SourcePersistentProperty) MappedProperty(io.micronaut.data.annotation.MappedProperty) PersistentProperty(io.micronaut.data.model.PersistentProperty) Property(io.micronaut.context.annotation.Property) PropertyElement(io.micronaut.inject.ast.PropertyElement)

Aggregations

AnnotationMetadata (io.micronaut.core.annotation.AnnotationMetadata)2 Relation (io.micronaut.data.annotation.Relation)2 Association (io.micronaut.data.model.Association)2 ArrayList (java.util.ArrayList)2 List (java.util.List)2 Property (io.micronaut.context.annotation.Property)1 AnnotationClassValue (io.micronaut.core.annotation.AnnotationClassValue)1 AnnotationValue (io.micronaut.core.annotation.AnnotationValue)1 Internal (io.micronaut.core.annotation.Internal)1 NonNull (io.micronaut.core.annotation.NonNull)1 BeanProperty (io.micronaut.core.beans.BeanProperty)1 ArgumentConversionContext (io.micronaut.core.convert.ArgumentConversionContext)1 ConversionContext (io.micronaut.core.convert.ConversionContext)1 ConversionService (io.micronaut.core.convert.ConversionService)1 ConversionErrorException (io.micronaut.core.convert.exceptions.ConversionErrorException)1 InstantiationUtils (io.micronaut.core.reflect.InstantiationUtils)1 Argument (io.micronaut.core.type.Argument)1 CollectionUtils (io.micronaut.core.util.CollectionUtils)1 Index (io.micronaut.data.annotation.Index)1 Indexes (io.micronaut.data.annotation.Indexes)1