initial working dynamic instantiation support;

cleanup
This commit is contained in:
Steve Ebersole 2019-09-19 15:13:50 -05:00
parent 055ce0c542
commit 5631a702a7
42 changed files with 662 additions and 594 deletions

View File

@ -14,12 +14,14 @@ import java.io.Serializable;
import java.net.URL;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.jar.JarFile;
import java.util.zip.ZipEntry;
import javax.xml.transform.dom.DOMSource;
import org.hibernate.HibernateException;
@ -41,6 +43,7 @@ import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.service.ServiceRegistry;
import org.hibernate.type.SerializationException;
import org.w3c.dom.Document;
/**
@ -64,6 +67,8 @@ public class MetadataSources implements Serializable {
private LinkedHashSet<String> annotatedClassNames = new LinkedHashSet<>();
private LinkedHashSet<String> annotatedPackages = new LinkedHashSet<>();
private Map<String,Class<?>> extraQueryImports;
public MetadataSources() {
this( new BootstrapServiceRegistryBuilder().build() );
}
@ -111,6 +116,10 @@ public class MetadataSources implements Serializable {
return annotatedClassNames;
}
public Map<String,Class<?>> getExtraQueryImports() {
return extraQueryImports;
}
public ServiceRegistry getServiceRegistry() {
return serviceRegistry;
}
@ -196,6 +205,16 @@ public class MetadataSources implements Serializable {
return this;
}
/**
* Var-arg form of {@link #addAnnotatedClass}
*/
public MetadataSources addAnnotatedClasses(Class<?>... annotatedClasses) {
if ( annotatedClasses != null && annotatedClasses.length > 0 ) {
Collections.addAll( this.annotatedClasses, annotatedClasses );
}
return this;
}
/**
* Read metadata from the annotations attached to the given class. The important
* distinction here is that the {@link Class} will not be accessed until later
@ -210,6 +229,26 @@ public class MetadataSources implements Serializable {
return this;
}
/**
* Var-arg form of {@link #addAnnotatedClassName}
*/
public MetadataSources addAnnotatedClassNames(String... annotatedClassNames) {
if ( annotatedClassNames != null && annotatedClassNames.length > 0 ) {
Collections.addAll( this.annotatedClassNames, annotatedClassNames );
}
return this;
}
public MetadataSources addQueryImport(String importedName, Class<?> target) {
if ( extraQueryImports == null ) {
extraQueryImports = new HashMap<>();
}
extraQueryImports.put( importedName, target );
return this;
}
/**
* Read package-level metadata.
*

View File

@ -30,6 +30,7 @@ public class ManagedResourcesImpl implements ManagedResources {
private Set<String> annotatedClassNames = new LinkedHashSet<>();
private Set<String> annotatedPackageNames = new LinkedHashSet<>();
private List<Binding> mappingFileBindings = new ArrayList<>();
private Map<String, Class<?>> extraQueryImports;
public static ManagedResourcesImpl baseline(MetadataSources sources, BootstrapContext bootstrapContext) {
final ManagedResourcesImpl impl = new ManagedResourcesImpl();
@ -38,6 +39,7 @@ public class ManagedResourcesImpl implements ManagedResources {
impl.annotatedClassNames.addAll( sources.getAnnotatedClassNames() );
impl.annotatedPackageNames.addAll( sources.getAnnotatedPackages() );
impl.mappingFileBindings.addAll( sources.getXmlBindings() );
impl.extraQueryImports = sources.getExtraQueryImports();
return impl;
}
@ -69,6 +71,11 @@ public class ManagedResourcesImpl implements ManagedResources {
return Collections.unmodifiableList( mappingFileBindings );
}
@Override
public Map<String, Class<?>> getExtraQueryImports() {
return extraQueryImports;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// package private

View File

@ -7,6 +7,8 @@
package org.hibernate.boot.model.process.spi;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import org.hibernate.boot.AttributeConverterInfo;
import org.hibernate.boot.jaxb.spi.Binding;
@ -66,4 +68,6 @@ public interface ManagedResources {
* @return The list of bindings for all known XML mapping files.
*/
Collection<Binding> getXmlMappingBindings();
Map<String,Class<?>> getExtraQueryImports();
}

View File

@ -8,6 +8,7 @@ package org.hibernate.boot.model.process.spi;
import java.util.Collection;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.hibernate.boot.MetadataSources;
@ -304,9 +305,24 @@ public class MetadataBuildingProcess {
}
}
applyExtraQueryImports( managedResources, metadataCollector );
return metadataCollector.buildMetadataInstance( rootMetadataBuildingContext );
}
private static void applyExtraQueryImports(
ManagedResources managedResources,
InFlightMetadataCollectorImpl metadataCollector) {
final Map<String, Class<?>> extraQueryImports = managedResources.getExtraQueryImports();
if ( extraQueryImports == null || extraQueryImports.isEmpty() ) {
return;
}
for ( Map.Entry<String, Class<?>> entry : extraQueryImports.entrySet() ) {
metadataCollector.addImport( entry.getKey(), entry.getValue().getName() );
}
}
// todo (7.0) : buildJandexInitializer
// private static JandexInitManager buildJandexInitializer(
// MetadataBuildingOptions options,

View File

@ -81,6 +81,8 @@ public interface JpaMetamodel extends javax.persistence.metamodel.Metamodel {
void visitEmbeddables(Consumer<EmbeddableDomainType<?>> action);
String qualifyImportableName(String queryName);
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Covariant returns

View File

@ -269,6 +269,11 @@ public class JpaMetamodelImpl implements JpaMetamodel {
return results;
}
@Override
public String qualifyImportableName(String queryName) {
return resolveImportedName( queryName );
}
private String resolveImportedName(String name) {
String result = nameToImportNameMap.get( name );
if ( result == null ) {

View File

@ -238,9 +238,4 @@ public class FullyQualifiedReflectivePathTerminal
public NodeBuilder nodeBuilder() {
return null;
}
@Override
public SqmExpressable getExpressableType() {
return expressableType;
}
}

View File

@ -570,11 +570,7 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
else {
final String className = ctx.dynamicInstantiationTarget().dotIdentifierSequence().getText();
try {
final Class<?> targetJavaType = classForName( className );
final JavaTypeDescriptor jtd = creationContext.getJpaMetamodel()
.getTypeConfiguration()
.getJavaTypeDescriptorRegistry()
.resolveDescriptor( targetJavaType );
final JavaTypeDescriptor jtd = resolveInstantiationTargetJtd( className );
dynamicInstantiation = SqmDynamicInstantiation.forClassInstantiation(
jtd,
creationContext.getNodeBuilder()
@ -592,6 +588,14 @@ public class SemanticQueryBuilder extends HqlParserBaseVisitor implements SqmCre
return dynamicInstantiation;
}
private JavaTypeDescriptor resolveInstantiationTargetJtd(String className) {
final Class<?> targetJavaType = classForName( creationContext.getJpaMetamodel().qualifyImportableName( className ) );
return creationContext.getJpaMetamodel()
.getTypeConfiguration()
.getJavaTypeDescriptorRegistry()
.resolveDescriptor( targetJavaType );
}
private Class classForName(String className) {
return creationContext.getServiceRegistry().getService( ClassLoaderService.class ).classForName( className );
}

View File

@ -20,7 +20,7 @@ import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.engine.spi.LoadQueryInfluencers;
import org.hibernate.internal.util.collections.Stack;
import org.hibernate.internal.util.collections.StandardStack;
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
import org.hibernate.metamodel.mapping.BasicValuedMapping;
import org.hibernate.metamodel.mapping.MappingModelExpressable;
import org.hibernate.metamodel.model.domain.EmbeddableDomainType;
import org.hibernate.metamodel.model.domain.EntityDomainType;
@ -35,12 +35,12 @@ import org.hibernate.query.sqm.SqmExpressable;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.function.SqmFunction;
import org.hibernate.query.sqm.internal.DomainParameterXref;
import org.hibernate.query.sqm.internal.SqmMappingModelHelper;
import org.hibernate.query.sqm.spi.BaseSemanticQueryWalker;
import org.hibernate.query.sqm.spi.JdbcParameterBySqmParameterAccess;
import org.hibernate.query.sqm.sql.internal.BasicValuedPathInterpretation;
import org.hibernate.query.sqm.sql.internal.EmbeddableValuedPathInterpretation;
import org.hibernate.query.sqm.sql.internal.SqlAstQuerySpecProcessingStateImpl;
import org.hibernate.query.sqm.sql.internal.SqmExpressionInterpretation;
import org.hibernate.query.sqm.sql.internal.SqmParameterInterpretation;
import org.hibernate.query.sqm.sql.internal.SqmPathInterpretation;
import org.hibernate.query.sqm.tree.delete.SqmDeleteStatement;
@ -614,8 +614,12 @@ public abstract class BaseSqmToSqlAstConverter
// General expressions
@Override
public SqmExpressionInterpretation visitLiteral(SqmLiteral literal) {
return literal;
public Expression visitLiteral(SqmLiteral literal) {
return new QueryLiteral(
literal.getLiteralValue(),
(BasicValuedMapping) SqmMappingModelHelper.resolveMappingModelExpressable( literal, this ),
getCurrentClauseStack().getCurrent()
);
}
private final Map<SqmParameter,List<JdbcParameter>> jdbcParamsBySqmParam = new IdentityHashMap<>();
@ -627,12 +631,12 @@ public abstract class BaseSqmToSqlAstConverter
}
@Override
public SqmExpressionInterpretation visitNamedParameterExpression(SqmNamedParameter expression) {
public Expression visitNamedParameterExpression(SqmNamedParameter expression) {
return consumeSqmParameter( expression );
}
private SqmExpressionInterpretation consumeSqmParameter(SqmParameter sqmParameter) {
private Expression consumeSqmParameter(SqmParameter sqmParameter) {
final MappingModelExpressable valueMapping = determineValueMapping( sqmParameter );
final List<JdbcParameter> jdbcParametersForSqm = new ArrayList<>();
@ -1242,7 +1246,7 @@ public abstract class BaseSqmToSqlAstConverter
public Object visitEnumLiteral(SqmEnumLiteral sqmEnumLiteral) {
return new QueryLiteral(
sqmEnumLiteral.getEnumValue(),
determineValueMapping( sqmEnumLiteral ),
(BasicValuedMapping) determineValueMapping( sqmEnumLiteral ),
getCurrentClauseStack().getCurrent()
);
}
@ -1251,7 +1255,7 @@ public abstract class BaseSqmToSqlAstConverter
public Object visitFieldLiteral(SqmFieldLiteral sqmFieldLiteral) {
return new QueryLiteral(
sqmFieldLiteral.getValue(),
determineValueMapping( sqmFieldLiteral ),
(BasicValuedMapping) determineValueMapping( sqmFieldLiteral ),
getCurrentClauseStack().getCurrent()
);
}
@ -1322,11 +1326,7 @@ public abstract class BaseSqmToSqlAstConverter
final Expression lhs;
try {
lhs = ( (SqmExpressionInterpretation) predicate.getLeftHandExpression().accept( this ) ).toSqlExpression(
getCurrentClauseStack().getCurrent(),
this,
this
);
lhs = (Expression) predicate.getLeftHandExpression().accept( this );
}
finally {
inferableTypeAccessStack.pop();
@ -1336,11 +1336,7 @@ public abstract class BaseSqmToSqlAstConverter
final Expression rhs;
try {
rhs = ( (SqmExpressionInterpretation) predicate.getRightHandExpression().accept( this ) ).toSqlExpression(
getCurrentClauseStack().getCurrent(),
this,
this
);
rhs = (Expression) predicate.getRightHandExpression().accept( this );
}
finally {
inferableTypeAccessStack.pop();
@ -1472,13 +1468,7 @@ public abstract class BaseSqmToSqlAstConverter
domainParameterXref.addExpansion( domainParam, sqmParameter, sqmParamToConsume );
}
inListPredicate.addExpression(
consumeSqmParameter( sqmParamToConsume ).toSqlExpression(
getCurrentClauseStack().getCurrent(),
this,
this
)
);
inListPredicate.addExpression( consumeSqmParameter( sqmParamToConsume ) );
}
}
finally {

View File

@ -6,8 +6,10 @@
*/
package org.hibernate.query.sqm.sql;
import org.hibernate.internal.util.collections.Stack;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.sql.SqlAstCreationState;
import org.hibernate.sql.ast.Clause;
/**
* Specialized SemanticQueryWalker (SQM visitor) for producing SQL AST.
@ -15,4 +17,5 @@ import org.hibernate.query.sqm.sql.SqlAstCreationState;
* @author Steve Ebersole
*/
public interface SqmToSqlAstConverter extends SemanticQueryWalker<Object>, SqlAstCreationState {
Stack<Clause> getCurrentClauseStack();
}

View File

@ -10,15 +10,16 @@ import java.util.function.Consumer;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
import org.hibernate.query.NavigablePath;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.internal.SqmMappingModelHelper;
import org.hibernate.query.sqm.sql.SqlAstCreationState;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.sql.SqlExpressionResolver;
import org.hibernate.query.sqm.tree.domain.SqmBasicValuedSimplePath;
import org.hibernate.sql.ast.Clause;
import org.hibernate.query.sqm.tree.domain.SqmPath;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.spi.SqlAstWalker;
import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.update.Assignment;
@ -44,45 +45,63 @@ public class BasicValuedPathInterpretation<T> implements AssignableSqmPathInterp
null
);
return new BasicValuedPathInterpretation<>( sqmPath, mapping, tableGroup );
final ColumnReference columnReference = (ColumnReference) sqlAstCreationState.getSqlExpressionResolver().resolveSqlExpression(
SqlExpressionResolver.createColumnReferenceKey(
mapping.getContainingTableExpression(),
mapping.getMappedColumnExpression()
),
sacs -> new ColumnReference(
mapping.getMappedColumnExpression(),
tableGroup.resolveTableReference( mapping.getContainingTableExpression() )
.getIdentificationVariable(),
mapping.getJdbcMapping(),
sqlAstCreationState.getCreationContext().getSessionFactory()
)
);
return new BasicValuedPathInterpretation<>( columnReference, sqmPath, mapping, tableGroup );
}
private final ColumnReference columnReference;
private final SqmBasicValuedSimplePath<T> sqmPath;
private final BasicValuedModelPart mapping;
private final TableGroup tableGroup;
private Expression expression;
private BasicValuedPathInterpretation(
ColumnReference columnReference,
SqmBasicValuedSimplePath<T> sqmPath,
BasicValuedModelPart mapping,
TableGroup tableGroup) {
assert columnReference != null;
this.columnReference = columnReference;
assert sqmPath != null;
this.sqmPath = sqmPath;
assert mapping != null;
this.mapping = mapping;
assert tableGroup != null;
this.tableGroup = tableGroup;
}
@Override
public NavigablePath getNavigablePath() {
return sqmPath.getNavigablePath();
public SqmPath<T> getInterpretedSqmPath() {
return sqmPath;
}
@Override
public SqmPathSource<T> getSqmPathSource() {
return sqmPath.getReferencedPathSource();
public ModelPart getExpressionType() {
return mapping;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// DomainResultProducer
@Override
public DomainResultProducer<T> getDomainResultProducer(
SqmToSqlAstConverter walker,
SqlAstCreationState sqlAstCreationState) {
return this;
}
@Override
public DomainResult<T> createDomainResult(
String resultVariable,
@ -95,17 +114,6 @@ public class BasicValuedPathInterpretation<T> implements AssignableSqmPathInterp
mapping.applySqlSelections( getNavigablePath(), tableGroup, creationState );
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// SqmExpressionInterpretation
@Override
public Expression toSqlExpression(
Clause clause, SqmToSqlAstConverter walker,
SqlAstCreationState sqlAstCreationState) {
throw new NotYetImplementedFor6Exception( getClass() );
}
@Override
public void applySqlAssignments(
Expression newValueExpression,
@ -115,6 +123,11 @@ public class BasicValuedPathInterpretation<T> implements AssignableSqmPathInterp
throw new NotYetImplementedFor6Exception( getClass() );
}
@Override
public void accept(SqlAstWalker sqlTreeWalker) {
columnReference.accept( sqlTreeWalker );
}
@Override
public String toString() {
return "BasicValuedPathInterpretation(" + sqmPath.getNavigablePath().getFullPath() + ')';

View File

@ -10,15 +10,15 @@ import java.util.function.Consumer;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.metamodel.mapping.EmbeddableValuedModelPart;
import org.hibernate.query.NavigablePath;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.internal.SqmMappingModelHelper;
import org.hibernate.query.sqm.sql.SqlAstCreationState;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.tree.domain.SqmEmbeddedValuedSimplePath;
import org.hibernate.sql.ast.Clause;
import org.hibernate.query.sqm.tree.domain.SqmPath;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.spi.SqlAstWalker;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.update.Assignment;
@ -28,59 +28,67 @@ import org.hibernate.sql.results.spi.DomainResultCreationState;
/**
* @author Steve Ebersole
*/
public class EmbeddableValuedPathInterpretation<T> implements AssignableSqmPathInterpretation<T>, DomainResultProducer<T> {
public class EmbeddableValuedPathInterpretation<T> implements AssignableSqmPathInterpretation<T> {
/**
* Static factory
*/
public static <T> EmbeddableValuedPathInterpretation<T> from(
SqmEmbeddedValuedSimplePath<T> sqmPath,
SqlAstCreationState sqlAstCreationState,
SqmToSqlAstConverter converter,
SemanticQueryWalker sqmWalker) {
final TableGroup tableGroup = SqmMappingModelHelper.resolveLhs( sqmPath.getNavigablePath(), sqlAstCreationState );
tableGroup.getModelPart().prepareAsLhs( sqmPath.getNavigablePath(), sqlAstCreationState );
final TableGroup tableGroup = SqmMappingModelHelper.resolveLhs( sqmPath.getNavigablePath(), converter );
tableGroup.getModelPart().prepareAsLhs( sqmPath.getNavigablePath(), converter );
final EmbeddableValuedModelPart mapping = (EmbeddableValuedModelPart) tableGroup.getModelPart().findSubPart(
sqmPath.getReferencedPathSource().getPathName(),
null
);
return new EmbeddableValuedPathInterpretation<>( sqmPath, mapping, tableGroup );
return new EmbeddableValuedPathInterpretation<>(
mapping.toSqlExpression(
tableGroup,
converter.getCurrentClauseStack().getCurrent(),
converter,
converter
),
sqmPath,
mapping,
tableGroup
);
}
private final Expression sqlExpression;
private final SqmEmbeddedValuedSimplePath<T> sqmPath;
private final EmbeddableValuedModelPart mapping;
private final TableGroup tableGroup;
public EmbeddableValuedPathInterpretation(
Expression sqlExpression,
SqmEmbeddedValuedSimplePath<T> sqmPath,
EmbeddableValuedModelPart mapping,
TableGroup tableGroup) {
this.sqlExpression = sqlExpression;
this.sqmPath = sqmPath;
this.mapping = mapping;
this.tableGroup = tableGroup;
}
@Override
public NavigablePath getNavigablePath() {
return sqmPath.getNavigablePath();
public SqmPath<T> getInterpretedSqmPath() {
return sqmPath;
}
@Override
public SqmPathSource<T> getSqmPathSource() {
return sqmPath.getReferencedPathSource();
public ModelPart getExpressionType() {
return mapping;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// DomainResultProducer
@Override
public DomainResultProducer<T> getDomainResultProducer(
SqmToSqlAstConverter walker,
SqlAstCreationState sqlAstCreationState) {
return this;
public void accept(SqlAstWalker sqlTreeWalker) {
sqlExpression.accept( sqlTreeWalker );
}
@Override
@ -93,18 +101,6 @@ public class EmbeddableValuedPathInterpretation<T> implements AssignableSqmPathI
mapping.applySqlSelections( getNavigablePath(), tableGroup, creationState );
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// SqmPathInterpretation
@Override
public Expression toSqlExpression(
Clause clause,
SqmToSqlAstConverter walker,
SqlAstCreationState sqlAstCreationState) {
return mapping.toSqlExpression( tableGroup, clause, walker, sqlAstCreationState );
}
@Override
public void applySqlAssignments(
Expression newValueExpression,

View File

@ -1,34 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.query.sqm.sql.internal;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.query.sqm.SqmExpressable;
import org.hibernate.query.sqm.sql.SqlAstCreationState;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.tree.expression.Expression;
/**
* The interpretation of an SqmExpression as part of the SQM -> SQL conversion.
*
* Allows multi-column navigable references to be used anywhere a (SqlExpression)
* can be. The trick is to properly define methods on this interface for how the
* thing should be rendered into the SQL AST.
*
* @author Steve Ebersole
*/
public interface SqmExpressionInterpretation<T> extends SqmSelectableInterpretation<T> {
SqmExpressable<T> getExpressableType();
default Expression toSqlExpression(
Clause clause,
SqmToSqlAstConverter walker,
SqlAstCreationState sqlAstCreationState) {
throw new NotYetImplementedFor6Exception( getClass() );
}
}

View File

@ -9,13 +9,8 @@ package org.hibernate.query.sqm.sql.internal;
import java.util.List;
import org.hibernate.metamodel.mapping.MappingModelExpressable;
import org.hibernate.metamodel.model.domain.internal.DomainModelHelper;
import org.hibernate.query.SemanticException;
import org.hibernate.query.sqm.SqmExpressable;
import org.hibernate.query.sqm.sql.SqlAstCreationState;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.tree.expression.SqmParameter;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.spi.SqlAstWalker;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.exec.spi.JdbcParameter;
@ -23,44 +18,34 @@ import org.hibernate.sql.exec.spi.JdbcParameter;
/**
* @author Steve Ebersole
*/
public class SqmParameterInterpretation implements SqmExpressionInterpretation {
public class SqmParameterInterpretation implements Expression {
private final SqmParameter sqmParameter;
private final List<JdbcParameter> jdbcParameters;
private final MappingModelExpressable valueMapping;
private final Expression resolvedExpression;
public SqmParameterInterpretation(
SqmParameter sqmParameter,
List<JdbcParameter> jdbcParameters,
MappingModelExpressable valueMapping) {
this.sqmParameter = sqmParameter;
this.valueMapping = valueMapping;
assert jdbcParameters != null;
assert jdbcParameters.size() > 0;
this.sqmParameter = sqmParameter;
this.jdbcParameters = jdbcParameters;
this.resolvedExpression = jdbcParameters.size() == 1
? jdbcParameters.get( 0 )
: new SqlTuple( jdbcParameters, valueMapping );
}
@Override
public SqmExpressable getExpressableType() {
return sqmParameter.getExpressableType();
public void accept(SqlAstWalker sqlTreeWalker) {
resolvedExpression.accept( sqlTreeWalker );
}
@Override
public Expression toSqlExpression(
Clause clause,
SqmToSqlAstConverter walker,
SqlAstCreationState sqlAstCreationState) {
if ( jdbcParameters.size() == 1 ) {
return jdbcParameters.get( 0 );
}
return new SqlTuple( jdbcParameters, valueMapping );
}
@Override
public DomainResultProducer getDomainResultProducer(
SqmToSqlAstConverter walker,
SqlAstCreationState sqlAstCreationState) {
throw new SemanticException( "SqmParameter parameter cannot be a DomainResult" );
public MappingModelExpressable getExpressionType() {
return valueMapping;
}
}

View File

@ -6,68 +6,26 @@
*/
package org.hibernate.query.sqm.sql.internal;
import java.util.List;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.metamodel.model.domain.internal.BasicSqmPathSource;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.sqm.SqmPathSource;
import org.hibernate.query.sqm.sql.ConversionException;
import org.hibernate.query.sqm.sql.SqlAstCreationState;
import org.hibernate.query.sqm.tree.domain.SqmPath;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.sql.ast.tree.from.TableGroup;
/**
* todo (6.0) : consider having `SqmPathInterpretation` extend `org.hibernate.sql.ast.tree.expression.Expression`.
* - Basic paths would logically resolve to a `ColumnReference`
* - Composite and entity-valued paths would logically resolve to a `SqlTuple`
* Interpretation of a {@link SqmPath} as part of the translation to SQL AST
*
* @see org.hibernate.query.sqm.sql.SqmToSqlAstConverter
* @see #getInterpretedSqmPath
*
* @author Steve Ebersole
*/
public interface SqmPathInterpretation<T> extends SqmExpressionInterpretation<T> {
NavigablePath getNavigablePath();
@Override
default SqmPathSource<T> getExpressableType() {
return getSqmPathSource();
public interface SqmPathInterpretation<T> extends Expression, DomainResultProducer<T> {
default NavigablePath getNavigablePath() {
return getInterpretedSqmPath().getNavigablePath();
}
SqmPathSource<T> getSqmPathSource();
SqmPath<T> getInterpretedSqmPath();
// @Override
// default Expression toSqlExpression(SqlAstCreationState sqlAstCreationState) {
// throw new NotYetImplementedFor6Exception( getClass() );
// final TableGroup tableGroup;
//
// if ( getSqmPathSource() instanceof BasicSqmPathSource ) {
// // maybe we should register the LHS TableGroup for the basic value
// // under its NavigablePath, similar to what we do for embeddables
// tableGroup = sqlAstCreationState.getFromClauseAccess().findTableGroup( getNavigablePath().getParent() );
// }
// else {
// // for embeddable-, entity- and plural-valued Navigables we maybe do not have a TableGroup
// final TableGroup thisTableGroup = sqlAstCreationState.getFromClauseAccess().findTableGroup( getNavigablePath() );
// if ( thisTableGroup != null ) {
// tableGroup = thisTableGroup;
// }
// else {
// final NavigablePath lhsNavigablePath = getNavigablePath().getParent();
// if ( lhsNavigablePath == null ) {
// throw new ConversionException( "Could not find TableGroup to use - " + getNavigablePath().getFullPath() );
// }
// tableGroup = sqlAstCreationState.getFromClauseAccess().findTableGroup( lhsNavigablePath );
// }
// }
//
// sqlAstCreationState.getCreationContext().getDomainModel().resolveMappingExpressable( )
//
// final List list = getNavigable().resolveColumnReferences( tableGroup, sqlAstCreationState );
// if ( list.size() == 1 ) {
// assert list.get( 0 ) instanceof Expression;
// return (Expression) list.get( 0 );
// }
//
// return new SqlTuple( list, sqlAstCreationState.getJdbcMapping() );
// }
@Override
ModelPart getExpressionType();
}

View File

@ -13,7 +13,6 @@ import java.util.Locale;
import java.util.Map;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Supplier;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
@ -32,10 +31,6 @@ import org.hibernate.query.spi.QueryParameterBindings;
import org.hibernate.query.sqm.internal.DomainParameterXref;
import org.hibernate.query.sqm.sql.BaseSqmToSqlAstConverter;
import org.hibernate.query.sqm.sql.SqlAstCreationState;
import org.hibernate.query.sqm.tree.expression.JpaCriteriaParameter;
import org.hibernate.query.sqm.tree.expression.SqmJpaCriteriaParameterWrapper;
import org.hibernate.query.sqm.tree.expression.SqmParameter;
import org.hibernate.sql.results.internal.domain.instantiation.DynamicInstantiation;
import org.hibernate.query.sqm.tree.expression.SqmLiteralEntityType;
import org.hibernate.query.sqm.tree.from.SqmAttributeJoin;
import org.hibernate.query.sqm.tree.select.SqmDynamicInstantiation;
@ -53,6 +48,7 @@ import org.hibernate.sql.ast.tree.from.TableGroupJoin;
import org.hibernate.sql.ast.tree.from.TableGroupJoinProducer;
import org.hibernate.sql.ast.tree.select.QuerySpec;
import org.hibernate.sql.ast.tree.select.SelectStatement;
import org.hibernate.sql.results.internal.domain.instantiation.DynamicInstantiation;
import org.hibernate.sql.results.spi.CircularFetchDetector;
import org.hibernate.sql.results.spi.DomainResult;
import org.hibernate.sql.results.spi.DomainResultCreationState;
@ -141,8 +137,7 @@ public class SqmSelectToSqlAstConverter
}
private DomainResultProducer resolveDomainResultProducer(SqmSelection sqmSelection) {
SqmSelectableInterpretation<?> interpretation = (SqmSelectableInterpretation<?>) sqmSelection.getSelectableNode().accept( this );
return interpretation.getDomainResultProducer( this, getSqlAstCreationState() );
return (DomainResultProducer) sqmSelection.getSelectableNode().accept( this );
}
private int fetchDepth = 0;

View File

@ -1,20 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.query.sqm.sql.internal;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.query.sqm.sql.SqlAstCreationState;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
/**
* @author Steve Ebersole
*/
public interface SqmSelectableInterpretation<T> {
default DomainResultProducer<T> getDomainResultProducer(SqmToSqlAstConverter walker, SqlAstCreationState sqlAstCreationState) {
throw new NotYetImplementedFor6Exception( getClass() );
}
}

View File

@ -1,36 +0,0 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.query.sqm.sql.internal;
import org.hibernate.metamodel.model.domain.EmbeddableDomainType;
import org.hibernate.query.sqm.sql.ConversionException;
import org.hibernate.query.sqm.sql.SqlAstCreationState;
import org.hibernate.query.sqm.tree.domain.SqmPath;
import org.hibernate.sql.ast.tree.from.TableGroup;
/**
* @author Steve Ebersole
*/
@SuppressWarnings("WeakerAccess")
public class SqmSqlHelper {
private SqmSqlHelper() {
}
public static TableGroup resolveTableGroup(SqmPath<?> sqmPath, SqlAstCreationState creationState) {
SqmPath<?> lhs = sqmPath;
while ( lhs.getReferencedPathSource().getSqmPathType() instanceof EmbeddableDomainType ) {
lhs = lhs.getLhs();
}
final TableGroup tableGroup = creationState.getFromClauseAccess().findTableGroup( lhs.getNavigablePath() );
if ( tableGroup != null ) {
return tableGroup;
}
throw new ConversionException( "Could not locate TableGroup to use : " + lhs.getNavigablePath() );
}
}

View File

@ -0,0 +1,57 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.query.sqm.sql.internal;
import java.util.ArrayList;
import java.util.List;
import org.hibernate.metamodel.mapping.MappingModelExpressable;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.internal.SqmMappingModelHelper;
import org.hibernate.query.sqm.sql.SqlAstCreationState;
import org.hibernate.query.sqm.tree.expression.SqmExpression;
import org.hibernate.query.sqm.tree.expression.SqmTuple;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
/**
* @author Steve Ebersole
*/
public class SqmTupleInterpretation<T> extends SqlTuple {
public static <T> SqmTupleInterpretation<T> from(
SqmTuple<T> sqmTuple,
SemanticQueryWalker<?> walker,
SqlAstCreationState sqlAstCreationState) {
final List<Expression> groupedSqlExpressions = new ArrayList<>();
for ( SqmExpression<?> groupedExpression : sqmTuple.getGroupedExpressions() ) {
groupedSqlExpressions.add( (Expression) groupedExpression.accept( walker ) );
}
return new SqmTupleInterpretation<>(
sqmTuple,
groupedSqlExpressions,
SqmMappingModelHelper.resolveMappingModelExpressable( sqmTuple, sqlAstCreationState )
);
}
private final SqmTuple<T> interpretedSqmTuple;
public SqmTupleInterpretation(
SqmTuple<T> sqmTuple,
List<? extends Expression> expressions,
MappingModelExpressable valueMapping) {
super( expressions, valueMapping );
interpretedSqmTuple = sqmTuple;
}
public SqmTuple<T> getInterpretedSqmTuple() {
return interpretedSqmTuple;
}
}

View File

@ -31,11 +31,6 @@ public abstract class AbstractSqmExpression<T> extends AbstractJpaSelection<T> i
super( type, criteriaBuilder );
}
@Override
public SqmExpressable<T> getExpressableType() {
return getNodeType();
}
@Override
public final void applyInferableType(SqmExpressable<?> type) {
if ( type == null ) {

View File

@ -65,11 +65,6 @@ public class SqmEnumLiteral implements SqmExpression<Enum>, SqmExpressable<Enum>
return referencedEnumTypeDescriptor;
}
@Override
public SqmExpressable<Enum> getExpressableType() {
return expressable;
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// SemanticPathPart

View File

@ -16,7 +16,6 @@ import org.hibernate.metamodel.model.domain.AllowableFunctionReturnType;
import org.hibernate.metamodel.model.domain.DomainType;
import org.hibernate.query.criteria.JpaExpression;
import org.hibernate.query.sqm.SqmExpressable;
import org.hibernate.query.sqm.sql.internal.SqmExpressionInterpretation;
import org.hibernate.query.sqm.tree.predicate.SqmPredicate;
import org.hibernate.query.sqm.tree.select.SqmSelectableNode;
@ -29,7 +28,7 @@ import org.hibernate.query.sqm.tree.select.SqmSelectableNode;
*
* @author Steve Ebersole
*/
public interface SqmExpression<T> extends SqmSelectableNode<T>, JpaExpression<T>, SqmExpressionInterpretation<T> {
public interface SqmExpression<T> extends SqmSelectableNode<T>, JpaExpression<T> {
/**
* The expression's type.
*

View File

@ -77,11 +77,6 @@ public class SqmFieldLiteral<T> implements SqmExpression<T>, SqmExpressable<T>,
return value;
}
@Override
public SqmExpressable<T> getExpressableType() {
return expressable;
}
public JavaTypeDescriptor<T> getFieldJavaTypeDescriptor() {
return fieldJavaTypeDescriptor;
}

View File

@ -9,13 +9,7 @@ package org.hibernate.query.sqm.tree.expression;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmExpressable;
import org.hibernate.query.sqm.internal.SqmMappingModelHelper;
import org.hibernate.query.sqm.sql.SqlAstCreationState;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.QueryLiteral;
/**
* Represents a literal value in the sqm, e.g.<ul>
@ -46,18 +40,6 @@ public class SqmLiteral<T>
return walker.visitLiteral( this );
}
@Override
public Expression toSqlExpression(
Clause clause,
SqmToSqlAstConverter walker,
SqlAstCreationState sqlAstCreationState) {
return new QueryLiteral(
getLiteralValue(),
SqmMappingModelHelper.resolveMappingModelExpressable( this, sqlAstCreationState ),
clause
);
}
@Override
public String asLoggableText() {
return "Literal( " + value + ")";

View File

@ -6,7 +6,6 @@
*/
package org.hibernate.query.sqm.tree.expression;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@ -16,14 +15,7 @@ import org.hibernate.query.criteria.JpaSelection;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmExpressable;
import org.hibernate.query.sqm.sql.SqlAstCreationState;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
import org.hibernate.query.sqm.sql.internal.SqmExpressionInterpretation;
import org.hibernate.query.sqm.tree.select.SqmJpaCompoundSelection;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.ast.tree.expression.SqlTuple;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/**
@ -38,7 +30,7 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
*/
public class SqmTuple<T>
extends AbstractSqmExpression<T>
implements JpaCompoundSelection<T>, SqmExpressionInterpretation<T> {
implements JpaCompoundSelection<T> {
private final List<SqmExpression<?>> groupedExpressions;
public SqmTuple(NodeBuilder nodeBuilder, SqmExpression<?>... groupedExpressions) {
@ -63,6 +55,10 @@ public class SqmTuple<T>
applyInferableType( type );
}
public List<SqmExpression<?>> getGroupedExpressions() {
return groupedExpressions;
}
@Override
public SqmExpressable<T> getNodeType() {
final SqmExpressable<T> expressableType = super.getNodeType();
@ -86,37 +82,6 @@ public class SqmTuple<T>
return walker.visitTuple( this );
}
@Override
public Expression toSqlExpression(
Clause clause,
SqmToSqlAstConverter walker,
SqlAstCreationState sqlAstCreationState) {
final List<Expression> groupedSqlExpressions = new ArrayList<>();
for ( SqmExpression groupedExpression : groupedExpressions ) {
final SqmExpressionInterpretation interpretation = (SqmExpressionInterpretation) groupedExpression.accept( walker );
final Expression sqlExpression = interpretation.toSqlExpression(
clause, walker,
sqlAstCreationState
);
groupedSqlExpressions.add( sqlExpression );
}
return new SqlTuple(
groupedSqlExpressions,
sqlAstCreationState.getCreationContext().getDomainModel()
.resolveMappingExpressable( getExpressableType() )
);
}
@Override
public DomainResultProducer getDomainResultProducer(
SqmToSqlAstConverter walker,
SqlAstCreationState sqlAstCreationState) {
return null;
}
@Override
public String asLoggableText() {
return toString();
@ -134,7 +99,7 @@ public class SqmTuple<T>
@Override
public List<? extends JpaSelection<?>> getSelectionItems() {
return groupedExpressions;
return getGroupedExpressions();
}
}

View File

@ -8,7 +8,6 @@ package org.hibernate.query.sqm.tree.from;
import java.util.function.Consumer;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.model.domain.EntityDomainType;
import org.hibernate.persister.entity.EntityPersister;
@ -16,15 +15,12 @@ import org.hibernate.query.PathException;
import org.hibernate.query.criteria.JpaRoot;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.sql.SqlAstCreationState;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
import org.hibernate.query.sqm.tree.domain.AbstractSqmFrom;
import org.hibernate.query.sqm.tree.domain.SqmPath;
import org.hibernate.query.sqm.tree.domain.SqmTreatedPath;
import org.hibernate.query.sqm.tree.domain.SqmTreatedRoot;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.sql.results.spi.DomainResult;
import org.hibernate.sql.results.spi.DomainResultCreationState;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
@ -102,20 +98,6 @@ public class SqmRoot<E> extends AbstractSqmFrom<E,E> implements JpaRoot<E>, Doma
return new SqmTreatedRoot<>( this, treatTarget, nodeBuilder() );
}
@Override
public DomainResultProducer<E> getDomainResultProducer(
SqmToSqlAstConverter walker,
SqlAstCreationState sqlAstCreationState) {
return this;
}
@Override
public Expression toSqlExpression(
Clause clause, SqmToSqlAstConverter walker,
SqlAstCreationState sqlAstCreationState) {
throw new NotYetImplementedFor6Exception( getClass() );
}
@Override
public void visitJdbcTypes(Consumer<JdbcMapping> action, TypeConfiguration typeConfiguration) {
final String entityName = getReferencedPathSource().getHibernateEntityName();

View File

@ -9,12 +9,7 @@ package org.hibernate.query.sqm.tree.select;
import java.util.function.Consumer;
import javax.persistence.criteria.Selection;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.query.criteria.JpaSelection;
import org.hibernate.query.sqm.sql.SqlAstCreationState;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
import org.hibernate.query.sqm.sql.internal.SqmSelectableInterpretation;
import org.hibernate.query.sqm.tree.SqmTypedNode;
import org.hibernate.query.sqm.tree.SqmVisitableNode;
@ -24,7 +19,7 @@ import org.hibernate.query.sqm.tree.SqmVisitableNode;
*
* @author Steve Ebersole
*/
public interface SqmSelectableNode<T> extends JpaSelection<T>, SqmTypedNode<T>, SqmVisitableNode, SqmSelectableInterpretation<T> {
public interface SqmSelectableNode<T> extends JpaSelection<T>, SqmTypedNode<T>, SqmVisitableNode {
/**
* Visit each of this selectable's direct sub-selectables - used to
* support JPA's {@link Selection} model (which is really a "selectable",
@ -34,8 +29,4 @@ public interface SqmSelectableNode<T> extends JpaSelection<T>, SqmTypedNode<T>,
* @see Selection#getCompoundSelectionItems()
*/
void visitSubSelectableNodes(Consumer<SqmSelectableNode<?>> jpaSelectionConsumer);
default DomainResultProducer<T> getDomainResultProducer(SqmToSqlAstConverter walker, SqlAstCreationState sqlAstCreationState) {
throw new NotYetImplementedFor6Exception( getClass() );
}
}

View File

@ -25,8 +25,8 @@ import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.query.criteria.JpaSelection;
import org.hibernate.query.criteria.JpaSubQuery;
import org.hibernate.query.sqm.NodeBuilder;
import org.hibernate.query.sqm.SqmExpressable;
import org.hibernate.query.sqm.SemanticQueryWalker;
import org.hibernate.query.sqm.SqmExpressable;
import org.hibernate.query.sqm.tree.SqmQuery;
import org.hibernate.query.sqm.tree.domain.SqmBagJoin;
import org.hibernate.query.sqm.tree.domain.SqmListJoin;
@ -72,11 +72,6 @@ public class SqmSubQuery<T> extends AbstractSqmSelectQuery<T> implements SqmSele
this.parent = parent;
}
@Override
public SqmExpressable<T> getExpressableType() {
return expressableType;
}
@Override
public SqmQuery<?> getContainingQuery() {
return parent;

View File

@ -22,5 +22,7 @@ import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
* @author Steve Ebersole
*/
public interface JdbcLiteralFormatter<T> {
String NULL = "null";
String toJdbcLiteral(T value, Dialect dialect, SharedSessionContractImplementor session);
}

View File

@ -8,17 +8,24 @@ package org.hibernate.sql.ast.tree.expression;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.util.function.Consumer;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.metamodel.mapping.MappingModelExpressable;
import org.hibernate.metamodel.mapping.BasicValuedMapping;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.query.sqm.sql.SqlExpressionResolver;
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.exec.spi.ExecutionContext;
import org.hibernate.sql.exec.spi.JdbcParameterBinder;
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
import org.hibernate.sql.results.internal.SqlSelectionImpl;
import org.hibernate.sql.results.internal.domain.basic.BasicResult;
import org.hibernate.sql.results.spi.DomainResult;
import org.hibernate.sql.results.spi.DomainResultCreationState;
import org.hibernate.type.BasicType;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.spi.TypeConfiguration;
/**
* We classify literals different based on their source so that we can handle then differently
@ -31,10 +38,10 @@ import org.hibernate.type.BasicType;
public abstract class AbstractLiteral<T>
implements JdbcParameterBinder, Expression, DomainResultProducer<T> {
private final Object value;
private final MappingModelExpressable type;
private final BasicValuedMapping type;
private final Clause clause;
public AbstractLiteral(Object value, MappingModelExpressable type, Clause clause) {
public AbstractLiteral(Object value, BasicValuedMapping type, Clause clause) {
this.value = value;
this.type = type;
this.clause = clause;
@ -49,15 +56,51 @@ public abstract class AbstractLiteral<T>
}
@Override
public MappingModelExpressable getExpressionType() {
public BasicValuedMapping getExpressionType() {
return type;
}
@Override
public DomainResult createDomainResult(
public DomainResult<T> createDomainResult(
String resultVariable,
DomainResultCreationState creationState) {
throw new NotYetImplementedFor6Exception( getClass() );
final SqlExpressionResolver sqlExpressionResolver = creationState.getSqlAstCreationState().getSqlExpressionResolver();
final SqlSelection sqlSelection = sqlExpressionResolver.resolveSqlSelection(
this,
type.getMappedTypeDescriptor().getMappedJavaTypeDescriptor(),
creationState.getSqlAstCreationState()
.getCreationContext()
.getSessionFactory()
.getTypeConfiguration()
);
//noinspection unchecked
return new BasicResult<>(
sqlSelection.getJdbcResultSetIndex(),
resultVariable,
type.getMappedTypeDescriptor().getMappedJavaTypeDescriptor()
);
}
@Override
public SqlSelection createSqlSelection(
int jdbcPosition,
int valuesArrayPosition,
JavaTypeDescriptor javaTypeDescriptor,
TypeConfiguration typeConfiguration) {
return new SqlSelectionImpl(
jdbcPosition,
valuesArrayPosition,
this,
type.getJdbcMapping()
);
}
@Override
public void visitJdbcTypes(
Consumer<JdbcMapping> action,
TypeConfiguration typeConfiguration) {
action.accept( type.getJdbcMapping() );
}
@Override

View File

@ -6,7 +6,7 @@
*/
package org.hibernate.sql.ast.tree.expression;
import org.hibernate.metamodel.mapping.MappingModelExpressable;
import org.hibernate.metamodel.mapping.BasicValuedMapping;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.spi.SqlAstWalker;
@ -16,7 +16,7 @@ import org.hibernate.sql.ast.spi.SqlAstWalker;
* @author Steve Ebersole
*/
public class QueryLiteral<T> extends AbstractLiteral<T> {
public QueryLiteral(Object value, MappingModelExpressable expressableType, Clause clause) {
public QueryLiteral(Object value, BasicValuedMapping expressableType, Clause clause) {
super( value, expressableType, clause );
}

View File

@ -12,9 +12,6 @@ import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.sqm.sql.SqlAstCreationState;
import org.hibernate.query.sqm.sql.SqmToSqlAstConverter;
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.spi.SqlAstWalker;
@ -77,10 +74,4 @@ public class StandardTableGroup extends AbstractTableGroup {
public List<TableReferenceJoin> getTableReferenceJoins() {
return tableJoins;
}
@Override
public DomainResultProducer getDomainResultProducer(
SqmToSqlAstConverter walker, SqlAstCreationState sqlAstCreationState) {
return this;
}
}

View File

@ -11,11 +11,9 @@ import java.util.Set;
import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.metamodel.mapping.ModelPartContainer;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
import org.hibernate.query.sqm.sql.internal.SqmSelectableInterpretation;
import org.hibernate.sql.ast.spi.SqlAppender;
import org.hibernate.sql.ast.spi.SqlAstWalker;
import org.hibernate.sql.ast.tree.SqlAstNode;
@ -30,7 +28,7 @@ import org.hibernate.sql.results.spi.DomainResultCreationState;
* @author Steve Ebersole
*/
public interface TableGroup
extends SqlAstNode, ColumnReferenceQualifier, DomainResultProducer, SqmSelectableInterpretation {
extends SqlAstNode, ColumnReferenceQualifier, DomainResultProducer {
NavigablePath getNavigablePath();
ModelPartContainer getModelPart();

View File

@ -37,6 +37,10 @@ public class ArgumentDomainResult<A> implements DomainResult<A> {
public ArgumentReader<A> createResultAssembler(
Consumer<Initializer> initializerCollector,
AssemblerCreationState creationState) {
return null;
//noinspection unchecked
return new ArgumentReader(
realDomainResult.createResultAssembler( initializerCollector, creationState ),
getResultVariable()
);
}
}

View File

@ -6,20 +6,15 @@
*/
package org.hibernate.sql.results.internal.domain.instantiation;
import java.lang.reflect.Constructor;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.query.DynamicInstantiationNature;
import org.hibernate.query.sqm.sql.ConversionException;
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
import org.hibernate.query.sqm.tree.expression.Compatibility;
import org.hibernate.sql.results.spi.AssemblerCreationState;
import org.hibernate.sql.results.spi.DomainResult;
import org.hibernate.sql.results.spi.DomainResultAssembler;
import org.hibernate.sql.results.spi.DomainResultCreationState;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
@ -116,131 +111,124 @@ public class DynamicInstantiation<T> implements DomainResultProducer {
public DomainResult createDomainResult(
String resultVariable,
DomainResultCreationState creationState) {
throw new NotYetImplementedFor6Exception( getClass() );
//noinspection unchecked
return new DynamicInstantiationResultImpl(
resultVariable,
getNature(),
getTargetJavaTypeDescriptor(),
getArguments().stream()
.map( argument -> argument.buildArgumentDomainResult( creationState ) )
.collect( Collectors.toList() )
);
}
// @Override
//
// @SuppressWarnings("unchecked")
// public DomainResult createDomainResult(
// String resultVariable,
// DomainResultCreationState creationState) {
// return new DynamicInstantiationResult(
// resultVariable,
// getNature(),
// (JavaTypeDescriptor) getTargetJavaTypeDescriptor(),
// getArguments().stream()
// .map( argument -> argument.buildArgumentDomainResult( creationState ) )
// .collect( Collectors.toList() )
// );
// private static DomainResultAssembler resolveAssembler(
// DynamicInstantiation dynamicInstantiation,
// boolean areAllArgumentsAliased,
// boolean areAnyArgumentsAliased,
// List<String> duplicatedAliases,
// List<ArgumentReader<?>> argumentReaders,
// AssemblerCreationState creationState) {
//
// if ( dynamicInstantiation.getNature() == DynamicInstantiationNature.LIST ) {
// if ( log.isDebugEnabled() && areAnyArgumentsAliased ) {
// log.debug( "One or more arguments for List dynamic instantiation (`new list(...)`) specified an alias; ignoring" );
// }
// return new DynamicInstantiationListAssemblerImpl(
// (JavaTypeDescriptor<List>) dynamicInstantiation.getTargetJavaTypeDescriptor(),
// argumentReaders
// );
// }
// else if ( dynamicInstantiation.getNature() == DynamicInstantiationNature.MAP ) {
// if ( ! areAllArgumentsAliased ) {
// throw new IllegalStateException( "Map dynamic instantiation contained one or more arguments with no alias" );
// }
// if ( !duplicatedAliases.isEmpty() ) {
// throw new IllegalStateException(
// "Map dynamic instantiation contained arguments with duplicated aliases [" + StringHelper.join( ",", duplicatedAliases ) + "]"
// );
// }
// return new DynamicInstantiationMapAssemblerImpl(
// (JavaTypeDescriptor<Map>) dynamicInstantiation.getTargetJavaTypeDescriptor(),
// argumentReaders
// );
// }
// else {
// // find a constructor matching argument types
// constructor_loop:
// for ( Constructor constructor : dynamicInstantiation.getTargetJavaTypeDescriptor().getJavaType().getDeclaredConstructors() ) {
// if ( constructor.getParameterTypes().length != dynamicInstantiation.arguments.size() ) {
// continue;
// }
//
// for ( int i = 0; i < dynamicInstantiation.arguments.size(); i++ ) {
// final ArgumentReader argumentReader = argumentReaders.get( i );
// final JavaTypeDescriptor argumentTypeDescriptor = creationState.getSqlAstCreationContext().getDomainModel()
// .getTypeConfiguration()
// .getJavaTypeDescriptorRegistry()
// .resolveDescriptor( constructor.getParameterTypes()[i] );
//
// final boolean assignmentCompatible = Compatibility.areAssignmentCompatible(
// argumentTypeDescriptor,
// argumentReader.getAssembledJavaTypeDescriptor()
// );
// if ( !assignmentCompatible ) {
// log.debugf(
// "Skipping constructor for dynamic-instantiation match due to argument mismatch [%s] : %s -> %s",
// i,
// constructor.getParameterTypes()[i].getName(),
// argumentTypeDescriptor.getJavaType().getName()
// );
// continue constructor_loop;
// }
// }
//
// constructor.setAccessible( true );
// return new DynamicInstantiationConstructorAssemblerImpl(
// constructor,
// dynamicInstantiation.getTargetJavaTypeDescriptor(),
// argumentReaders
// );
// }
//
// log.debugf(
// "Could not locate appropriate constructor for dynamic instantiation of [%s]; attempting bean-injection instantiation",
// dynamicInstantiation.getTargetJavaTypeDescriptor().getJavaType().getName()
// );
//
//
// if ( ! areAllArgumentsAliased ) {
// throw new IllegalStateException(
// "Could not determine appropriate instantiation strategy - no matching constructor found and one or more arguments did not define alias for bean-injection"
// );
// }
// if ( !duplicatedAliases.isEmpty() ) {
// throw new IllegalStateException(
// "Could not determine appropriate instantiation strategy - no matching constructor found and arguments defined duplicated aliases [" +
// StringHelper.join( ",", duplicatedAliases ) + "] for bean-injection"
// );
// }
//
// return new DynamicInstantiationInjectionAssemblerImpl(
// dynamicInstantiation.getTargetJavaTypeDescriptor(),
// argumentReaders
// );
// }
// }
//
@SuppressWarnings("unchecked")
private static DomainResultAssembler resolveAssembler(
DynamicInstantiation dynamicInstantiation,
boolean areAllArgumentsAliased,
boolean areAnyArgumentsAliased,
List<String> duplicatedAliases,
List<ArgumentReader<?>> argumentReaders,
AssemblerCreationState creationState) {
if ( dynamicInstantiation.getNature() == DynamicInstantiationNature.LIST ) {
if ( log.isDebugEnabled() && areAnyArgumentsAliased ) {
log.debug( "One or more arguments for List dynamic instantiation (`new list(...)`) specified an alias; ignoring" );
}
return new DynamicInstantiationListAssemblerImpl(
(JavaTypeDescriptor<List>) dynamicInstantiation.getTargetJavaTypeDescriptor(),
argumentReaders
);
}
else if ( dynamicInstantiation.getNature() == DynamicInstantiationNature.MAP ) {
if ( ! areAllArgumentsAliased ) {
throw new IllegalStateException( "Map dynamic instantiation contained one or more arguments with no alias" );
}
if ( !duplicatedAliases.isEmpty() ) {
throw new IllegalStateException(
"Map dynamic instantiation contained arguments with duplicated aliases [" + StringHelper.join( ",", duplicatedAliases ) + "]"
);
}
return new DynamicInstantiationMapAssemblerImpl(
(JavaTypeDescriptor<Map>) dynamicInstantiation.getTargetJavaTypeDescriptor(),
argumentReaders
);
}
else {
// find a constructor matching argument types
constructor_loop:
for ( Constructor constructor : dynamicInstantiation.getTargetJavaTypeDescriptor().getJavaType().getDeclaredConstructors() ) {
if ( constructor.getParameterTypes().length != dynamicInstantiation.arguments.size() ) {
continue;
}
for ( int i = 0; i < dynamicInstantiation.arguments.size(); i++ ) {
final ArgumentReader argumentReader = argumentReaders.get( i );
final JavaTypeDescriptor argumentTypeDescriptor = creationState.getSqlAstCreationContext().getDomainModel()
.getTypeConfiguration()
.getJavaTypeDescriptorRegistry()
.resolveDescriptor( constructor.getParameterTypes()[i] );
final boolean assignmentCompatible = Compatibility.areAssignmentCompatible(
argumentTypeDescriptor,
argumentReader.getAssembledJavaTypeDescriptor()
);
if ( !assignmentCompatible ) {
log.debugf(
"Skipping constructor for dynamic-instantiation match due to argument mismatch [%s] : %s -> %s",
i,
constructor.getParameterTypes()[i].getName(),
argumentTypeDescriptor.getJavaType().getName()
);
continue constructor_loop;
}
}
constructor.setAccessible( true );
return new DynamicInstantiationConstructorAssemblerImpl(
constructor,
dynamicInstantiation.getTargetJavaTypeDescriptor(),
argumentReaders
);
}
log.debugf(
"Could not locate appropriate constructor for dynamic instantiation of [%s]; attempting bean-injection instantiation",
dynamicInstantiation.getTargetJavaTypeDescriptor().getJavaType().getName()
);
if ( ! areAllArgumentsAliased ) {
throw new IllegalStateException(
"Could not determine appropriate instantiation strategy - no matching constructor found and one or more arguments did not define alias for bean-injection"
);
}
if ( !duplicatedAliases.isEmpty() ) {
throw new IllegalStateException(
"Could not determine appropriate instantiation strategy - no matching constructor found and arguments defined duplicated aliases [" +
StringHelper.join( ",", duplicatedAliases ) + "] for bean-injection"
);
}
return new DynamicInstantiationInjectionAssemblerImpl(
dynamicInstantiation.getTargetJavaTypeDescriptor(),
argumentReaders
);
}
}
class Builder {
private final DynamicInstantiationNature nature;
private final JavaTypeDescriptor<T> targetJavaTypeDescriptor;
private List<DynamicInstantiationArgument> arguments;
public Builder(
DynamicInstantiationNature nature,
JavaTypeDescriptor<T> targetJavaTypeDescriptor) {
this.nature = nature;
this.targetJavaTypeDescriptor = targetJavaTypeDescriptor;
}
}
// class Builder {
// private final DynamicInstantiationNature nature;
// private final JavaTypeDescriptor<T> targetJavaTypeDescriptor;
// private List<DynamicInstantiationArgument> arguments;
//
// public Builder(
// DynamicInstantiationNature nature,
// JavaTypeDescriptor<T> targetJavaTypeDescriptor) {
// this.nature = nature;
// this.targetJavaTypeDescriptor = targetJavaTypeDescriptor;
// }
//
//
// }
}

View File

@ -12,11 +12,14 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import org.hibernate.sql.ast.spi.JdbcLiteralFormatter;
import org.hibernate.type.descriptor.ValueBinder;
import org.hibernate.type.descriptor.ValueExtractor;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import static org.hibernate.sql.ast.spi.JdbcLiteralFormatter.NULL;
/**
* Descriptor for {@link Types#NVARCHAR NVARCHAR} handling.
*
@ -38,6 +41,11 @@ public class NVarcharTypeDescriptor implements SqlTypeDescriptor {
return true;
}
@Override
public <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaTypeDescriptor<T> javaTypeDescriptor) {
return (value, dialect, session) -> value == null ? NULL : "'" + value.toString() + "'";
}
@Override
public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
return new BasicBinder<X>( javaTypeDescriptor, this ) {

View File

@ -12,11 +12,14 @@ import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import org.hibernate.sql.ast.spi.JdbcLiteralFormatter;
import org.hibernate.type.descriptor.ValueBinder;
import org.hibernate.type.descriptor.ValueExtractor;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import static org.hibernate.sql.ast.spi.JdbcLiteralFormatter.NULL;
/**
* Descriptor for {@link Types#VARCHAR VARCHAR} handling.
*
@ -38,6 +41,11 @@ public class VarcharTypeDescriptor implements SqlTypeDescriptor {
return true;
}
@Override
public <T> JdbcLiteralFormatter<T> getJdbcLiteralFormatter(JavaTypeDescriptor<T> javaTypeDescriptor) {
return (value, dialect, session) -> value == null ? NULL : "'" + value.toString() + "'";
}
@Override
public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
return new BasicBinder<X>( javaTypeDescriptor, this ) {

View File

@ -163,6 +163,14 @@ public class SmokeTests {
private String attribute1;
private String attribute2;
public Component() {
}
public Component(String attribute1, String attribute2) {
this.attribute1 = attribute1;
this.attribute2 = attribute2;
}
public String getAttribute1() {
return attribute1;
}

View File

@ -125,15 +125,6 @@ public class SmokeTests {
);
}
@Test
public void testSimpleHqlExecution(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
final QueryImplementor<String> query = session.createQuery( "select e.name from SimpleEntity e", String.class );
query.list();
}
);
}
@Test
public void testConvertedHqlInterpretation(SessionFactoryScope scope) {
scope.inTransaction(
@ -232,46 +223,6 @@ public class SmokeTests {
);
}
@Test
public void testConvertedHqlExecution(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
final QueryImplementor<Gender> query = session.createQuery( "select e.gender from SimpleEntity e", Gender.class );
query.list();
}
);
}
@Test
public void testSelectRootHqlExecution(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
final QueryImplementor<SimpleEntity> query = session.createQuery( "select e from SimpleEntity e", SimpleEntity.class );
query.list();
}
);
}
@Test
public void testSelectEmbeddedHqlExecution(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
final QueryImplementor<Component> query = session.createQuery( "select e.component from SimpleEntity e", Component.class );
query.list();
}
);
}
@Test
public void testSelectEmbeddableSubPathHqlExecution(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
final QueryImplementor<String> query = session.createQuery( "select e.component.attribute1 from SimpleEntity e", String.class );
query.list();
}
);
}
@Test
public void testBadQueryResultType(SessionFactoryScope scope) {
scope.inTransaction(

View File

@ -10,8 +10,10 @@ import java.sql.Statement;
import java.util.List;
import org.hibernate.cfg.AvailableSettings;
import org.hibernate.orm.test.metamodel.mapping.SmokeTests.Component;
import org.hibernate.orm.test.metamodel.mapping.SmokeTests.SimpleEntity;
import org.hibernate.orm.test.metamodel.mapping.SmokeTests.Gender;
import org.hibernate.query.Query;
import org.hibernate.query.spi.QueryImplementor;
import org.hibernate.testing.orm.junit.DomainModel;
@ -24,6 +26,7 @@ import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hibernate.orm.test.metamodel.mapping.SmokeTests.Gender.FEMALE;
import static org.hibernate.orm.test.metamodel.mapping.SmokeTests.Gender.MALE;
@ -33,13 +36,21 @@ import static org.hibernate.orm.test.metamodel.mapping.SmokeTests.Gender.MALE;
* @author Steve Ebersole
*/
@DomainModel(
annotatedClasses = SimpleEntity.class
annotatedClasses = SimpleEntity.class,
extraQueryImportClasses = {
SmokeTests.ListItemDto.class,
SmokeTests.CategorizedListItemDto.class,
SmokeTests.CompoundDto.class,
SmokeTests.BasicSetterBasedDto.class
}
)
@ServiceRegistry(
settings = @ServiceRegistry.Setting(
name = AvailableSettings.HBM2DDL_AUTO,
value = "create-drop"
)
settings = {
@ServiceRegistry.Setting(
name = AvailableSettings.HBM2DDL_AUTO,
value = "create-drop"
)
}
)
@SessionFactory
public class SmokeTests {
@ -53,6 +64,7 @@ public class SmokeTests {
simpleEntity.setGender( FEMALE );
simpleEntity.setName( "Fab" );
simpleEntity.setGender2( MALE );
simpleEntity.setComponent( new Component( "a1", "a2" ) );
session.save( simpleEntity );
}
);
@ -73,7 +85,7 @@ public class SmokeTests {
}
@Test
public void testSelectEntityFieldHqlExecution(SessionFactoryScope scope) {
public void testHqlSelectEntityBasicAttribute(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
final QueryImplementor<String> query = session.createQuery(
@ -88,7 +100,7 @@ public class SmokeTests {
}
@Test
public void testSelectGenderHql(SessionFactoryScope scope) {
public void testHqlSelectConvertedAttribute(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
final QueryImplementor<Gender> query = session.createQuery(
@ -103,7 +115,7 @@ public class SmokeTests {
}
@Test
public void testSelectEntityHqlExecution(SessionFactoryScope scope) {
public void testHqlSelectRootEntity(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
final QueryImplementor<SimpleEntity> query = session.createQuery(
@ -117,6 +129,168 @@ public class SmokeTests {
assertThat( simpleEntity.getGender(), is(FEMALE) );
assertThat( simpleEntity.getGender2(), is(MALE) );
assertThat( simpleEntity.getName(), is("Fab") );
assertThat( simpleEntity.getComponent(), notNullValue() );
assertThat( simpleEntity.getComponent().getAttribute1(), is( "a1" ) );
assertThat( simpleEntity.getComponent().getAttribute2(), is( "a2" ) );
}
);
}
@Test
public void testHqlSelectEmbeddedAttribute(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
final QueryImplementor<Component> query = session.createQuery( "select e.component from SimpleEntity e", Component.class );
final Component component = query.uniqueResult();
assertThat( component, notNullValue() );
assertThat( component.getAttribute1(), is( "a1" ) );
assertThat( component.getAttribute2(), is( "a2" ) );
}
);
}
@Test
public void testHqlSelectEmbeddableSubAttribute(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
final QueryImplementor<String> query = session.createQuery( "select e.component.attribute1 from SimpleEntity e", String.class );
final String attribute1 = query.uniqueResult();
assertThat( attribute1, is( "a1" ) );
}
);
}
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Dynamic instantiations
public static class ListItemDto {
private String code;
private String value;
public ListItemDto(String code, String value) {
this.code = code;
this.value = value;
}
}
public static class CategorizedListItemDto {
private ListItemDto category;
private String code;
private String value;
public CategorizedListItemDto(ListItemDto category, String code, String value) {
this.category = category;
this.code = code;
this.value = value;
}
}
public static class CompoundDto {
private ListItemDto first;
private ListItemDto second;
public CompoundDto(ListItemDto first, ListItemDto second) {
this.first = first;
this.second = second;
}
}
public static class BasicSetterBasedDto {
private String code;
private String value;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
}
@Test
public void testHqlBasicDynamicInstantiation(SessionFactoryScope scope) {
scope.getSessionFactory().inTransaction(
session -> {
final Query<ListItemDto> query = session.createQuery(
"select new ListItemDto( e.component.attribute1, e.name ) from SimpleEntity e",
ListItemDto.class
);
final ListItemDto dto = query.getSingleResult();
assertThat( dto, notNullValue() );
assertThat( dto.code, is( "a1" ) );
assertThat( dto.value, is( "Fab" ) );
}
);
}
@Test
public void testHqlNestedDynamicInstantiation(SessionFactoryScope scope) {
scope.getSessionFactory().inTransaction(
session -> {
final Query<CategorizedListItemDto> query = session.createQuery(
"select new CategorizedListItemDto( new ListItemDto( e.component.attribute2, e.component.attribute1 ), e.component.attribute1, e.name ) from SimpleEntity e",
CategorizedListItemDto.class
);
final CategorizedListItemDto dto = query.getSingleResult();
assertThat( dto, notNullValue() );
assertThat( dto.category, notNullValue() );
assertThat( dto.category.code, is( "a2") );
assertThat( dto.category.value, is( "a1") );
assertThat( dto.code, is( "a1" ) );
assertThat( dto.value, is( "Fab" ) );
}
);
}
@Test
public void testHqlMultipleDynamicInstantiation(SessionFactoryScope scope) {
scope.getSessionFactory().inTransaction(
session -> {
final Query<CompoundDto> query = session.createQuery(
"select new CompoundDto( new ListItemDto( e.component.attribute1, e.name ), new ListItemDto( e.component.attribute2, e.name ) ) from SimpleEntity e",
CompoundDto.class
);
final CompoundDto dto = query.getSingleResult();
assertThat( dto, notNullValue() );
assertThat( dto.first, notNullValue() );
assertThat( dto.first.code, is( "a1" ) );
assertThat( dto.first.value, is( "Fab" ) );
assertThat( dto.second, notNullValue() );
assertThat( dto.second.code, is( "a2" ) );
assertThat( dto.second.value, is( "Fab" ) );
}
);
}
@Test
public void testBasicSetterDynamicInstantiation(SessionFactoryScope scope) {
scope.getSessionFactory().inTransaction(
session -> {
final Query<BasicSetterBasedDto> query = session.createQuery(
"select new BasicSetterBasedDto( e.component.attribute1 as code, e.name as value ) from SimpleEntity e",
BasicSetterBasedDto.class
);
final BasicSetterBasedDto dto = query.getSingleResult();
assertThat( dto, notNullValue() );
assertThat( dto.code, is( "a1" ) );
assertThat( dto.value, is( "Fab" ) );
}
);
}

View File

@ -93,4 +93,11 @@ public @interface DomainModel {
Class[] annotatedClasses() default {};
String[] annotatedClassNames() default {};
String[] xmlMappings() default {};
ExtraQueryImport[] extraQueryImports() default {};
Class<?>[] extraQueryImportClasses() default {};
@interface ExtraQueryImport {
String name();
Class<?> importedClass();
}
}

View File

@ -95,6 +95,14 @@ public class DomainModelExtension
metadataSources.addResource( xmlMapping );
}
for ( DomainModel.ExtraQueryImport extraQueryImport : domainModelAnnotation.extraQueryImports() ) {
metadataSources.addQueryImport( extraQueryImport.name(), extraQueryImport.importedClass() );
}
for ( Class<?> importedClass : domainModelAnnotation.extraQueryImportClasses() ) {
metadataSources.addQueryImport( importedClass.getSimpleName(), importedClass );
}
return (MetadataImplementor) metadataSources.buildMetadata();
};
}