use of com.blazebit.persistence.view.CorrelationProviderFactory in project blaze-persistence by Blazebit.
the class ManagedViewTypeImpl method checkAttributes.
@Override
public void checkAttributes(MetamodelBuildingContext context) {
if (inheritanceMapping != null) {
ScalarTargetResolvingExpressionVisitor visitor = new ScalarTargetResolvingExpressionVisitor(jpaManagedType, context.getEntityMetamodel(), context.getJpqlFunctions(), viewRootTypes);
try {
context.getExpressionFactory().createBooleanExpression(inheritanceMapping, false).accept(visitor);
} catch (RuntimeException ex) {
context.addError("Invalid inheritance mapping expression '" + inheritanceMapping + "' on the entity view " + javaType.getName() + ". Encountered error: " + ex.getMessage());
}
}
// Ensure that a plural entity attribute is not used multiple times in different plural entity view attributes
// If it were used multiple times, the second collection would not receive all expected elements, because both are based on the same join
// and the first collection will already cause a "fold" of the results for materializing the collection in the entity view
// We could theoretically try to defer the "fold" action, but the current model makes this pretty hard. The obvious workaround is to map a plural subview attribute
// and put all mappings into that. This will guarantee that the "fold" action only happens after all properties have been processed
Map<String, List<String>> collectionMappings = new HashMap<>();
Map<String, List<String>> collectionMappingSingulars = new HashMap<>();
for (AbstractMethodAttribute<? super X, ?> attribute : attributes.values()) {
attribute.checkAttribute(jpaManagedType, context);
for (Map.Entry<String, Boolean> entry : attribute.getCollectionJoinMappings(jpaManagedType, context).entrySet()) {
if (entry.getValue()) {
List<String> locations = collectionMappingSingulars.get(entry.getKey());
if (locations == null) {
locations = new ArrayList<>(2);
collectionMappingSingulars.put(entry.getKey(), locations);
}
locations.add("Attribute '" + attribute.getName() + "' in entity view '" + javaType.getName() + "'");
} else {
List<String> locations = collectionMappings.get(entry.getKey());
if (locations == null) {
locations = new ArrayList<>(2);
collectionMappings.put(entry.getKey(), locations);
}
locations.add("Attribute '" + attribute.getName() + "' in entity view '" + javaType.getName() + "'");
}
}
}
if (!constructorIndex.isEmpty()) {
for (MappingConstructorImpl<X> constructor : constructorIndex.values()) {
Map<String, List<String>> constructorCollectionMappings = new HashMap<>();
for (Map.Entry<String, List<String>> entry : collectionMappings.entrySet()) {
constructorCollectionMappings.put(entry.getKey(), new ArrayList<>(entry.getValue()));
}
constructor.checkParameters(jpaManagedType, constructorCollectionMappings, collectionMappingSingulars, context);
reportCollectionMappingErrors(context, collectionMappings, collectionMappingSingulars);
}
} else {
reportCollectionMappingErrors(context, collectionMappings, collectionMappingSingulars);
}
for (ViewRoot viewRoot : viewRoots) {
if (viewRoot.getType() != null) {
String location = "entity view root with the name '" + viewRoot.getName() + "' on type '" + javaType.getName() + "'";
ScalarTargetResolvingExpressionVisitor visitor = new ScalarTargetResolvingExpressionVisitor((ManagedType<?>) viewRoot.getType(), context.getEntityMetamodel(), context.getJpqlFunctions(), viewRootTypes);
String[] fetches = viewRoot.getFetches();
if (fetches.length != 0) {
if (!(viewRoot.getType() instanceof ManagedType<?>)) {
context.addError("Specifying fetches for non-entity attribute type [" + Arrays.toString(fetches) + "] at the " + location + " is not allowed!");
} else {
for (int i = 0; i < fetches.length; i++) {
final String fetch = fetches[i];
final String errorLocation;
if (fetches.length == 1) {
errorLocation = "the fetch expression";
} else {
errorLocation = "the " + (i + 1) + ". fetch expression";
}
visitor.clear();
try {
// Validate the fetch expression parses
context.getExpressionFactory().createPathExpression(fetch).accept(visitor);
} catch (SyntaxErrorException ex) {
try {
context.getExpressionFactory().createSimpleExpression(fetch, false, false, true);
// The used expression is not usable for fetches
context.addError("Invalid fetch expression '" + fetch + "' of the " + location + ". Simplify the fetch expression to a simple path expression. Encountered error: " + ex.getMessage());
} catch (SyntaxErrorException ex2) {
// This is a real syntax error
context.addError("Syntax error in " + errorLocation + " '" + fetch + "' of the " + location + ": " + ex.getMessage());
}
} catch (IllegalArgumentException ex) {
context.addError("An error occurred while trying to resolve the " + errorLocation + " '" + fetch + "' of the " + location + ": " + ex.getMessage());
}
}
}
}
String limitExpression = viewRoot.getLimitExpression();
if (limitExpression != null) {
try {
Expression inItemExpression = context.getTypeValidationExpressionFactory().createInItemExpression(limitExpression);
if (!(inItemExpression instanceof ParameterExpression) && !(inItemExpression instanceof NumericLiteral) || inItemExpression instanceof NumericLiteral && ((NumericLiteral) inItemExpression).getNumericType() != NumericType.INTEGER) {
context.addError("Syntax error in the limit expression '" + limitExpression + "' of the " + location + ": The expression must be a integer literal or a parameter expression");
}
} catch (SyntaxErrorException ex) {
context.addError("Syntax error in the limit expression '" + limitExpression + "' of the " + location + ": " + ex.getMessage());
} catch (IllegalArgumentException ex) {
context.addError("An error occurred while trying to resolve the limit expression '" + limitExpression + "' of the " + location + ": " + ex.getMessage());
}
String offsetExpression = viewRoot.getOffsetExpression();
try {
Expression inItemExpression = context.getTypeValidationExpressionFactory().createInItemExpression(offsetExpression);
if (!(inItemExpression instanceof ParameterExpression) && !(inItemExpression instanceof NumericLiteral) || inItemExpression instanceof NumericLiteral && ((NumericLiteral) inItemExpression).getNumericType() != NumericType.INTEGER) {
context.addError("Syntax error in the offset expression '" + offsetExpression + "' of the " + location + ": The expression must be a integer literal or a parameter expression");
}
} catch (SyntaxErrorException ex) {
context.addError("Syntax error in the offset expression '" + offsetExpression + "' of the " + location + ": " + ex.getMessage());
} catch (IllegalArgumentException ex) {
context.addError("An error occurred while trying to resolve the offset expression '" + offsetExpression + "' of the " + location + ": " + ex.getMessage());
}
List<OrderByItem> orderByItems = viewRoot.getOrderByItems();
for (int i = 0; i < orderByItems.size(); i++) {
OrderByItem orderByItem = orderByItems.get(i);
String expression = orderByItem.getExpression();
try {
visitor.clear();
context.getTypeValidationExpressionFactory().createSimpleExpression(expression, false, false, true).accept(visitor);
} catch (SyntaxErrorException ex) {
context.addError("Syntax error in the " + (i + 1) + "th order by expression '" + expression + "' of the " + location + ": " + ex.getMessage());
} catch (IllegalArgumentException ex) {
context.addError("An error occurred while trying to resolve the " + (i + 1) + "th order by expression '" + expression + "' of the " + location + ": " + ex.getMessage());
}
}
}
CorrelationProviderFactory correlationProviderFactory = viewRoot.getCorrelationProviderFactory();
Predicate correlationPredicate = null;
if (correlationProviderFactory instanceof StaticCorrelationProvider) {
correlationPredicate = ((StaticCorrelationProvider) correlationProviderFactory).getCorrelationPredicate();
} else if (correlationProviderFactory instanceof StaticPathCorrelationProvider) {
correlationPredicate = ((StaticPathCorrelationProvider) correlationProviderFactory).getCorrelationPredicate();
String correlationPath = ((StaticPathCorrelationProvider) correlationProviderFactory).getCorrelationPath();
try {
ScalarTargetResolvingExpressionVisitor correlationPathVisitor = new ScalarTargetResolvingExpressionVisitor(getJpaManagedType(), context.getEntityMetamodel(), context.getJpqlFunctions(), viewRootTypes);
context.getTypeValidationExpressionFactory().createSimpleExpression(correlationPath, false, false, true).accept(correlationPathVisitor);
} catch (SyntaxErrorException ex) {
context.addError("Syntax error in the expression '" + correlationPath + "' of the " + location + ": " + ex.getMessage());
} catch (IllegalArgumentException ex) {
context.addError("An error occurred while trying to resolve the expression '" + correlationPath + "' of the " + location + ": " + ex.getMessage());
}
}
if (correlationPredicate != null) {
try {
visitor.clear();
correlationPredicate.accept(visitor);
} catch (SyntaxErrorException ex) {
context.addError("Syntax error in the condition expression '" + correlationPredicate + "' of the " + location + ": " + ex.getMessage());
} catch (IllegalArgumentException ex) {
context.addError("An error occurred while trying to resolve the condition expression '" + correlationPredicate + "' of the " + location + ": " + ex.getMessage());
}
}
}
}
}
use of com.blazebit.persistence.view.CorrelationProviderFactory in project blaze-persistence by Blazebit.
the class ViewTypeObjectBuilderTemplate method applyBasicCorrelatedMapping.
private void applyBasicCorrelatedMapping(AbstractAttribute<?, ?> attribute, String attributePath, TupleElementMapperBuilder mapperBuilder, Set<Feature> features, ExpressionFactory ef, int batchSize, boolean dirtyTracking, EmbeddingViewJpqlMacro embeddingViewJpqlMacro) {
Expression correlationResult = attribute.getCorrelationResultExpression();
CorrelationProviderFactory factory = attribute.getCorrelationProviderFactory();
String correlationBasis = attribute.getCorrelationBasis();
String correlationAlias = CorrelationProviderHelper.getDefaultCorrelationAlias(attributePath);
if (attribute.getFetchStrategy() == FetchStrategy.JOIN) {
String alias = mapperBuilder.getAlias(attribute, false);
correlationBasis = mapperBuilder.getMapping(attribute.getCorrelationBasisExpression());
TupleElementMapper mapper;
String joinBase = mapperBuilder.getMapping();
String joinCorrelationAttributePath = mapperBuilder.getJoinCorrelationAttributePath(attributePath);
String embeddingViewPath = joinBase;
if (factory.isParameterized()) {
mapper = new ParameterizedExpressionCorrelationJoinTupleElementMapper(factory, ef, joinBase, correlationBasis, attribute.getCorrelationResultExpression(), alias, joinCorrelationAttributePath, embeddingViewPath, attribute.getFetches(), createLimiter(mapperBuilder, correlationAlias, attribute), viewRoot.getEntityViewRootTypes().keySet());
} else {
mapper = new ExpressionCorrelationJoinTupleElementMapper(factory.create(null, null), ef, joinBase, correlationBasis, attribute.getCorrelationResultExpression(), alias, joinCorrelationAttributePath, embeddingViewPath, attribute.getFetches(), createLimiter(mapperBuilder, correlationAlias, attribute), viewRoot.getEntityViewRootTypes().keySet());
}
mapperBuilder.addMapper(mapper);
} else if (attribute.getFetchStrategy() == FetchStrategy.SELECT) {
String subviewAliasPrefix = mapperBuilder.getAlias(attribute, false);
int viewRootIndex = viewRoot.hasSubtypes() ? 1 : 0;
int embeddingViewIndex = tupleOffset;
int startIndex = tupleOffset + mapperBuilder.mapperIndex();
Class<?> correlationBasisType = getCorrelationBasisType(attribute.getCorrelationBasisExpression(), AbstractAttribute.stripThisFromMapping(correlationBasis), attribute.getDeclaringType().getEntityViewRootTypes());
Class<?> correlationBasisEntity = getCorrelationBasisEntityType(correlationBasisType);
String correlationBasisExpression = AbstractAttribute.stripThisFromMapping(correlationBasis);
String correlationKeyExpression = mapperBuilder.getMapping(attribute.getCorrelationBasisExpression(), correlationBasisEntity);
String embeddingViewPath = mapperBuilder.getMapping();
boolean correlatesThis = correlatesThis(evm, ef, managedTypeClass, attribute.getCorrelated(), correlationBasisExpression, attribute.getCorrelationPredicate(), attribute.getCorrelationKeyAlias());
BasicUserTypeStringSupport<Object> correlationKeyExpressionBasicTypeType = getCorrelationKeyExpressionBasicTypeSupport(correlationBasisType, correlationBasisEntity);
mapperBuilder.addMapper(createMapper(correlationKeyExpressionBasicTypeType, correlationKeyExpression, subviewAliasPrefix, attributePath, embeddingViewPath, embeddingViewJpqlMacro.getEmbeddingViewPath(), attribute.getFetches()));
// We need a special mapping for the VIEW_ROOT/EMBEDDING_VIEW macro in certain cases
viewRootIndex = addViewRootMappingIfNeeded(mapperBuilder, features, subviewAliasPrefix, attributePath, viewRootIndex);
embeddingViewIndex = addEmbeddingViewMappingIfNeeded(mapperBuilder, features, subviewAliasPrefix, attributePath, embeddingViewIndex);
if (batchSize == -1) {
batchSize = 1;
}
if (attribute.isCollection()) {
PluralAttribute<?, ?, ?> pluralAttribute = (PluralAttribute<?, ?, ?>) attribute;
String[] indexFetches = EMPTY;
Expression indexExpression = null;
Correlator indexCorrelator = null;
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!");
}
indexExpression = attribute.getMappingIndexExpression();
indexCorrelator = indexExpression == null ? null : new BasicCorrelator();
break;
case SET:
break;
case MAP:
MapAttribute<?, ?, ?> mapAttribute = (MapAttribute<?, ?, ?>) attribute;
indexExpression = attribute.getKeyMappingExpression();
indexFetches = mapAttribute.getKeyFetches();
if (mapAttribute.isKeySubview()) {
indexCorrelator = new SubviewCorrelator((ManagedViewTypeImplementor<?>) mapAttribute.getKeyType(), null, evm, subviewAliasPrefix, attributePath);
} else {
indexCorrelator = new BasicCorrelator();
}
mapperBuilder.addTupleListTransformerFactory(new CorrelatedMapBatchTupleListTransformerFactory(new BasicCorrelator(), viewRoot, viewType, correlationResult, factory, attributePath, attribute.getFetches(), correlatesThis, viewRootIndex, embeddingViewIndex, startIndex, batchSize, correlationBasisType, correlationBasisEntity, createLimiter(mapperBuilder, correlationAlias, attribute), indexFetches, indexExpression, indexCorrelator, attribute.getContainerAccumulator(), dirtyTracking));
return;
default:
throw new IllegalArgumentException("Unknown collection type: " + pluralAttribute.getCollectionType());
}
mapperBuilder.addTupleListTransformerFactory(new CorrelatedCollectionBatchTupleListTransformerFactory(new BasicCorrelator(), viewRoot, viewType, correlationResult, factory, attributePath, attribute.getFetches(), correlatesThis, viewRootIndex, embeddingViewIndex, startIndex, batchSize, correlationBasisType, correlationBasisEntity, createLimiter(mapperBuilder, correlationAlias, attribute), indexFetches, indexExpression, indexCorrelator, attribute.getContainerAccumulator(), dirtyTracking));
} else {
mapperBuilder.addTupleListTransformerFactory(new CorrelatedSingularBatchTupleListTransformerFactory(new BasicCorrelator(), viewRoot, viewType, correlationResult, factory, attributePath, attribute.getFetches(), correlatesThis, viewRootIndex, embeddingViewIndex, startIndex, batchSize, correlationBasisType, correlationBasisEntity, createLimiter(mapperBuilder, correlationAlias, attribute)));
}
} else if (attribute.getFetchStrategy() == FetchStrategy.SUBSELECT) {
String subviewAliasPrefix = mapperBuilder.getAlias(attribute, false);
int viewRootIndex = viewRoot.hasSubtypes() ? 1 : 0;
int embeddingViewIndex = tupleOffset;
int startIndex = tupleOffset + mapperBuilder.mapperIndex();
Class<?> correlationBasisType = getCorrelationBasisType(attribute.getCorrelationBasisExpression(), AbstractAttribute.stripThisFromMapping(correlationBasis), attribute.getDeclaringType().getEntityViewRootTypes());
Class<?> correlationBasisEntity = getCorrelationBasisEntityType(correlationBasisType);
String correlationBasisExpression = mapperBuilder.getMapping(attribute.getCorrelationBasisExpression());
String correlationKeyExpression = mapperBuilder.getMapping(attribute.getCorrelationBasisExpression(), correlationBasisEntity);
BasicUserTypeStringSupport<Object> correlationKeyExpressionBasicTypeType = getCorrelationKeyExpressionBasicTypeSupport(correlationBasisType, correlationBasisEntity);
String embeddingViewPath = mapperBuilder.getMapping();
mapperBuilder.addMapper(createMapper(correlationKeyExpressionBasicTypeType, correlationKeyExpression, subviewAliasPrefix, attributePath, embeddingViewPath, embeddingViewJpqlMacro.getEmbeddingViewPath(), attribute.getFetches()));
if (attribute.isCollection()) {
PluralAttribute<?, ?, ?> pluralAttribute = (PluralAttribute<?, ?, ?>) attribute;
String[] indexFetches = EMPTY;
Expression indexExpression = null;
Correlator indexCorrelator = null;
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!");
}
indexExpression = attribute.getMappingIndexExpression();
indexCorrelator = indexExpression == null ? null : new BasicCorrelator();
break;
case SET:
break;
case MAP:
MapAttribute<?, ?, ?> mapAttribute = (MapAttribute<?, ?, ?>) attribute;
indexExpression = attribute.getKeyMappingExpression();
indexFetches = mapAttribute.getKeyFetches();
if (mapAttribute.isKeySubview()) {
indexCorrelator = new SubviewCorrelator((ManagedViewTypeImplementor<?>) mapAttribute.getKeyType(), null, evm, subviewAliasPrefix, attributePath);
} else {
indexCorrelator = new BasicCorrelator();
}
mapperBuilder.addTupleTransformerFactory(new CorrelatedMapSubselectTupleTransformerFactory(new BasicCorrelator(), evm, viewRoot, viewRootAlias, viewType, embeddingViewPath, correlationResult, correlationBasisExpression, correlationKeyExpression, factory, attributePath, attribute.getFetches(), viewRootIndex, embeddingViewIndex, startIndex, correlationBasisType, correlationBasisEntity, createLimiter(mapperBuilder, correlationAlias, attribute), indexFetches, indexExpression, indexCorrelator, attribute.getContainerAccumulator(), dirtyTracking));
return;
default:
throw new IllegalArgumentException("Unknown collection type: " + pluralAttribute.getCollectionType());
}
mapperBuilder.addTupleTransformerFactory(new CorrelatedCollectionSubselectTupleTransformerFactory(new BasicCorrelator(), evm, viewRoot, viewRootAlias, viewType, embeddingViewPath, correlationResult, correlationBasisExpression, correlationKeyExpression, factory, attributePath, attribute.getFetches(), viewRootIndex, embeddingViewIndex, startIndex, correlationBasisType, correlationBasisEntity, createLimiter(mapperBuilder, correlationAlias, attribute), indexFetches, indexExpression, indexCorrelator, attribute.getContainerAccumulator(), dirtyTracking));
} else {
mapperBuilder.addTupleTransformerFactory(new CorrelatedSingularSubselectTupleTransformerFactory(new BasicCorrelator(), evm, viewRoot, viewRootAlias, viewType, embeddingViewPath, correlationResult, correlationBasisExpression, correlationKeyExpression, factory, attributePath, attribute.getFetches(), viewRootIndex, embeddingViewIndex, startIndex, correlationBasisType, correlationBasisEntity, createLimiter(mapperBuilder, correlationAlias, attribute)));
}
} else {
throw new UnsupportedOperationException("Unknown fetch strategy: " + attribute.getFetchStrategy());
}
}
use of com.blazebit.persistence.view.CorrelationProviderFactory in project blaze-persistence by Blazebit.
the class ViewTypeObjectBuilderTemplate method applyCorrelatedSubviewMapping.
@SuppressWarnings("unchecked")
private ViewTypeObjectBuilderTemplate<Object[]>[] applyCorrelatedSubviewMapping(AbstractAttribute<?, ?> attribute, String attributePath, TupleIdDescriptor tupleIdDescriptor, ManagedViewTypeImplementor<Object[]> managedViewType, TupleElementMapperBuilder mapperBuilder, Set<Feature> features, ViewJpqlMacro viewJpqlMacro, EmbeddingViewJpqlMacro embeddingViewJpqlMacro, ExpressionFactory ef, int batchSize, boolean dirtyTracking) {
Expression correlationResult = attribute.getCorrelationResultExpression();
String correlationBasis = attribute.getCorrelationBasis();
CorrelationProviderFactory factory = attribute.getCorrelationProviderFactory();
String correlationAlias = CorrelationProviderHelper.getDefaultCorrelationAlias(attributePath);
if (attribute.getFetchStrategy() == FetchStrategy.JOIN || attribute.getFetchStrategy() == FetchStrategy.MULTISET) {
@SuppressWarnings("unchecked") String subviewAliasPrefix = mapperBuilder.getAlias(attribute, false);
correlationBasis = mapperBuilder.getMapping(attribute.getCorrelationBasisExpression());
Limiter limiter = createLimiter(mapperBuilder, correlationAlias, attribute);
String correlationExternalAlias;
if (limiter == null) {
correlationExternalAlias = correlationAlias;
} else {
correlationExternalAlias = CorrelationProviderHelper.getDefaultExternalCorrelationAlias(attributePath);
}
String subviewIdPrefix = correlationExternalAlias;
if (!ExpressionUtils.isEmptyOrThis(correlationResult)) {
subviewIdPrefix = PrefixingQueryGenerator.prefix(ef, correlationResult, correlationExternalAlias, viewRoot.getEntityViewRootTypes().keySet(), true);
}
String subviewMappingPrefix = subviewIdPrefix;
int startIndex;
if (attribute.getFetchStrategy() == FetchStrategy.MULTISET) {
startIndex = 0;
} else {
startIndex = tupleOffset + mapperBuilder.mapperIndex();
}
boolean updatableObjectCache = managedViewType.isUpdatable() || managedViewType.isCreatable();
TupleIdDescriptor subviewTupleIdDescriptor = new TupleIdDescriptor(tupleIdDescriptor);
TupleIdDescriptor subviewIdDescriptor;
if (managedViewType instanceof ViewType<?>) {
// When the attribute is not update mappable i.e. joining over other associations, we use its parent's parent id
if (attribute.isUpdateMappable()) {
subviewIdDescriptor = new TupleIdDescriptor();
} else {
subviewIdDescriptor = new TupleIdDescriptor(tupleIdDescriptor);
}
} else {
subviewIdDescriptor = new TupleIdDescriptor(tupleIdDescriptor);
subviewIdDescriptor.addIdPosition(flatViewIdPosition(attribute));
subviewTupleIdDescriptor.addIdPosition(flatViewIdPosition(attribute));
}
int endTupleElementsToAdd = 0;
String indexExpression = null;
ViewTypeObjectBuilderTemplate<Object[]> indexTemplate = null;
if (attribute.getFetchStrategy() == FetchStrategy.MULTISET) {
if (attribute.getKeyMappingExpression() != null) {
MapAttribute<?, ?, ?> mapAttribute = (MapAttribute<?, ?, ?>) attribute;
indexExpression = mapperBuilder.getKeyMapping(subviewMappingPrefix, mapAttribute);
if (mapAttribute.isKeySubview()) {
indexTemplate = new ViewTypeObjectBuilderTemplate<Object[]>(viewRoot, viewRootAlias, attributePath, subviewAliasPrefix, indexExpression, indexExpression, subviewTupleIdDescriptor, subviewIdDescriptor, 1, 0, viewJpqlMacro, embeddingViewJpqlMacro, (Map<ManagedViewType<? extends Object[]>, String>) (Map<?, ?>) mapAttribute.getKeyInheritanceSubtypeMappings(), evm, ef, (ManagedViewTypeImplementor<Object[]>) mapAttribute.getKeyType(), null, proxyFactory);
}
} else if (attribute.getMappingIndexExpression() != null) {
indexExpression = mapperBuilder.getIndexMapping(subviewMappingPrefix, (ListAttribute<?, ?>) attribute);
}
if (updatableObjectCache && managedViewType.getMappingType() == Type.MappingType.FLAT_VIEW) {
if (indexExpression != null) {
endTupleElementsToAdd = 1;
} else if (indexTemplate != null) {
endTupleElementsToAdd = indexTemplate.effectiveTupleSize;
}
}
}
Map<ManagedViewType<? extends Object[]>, String> inheritanceSubtypeMappings;
if (attribute instanceof PluralAttribute<?, ?, ?>) {
inheritanceSubtypeMappings = (Map<ManagedViewType<? extends Object[]>, String>) (Map<?, ?>) ((PluralAttribute<?, ?, ?>) attribute).getElementInheritanceSubtypeMappings();
} else {
inheritanceSubtypeMappings = (Map<ManagedViewType<? extends Object[]>, String>) (Map<?, ?>) ((SingularAttribute<?, ?>) attribute).getInheritanceSubtypeMappings();
}
String embeddingViewPath = mapperBuilder.getMapping();
String oldViewPath = viewJpqlMacro.getViewPath();
String oldEmbeddingViewPath = embeddingViewJpqlMacro.getEmbeddingViewPath();
viewJpqlMacro.setViewPath(subviewMappingPrefix);
embeddingViewJpqlMacro.setEmbeddingViewPath(embeddingViewPath);
ViewTypeObjectBuilderTemplate<Object[]> template = new ViewTypeObjectBuilderTemplate<Object[]>(viewRoot, viewRootAlias, attributePath, subviewAliasPrefix, subviewMappingPrefix, subviewIdPrefix, subviewTupleIdDescriptor, subviewIdDescriptor, startIndex, endTupleElementsToAdd, viewJpqlMacro, embeddingViewJpqlMacro, inheritanceSubtypeMappings, evm, ef, managedViewType, null, proxyFactory);
if (attribute.getFetchStrategy() == FetchStrategy.MULTISET) {
mapperBuilder.addMapper(new CorrelationMultisetTupleElementMapper(template, factory, correlationBasis, correlationExternalAlias, attributePath, mapperBuilder.getMapping(), indexExpression, indexTemplate, limiter));
} else {
mapperBuilder.addMappers(template.mappers);
mapperBuilder.addSecondaryMappers(template.secondaryMappers);
mapperBuilder.addTupleTransformatorFactory(template.tupleTransformatorFactory);
mapperBuilder.addTupleTransformerFactory(new CorrelatedSubviewJoinTupleTransformerFactory(template, factory, correlationAlias, mapperBuilder.getMapping(), correlationBasis, correlationExternalAlias, attributePath, embeddingViewPath, attribute.getFetches(), limiter));
}
embeddingViewJpqlMacro.setEmbeddingViewPath(oldEmbeddingViewPath);
viewJpqlMacro.setViewPath(oldViewPath);
return new ViewTypeObjectBuilderTemplate[] { template, indexTemplate };
} else if (attribute.getFetchStrategy() == FetchStrategy.SELECT) {
String subviewAliasPrefix = mapperBuilder.getAlias(attribute, false);
int viewRootIndex = viewRoot.hasSubtypes() ? 1 : 0;
int embeddingViewIndex = (viewType.hasSubtypes() ? 1 : 0) + tupleOffset;
int startIndex = tupleOffset + mapperBuilder.mapperIndex();
Class<?> correlationBasisType = getCorrelationBasisType(attribute.getCorrelationBasisExpression(), AbstractAttribute.stripThisFromMapping(correlationBasis), attribute.getDeclaringType().getEntityViewRootTypes());
Class<?> correlationBasisEntity = getCorrelationBasisEntityType(correlationBasisType);
String correlationBasisExpression = AbstractAttribute.stripThisFromMapping(correlationBasis);
String correlationKeyExpression = mapperBuilder.getMapping(attribute.getCorrelationBasisExpression(), correlationBasisEntity);
String embeddingViewPath = mapperBuilder.getMapping();
boolean correlatesThis = correlatesThis(evm, ef, managedTypeClass, attribute.getCorrelated(), correlationBasisExpression, attribute.getCorrelationPredicate(), attribute.getCorrelationKeyAlias());
BasicUserTypeStringSupport<Object> correlationKeyExpressionBasicTypeType = getCorrelationKeyExpressionBasicTypeSupport(correlationBasisType, correlationBasisEntity);
mapperBuilder.addMapper(createMapper(correlationKeyExpressionBasicTypeType, correlationKeyExpression, subviewAliasPrefix, attributePath, embeddingViewPath, embeddingViewJpqlMacro.getEmbeddingViewPath(), attribute.getFetches()));
// We need a special mapping for the VIEW_ROOT/EMBEDDING_VIEW macro in certain cases
viewRootIndex = addViewRootMappingIfNeeded(mapperBuilder, features, subviewAliasPrefix, attributePath, viewRootIndex);
embeddingViewIndex = addEmbeddingViewMappingIfNeeded(mapperBuilder, features, subviewAliasPrefix, attributePath, embeddingViewIndex);
if (batchSize == -1) {
batchSize = 1;
}
if (attribute.isCollection()) {
PluralAttribute<?, ?, ?> pluralAttribute = (PluralAttribute<?, ?, ?>) attribute;
String[] indexFetches = EMPTY;
Expression indexExpression = null;
Correlator indexCorrelator = null;
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!");
}
indexExpression = attribute.getMappingIndexExpression();
indexCorrelator = indexExpression == null ? null : new BasicCorrelator();
break;
case SET:
break;
case MAP:
MapAttribute<?, ?, ?> mapAttribute = (MapAttribute<?, ?, ?>) attribute;
indexExpression = attribute.getKeyMappingExpression();
indexFetches = mapAttribute.getKeyFetches();
if (mapAttribute.isKeySubview()) {
indexCorrelator = new SubviewCorrelator((ManagedViewTypeImplementor<?>) mapAttribute.getKeyType(), null, evm, subviewAliasPrefix, attributePath);
} else {
indexCorrelator = new BasicCorrelator();
}
mapperBuilder.addTupleListTransformerFactory(new CorrelatedMapBatchTupleListTransformerFactory(new SubviewCorrelator(managedViewType, null, evm, subviewAliasPrefix, attributePath), viewRoot, viewType, correlationResult, factory, attributePath, attribute.getFetches(), correlatesThis, viewRootIndex, embeddingViewIndex, startIndex, batchSize, correlationBasisType, correlationBasisEntity, createLimiter(mapperBuilder, correlationAlias, attribute), indexFetches, indexExpression, indexCorrelator, attribute.getContainerAccumulator(), dirtyTracking));
return null;
default:
throw new IllegalArgumentException("Unknown collection type: " + pluralAttribute.getCollectionType());
}
mapperBuilder.addTupleListTransformerFactory(new CorrelatedCollectionBatchTupleListTransformerFactory(new SubviewCorrelator(managedViewType, null, evm, subviewAliasPrefix, attributePath), viewRoot, viewType, correlationResult, factory, attributePath, attribute.getFetches(), correlatesThis, viewRootIndex, embeddingViewIndex, startIndex, batchSize, correlationBasisType, correlationBasisEntity, createLimiter(mapperBuilder, correlationAlias, attribute), indexFetches, indexExpression, indexCorrelator, attribute.getContainerAccumulator(), dirtyTracking));
} else {
mapperBuilder.addTupleListTransformerFactory(new CorrelatedSingularBatchTupleListTransformerFactory(new SubviewCorrelator(managedViewType, null, evm, subviewAliasPrefix, attributePath), viewRoot, viewType, correlationResult, factory, attributePath, attribute.getFetches(), correlatesThis, viewRootIndex, embeddingViewIndex, startIndex, batchSize, correlationBasisType, correlationBasisEntity, createLimiter(mapperBuilder, correlationAlias, attribute)));
}
} else if (attribute.getFetchStrategy() == FetchStrategy.SUBSELECT) {
String subviewAliasPrefix = mapperBuilder.getAlias(attribute, false);
int viewRootIndex = viewRoot.hasSubtypes() ? 1 : 0;
int embeddingViewIndex = (viewType.hasSubtypes() ? 1 : 0) + tupleOffset;
int startIndex = tupleOffset + mapperBuilder.mapperIndex();
Class<?> correlationBasisType = getCorrelationBasisType(attribute.getCorrelationBasisExpression(), AbstractAttribute.stripThisFromMapping(correlationBasis), attribute.getDeclaringType().getEntityViewRootTypes());
Class<?> correlationBasisEntity = getCorrelationBasisEntityType(correlationBasisType);
String correlationBasisExpression = mapperBuilder.getMapping(attribute.getCorrelationBasisExpression());
String correlationKeyExpression = mapperBuilder.getMapping(attribute.getCorrelationBasisExpression(), correlationBasisEntity);
BasicUserTypeStringSupport<Object> correlationKeyExpressionBasicTypeType = getCorrelationKeyExpressionBasicTypeSupport(correlationBasisType, correlationBasisEntity);
String embeddingViewPath = mapperBuilder.getMapping();
mapperBuilder.addMapper(createMapper(correlationKeyExpressionBasicTypeType, correlationKeyExpression, subviewAliasPrefix, attributePath, embeddingViewPath, embeddingViewJpqlMacro.getEmbeddingViewPath(), attribute.getFetches()));
if (attribute.isCollection()) {
PluralAttribute<?, ?, ?> pluralAttribute = (PluralAttribute<?, ?, ?>) attribute;
String[] indexFetches = EMPTY;
Expression indexExpression = null;
Correlator indexCorrelator = null;
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!");
}
indexExpression = attribute.getMappingIndexExpression();
indexCorrelator = indexExpression == null ? null : new BasicCorrelator();
break;
case SET:
break;
case MAP:
MapAttribute<?, ?, ?> mapAttribute = (MapAttribute<?, ?, ?>) attribute;
indexExpression = attribute.getKeyMappingExpression();
indexFetches = mapAttribute.getKeyFetches();
if (mapAttribute.isKeySubview()) {
indexCorrelator = new SubviewCorrelator((ManagedViewTypeImplementor<?>) mapAttribute.getKeyType(), null, evm, subviewAliasPrefix, attributePath);
} else {
indexCorrelator = new BasicCorrelator();
}
mapperBuilder.addTupleTransformerFactory(new CorrelatedMapSubselectTupleTransformerFactory(new SubviewCorrelator(managedViewType, null, evm, subviewAliasPrefix, attributePath), evm, viewRoot, viewRootAlias, viewType, embeddingViewPath, correlationResult, correlationBasisExpression, correlationKeyExpression, factory, attributePath, attribute.getFetches(), viewRootIndex, embeddingViewIndex, startIndex, correlationBasisType, correlationBasisEntity, createLimiter(mapperBuilder, correlationAlias, attribute), indexFetches, indexExpression, indexCorrelator, attribute.getContainerAccumulator(), dirtyTracking));
return null;
default:
throw new IllegalArgumentException("Unknown collection type: " + pluralAttribute.getCollectionType());
}
mapperBuilder.addTupleTransformerFactory(new CorrelatedCollectionSubselectTupleTransformerFactory(new SubviewCorrelator(managedViewType, null, evm, subviewAliasPrefix, attributePath), evm, viewRoot, viewRootAlias, viewType, embeddingViewPath, correlationResult, correlationBasisExpression, correlationKeyExpression, factory, attributePath, attribute.getFetches(), viewRootIndex, embeddingViewIndex, startIndex, correlationBasisType, correlationBasisEntity, createLimiter(mapperBuilder, correlationAlias, attribute), indexFetches, indexExpression, indexCorrelator, attribute.getContainerAccumulator(), dirtyTracking));
} else {
mapperBuilder.addTupleTransformerFactory(new CorrelatedSingularSubselectTupleTransformerFactory(new SubviewCorrelator(managedViewType, null, evm, subviewAliasPrefix, attributePath), evm, viewRoot, viewRootAlias, viewType, embeddingViewPath, correlationResult, correlationBasisExpression, correlationKeyExpression, factory, attributePath, attribute.getFetches(), viewRootIndex, embeddingViewIndex, startIndex, correlationBasisType, correlationBasisEntity, createLimiter(mapperBuilder, correlationAlias, attribute)));
}
} else {
throw new UnsupportedOperationException("Unknown fetch strategy: " + attribute.getFetchStrategy());
}
return null;
}
use of com.blazebit.persistence.view.CorrelationProviderFactory in project blaze-persistence by Blazebit.
the class ViewMappingImpl method initViewRoots.
private void initViewRoots(MetamodelBuildingContext context) {
if (entityViewRoots == null || entityViewRoots.isEmpty()) {
this.viewRoots = Collections.emptySet();
this.viewRootTypes = Collections.emptyMap();
} else {
this.viewRoots = new LinkedHashSet<>(entityViewRoots.size());
this.viewRootTypes = new HashMap<>(entityViewRoots.size());
Set<String> rootAliases = new HashSet<>(entityViewRoots.size());
for (EntityViewRootMapping entityViewRoot : entityViewRoots) {
rootAliases.add(entityViewRoot.getName());
}
for (EntityViewRootMapping entityViewRoot : entityViewRoots) {
String viewRootName = entityViewRoot.getName();
Class<?> entityClass = entityViewRoot.getManagedTypeClass();
String joinExpression = entityViewRoot.getJoinExpression();
Class<? extends CorrelationProvider> correlationProvider = entityViewRoot.getCorrelationProvider();
CorrelationProviderFactory correlationProviderFactory = null;
javax.persistence.metamodel.Type<?> type = null;
String conditionExpression = entityViewRoot.getConditionExpression();
if (entityClass != null) {
if (joinExpression != null || correlationProvider != null) {
context.addError("Illegal entity view root mapping '" + viewRootName + "' at the class '" + entityViewClass.getName() + "'! Only one of the attributes entity, expression or correlator may be used!");
}
if (conditionExpression == null) {
context.addError("Illegal entity view root mapping '" + viewRootName + "' at the class '" + entityViewClass.getName() + "'! When using the entity attribute, a condition expression is required!");
} else {
correlationProviderFactory = new StaticCorrelationProvider(entityClass, viewRootName, conditionExpression, createPredicate(conditionExpression, context, viewRootName), rootAliases);
}
} else if (joinExpression != null) {
if (correlationProvider != null) {
context.addError("Illegal entity view root mapping '" + viewRootName + "' at the class '" + entityViewClass.getName() + "'! Only one of the attributes entity, expression or correlator may be used!");
}
if (conditionExpression == null) {
correlationProviderFactory = new StaticPathCorrelationProvider(joinExpression, viewRootName, "1=1", createPredicate("1=1", context, viewRootName), rootAliases);
} else {
correlationProviderFactory = new StaticPathCorrelationProvider(joinExpression, viewRootName, conditionExpression, createPredicate(conditionExpression, context, viewRootName), rootAliases);
}
} else if (correlationProvider != null) {
if (conditionExpression != null) {
context.addError("Illegal entity view root mapping '" + viewRootName + "' at the class '" + entityViewClass.getName() + "'! When using the correlator attribute, using a condition expression is illegal!");
}
correlationProviderFactory = CorrelationProviderHelper.getFactory(correlationProvider);
} else {
context.addError("Illegal entity view root mapping '" + viewRootName + "' at the class '" + entityViewClass.getName() + "'! One of the attributes entity, expression or correlator must be used for a valid entity view root definition!");
}
String limitExpression;
String offsetExpression;
List<OrderByItem> orderByItems;
if (entityViewRoot.getLimitExpression() == null || entityViewRoot.getLimitExpression().isEmpty()) {
limitExpression = null;
offsetExpression = null;
orderByItems = Collections.emptyList();
} else {
limitExpression = entityViewRoot.getLimitExpression();
offsetExpression = entityViewRoot.getOffsetExpression();
if (offsetExpression == null || offsetExpression.isEmpty()) {
offsetExpression = "0";
}
List<String> orderByItemExpressions = entityViewRoot.getOrderByItems();
orderByItems = AbstractAttribute.parseOrderByItems(orderByItemExpressions);
}
try {
type = TypeExtractingCorrelationBuilder.extractType(correlationProviderFactory, viewRootName, context, new ScalarTargetResolvingExpressionVisitor(getManagedType(context), context.getEntityMetamodel(), context.getJpqlFunctions(), viewRootTypes));
} catch (Exception ex) {
StringWriter sw = new StringWriter();
sw.append("Illegal entity view root mapping '").append(viewRootName).append("' at the class '").append(entityViewClass.getName()).append("'! The given entity class is not a valid managed type:\n");
ex.printStackTrace(new PrintWriter(sw));
context.addError(sw.toString());
}
viewRootTypes.put(viewRootName, type);
viewRoots.add(new ViewRootImpl(viewRootName, type, correlationProviderFactory, correlationProvider, entityViewRoot.getJoinType(), entityViewRoot.getFetches(), orderByItems, limitExpression, offsetExpression));
}
}
}
use of com.blazebit.persistence.view.CorrelationProviderFactory in project blaze-persistence by Blazebit.
the class MetamodelBuildingContextImpl method getPossibleTargetTypes.
@Override
public List<ScalarTargetResolvingExpressionVisitor.TargetType> getPossibleTargetTypes(Class<?> entityClass, Attribute<?, ?> rootAttribute, Annotation mapping, Map<String, javax.persistence.metamodel.Type<?>> rootTypes) {
ManagedType<?> managedType = entityMetamodel.getManagedType(entityClass);
String expression;
if (mapping instanceof Mapping) {
expression = ((Mapping) mapping).value();
} else if (mapping instanceof IdMapping) {
expression = ((IdMapping) mapping).value();
} else if (mapping instanceof MappingIndex) {
expression = ((MappingIndex) mapping).value();
} else if (mapping instanceof MappingCorrelatedSimple) {
MappingCorrelatedSimple m = (MappingCorrelatedSimple) mapping;
managedType = entityMetamodel.getManagedType(m.correlated());
expression = m.correlationResult();
// Correlation result is the correlated type, so the possible target type is the managed type
if (expression.isEmpty()) {
return Collections.<ScalarTargetResolvingExpressionVisitor.TargetType>singletonList(new ScalarTargetResolvingExpressionVisitor.TargetTypeImpl(false, null, managedType.getJavaType(), null, null));
}
} else if (mapping instanceof MappingCorrelated) {
MappingCorrelated m = (MappingCorrelated) mapping;
CorrelationProviderFactory correlationProviderFactory = CorrelationProviderHelper.getFactory(m.correlator());
ScalarTargetResolvingExpressionVisitor resolver = new ScalarTargetResolvingExpressionVisitor(entityClass, getEntityMetamodel(), getJpqlFunctions(), rootTypes);
javax.persistence.metamodel.Type<?> type = TypeExtractingCorrelationBuilder.extractType(correlationProviderFactory, "_alias", this, resolver);
if (type == null) {
// We can't determine the managed type
return Collections.emptyList();
}
managedType = (ManagedType<?>) type;
expression = m.correlationResult();
// Correlation result is the correlated type, so the possible target type is the managed type
if (expression.isEmpty()) {
return Collections.<ScalarTargetResolvingExpressionVisitor.TargetType>singletonList(new ScalarTargetResolvingExpressionVisitor.TargetTypeImpl(false, null, managedType.getJavaType(), null, null));
}
} else if (mapping instanceof MappingSubquery) {
MappingSubquery mappingSubquery = (MappingSubquery) mapping;
if (!mappingSubquery.expression().isEmpty()) {
Expression simpleExpression = typeValidationExpressionFactory.createSimpleExpression(((MappingSubquery) mapping).expression(), false, true, false);
AliasReplacementVisitor aliasReplacementVisitor = new AliasReplacementVisitor(NullExpression.INSTANCE, mappingSubquery.subqueryAlias());
simpleExpression.accept(aliasReplacementVisitor);
ScalarTargetResolvingExpressionVisitor visitor = new ScalarTargetResolvingExpressionVisitor(entityClass, entityMetamodel, jpqlFunctions, rootTypes);
simpleExpression.accept(visitor);
return visitor.getPossibleTargetTypes();
}
// We can't determine the managed type
return Collections.emptyList();
} else {
// There is no entity model type for other mappings
return Collections.emptyList();
}
// Don't bother with empty expressions or missing managed type, let the validation process handle this
if (expression.isEmpty() || managedType == null) {
return Collections.emptyList();
}
expression = AbstractAttribute.stripThisFromMapping(expression);
// The result is "THIS" apparently, so the possible target type is the managed type
if (expression.isEmpty()) {
Class<?> leafBaseClass = managedType.getJavaType();
Class<?> leafBaseKeyClass = null;
Class<?> leafBaseValueClass = null;
if (rootAttribute instanceof PluralAttribute<?, ?, ?>) {
leafBaseClass = rootAttribute.getJavaType();
leafBaseValueClass = ((PluralAttribute<?, ?, ?>) rootAttribute).getElementType().getJavaType();
if (rootAttribute instanceof MapAttribute<?, ?, ?>) {
leafBaseKeyClass = ((MapAttribute<?, ?, ?>) rootAttribute).getKeyJavaType();
}
} else if (rootAttribute instanceof SingularAttribute<?, ?>) {
leafBaseClass = rootAttribute.getJavaType();
}
return Collections.<ScalarTargetResolvingExpressionVisitor.TargetType>singletonList(new ScalarTargetResolvingExpressionVisitor.TargetTypeImpl(leafBaseValueClass != null, rootAttribute, leafBaseClass, leafBaseKeyClass, leafBaseValueClass));
}
Expression simpleExpression = typeValidationExpressionFactory.createSimpleExpression(expression, false, false, true);
if (simpleExpression instanceof EntityLiteral) {
// This is a special case where the mapping i.e. attribute name matches an entity name
try {
Attribute<?, ?> attribute = managedType.getAttribute(expression);
return Collections.<ScalarTargetResolvingExpressionVisitor.TargetType>singletonList(new ScalarTargetResolvingExpressionVisitor.TargetTypeImpl(false, attribute, attribute.getJavaType(), null, attribute.getJavaType()));
} catch (IllegalArgumentException ex) {
// Apparently it's not an attribute, so let it run through
}
}
ScalarTargetResolvingExpressionVisitor visitor = new ScalarTargetResolvingExpressionVisitor(managedType, rootAttribute, entityMetamodel, jpqlFunctions, rootTypes);
simpleExpression.accept(visitor);
return visitor.getPossibleTargetTypes();
}
Aggregations