use of com.blazebit.persistence.view.impl.entity.InverseViewToEntityMapper in project blaze-persistence by Blazebit.
the class InverseFlusher method forAttribute.
public static <E> InverseFlusher<E> forAttribute(EntityViewManagerImpl evm, Map<Object, EntityViewUpdaterImpl> localCache, ManagedViewType<?> viewType, AbstractMethodAttribute<?, ?> attribute, TypeDescriptor childTypeDescriptor, EntityViewUpdaterImpl owner, String ownerMapping) {
if (attribute.getMappedBy() != null) {
String attributeLocation = attribute.getLocation();
Type<?> elementType = attribute instanceof PluralAttribute<?, ?, ?> ? ((PluralAttribute<?, ?, ?>) attribute).getElementType() : ((SingularAttribute<?, ?>) attribute).getType();
Class<?> elementEntityClass = null;
AttributeAccessor parentReferenceAttributeAccessor = null;
Mapper<Object, Object> parentEntityOnChildViewMapper = null;
Mapper<Object, Object> parentEntityOnChildEntityAddMapper = null;
Mapper<Object, Object> parentEntityOnChildEntityRemoveMapper = null;
TargetViewClassBasedInverseViewToEntityMapper childViewToEntityMapper = null;
InverseEntityToEntityMapper childEntityToEntityMapper = null;
ViewToEntityMapper parentReferenceViewToEntityMapper = new LoadOnlyViewToEntityMapper(new ReferenceEntityLoader(evm, viewType, EntityViewUpdaterImpl.createViewIdMapper(evm, localCache, viewType)), Accessors.forViewId(evm, (ViewType<?>) viewType, true), evm.getEntityIdAccessor());
ViewToEntityMapper childReferenceViewToEntityMapper = null;
TypeDescriptor parentReferenceTypeDescriptor = TypeDescriptor.forInverseAttribute(parentReferenceViewToEntityMapper);
if (attribute.getWritableMappedByMappings() != null) {
// This happens when the mapped by attribute is insertable=false and updatable=false
if (childTypeDescriptor.isSubview()) {
ViewType<?> childViewType = (ViewType<?>) elementType;
elementEntityClass = childViewType.getEntityClass();
Map<Class<?>, Mapper<Object, Object>> mappers = new HashMap<>();
for (ManagedViewType<?> type : attribute.getViewTypes()) {
Mapper<Object, Object> mapper = Mappers.forViewConvertToViewAttributeMapping(evm, (ViewType<Object>) viewType, (ViewType<Object>) type, attribute.getWritableMappedByMappings(), (Mapper<Object, Object>) Mappers.forEntityAttributeMappingConvertToViewAttributeMapping(evm, viewType.getEntityClass(), type, attribute.getWritableMappedByMappings()));
if (mapper == null) {
mapper = NoopMapper.INSTANCE;
}
mappers.put(type.getJavaType(), mapper);
}
parentEntityOnChildViewMapper = (Mapper<Object, Object>) Mappers.targetViewClassBasedMapper(mappers);
parentEntityOnChildEntityAddMapper = parentEntityOnChildEntityRemoveMapper = (Mapper<Object, Object>) Mappers.forEntityAttributeMapping(evm, viewType.getEntityClass(), childViewType.getEntityClass(), attribute.getWritableMappedByMappings());
childReferenceViewToEntityMapper = new LoadOrPersistViewToEntityMapper(attributeLocation, evm, childViewType.getJavaType(), attribute.getReadOnlyAllowedSubtypes(), attribute.getPersistCascadeAllowedSubtypes(), attribute.getUpdateCascadeAllowedSubtypes(), new ReferenceEntityLoader(evm, childViewType, EntityViewUpdaterImpl.createViewIdMapper(evm, localCache, childViewType)), Accessors.forViewId(evm, childViewType, true), evm.getEntityIdAccessor(), true, owner, ownerMapping, localCache);
} else if (childTypeDescriptor.isJpaEntity()) {
Class<?> childType = elementType.getJavaType();
elementEntityClass = childType;
parentEntityOnChildViewMapper = (Mapper<Object, Object>) Mappers.forEntityAttributeMapping(evm, viewType.getEntityClass(), childType, attribute.getWritableMappedByMappings());
parentEntityOnChildEntityAddMapper = parentEntityOnChildEntityRemoveMapper = (Mapper<Object, Object>) Mappers.forEntityAttributeMapping(evm, viewType.getEntityClass(), elementEntityClass, attribute.getWritableMappedByMappings());
}
} else {
if (childTypeDescriptor.isSubview()) {
ViewType<?> childViewType = (ViewType<?>) elementType;
elementEntityClass = childViewType.getEntityClass();
parentReferenceAttributeAccessor = Accessors.forEntityMapping(evm, childViewType.getEntityClass(), attribute.getMappedBy());
childReferenceViewToEntityMapper = new LoadOrPersistViewToEntityMapper(attributeLocation, evm, childViewType.getJavaType(), attribute.getReadOnlyAllowedSubtypes(), attribute.getPersistCascadeAllowedSubtypes(), attribute.getUpdateCascadeAllowedSubtypes(), new ReferenceEntityLoader(evm, childViewType, EntityViewUpdaterImpl.createViewIdMapper(evm, localCache, childViewType)), Accessors.forViewId(evm, childViewType, true), evm.getEntityIdAccessor(), true, owner, ownerMapping, localCache);
parentEntityOnChildEntityAddMapper = parentEntityOnChildEntityRemoveMapper = Mappers.forAccessor(parentReferenceAttributeAccessor);
Map<Class<?>, Mapper<Object, Object>> mappers = new HashMap<>();
for (ManagedViewType<?> type : attribute.getViewTypes()) {
Mapper<Object, Object> mapper = (Mapper<Object, Object>) Mappers.forViewConvertToViewAttributeMapping(evm, (ViewType<Object>) viewType, (ViewType<Object>) type, attribute.getMappedBy(), null);
if (mapper == null) {
mapper = NoopMapper.INSTANCE;
}
mappers.put(type.getJavaType(), mapper);
}
parentEntityOnChildViewMapper = (Mapper<Object, Object>) Mappers.targetViewClassBasedMapper(mappers);
} else if (childTypeDescriptor.isJpaEntity()) {
Class<?> childType = elementType.getJavaType();
elementEntityClass = childType;
parentReferenceAttributeAccessor = Accessors.forEntityMapping(evm, childType, attribute.getMappedBy());
parentEntityOnChildEntityAddMapper = parentEntityOnChildEntityRemoveMapper = Mappers.forAccessor(parentReferenceAttributeAccessor);
parentEntityOnChildViewMapper = Mappers.forAccessor(parentReferenceAttributeAccessor);
}
}
DirtyAttributeFlusher<?, Object, ? extends Object> parentReferenceAttributeFlusher;
ManagedType<?> managedType = evm.getMetamodel().getEntityMetamodel().getManagedType(elementEntityClass);
Attribute<?, ?> inverseAttribute = JpaMetamodelUtils.getAttribute(managedType, attribute.getMappedBy());
// Many-To-Many relation can't be handled by the inverse flushers
if (inverseAttribute != null && inverseAttribute.isCollection()) {
// A collection can only have a single attribute, so it's safe to assume a SimpleMapper
parentEntityOnChildEntityAddMapper = new CollectionAddMapper<>(parentEntityOnChildEntityAddMapper == null ? parentReferenceAttributeAccessor : ((SimpleMapper<Object, Object>) parentEntityOnChildEntityAddMapper).getAttributeAccessor());
parentEntityOnChildEntityRemoveMapper = new CollectionRemoveMapper<>(parentEntityOnChildEntityRemoveMapper == null ? parentReferenceAttributeAccessor : ((SimpleMapper<Object, Object>) parentEntityOnChildEntityRemoveMapper).getAttributeAccessor());
parentReferenceAttributeFlusher = new ParentCollectionReferenceAttributeFlusher<>(attributeLocation, attribute.getMappedBy(), viewType.getFlushStrategy(), parentReferenceAttributeAccessor, null, null, null, TypeDescriptor.forInverseCollectionAttribute(viewType.getEntityClass(), new EntityBasicUserType(evm.getJpaProvider())));
} else {
parentEntityOnChildEntityRemoveMapper = new NullMapper<>(parentEntityOnChildEntityRemoveMapper);
parentReferenceAttributeFlusher = new ParentReferenceAttributeFlusher<>(evm, viewType.getEntityClass(), attributeLocation, attribute.getMappedBy(), attribute.getWritableMappedByMappings(), parentReferenceTypeDescriptor, parentReferenceAttributeAccessor, parentEntityOnChildViewMapper);
}
UnmappedAttributeCascadeDeleter deleter = null;
String parentIdAttributeName = null;
String childIdAttributeName = null;
Class<?> childIdViewClass = null;
// Only construct when orphanRemoval or delete cascading is enabled, orphanRemoval implies delete cascading
if (attribute.isDeleteCascaded()) {
EntityMetamodel entityMetamodel = evm.getMetamodel().getEntityMetamodel();
ExtendedManagedType<?> ownerManagedType = entityMetamodel.getManagedType(ExtendedManagedType.class, viewType.getEntityClass());
ExtendedManagedType<?> elementManagedType = entityMetamodel.getManagedType(ExtendedManagedType.class, elementEntityClass);
parentIdAttributeName = ownerManagedType.getIdAttribute().getName();
childIdAttributeName = elementManagedType.getIdAttribute().getName();
String mapping = attribute.getMappedBy();
if (mapping != null) {
if (mapping.isEmpty()) {
deleter = new UnmappedWritableBasicAttributeSetNullCascadeDeleter(evm, ownerManagedType.getType(), elementManagedType, attribute.getWritableMappedByMappings());
} else {
ExtendedAttribute extendedAttribute = elementManagedType.getAttribute(mapping);
if (childTypeDescriptor.isSubview()) {
if (elementType instanceof ViewType<?>) {
MethodAttribute<?, ?> idAttribute = ((ViewType<?>) elementType).getIdAttribute();
if (idAttribute.isSubview()) {
// in this case, we need to fetch the id as view as the deleter expects it this way
childIdViewClass = idAttribute.getJavaType();
}
}
deleter = new ViewTypeCascadeDeleter(childTypeDescriptor.getViewToEntityMapper());
} else if (childTypeDescriptor.isJpaEntity()) {
deleter = new UnmappedBasicAttributeCascadeDeleter(evm, mapping, extendedAttribute, mapping + "." + parentIdAttributeName, false);
}
}
}
}
if (childTypeDescriptor.isSubview()) {
InverseViewToEntityMapper<?> first = null;
Map<Class<?>, InverseViewToEntityMapper<?>> mappers = new HashMap<>();
for (ManagedViewType<?> type : attribute.getViewTypes()) {
InverseViewToEntityMapper inverseViewToEntityMapper = new InverseViewToEntityMapper(evm, localCache, (ViewType<?>) type, parentEntityOnChildViewMapper, parentEntityOnChildEntityAddMapper, parentEntityOnChildEntityRemoveMapper, childTypeDescriptor.getViewToEntityMapper(), parentReferenceAttributeFlusher, EntityViewUpdaterImpl.createIdFlusher(evm, localCache, (ViewType<?>) type, EntityViewUpdaterImpl.createViewIdMapper(evm, localCache, type)));
mappers.put(type.getJavaType(), inverseViewToEntityMapper);
if (type == elementType) {
first = inverseViewToEntityMapper;
}
}
childViewToEntityMapper = new TargetViewClassBasedInverseViewToEntityMapper(first, mappers);
} else if (childTypeDescriptor.isJpaEntity()) {
Class<?> childType = elementType.getJavaType();
childEntityToEntityMapper = new InverseEntityToEntityMapper(evm, evm.getMetamodel().getEntityMetamodel().entity(childType), parentEntityOnChildEntityAddMapper, parentEntityOnChildEntityRemoveMapper, parentReferenceAttributeFlusher);
}
return new InverseFlusher(viewType.getEntityClass(), attribute.getMapping(), parentIdAttributeName, childIdAttributeName, childIdViewClass, deleter, parentReferenceViewToEntityMapper, parentReferenceAttributeFlusher, parentEntityOnChildViewMapper, childViewToEntityMapper, childReferenceViewToEntityMapper, parentEntityOnChildEntityAddMapper, childEntityToEntityMapper);
}
return null;
}
Aggregations