use of com.blazebit.persistence.view.spi.type.TypeConverter in project blaze-persistence by Blazebit.
the class TypeDescriptor method forType.
public static TypeDescriptor forType(EntityViewManagerImpl evm, Map<Object, EntityViewUpdaterImpl> localCache, EntityViewUpdaterImpl updater, AbstractMethodAttribute<?, ?> attribute, Type<?> type, EntityViewUpdaterImpl owner, String ownerMapping) {
EntityMetamodel entityMetamodel = evm.getMetamodel().getEntityMetamodel();
String attributeLocation = attribute.getLocation();
boolean cascadePersist = attribute.isPersistCascaded();
boolean cascadeUpdate = attribute.isUpdateCascaded();
Set<Type<?>> readOnlyAllowedSubtypes = attribute.getReadOnlyAllowedSubtypes();
Set<Type<?>> persistAllowedSubtypes = attribute.getPersistCascadeAllowedSubtypes();
Set<Type<?>> updateAllowedSubtypes = attribute.getUpdateCascadeAllowedSubtypes();
EntityToEntityMapper entityToEntityMapper = null;
ViewToEntityMapper viewToEntityMapper = null;
ViewToEntityMapper loadOnlyViewToEntityMapper = null;
final ManagedType<?> managedType = entityMetamodel.getManagedType(type.getJavaType());
final boolean jpaEntity = managedType instanceof EntityType<?>;
final boolean jpaManaged = managedType != null;
final boolean mutable;
final boolean identifiable;
TypeConverter<Object, Object> converter = (TypeConverter<Object, Object>) type.getConverter();
BasicUserType<Object> basicUserType;
ManagedType<?> ownerEntityType = owner == null ? attribute.getDeclaringType().getJpaManagedType() : owner.getManagedViewType().getJpaManagedType();
String attributeIdAttributeName = null;
String entityIdAttributeName = null;
Class<?> jpaType;
// TODO: currently we only check if the declared type is mutable, but we have to let the collection flusher which types are considered updatable/creatable
if (type instanceof BasicType<?>) {
jpaType = type.getJavaType();
basicUserType = (BasicUserType<Object>) ((BasicType<?>) type).getUserType();
mutable = basicUserType.isMutable();
identifiable = jpaEntity || !jpaManaged;
if (jpaEntity) {
Map<String, Map<?, ?>> fetchGraph = null;
UnmappedAttributeCascadeDeleter deleter = null;
// We only need to know the fetch graph when we actually do updates
if (cascadeUpdate) {
fetchGraph = getFetchGraph(attribute.getFetches(), attribute.getMapping(), managedType);
}
if (ownerEntityType instanceof EntityType<?>) {
ExtendedManagedType<?> extendedManagedType = evm.getMetamodel().getEntityMetamodel().getManagedType(ExtendedManagedType.class, type.getJavaType());
entityIdAttributeName = extendedManagedType.getIdAttribute().getName();
attributeIdAttributeName = getAttributeElementIdentifier(evm, (EntityType<?>) ownerEntityType, attribute.getName(), ownerMapping, attribute.getMapping(), extendedManagedType.getType());
// Only construct when orphanRemoval or delete cascading is enabled, orphanRemoval implies delete cascading
if (attribute.isDeleteCascaded()) {
String mapping = attribute.getMapping();
ExtendedManagedType elementManagedType = entityMetamodel.getManagedType(ExtendedManagedType.class, attribute.getDeclaringType().getJpaManagedType());
deleter = new UnmappedBasicAttributeCascadeDeleter(evm, mapping, elementManagedType.getAttribute(mapping), mapping + "." + attributeIdAttributeName, false);
}
}
// TODO: EntityToEntityMapper should also use the attributeIdAttributeName
entityToEntityMapper = new DefaultEntityToEntityMapper(cascadePersist, cascadeUpdate, jpaType, basicUserType, new DefaultEntityLoaderFetchGraphNode(evm, attribute.getName(), (EntityType<?>) managedType, fetchGraph), deleter);
}
} else {
ManagedViewTypeImplementor<?> elementType = (ManagedViewTypeImplementor<?>) type;
jpaType = elementType.getEntityClass();
basicUserType = null;
mutable = elementType.isUpdatable() || elementType.isCreatable() || !persistAllowedSubtypes.isEmpty() || !updateAllowedSubtypes.isEmpty();
Set<ManagedViewType<?>> viewTypes = attribute.getViewTypes();
if (elementType.getJpaManagedType() instanceof EntityType<?> && ownerEntityType instanceof EntityType<?>) {
ExtendedManagedType<?> extendedManagedType = evm.getMetamodel().getEntityMetamodel().getManagedType(ExtendedManagedType.class, elementType.getEntityClass());
entityIdAttributeName = extendedManagedType.getIdAttribute().getName();
attributeIdAttributeName = getAttributeElementIdentifier(evm, (EntityType<?>) ownerEntityType, attribute.getName(), ownerMapping, attribute.getMapping(), extendedManagedType.getType());
}
viewToEntityMapper = createViewToEntityMapper(evm, localCache, updater, attributeIdAttributeName, attribute.getMapping(), attributeLocation, elementType, cascadePersist, cascadeUpdate, readOnlyAllowedSubtypes, persistAllowedSubtypes, updateAllowedSubtypes, EntityLoaders.referenceLoaderForAttribute(evm, localCache, elementType, viewTypes, attributeIdAttributeName), owner, ownerMapping);
loadOnlyViewToEntityMapper = createLoadOnlyViewToEntityMapper(attributeLocation, evm, localCache, attributeIdAttributeName, attribute.getMapping(), elementType, cascadePersist, cascadeUpdate, readOnlyAllowedSubtypes, persistAllowedSubtypes, updateAllowedSubtypes, EntityLoaders.referenceLoaderForAttribute(evm, localCache, elementType, viewTypes, attributeIdAttributeName), owner, ownerMapping);
identifiable = viewToEntityMapper.getViewIdAccessor() != null;
}
final boolean shouldJpaMerge = jpaEntity && mutable && cascadeUpdate;
final boolean shouldJpaPersist = jpaEntity && mutable && cascadePersist;
final boolean shouldFlushUpdates = cascadeUpdate && !updateAllowedSubtypes.isEmpty();
final boolean shouldFlushPersists = cascadePersist && !persistAllowedSubtypes.isEmpty();
return new TypeDescriptor(mutable, identifiable, jpaManaged, jpaEntity, shouldJpaMerge, shouldJpaPersist, shouldFlushPersists, shouldFlushUpdates, entityIdAttributeName, attributeIdAttributeName, jpaType, converter, basicUserType, entityToEntityMapper, viewToEntityMapper, loadOnlyViewToEntityMapper);
}
use of com.blazebit.persistence.view.spi.type.TypeConverter in project blaze-persistence by Blazebit.
the class ViewTypeObjectBuilderTemplate method applyMapping.
@SuppressWarnings("unchecked")
private void applyMapping(AbstractAttribute<?, ?> attribute, String parentAttributePath, TupleElementMapperBuilder mapperBuilder, Set<Feature> features, TupleIdDescriptor tupleIdDescriptor, ViewJpqlMacro viewJpqlMacro, EmbeddingViewJpqlMacro embeddingViewJpqlMacro, ExpressionFactory ef) {
String attributePath = getAttributePath(parentAttributePath, attribute, false);
int batchSize = attribute.getBatchSize();
if (batchSize == -1) {
batchSize = attribute.getDeclaringType().getDefaultBatchSize();
}
if (attribute.isSubquery()) {
applySubqueryMapping((SubqueryAttribute<? super T, ?>) attribute, attributePath, mapperBuilder, embeddingViewJpqlMacro);
} else {
if (attribute.isCollection()) {
PluralAttribute<? super T, ?, ?> pluralAttribute = (PluralAttribute<? super T, ?, ?>) attribute;
TypeConverter<Object, Object> keyConverter = null;
TypeConverter<Object, Object> valueConverter = (TypeConverter<Object, Object>) pluralAttribute.getElementType().getConverter();
boolean listKey = pluralAttribute.isIndexed() && pluralAttribute instanceof ListAttribute<?, ?>;
boolean mapKey = pluralAttribute.isIndexed() && pluralAttribute instanceof MapAttribute<?, ?, ?>;
int startIndex = tupleOffset + mapperBuilder.mapperIndex();
int valueStartIndex = startIndex + 1;
if (pluralAttribute.getFetchStrategy() == FetchStrategy.JOIN) {
if (listKey) {
MappingAttribute<? super T, ?> mappingAttribute = (MappingAttribute<? super T, ?>) attribute;
features.add(Feature.INDEXED_COLLECTIONS);
applyIndexCollectionFunctionMapping(IntegerBasicUserType.INSTANCE, mappingAttribute, attributePath, mapperBuilder, embeddingViewJpqlMacro);
} else if (mapKey) {
MappingAttribute<? super T, ?> mappingAttribute = (MappingAttribute<? super T, ?>) attribute;
features.add(Feature.INDEXED_COLLECTIONS);
MapAttribute<?, ?, ?> mapAttribute = (MapAttribute<?, ?, ?>) pluralAttribute;
keyConverter = (TypeConverter<Object, Object>) mapAttribute.getKeyType().getConverter();
if (mapAttribute.isKeySubview()) {
features.add(Feature.SUBVIEWS);
ManagedViewTypeImpl<Object[]> managedViewType = (ManagedViewTypeImpl<Object[]>) mapAttribute.getKeyType();
applySubviewMapping(mappingAttribute, attributePath, tupleIdDescriptor, managedViewType, mapperBuilder, viewJpqlMacro, embeddingViewJpqlMacro, ef, true, true);
valueStartIndex = tupleOffset + mapperBuilder.mapperIndex();
} else {
applyIndexCollectionFunctionMapping(TypeUtils.forType(mapAttribute.getKeyType()), mappingAttribute, attributePath, mapperBuilder, embeddingViewJpqlMacro);
}
}
}
boolean dirtyTracking = pluralAttribute instanceof MethodAttribute<?, ?> && attribute.needsDirtyTracker();
if (pluralAttribute.isSubview()) {
features.add(Feature.SUBVIEWS);
TupleIdDescriptor newTupleIdDescriptor;
if ((listKey || mapKey) && pluralAttribute.getFetchStrategy() == FetchStrategy.JOIN && !pluralAttribute.isCorrelated()) {
newTupleIdDescriptor = new TupleIdDescriptor(tupleIdDescriptor);
newTupleIdDescriptor.addIdPosition(startIndex);
} else {
newTupleIdDescriptor = tupleIdDescriptor;
}
if (pluralAttribute.isCorrelated() || (pluralAttribute.getFetchStrategy() != FetchStrategy.JOIN || attribute.getLimitExpression() != null) && pluralAttribute.getFetchStrategy() != FetchStrategy.MULTISET) {
ManagedViewTypeImplementor<Object> managedViewType = (ManagedViewTypeImplementor<Object>) pluralAttribute.getElementType();
if (attribute.getFetchStrategy() == FetchStrategy.MULTISET) {
boolean updatableObjectCache = managedViewType.isUpdatable() || managedViewType.isCreatable();
boolean nullIfEmpty = managedViewType instanceof ViewType<?>;
ViewTypeObjectBuilderTemplate<Object[]>[] templates = applyCorrelatedSubviewMapping(attribute, attributePath, tupleIdDescriptor, (ManagedViewTypeImplementor<Object[]>) (ManagedViewTypeImplementor<?>) managedViewType, mapperBuilder, features, viewJpqlMacro, embeddingViewJpqlMacro, ef, batchSize, false);
ViewTypeObjectBuilderTemplate<Object[]> subviewTemplate = templates[0];
ViewTypeObjectBuilderTemplate<Object[]> indexTemplate = templates[1];
SubviewTupleTransformerFactory indexTransformerFactory = null;
BasicUserTypeStringSupport<?> indexBasicTypeSupport = null;
if (indexTemplate != null) {
boolean updatableKeyObjectCache = indexTemplate.viewType.isUpdatable() || indexTemplate.viewType.isCreatable();
indexTransformerFactory = new SubviewTupleTransformerFactory(attributePath, indexTemplate, updatableKeyObjectCache, true);
} else if (mapKey) {
indexBasicTypeSupport = TypeUtils.forType(((MapAttribute<?, ?, ?>) attribute).getKeyType());
} else if (listKey) {
indexBasicTypeSupport = IntegerBasicUserType.INSTANCE;
}
mapperBuilder.addTupleTransformerFactory(new CollectionMultisetTupleTransformerFactory(startIndex, null, attributePath, getMultisetResultAlias(attributePath), valueConverter, attribute.getContainerAccumulator(), dirtyTracking, subviewTemplate, indexTemplate, managedViewType.hasSelectOrSubselectFetchedAttributes(), new SubviewTupleTransformerFactory(attributePath, subviewTemplate, updatableObjectCache, nullIfEmpty), indexTransformerFactory, null, indexBasicTypeSupport));
} else {
applyCorrelatedSubviewMapping(attribute, attributePath, newTupleIdDescriptor, (ManagedViewTypeImplementor<Object[]>) (ManagedViewTypeImplementor<?>) managedViewType, mapperBuilder, features, viewJpqlMacro, embeddingViewJpqlMacro, ef, batchSize, dirtyTracking);
}
} else {
MappingAttribute<? super T, ?> mappingAttribute = (MappingAttribute<? super T, ?>) attribute;
ManagedViewTypeImplementor<Object[]> managedViewType = (ManagedViewTypeImplementor<Object[]>) pluralAttribute.getElementType();
boolean nullIfEmpty = managedViewType instanceof ViewType<?> || !listKey && !mapKey;
if (pluralAttribute.getFetchStrategy() == FetchStrategy.MULTISET) {
boolean updatableObjectCache = managedViewType.isUpdatable() || managedViewType.isCreatable();
String mapping = mapperBuilder.getMapping(mappingAttribute);
ViewTypeObjectBuilderTemplate<Object[]>[] templates = applySubviewMapping(mappingAttribute, attributePath, newTupleIdDescriptor, managedViewType, mapperBuilder, viewJpqlMacro, embeddingViewJpqlMacro, ef, false, nullIfEmpty);
ViewTypeObjectBuilderTemplate<Object[]> subviewTemplate = templates[0];
ViewTypeObjectBuilderTemplate<Object[]> indexTemplate = templates[1];
SubviewTupleTransformerFactory indexTransformerFactory = null;
BasicUserTypeStringSupport<?> indexBasicTypeSupport = null;
if (indexTemplate != null) {
boolean updatableKeyObjectCache = indexTemplate.viewType.isUpdatable() || indexTemplate.viewType.isCreatable();
indexTransformerFactory = new SubviewTupleTransformerFactory(attributePath, indexTemplate, updatableKeyObjectCache, true);
} else if (mapKey) {
indexBasicTypeSupport = TypeUtils.forType(((MapAttribute<?, ?, ?>) attribute).getKeyType());
} else if (listKey) {
indexBasicTypeSupport = IntegerBasicUserType.INSTANCE;
}
mapperBuilder.addTupleTransformerFactory(new CollectionMultisetTupleTransformerFactory(startIndex, mapping, attributePath, getMultisetResultAlias(attributePath), valueConverter, attribute.getContainerAccumulator(), dirtyTracking, subviewTemplate, indexTemplate, managedViewType.hasSelectOrSubselectFetchedAttributes(), new SubviewTupleTransformerFactory(attributePath, subviewTemplate, updatableObjectCache, nullIfEmpty), indexTransformerFactory, null, indexBasicTypeSupport));
} else {
// Obviously, we produce null if the object type is identifiable i.e. a ViewType and it is empty = null id
// Additionally, we also consider empty embeddables as null when we have a non-indexed collection so we can filter out these elements
applySubviewMapping(mappingAttribute, attributePath, newTupleIdDescriptor, managedViewType, mapperBuilder, viewJpqlMacro, embeddingViewJpqlMacro, ef, false, nullIfEmpty);
}
}
} else if (mapKey) {
MappingAttribute<? super T, ?> mappingAttribute = (MappingAttribute<? super T, ?>) attribute;
applyCollectionFunctionMapping(TypeUtils.forType(getType(mappingAttribute)), mappingAttribute, attributePath, mapperBuilder, mappingAttribute.getFetches(), embeddingViewJpqlMacro);
} else {
// TODO: Multiset basic fetching?
if (pluralAttribute.isCorrelated() || attribute.getFetchStrategy() == FetchStrategy.JOIN && !attribute.getOrderByItems().isEmpty() || pluralAttribute.getFetchStrategy() != FetchStrategy.JOIN && pluralAttribute.getFetchStrategy() != FetchStrategy.MULTISET) {
applyBasicCorrelatedMapping(attribute, attributePath, mapperBuilder, features, ef, batchSize, dirtyTracking, embeddingViewJpqlMacro);
} else {
MappingAttribute<? super T, ?> mappingAttribute = (MappingAttribute<? super T, ?>) attribute;
applyBasicMapping(mappingAttribute, attributePath, mapperBuilder, embeddingViewJpqlMacro);
}
}
if (pluralAttribute.getFetchStrategy() == FetchStrategy.JOIN) {
if (listKey) {
if (pluralAttribute.isSorted()) {
throw new IllegalArgumentException("The list attribute '" + pluralAttribute + "' can not be sorted!");
} else {
mapperBuilder.addTupleListTransformer(new IndexedTupleListTransformer(tupleIdDescriptor.createIdPositions(), startIndex, valueStartIndex, attribute.getContainerAccumulator(), dirtyTracking, null, valueConverter));
}
} else if (mapKey) {
mapperBuilder.addTupleListTransformer(new IndexedTupleListTransformer(tupleIdDescriptor.createIdPositions(), startIndex, valueStartIndex, attribute.getContainerAccumulator(), dirtyTracking, keyConverter, valueConverter));
} else {
switch(pluralAttribute.getCollectionType()) {
case COLLECTION:
if (pluralAttribute.isSorted()) {
throw new IllegalArgumentException("The collection attribute '" + pluralAttribute + "' can not be sorted!");
}
break;
case LIST:
if (pluralAttribute.isSorted()) {
throw new IllegalArgumentException("The list attribute '" + pluralAttribute + "' can not be sorted!");
}
break;
case SET:
break;
case MAP:
throw new IllegalArgumentException("Ignoring the index on the attribute '" + pluralAttribute + "' is not possible!");
default:
throw new IllegalArgumentException("Unknown collection type: " + pluralAttribute.getCollectionType());
}
mapperBuilder.addTupleListTransformer(new NonIndexedTupleListTransformer(tupleIdDescriptor.createIdPositions(), startIndex, attribute.getCollectionInstantiator(), dirtyTracking, valueConverter));
}
}
} else if (attribute.isQueryParameter()) {
MappingAttribute<? super T, ?> mappingAttribute = (MappingAttribute<? super T, ?>) attribute;
features.add(Feature.PARAMETERS);
applyQueryParameterMapping(mappingAttribute, mapperBuilder);
} else if (attribute.isSubview()) {
features.add(Feature.SUBVIEWS);
boolean nullIfEmpty = !((SingularAttribute<?, ?>) attribute).isCreateEmptyFlatView();
if (attribute.isCorrelated() || attribute.getFetchStrategy() == FetchStrategy.JOIN && !attribute.getOrderByItems().isEmpty() || attribute.getFetchStrategy() != FetchStrategy.JOIN && attribute.getFetchStrategy() != FetchStrategy.MULTISET) {
ManagedViewTypeImplementor<Object> managedViewType = (ManagedViewTypeImplementor<Object>) ((SingularAttribute<?, ?>) attribute).getType();
if (attribute.getFetchStrategy() == FetchStrategy.MULTISET) {
int startIndex = tupleOffset + mapperBuilder.mapperIndex();
boolean updatableObjectCache = managedViewType.isUpdatable() || managedViewType.isCreatable();
ViewTypeObjectBuilderTemplate<Object[]> subviewTemplate = applyCorrelatedSubviewMapping(attribute, attributePath, tupleIdDescriptor, (ManagedViewTypeImplementor<Object[]>) (ManagedViewTypeImplementor<?>) managedViewType, mapperBuilder, features, viewJpqlMacro, embeddingViewJpqlMacro, ef, batchSize, false)[0];
TypeConverter<Object, Object> elementConverter = (TypeConverter<Object, Object>) (TypeConverter<?, ?>) managedViewType.getConverter();
mapperBuilder.addTupleTransformerFactory(new SingularMultisetTupleTransformerFactory(startIndex, null, attributePath, getMultisetResultAlias(attributePath), elementConverter, subviewTemplate, managedViewType.hasSelectOrSubselectFetchedAttributes(), new SubviewTupleTransformerFactory(attributePath, subviewTemplate, updatableObjectCache, nullIfEmpty)));
} else {
applyCorrelatedSubviewMapping(attribute, attributePath, tupleIdDescriptor, (ManagedViewTypeImplementor<Object[]>) (ManagedViewTypeImplementor<?>) managedViewType, mapperBuilder, features, viewJpqlMacro, embeddingViewJpqlMacro, ef, batchSize, false);
}
} else {
MappingAttribute<? super T, ?> mappingAttribute = (MappingAttribute<? super T, ?>) attribute;
ManagedViewTypeImplementor<Object[]> managedViewType = (ManagedViewTypeImplementor<Object[]>) ((SingularAttribute<?, ?>) attribute).getType();
if (attribute.getFetchStrategy() == FetchStrategy.MULTISET) {
int startIndex = tupleOffset + mapperBuilder.mapperIndex();
boolean updatableObjectCache = managedViewType.isUpdatable() || managedViewType.isCreatable();
String mapping = mapperBuilder.getMapping(mappingAttribute);
ViewTypeObjectBuilderTemplate<Object[]> subviewTemplate = applySubviewMapping(mappingAttribute, attributePath, tupleIdDescriptor, managedViewType, mapperBuilder, viewJpqlMacro, embeddingViewJpqlMacro, ef, false, nullIfEmpty)[0];
TypeConverter<Object, Object> elementConverter = (TypeConverter<Object, Object>) (TypeConverter<?, ?>) managedViewType.getConverter();
mapperBuilder.addTupleTransformerFactory(new SingularMultisetTupleTransformerFactory(startIndex, mapping, attributePath, getMultisetResultAlias(attributePath), elementConverter, subviewTemplate, managedViewType.hasSelectOrSubselectFetchedAttributes(), new SubviewTupleTransformerFactory(attributePath, subviewTemplate, updatableObjectCache, nullIfEmpty)));
} else {
applySubviewMapping(mappingAttribute, attributePath, tupleIdDescriptor, managedViewType, mapperBuilder, viewJpqlMacro, embeddingViewJpqlMacro, ef, false, nullIfEmpty);
}
}
} else {
if (attribute.isCorrelated() || attribute.getFetchStrategy() == FetchStrategy.JOIN && !attribute.getOrderByItems().isEmpty() || attribute.getFetchStrategy() != FetchStrategy.JOIN && attribute.getFetchStrategy() != FetchStrategy.MULTISET) {
applyBasicCorrelatedMapping(attribute, attributePath, mapperBuilder, features, ef, batchSize, false, embeddingViewJpqlMacro);
} else {
MappingAttribute<? super T, ?> mappingAttribute = (MappingAttribute<? super T, ?>) attribute;
applyBasicMapping(mappingAttribute, attributePath, mapperBuilder, embeddingViewJpqlMacro);
}
}
}
}
Aggregations