ResultSet mapping

Split handling of result / fetch builders created from:
    complete:: Cases where we completely know the builder graph up-front
    dynamic:: Cases where the builder graph is generated at runtime
This commit is contained in:
Steve Ebersole 2020-08-07 16:40:57 -05:00
parent 283c3fefb5
commit b1e8f64bda
88 changed files with 3023 additions and 1019 deletions

View File

@ -0,0 +1,24 @@
/*
* 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.annotations;
import javax.persistence.AttributeConverter;
/**
* @author Steve Ebersole
*/
public class NoAttributeConverter<O,R> implements AttributeConverter<O,R> {
@Override
public R convertToDatabaseColumn(Object attribute) {
throw new UnsupportedOperationException();
}
@Override
public O convertToEntityAttribute(Object dbData) {
throw new UnsupportedOperationException();
}
}

View File

@ -17,7 +17,7 @@
import org.hibernate.boot.query.NamedHqlQueryDefinition;
import org.hibernate.boot.query.NamedNativeQueryDefinition;
import org.hibernate.boot.query.NamedProcedureCallDefinition;
import org.hibernate.boot.query.NamedResultSetMappingDefinition;
import org.hibernate.boot.query.NamedResultSetMappingDescriptor;
import org.hibernate.cfg.annotations.NamedEntityGraphDefinition;
import org.hibernate.engine.spi.FilterDefinition;
import org.hibernate.engine.spi.Mapping;
@ -147,12 +147,12 @@ public interface Metadata extends Mapping {
*
* @return The named result set mapping metadata, or {@code null} if none found.
*/
NamedResultSetMappingDefinition getResultSetMapping(String name);
NamedResultSetMappingDescriptor getResultSetMapping(String name);
/**
* Visit all named SQL result set mapping definitions
*/
void visitNamedResultSetMappingDefinition(Consumer<NamedResultSetMappingDefinition> definitionConsumer);
void visitNamedResultSetMappingDefinition(Consumer<NamedResultSetMappingDescriptor> definitionConsumer);
/**
* Retrieve a type definition by name.

View File

@ -61,7 +61,7 @@
import org.hibernate.boot.query.NamedHqlQueryDefinition;
import org.hibernate.boot.query.NamedNativeQueryDefinition;
import org.hibernate.boot.query.NamedProcedureCallDefinition;
import org.hibernate.boot.query.NamedResultSetMappingDefinition;
import org.hibernate.boot.query.NamedResultSetMappingDescriptor;
import org.hibernate.boot.spi.NaturalIdUniqueKeyBinder;
import org.hibernate.cfg.AnnotatedClassType;
import org.hibernate.cfg.AvailableSettings;
@ -142,7 +142,7 @@ public class InFlightMetadataCollectorImpl implements InFlightMetadataCollector
private final Map<String, NamedHqlQueryDefinition> namedQueryMap = new HashMap<>();
private final Map<String, NamedNativeQueryDefinition> namedNativeQueryMap = new HashMap<>();
private final Map<String, NamedProcedureCallDefinition> namedProcedureCallMap = new HashMap<>();
private final Map<String, NamedResultSetMappingDefinition> sqlResultSetMappingMap = new HashMap<>();
private final Map<String, NamedResultSetMappingDescriptor> sqlResultSetMappingMap = new HashMap<>();
private final Map<String, NamedEntityGraphDefinition> namedEntityGraphMap = new HashMap<>();
private final Map<String, FetchProfile> fetchProfileMap = new HashMap<>();
@ -648,17 +648,17 @@ public void addDefaultNamedProcedureCall(NamedProcedureCallDefinitionImpl defini
// result-set mapping handling
@Override
public NamedResultSetMappingDefinition getResultSetMapping(String name) {
public NamedResultSetMappingDescriptor getResultSetMapping(String name) {
return sqlResultSetMappingMap.get( name );
}
@Override
public void visitNamedResultSetMappingDefinition(Consumer<NamedResultSetMappingDefinition> definitionConsumer) {
public void visitNamedResultSetMappingDefinition(Consumer<NamedResultSetMappingDescriptor> definitionConsumer) {
sqlResultSetMappingMap.values().forEach( definitionConsumer );
}
@Override
public void addResultSetMapping(NamedResultSetMappingDefinition resultSetMappingDescriptor) {
public void addResultSetMapping(NamedResultSetMappingDescriptor resultSetMappingDescriptor) {
if ( resultSetMappingDescriptor == null ) {
throw new IllegalArgumentException( "Result-set mapping was null" );
}
@ -675,8 +675,8 @@ public void addResultSetMapping(NamedResultSetMappingDefinition resultSetMapping
applyResultSetMapping( resultSetMappingDescriptor );
}
public void applyResultSetMapping(NamedResultSetMappingDefinition resultSetMappingDescriptor) {
final NamedResultSetMappingDefinition old = sqlResultSetMappingMap.put(
public void applyResultSetMapping(NamedResultSetMappingDescriptor resultSetMappingDescriptor) {
final NamedResultSetMappingDescriptor old = sqlResultSetMappingMap.put(
resultSetMappingDescriptor.getRegistrationName(),
resultSetMappingDescriptor
);
@ -689,7 +689,7 @@ public void applyResultSetMapping(NamedResultSetMappingDefinition resultSetMappi
}
@Override
public void addDefaultResultSetMapping(NamedResultSetMappingDefinition definition) {
public void addDefaultResultSetMapping(NamedResultSetMappingDescriptor definition) {
final String name = definition.getRegistrationName();
if ( !defaultSqlResultSetMappingNames.contains( name ) ) {
sqlResultSetMappingMap.remove( name );

View File

@ -33,7 +33,7 @@
import org.hibernate.boot.query.NamedHqlQueryDefinition;
import org.hibernate.boot.query.NamedNativeQueryDefinition;
import org.hibernate.boot.query.NamedProcedureCallDefinition;
import org.hibernate.boot.query.NamedResultSetMappingDefinition;
import org.hibernate.boot.query.NamedResultSetMappingDescriptor;
import org.hibernate.boot.spi.SessionFactoryBuilderFactory;
import org.hibernate.boot.spi.SessionFactoryBuilderImplementor;
import org.hibernate.boot.spi.SessionFactoryBuilderService;
@ -89,7 +89,7 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
private final Map<String, NamedHqlQueryDefinition> namedQueryMap;
private final Map<String, NamedNativeQueryDefinition> namedNativeQueryMap;
private final Map<String, NamedProcedureCallDefinition> namedProcedureCallMap;
private final Map<String, NamedResultSetMappingDefinition> sqlResultSetMappingMap;
private final Map<String, NamedResultSetMappingDescriptor> sqlResultSetMappingMap;
private final Map<String, NamedEntityGraphDefinition> namedEntityGraphMap;
private final Map<String, SqmFunctionDescriptor> sqlFunctionMap;
private final Database database;
@ -110,7 +110,7 @@ public MetadataImpl(
Map<String, NamedHqlQueryDefinition> namedQueryMap,
Map<String, NamedNativeQueryDefinition> namedNativeQueryMap,
Map<String, NamedProcedureCallDefinition> namedProcedureCallMap,
Map<String, NamedResultSetMappingDefinition> sqlResultSetMappingMap,
Map<String, NamedResultSetMappingDescriptor> sqlResultSetMappingMap,
Map<String, NamedEntityGraphDefinition> namedEntityGraphMap,
Map<String, SqmFunctionDescriptor> sqlFunctionMap,
Database database,
@ -253,12 +253,12 @@ public void visitNamedProcedureCallDefinition(Consumer<NamedProcedureCallDefinit
}
@Override
public NamedResultSetMappingDefinition getResultSetMapping(String name) {
public NamedResultSetMappingDescriptor getResultSetMapping(String name) {
return sqlResultSetMappingMap.get( name );
}
@Override
public void visitNamedResultSetMappingDefinition(Consumer<NamedResultSetMappingDefinition> definitionConsumer) {
public void visitNamedResultSetMappingDefinition(Consumer<NamedResultSetMappingDescriptor> definitionConsumer) {
sqlResultSetMappingMap.values().forEach( definitionConsumer );
}
@ -350,14 +350,6 @@ private Map<String, NamedCallableQueryMemento> buildProcedureCallMementos(Sessio
return map;
}
private Map<String, NamedResultSetMappingMemento> buildResultSetMappingMementos(SessionFactoryImplementor sessionFactory) {
final HashMap<String, NamedResultSetMappingMemento> map = new HashMap<>();
if ( sqlResultSetMappingMap != null ) {
sqlResultSetMappingMap.forEach( (key, value) -> map.put( key, value.resolve( sessionFactory ) ) );
}
return map;
}
@Override
public void validate() throws MappingException {
for ( PersistentClass entityBinding : this.getEntityBindings() ) {

View File

@ -28,7 +28,7 @@
import org.hibernate.boot.model.source.spi.ToolingHintContext;
import org.hibernate.boot.spi.BootstrapContext;
import org.hibernate.boot.spi.ClassLoaderAccess;
import org.hibernate.boot.query.HbmResultSetMappingDefinition;
import org.hibernate.boot.query.HbmResultSetMappingDescriptor;
import org.hibernate.boot.spi.InFlightMetadataCollector;
import org.hibernate.boot.spi.MappingDefaults;
import org.hibernate.boot.spi.MetadataBuildingContext;
@ -244,7 +244,7 @@ public void postProcessEntityHierarchies() {
@Override
public void processResultSetMappings() {
for ( ResultSetMappingBindingDefinition resultSetMappingBinding : documentRoot.getResultset() ) {
final HbmResultSetMappingDefinition binding = ResultSetMappingBinder.bind( resultSetMappingBinding, this );
final HbmResultSetMappingDescriptor binding = ResultSetMappingBinder.bind( resultSetMappingBinding, this );
getMetadataCollector().addResultSetMapping( binding );
}
}

View File

@ -17,7 +17,6 @@
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmNativeQueryScalarReturnType;
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmQueryParamType;
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmSynchronizeType;
import org.hibernate.boot.query.HbmResultSetMappingDefinition;
import org.hibernate.boot.query.HbmResultSetMappingDefinitionBuilder;
import org.hibernate.boot.query.NamedHqlQueryDefinition;
import org.hibernate.boot.query.NamedNativeQueryDefinitionBuilder;

View File

@ -24,7 +24,7 @@
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmNativeQueryScalarReturnType;
import org.hibernate.boot.jaxb.hbm.spi.NativeQueryNonScalarRootReturn;
import org.hibernate.boot.jaxb.hbm.spi.ResultSetMappingBindingDefinition;
import org.hibernate.boot.query.HbmResultSetMappingDefinition;
import org.hibernate.boot.query.HbmResultSetMappingDescriptor;
import org.hibernate.boot.query.HbmResultSetMappingDefinitionBuilder;
import org.hibernate.engine.query.spi.sql.NativeSQLQueryCollectionReturn;
import org.hibernate.engine.query.spi.sql.NativeSQLQueryJoinReturn;
@ -56,7 +56,7 @@ public abstract class ResultSetMappingBinder {
*
* @return The ResultSet mapping descriptor
*/
public static HbmResultSetMappingDefinition bind(
public static HbmResultSetMappingDescriptor bind(
ResultSetMappingBindingDefinition resultSetMappingSource,
HbmLocalMetadataBuildingContext context) {
if ( resultSetMappingSource.getName() == null ) {
@ -80,7 +80,7 @@ else if ( valueMappingSource instanceof JaxbHbmNativeQueryScalarReturnType ) {
}
}
final HbmResultSetMappingDefinition mappingDefinition = builder.build( context );
final HbmResultSetMappingDescriptor mappingDefinition = builder.build( context );
context.getMetadataCollector().addResultSetMapping( mappingDefinition );
return mappingDefinition;
}

View File

@ -0,0 +1,21 @@
/*
* 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.boot.query;
import org.hibernate.query.internal.FetchMappingMemento;
import org.hibernate.query.internal.ResultSetMappingResolutionContext;
/**
* Describes the mapping for a fetch as part of a {@link NamedResultSetMappingDescriptor}
*/
public interface FetchDescriptor {
/**
* Resolve the descriptor into a memento capable of being stored in the
* {@link org.hibernate.query.named.NamedQueryRepository}
*/
FetchMappingMemento resolve(ResultSetMappingResolutionContext resolutionContext);
}

View File

@ -22,10 +22,10 @@
public class HbmResultSetMappingDefinitionBuilder {
private final String registrationName;
private NamedResultSetMappingDefinition.ResultMapping rootEntityReturn;
private NamedResultSetMappingDefinition.ResultMapping rootCollectionReturn;
private List<NamedResultSetMappingDefinition.ResultMapping> joinReturns;
private List<HbmResultSetMappingDefinition.ScalarMappingDefinition> rootScalarReturns;
private ResultDescriptor rootEntityReturn;
private ResultDescriptor rootCollectionReturn;
private List<ResultDescriptor> joinReturns;
private List<HbmResultSetMappingDescriptor.ScalarDescriptor> rootScalarReturns;
public HbmResultSetMappingDefinitionBuilder(String queryRegistrationName) {
this.registrationName = queryRegistrationName;
@ -37,7 +37,7 @@ public String getRegistrationName() {
public HbmResultSetMappingDefinitionBuilder addReturn(JaxbHbmNativeQueryScalarReturnType returnMapping) {
rootScalarReturns.add(
new HbmResultSetMappingDefinition.ScalarMappingDefinition(
new HbmResultSetMappingDescriptor.ScalarDescriptor(
returnMapping.getColumn(),
returnMapping.getType()
)
@ -61,7 +61,7 @@ public boolean hasAnyReturns() {
return rootEntityReturn != null || rootCollectionReturn != null || rootScalarReturns != null;
}
public HbmResultSetMappingDefinition build(HbmLocalMetadataBuildingContext context) {
public HbmResultSetMappingDescriptor build(HbmLocalMetadataBuildingContext context) {
if ( rootCollectionReturn != null
&& ( rootEntityReturn != null || rootScalarReturns != null ) ) {
throw new MappingException(
@ -79,7 +79,7 @@ public HbmResultSetMappingDefinition build(HbmLocalMetadataBuildingContext conte
}
}
return new HbmResultSetMappingDefinition(
return new HbmResultSetMappingDescriptor(
registrationName,
rootEntityReturn,
rootCollectionReturn,

View File

@ -7,14 +7,14 @@
package org.hibernate.boot.query;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.hibernate.LockMode;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.internal.ResultSetMappingResolutionContext;
import org.hibernate.query.internal.ScalarResultMappingMemento;
import org.hibernate.query.named.NamedResultSetMappingMemento;
import org.hibernate.query.results.Builders;
import org.hibernate.query.results.ScalarResultBuilder;
import org.hibernate.type.BasicType;
/**
@ -27,22 +27,22 @@
*
* @author Steve Ebersole
*/
public class HbmResultSetMappingDefinition implements NamedResultSetMappingDefinition {
public class HbmResultSetMappingDescriptor implements NamedResultSetMappingDescriptor {
// todo (6.0) : see note on org.hibernate.boot.query.SqlResultSetMappingDefinition
private final String registrationName;
private final ResultMapping rootEntityReturn;
private final ResultMapping rootCollectionReturn;
private final List<ResultMapping> joinReturns;
private final List<ScalarMappingDefinition> scalarResultMappings;
private final ResultDescriptor rootEntityReturn;
private final ResultDescriptor rootCollectionReturn;
private final List<ResultDescriptor> joinReturns;
private final List<ScalarDescriptor> scalarResultMappings;
public HbmResultSetMappingDefinition(
public HbmResultSetMappingDescriptor(
String registrationName,
ResultMapping rootEntityReturn,
ResultMapping rootCollectionReturn,
List<ResultMapping> joinReturns,
List<ScalarMappingDefinition> scalarResultMappings) {
ResultDescriptor rootEntityReturn,
ResultDescriptor rootCollectionReturn,
List<ResultDescriptor> joinReturns,
List<ScalarDescriptor> scalarResultMappings) {
this.registrationName = registrationName;
this.rootEntityReturn = rootEntityReturn;
@ -57,16 +57,16 @@ public String getRegistrationName() {
}
@Override
public NamedResultSetMappingMemento resolve(SessionFactoryImplementor factory) {
final List<ScalarResultBuilder> scalarResultBuilders;
public NamedResultSetMappingMemento resolve(ResultSetMappingResolutionContext resolutionContext) {
final List<ScalarResultMappingMemento> scalarResultMementos;
if ( scalarResultMappings == null || scalarResultMappings.isEmpty() ) {
scalarResultBuilders = null;
scalarResultMementos = Collections.emptyList();
}
else {
scalarResultBuilders = new ArrayList<>( scalarResultMappings.size() );
scalarResultMementos = new ArrayList<>( scalarResultMappings.size() );
scalarResultMappings.forEach(
resultMapping -> {
scalarResultBuilders.add( resultMapping.resolve( factory ) );
scalarResultMementos.add( resultMapping.resolve( resolutionContext ) );
}
);
}
@ -81,12 +81,12 @@ public NamedResultSetMappingMemento resolve(SessionFactoryImplementor factory) {
/**
* @see org.hibernate.boot.jaxb.hbm.spi.JaxbHbmNativeQueryReturnType
*/
public interface RootEntityMappingDefinition extends ResultMapping {
public interface RootEntityDescriptor extends ResultDescriptor {
String getEntityName();
String getSqlAlias();
List<HbmPropertyMappingDefinition> getProperties();
List<HbmPropertyDescriptor> getProperties();
String getDiscriminatorColumnName();
@ -96,7 +96,7 @@ public interface RootEntityMappingDefinition extends ResultMapping {
/**
* @see org.hibernate.boot.jaxb.hbm.spi.JaxbHbmNativeQueryPropertyReturnType
*/
public interface HbmPropertyMappingDefinition extends ResultMapping {
public interface HbmPropertyDescriptor extends ResultDescriptor {
String getPropertyPath();
List<String> getColumnNames();
}
@ -104,12 +104,12 @@ public interface HbmPropertyMappingDefinition extends ResultMapping {
/**
* @see org.hibernate.boot.jaxb.hbm.spi.JaxbHbmNativeQueryJoinReturnType
*/
public interface JoinMappingDefinition extends ResultMapping {
public interface JoinDescriptor extends ResultDescriptor {
String getJoinedPropertyPath();
String getSqlAlias();
List<HbmPropertyMappingDefinition> getProperties();
List<HbmPropertyDescriptor> getProperties();
LockMode getLockMode();
}
@ -117,12 +117,12 @@ public interface JoinMappingDefinition extends ResultMapping {
/**
* @see org.hibernate.boot.jaxb.hbm.spi.JaxbHbmNativeQueryCollectionLoadReturnType
*/
public interface RootCollectionMappingDefinition extends ResultMapping {
public interface RootCollectionDescriptor extends ResultDescriptor {
String getCollectionRole();
String getSqlAlias();
List<HbmPropertyMappingDefinition> getProperties();
List<HbmPropertyDescriptor> getProperties();
LockMode getLockMode();
}
@ -130,11 +130,11 @@ public interface RootCollectionMappingDefinition extends ResultMapping {
/**
* @see org.hibernate.boot.jaxb.hbm.spi.JaxbHbmNativeQueryScalarReturnType
*/
public static class ScalarMappingDefinition implements ResultMapping {
public static class ScalarDescriptor implements ResultDescriptor {
private final String columnName;
private final String hibernateTypeName;
public ScalarMappingDefinition(String columnName, String hibernateTypeName) {
public ScalarDescriptor(String columnName, String hibernateTypeName) {
this.columnName = columnName;
this.hibernateTypeName = hibernateTypeName;
}
@ -148,9 +148,10 @@ public String getHibernateTypeName() {
}
@Override
public ScalarResultBuilder resolve(SessionFactoryImplementor factory) {
public ScalarResultMappingMemento resolve(ResultSetMappingResolutionContext resolutionContext) {
if ( hibernateTypeName != null ) {
final BasicType<?> namedType = factory.getTypeConfiguration()
final BasicType<?> namedType = resolutionContext.getSessionFactory()
.getTypeConfiguration()
.getBasicTypeRegistry()
.getRegisteredType( hibernateTypeName );
@ -158,12 +159,12 @@ public ScalarResultBuilder resolve(SessionFactoryImplementor factory) {
throw new IllegalArgumentException( "Could not resolve named type : " + hibernateTypeName );
}
return Builders.scalar( columnName );
return new ScalarResultMappingMemento( columnName, namedType, resolutionContext );
}
// todo (6.0) : column name may be optional in HBM - double check
return Builders.scalar( columnName );
return new ScalarResultMappingMemento( columnName, null, resolutionContext );
}
}

View File

@ -6,9 +6,10 @@
*/
package org.hibernate.boot.query;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.internal.FetchMappingMemento;
import org.hibernate.query.internal.ResultMappingMemento;
import org.hibernate.query.internal.ResultSetMappingResolutionContext;
import org.hibernate.query.named.NamedResultSetMappingMemento;
import org.hibernate.query.results.ResultBuilder;
/**
* Models the "boot view" of a ResultSet mapping used in the mapping
@ -20,21 +21,15 @@
*
* @author Steve Ebersole
*/
public interface NamedResultSetMappingDefinition {
public interface NamedResultSetMappingDescriptor {
/**
* The name under which the result-set-mapping is to be registered
*/
String getRegistrationName();
/**
* Contract for the individual result mappings
*/
interface ResultMapping {
ResultBuilder resolve(SessionFactoryImplementor factory);
}
/**
* Create the named runtime memento instance
* @param resolutionContext
*/
NamedResultSetMappingMemento resolve(SessionFactoryImplementor factory);
NamedResultSetMappingMemento resolve(ResultSetMappingResolutionContext resolutionContext);
}

View File

@ -0,0 +1,23 @@
/*
* 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.boot.query;
import org.hibernate.query.internal.ResultMappingMemento;
import org.hibernate.query.internal.ResultSetMappingResolutionContext;
/**
* Describes the mapping for a result as part of a {@link NamedResultSetMappingDescriptor}
*
* @author Steve Ebersole
*/
public interface ResultDescriptor {
/**
* Resolve the descriptor into a memento capable of being stored in the
* {@link org.hibernate.query.named.NamedQueryRepository}
*/
ResultMappingMemento resolve(ResultSetMappingResolutionContext resolutionContext);
}

View File

@ -1,261 +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.boot.query;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.persistence.ColumnResult;
import javax.persistence.ConstructorResult;
import javax.persistence.EntityResult;
import javax.persistence.SqlResultSetMapping;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.boot.BootLogging;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.internal.NamedResultSetMappingMementoImpl;
import org.hibernate.query.named.NamedResultSetMappingMemento;
import org.hibernate.query.results.EntityResultBuilder;
import org.hibernate.query.results.InstantiationResultBuilder;
import org.hibernate.query.results.ResultBuilder;
import org.hibernate.query.results.ScalarResultBuilder;
import org.hibernate.query.results.StandardInstantiationResultBuilder;
import org.hibernate.query.results.StandardScalarResultBuilder;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/**
* @author Steve Ebersole
*/
public class SqlResultSetMappingDefinition implements NamedResultSetMappingDefinition {
// todo (6.0) : we can probably reuse the NamedResultSetMappingDefinition
// implementation between HBM and annotation handling. We'd
// just need different "builders" for each source and handle the
// variances in those builders. But once we have a
// NamedResultSetMappingDefinition and all of its sub-parts,
// resolving to a memento is the same
// -
// additionally, consider having the sub-parts (the return
// representations) be what is used and handed to the
// NamedResultSetMappingMemento directly. They simply need
// to be capable of resolving themselves into ResultBuilders
// (`org.hibernate.query.results.ResultBuilder`) as part of the
// memento for its resolution
public static SqlResultSetMappingDefinition from(
SqlResultSetMapping mappingAnnotation,
MetadataBuildingContext context) {
final List<EntityResultMapping> entityResultMappings;
final List<ConstructorResultMapping> constructorResultMappings;
final List<JpaColumnResultMapping> columnResultMappings;
final EntityResult[] entityResults = mappingAnnotation.entities();
if ( entityResults.length > 0 ) {
entityResultMappings = Collections.emptyList();
}
else {
entityResultMappings = new ArrayList<>( entityResults.length );
for ( int i = 0; i < entityResults.length; i++ ) {
final EntityResult entityResult = entityResults[i];
entityResultMappings.add( EntityResultMapping.from( entityResult, context ) );
}
}
final ConstructorResult[] constructorResults = mappingAnnotation.classes();
if ( constructorResults.length == 0 ) {
constructorResultMappings = Collections.emptyList();
}
else {
constructorResultMappings = new ArrayList<>( constructorResults.length );
for ( int i = 0; i < constructorResults.length; i++ ) {
final ConstructorResult constructorResult = constructorResults[i];
constructorResultMappings.add( ConstructorResultMapping.from( constructorResult, context ) );
}
}
final ColumnResult[] columnResults = mappingAnnotation.columns();
if ( columnResults.length == 0 ) {
columnResultMappings = Collections.emptyList();
}
else {
columnResultMappings = new ArrayList<>( columnResults.length );
for ( int i = 0; i < columnResults.length; i++ ) {
final ColumnResult columnResult = columnResults[i];
columnResultMappings.add( JpaColumnResultMapping.from( columnResult, context ) );
}
}
return new SqlResultSetMappingDefinition(
mappingAnnotation.name(),
entityResultMappings,
constructorResultMappings,
columnResultMappings,
context
);
}
private final String mappingName;
private final List<EntityResultMapping> entityResultMappings;
private final List<ConstructorResultMapping> constructorResultMappings;
private final List<JpaColumnResultMapping> columnResultMappings;
private SqlResultSetMappingDefinition(
String mappingName,
List<EntityResultMapping> entityResultMappings,
List<ConstructorResultMapping> constructorResultMappings,
List<JpaColumnResultMapping> columnResultMappings,
MetadataBuildingContext context) {
this.mappingName = mappingName;
this.entityResultMappings = entityResultMappings;
this.constructorResultMappings = constructorResultMappings;
this.columnResultMappings = columnResultMappings;
}
@Override
public String getRegistrationName() {
return mappingName;
}
@Override
public NamedResultSetMappingMemento resolve(SessionFactoryImplementor factory) {
final List<EntityResultBuilder> entityResultBuilders = new ArrayList<>();
for ( int i = 0; i < entityResultMappings.size(); i++ ) {
final EntityResultMapping resultMapping = entityResultMappings.get( i );
entityResultBuilders.add( resultMapping.resolve( factory ) );
}
final List<InstantiationResultBuilder> instantiationResultBuilders = new ArrayList<>();
for ( int i = 0; i < constructorResultMappings.size(); i++ ) {
final ConstructorResultMapping resultMapping = constructorResultMappings.get( i );
instantiationResultBuilders.add( resultMapping.resolve( factory ) );
}
final List<ScalarResultBuilder> scalarResultBuilders = new ArrayList<>();
for ( int i = 0; i < columnResultMappings.size(); i++ ) {
final JpaColumnResultMapping resultMapping = columnResultMappings.get( i );
scalarResultBuilders.add( resultMapping.resolve( factory ) );
}
return new NamedResultSetMappingMementoImpl(
mappingName,
entityResultBuilders,
instantiationResultBuilders,
scalarResultBuilders,
factory
);
}
/**
* @see javax.persistence.ColumnResult
*/
private static class JpaColumnResultMapping implements ResultMapping {
private final String columnName;
private final Class<?> explicitJavaType;
public JpaColumnResultMapping(String columnName, Class<?> explicitJavaType) {
this.columnName = columnName;
this.explicitJavaType = explicitJavaType == void.class
? null
: explicitJavaType;
}
public static JpaColumnResultMapping from(ColumnResult columnResult, MetadataBuildingContext context) {
return new JpaColumnResultMapping( columnResult.name(), columnResult.type() );
}
public String getColumnName() {
return columnName;
}
public Class<?> getExplicitJavaType() {
return explicitJavaType;
}
@Override
public ScalarResultBuilder resolve(SessionFactoryImplementor factory) {
if ( explicitJavaType != null ) {
final JavaTypeDescriptor<?> jtd = factory.getTypeConfiguration()
.getJavaTypeDescriptorRegistry()
.getDescriptor( explicitJavaType );
BootLogging.LOGGER.debugf( "ColumnResult explicit type resolved to : " + jtd );
return new StandardScalarResultBuilder( columnName, jtd );
}
return new StandardScalarResultBuilder( columnName );
}
}
/**
* @see javax.persistence.ConstructorResult
*/
private static class ConstructorResultMapping implements ResultMapping {
public static ConstructorResultMapping from(
ConstructorResult constructorResult,
MetadataBuildingContext context) {
final ColumnResult[] columnResults = constructorResult.columns();
if ( columnResults.length == 0 ) {
throw new IllegalArgumentException( "ConstructorResult did not define any ColumnResults" );
}
final List<ResultMapping> argumentResultMappings = new ArrayList<>( columnResults.length );
for ( int i = 0; i < columnResults.length; i++ ) {
final ColumnResult columnResult = columnResults[i];
argumentResultMappings.add( JpaColumnResultMapping.from( columnResult, context ) );
}
return new ConstructorResultMapping(
constructorResult.targetClass(),
argumentResultMappings
);
}
private final Class<?> targetJavaType;
private final List<ResultMapping> argumentResultMappings;
public ConstructorResultMapping(
Class<?> targetJavaType,
List<ResultMapping> argumentResultMappings) {
this.targetJavaType = targetJavaType;
this.argumentResultMappings = argumentResultMappings;
}
@Override
public InstantiationResultBuilder resolve(SessionFactoryImplementor factory) {
final List<ResultBuilder> argumentResultBuilders = new ArrayList<>( argumentResultMappings.size() );
argumentResultMappings.forEach( mapping -> argumentResultBuilders.add( mapping.resolve( factory ) ) );
final JavaTypeDescriptor<?> targetJtd = factory.getTypeConfiguration()
.getJavaTypeDescriptorRegistry()
.getDescriptor( targetJavaType );
return new StandardInstantiationResultBuilder( targetJtd, argumentResultBuilders );
}
}
/**
* @see javax.persistence.EntityResult
*/
private static class EntityResultMapping implements ResultMapping {
public static EntityResultMapping from(
EntityResult entityResult,
MetadataBuildingContext context) {
throw new NotYetImplementedFor6Exception( "Support for dynamic-instantiation results not yet implemented" );
}
@Override
public EntityResultBuilder resolve(SessionFactoryImplementor factory) {
throw new NotYetImplementedFor6Exception( getClass() );
}
}
}

View File

@ -0,0 +1,347 @@
/*
* 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.boot.query;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import javax.persistence.ColumnResult;
import javax.persistence.ConstructorResult;
import javax.persistence.EntityResult;
import javax.persistence.FieldResult;
import javax.persistence.SqlResultSetMapping;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.boot.BootLogging;
import org.hibernate.boot.spi.MetadataBuildingContext;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.metamodel.RuntimeMetamodels;
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.internal.BasicFetchMemento;
import org.hibernate.query.internal.EntityResultMappingMemento;
import org.hibernate.query.internal.FetchMappingMemento;
import org.hibernate.query.internal.InstantiationResultMappingMemento;
import org.hibernate.query.internal.InstantiationResultMappingMemento.ArgumentMemento;
import org.hibernate.query.internal.NamedResultSetMappingMementoImpl;
import org.hibernate.query.internal.ResultMappingMemento;
import org.hibernate.query.internal.ResultSetMappingResolutionContext;
import org.hibernate.query.internal.ScalarResultMappingMemento;
import org.hibernate.query.named.NamedResultSetMappingMemento;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/**
* @author Steve Ebersole
*/
public class SqlResultSetMappingDescriptor implements NamedResultSetMappingDescriptor {
// todo (6.0) : we can probably reuse the NamedResultSetMappingDefinition
// implementation between HBM and annotation handling. We'd
// just need different "builders" for each source and handle the
// variances in those builders. But once we have a
// NamedResultSetMappingDefinition and all of its sub-parts,
// resolving to a memento is the same
// -
// additionally, consider having the sub-parts (the return
// representations) be what is used and handed to the
// NamedResultSetMappingMemento directly. They simply need
// to be capable of resolving themselves into ResultBuilders
// (`org.hibernate.query.results.ResultBuilder`) as part of the
// memento for its resolution
@SuppressWarnings("ForLoopReplaceableByForEach")
public static SqlResultSetMappingDescriptor from(
SqlResultSetMapping mappingAnnotation,
MetadataBuildingContext context) {
final EntityResult[] entityResults = mappingAnnotation.entities();
final ConstructorResult[] constructorResults = mappingAnnotation.classes();
final ColumnResult[] columnResults = mappingAnnotation.columns();
final List<ResultDescriptor> resultDescriptors = CollectionHelper.arrayList(
entityResults.length + columnResults.length + columnResults.length
);
for ( int i = 0; i < entityResults.length; i++ ) {
final EntityResult entityResult = entityResults[i];
resultDescriptors.add(
EntityResultDescriptor.from( entityResult, context )
);
}
for ( int i = 0; i < constructorResults.length; i++ ) {
final ConstructorResult constructorResult = constructorResults[i];
resultDescriptors.add(
new ConstructorResultDescriptor( constructorResult, mappingAnnotation )
);
}
for ( int i = 0; i < columnResults.length; i++ ) {
final ColumnResult columnResult = columnResults[i];
resultDescriptors.add(
new JpaColumnResultDescriptor( columnResult, mappingAnnotation )
);
}
return new SqlResultSetMappingDescriptor(
mappingAnnotation.name(),
resultDescriptors,
context
);
}
private final String mappingName;
private final List<ResultDescriptor> resultDescriptors;
private SqlResultSetMappingDescriptor(
String mappingName,
List<ResultDescriptor> resultDescriptors,
MetadataBuildingContext context) {
this.mappingName = mappingName;
this.resultDescriptors = resultDescriptors;
}
@Override
public String getRegistrationName() {
return mappingName;
}
@Override
public NamedResultSetMappingMemento resolve(ResultSetMappingResolutionContext resolutionContext) {
final List<ResultMappingMemento> resultMementos = CollectionHelper.arrayList( resultDescriptors.size() );
resultDescriptors.forEach(
resultDescriptor -> resultMementos.add( resultDescriptor.resolve( resolutionContext ) )
);
return new NamedResultSetMappingMementoImpl( mappingName, resultMementos );
}
/**
* @see javax.persistence.ColumnResult
*/
private static class JpaColumnResultDescriptor implements ResultDescriptor {
private final ColumnResult columnResult;
private final String mappingName;
public JpaColumnResultDescriptor(
ColumnResult columnResult,
SqlResultSetMapping mappingAnnotation) {
this.columnResult = columnResult;
this.mappingName = mappingAnnotation.name();
}
@Override
public ResultMappingMemento resolve(ResultSetMappingResolutionContext resolutionContext) {
BootLogging.LOGGER.debugf(
"Generating ScalarResultMappingMemento for JPA ColumnResult(%s) for ResultSet mapping `%s`",
columnResult.name(),
mappingName
);
return new ScalarResultMappingMemento( columnResult, resolutionContext );
}
}
/**
* @see javax.persistence.ConstructorResult
*/
private static class ConstructorResultDescriptor implements ResultDescriptor {
private static class ArgumentDescriptor {
private final JpaColumnResultDescriptor argumentResultDescriptor;
private ArgumentDescriptor(JpaColumnResultDescriptor argumentResultDescriptor) {
this.argumentResultDescriptor = argumentResultDescriptor;
}
ArgumentMemento resolve(ResultSetMappingResolutionContext resolutionContext) {
return new ArgumentMemento( argumentResultDescriptor.resolve( resolutionContext ) );
}
}
private final String mappingName;
private final Class<?> targetJavaType;
private final List<ArgumentDescriptor> argumentResultDescriptors;
public ConstructorResultDescriptor(
ConstructorResult constructorResult,
SqlResultSetMapping mappingAnnotation) {
this.mappingName = mappingAnnotation.name();
this.targetJavaType = constructorResult.targetClass();
final ColumnResult[] columnResults = constructorResult.columns();
if ( columnResults.length == 0 ) {
throw new IllegalArgumentException( "ConstructorResult did not define any ColumnResults" );
}
this.argumentResultDescriptors = CollectionHelper.arrayList( columnResults.length );
for ( int i = 0; i < columnResults.length; i++ ) {
final ColumnResult columnResult = columnResults[i];
final JpaColumnResultDescriptor argumentResultDescriptor = new JpaColumnResultDescriptor(
columnResult,
mappingAnnotation
);
argumentResultDescriptors.add( new ArgumentDescriptor( argumentResultDescriptor ) );
}
}
@Override
public ResultMappingMemento resolve(ResultSetMappingResolutionContext resolutionContext) {
BootLogging.LOGGER.debugf(
"Generating InstantiationResultMappingMemento for JPA ConstructorResult(%s) for ResultSet mapping `%s`",
targetJavaType.getName(),
mappingName
);
final List<ArgumentMemento> argumentResultMementos = new ArrayList<>( argumentResultDescriptors.size() );
argumentResultDescriptors.forEach(
(mapping) -> argumentResultMementos.add( mapping.resolve( resolutionContext ) )
);
final SessionFactoryImplementor sessionFactory = resolutionContext.getSessionFactory();
final JavaTypeDescriptor<?> targetJtd = sessionFactory.getTypeConfiguration()
.getJavaTypeDescriptorRegistry()
.getDescriptor( targetJavaType );
return new InstantiationResultMappingMemento( targetJtd, argumentResultMementos );
}
}
/**
* @see javax.persistence.EntityResult
*/
public static class EntityResultDescriptor implements ResultDescriptor {
private final NavigablePath navigablePath;
private final String entityName;
private final String discriminatorColumn;
private final Map<String, AttributeFetchDescriptor> fetchMappings;
public static EntityResultDescriptor from(EntityResult entityResult, MetadataBuildingContext context) {
final String entityName = entityResult.entityClass().getName();
final Map<String, AttributeFetchDescriptor> fetchMappings = new HashMap<>();
for ( int i = 0; i < entityResult.fields().length; i++ ) {
final FieldResult fieldResult = entityResult.fields()[ i ];
final AttributeFetchDescriptor existing = fetchMappings.get( fieldResult.name() );
if ( existing != null ) {
existing.addColumn( fieldResult );
}
else {
fetchMappings.put(
fieldResult.name(),
AttributeFetchDescriptor.from( entityName, fieldResult, context )
);
}
}
return new EntityResultDescriptor(
entityName,
entityResult.discriminatorColumn(),
fetchMappings
);
}
public EntityResultDescriptor(
String entityName,
String discriminatorColumn,
Map<String, AttributeFetchDescriptor> fetchMappings) {
this.navigablePath = new NavigablePath( entityName );
this.entityName = entityName;
this.discriminatorColumn = discriminatorColumn;
this.fetchMappings = fetchMappings;
}
@Override
public ResultMappingMemento resolve(ResultSetMappingResolutionContext resolutionContext) {
final RuntimeMetamodels runtimeMetamodels = resolutionContext.getSessionFactory().getRuntimeMetamodels();
final EntityMappingType entityDescriptor = runtimeMetamodels.getEntityMappingType( entityName );
final Map<String, FetchMappingMemento> fetchMementos = new HashMap<>();
fetchMappings.forEach(
(attrName, attrMapping) -> fetchMementos.put( attrName, attrMapping.resolve( resolutionContext ) )
);
return new EntityResultMappingMemento( entityDescriptor, discriminatorColumn, fetchMementos );
}
}
private static class AttributeFetchDescriptor implements FetchDescriptor {
private static AttributeFetchDescriptor from(
String entityName,
FieldResult fieldResult,
MetadataBuildingContext context) {
return new AttributeFetchDescriptor(
entityName,
fieldResult.name(),
fieldResult.column()
);
}
private final String entityName;
private final String attributeName;
private final List<String> columnNames;
private AttributeFetchDescriptor(String entityName, String attributeName, String columnName) {
this.entityName = entityName;
this.attributeName = attributeName;
this.columnNames = new ArrayList<>();
columnNames.add( columnName );
}
private void addColumn(FieldResult fieldResult) {
if ( ! attributeName.equals( fieldResult.name() ) ) {
throw new IllegalArgumentException(
String.format(
Locale.ROOT,
"Passed FieldResult [%s, %s] does not match AttributeFetchMapping [%s]",
fieldResult.name(),
fieldResult.column(),
attributeName
)
);
}
columnNames.add( fieldResult.column() );
}
@Override
public FetchMappingMemento resolve(ResultSetMappingResolutionContext resolutionContext) {
final RuntimeMetamodels runtimeMetamodels = resolutionContext.getSessionFactory().getRuntimeMetamodels();
final EntityMappingType entityMapping = runtimeMetamodels.getEntityMappingType( entityName );
final ModelPart subPart = entityMapping.findSubPart( attributeName, null );
if ( subPart == null ) {
// throw an exception
}
if ( subPart instanceof BasicValuedModelPart ) {
assert columnNames.size() == 1;
final BasicValuedModelPart basicPart = (BasicValuedModelPart) subPart;
return new BasicFetchMemento( basicPart, columnNames.get( 0 ) );
}
throw new NotYetImplementedFor6Exception(
"Only support for basic-valued model-parts have been implemented : " + attributeName + " [" + subPart + "]"
);
}
}
}

View File

@ -21,7 +21,7 @@
import org.hibernate.boot.query.NamedHqlQueryDefinition;
import org.hibernate.boot.query.NamedNativeQueryDefinition;
import org.hibernate.boot.query.NamedProcedureCallDefinition;
import org.hibernate.boot.query.NamedResultSetMappingDefinition;
import org.hibernate.boot.query.NamedResultSetMappingDescriptor;
import org.hibernate.cfg.annotations.NamedEntityGraphDefinition;
import org.hibernate.engine.spi.FilterDefinition;
import org.hibernate.engine.spi.SessionFactoryImplementor;
@ -144,12 +144,12 @@ public void visitNamedProcedureCallDefinition(Consumer<NamedProcedureCallDefinit
}
@Override
public NamedResultSetMappingDefinition getResultSetMapping(String name) {
public NamedResultSetMappingDescriptor getResultSetMapping(String name) {
return delegate.getResultSetMapping( name );
}
@Override
public void visitNamedResultSetMappingDefinition(Consumer<NamedResultSetMappingDefinition> definitionConsumer) {
public void visitNamedResultSetMappingDefinition(Consumer<NamedResultSetMappingDescriptor> definitionConsumer) {
delegate.visitNamedResultSetMappingDefinition( definitionConsumer );
}

View File

@ -33,7 +33,7 @@
import org.hibernate.boot.query.NamedHqlQueryDefinition;
import org.hibernate.boot.query.NamedNativeQueryDefinition;
import org.hibernate.boot.query.NamedProcedureCallDefinition;
import org.hibernate.boot.query.NamedResultSetMappingDefinition;
import org.hibernate.boot.query.NamedResultSetMappingDescriptor;
import org.hibernate.cfg.AnnotatedClassType;
import org.hibernate.cfg.AttributeConverterDefinition;
import org.hibernate.cfg.JPAIndexHolder;
@ -154,7 +154,7 @@ Table addDenormalizedTable(
/**
* Adds the metadata for a named SQL result set mapping to this collector.
*/
void addResultSetMapping(NamedResultSetMappingDefinition resultSetMappingDefinition) throws DuplicateMappingException;
void addResultSetMapping(NamedResultSetMappingDescriptor resultSetMappingDefinition) throws DuplicateMappingException;
/**
* Adds metadata for a named stored procedure call to this collector.
@ -271,7 +271,7 @@ void addTableNameBinding(
void addDefaultNamedNativeQuery(NamedNativeQueryDefinition query);
void addDefaultResultSetMapping(NamedResultSetMappingDefinition definition);
void addDefaultResultSetMapping(NamedResultSetMappingDescriptor definition);
void addDefaultNamedProcedureCall(NamedProcedureCallDefinitionImpl procedureCallDefinition);

View File

@ -46,7 +46,7 @@
import org.hibernate.boot.query.NamedHqlQueryDefinition;
import org.hibernate.boot.query.NamedNativeQueryDefinition;
import org.hibernate.boot.query.NamedProcedureCallDefinition;
import org.hibernate.boot.query.NamedResultSetMappingDefinition;
import org.hibernate.boot.query.NamedResultSetMappingDescriptor;
import org.hibernate.cfg.annotations.NamedEntityGraphDefinition;
import org.hibernate.context.spi.CurrentTenantIdentifierResolver;
import org.hibernate.internal.CoreLogging;
@ -100,7 +100,7 @@ public class Configuration {
private Map<String, NamedHqlQueryDefinition> namedQueries;
private Map<String, NamedNativeQueryDefinition> namedSqlQueries;
private Map<String, NamedProcedureCallDefinition> namedProcedureCallMap;
private Map<String, NamedResultSetMappingDefinition> sqlResultSetMappings;
private Map<String, NamedResultSetMappingDescriptor> sqlResultSetMappings;
private Map<String, NamedEntityGraphDefinition> namedEntityGraphMap;
private Map<String, SqmFunctionDescriptor> customFunctionDescriptors;

View File

@ -22,7 +22,7 @@
import org.hibernate.mapping.Property;
import org.hibernate.mapping.ToOne;
import org.hibernate.mapping.Value;
import org.hibernate.boot.query.SqlResultSetMappingDefinition;
import org.hibernate.boot.query.SqlResultSetMappingDescriptor;
/**
* @author Emmanuel Bernard
@ -46,7 +46,7 @@ public void doSecondPass(Map persistentClasses) throws MappingException {
return;
}
final SqlResultSetMappingDefinition mappingDefinition = SqlResultSetMappingDefinition.from( ann, context );
final SqlResultSetMappingDescriptor mappingDefinition = SqlResultSetMappingDescriptor.from( ann, context );
if ( isDefault ) {
context.getMetadataCollector().addDefaultResultSetMapping( mappingDefinition );

View File

@ -131,7 +131,7 @@ public ProcedureCallImpl(SharedSessionContractImplementor session, String proced
resultClasses,
resultSetMapping,
synchronizedQuerySpaces::add,
getSession().getFactory()
() -> getSession().getFactory()
);
}
@ -161,7 +161,7 @@ public ProcedureCallImpl(
resultSetMappingNames,
resultSetMapping,
synchronizedQuerySpaces::add,
getSession().getFactory()
() -> getSession().getFactory()
);
}
@ -186,7 +186,7 @@ public ProcedureCallImpl(
memento.getResultSetMappingClasses(),
resultSetMapping,
synchronizedQuerySpaces::add,
getSession().getFactory()
() -> getSession().getFactory()
);
applyOptions( memento );
@ -216,7 +216,7 @@ public ProcedureCallImpl(
resultTypes,
resultSetMapping,
synchronizedQuerySpaces::add,
getSession().getFactory()
() -> getSession().getFactory()
);
applyOptions( memento );
@ -240,7 +240,7 @@ public ProcedureCallImpl(
null,
resultSetMapping,
synchronizedQuerySpaces::add,
getSession().getFactory()
() -> getSession().getFactory()
);
}

View File

@ -9,12 +9,11 @@
import java.util.function.Consumer;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.query.internal.ResultSetMappingResolutionContext;
import org.hibernate.query.named.NamedQueryRepository;
import org.hibernate.query.named.NamedResultSetMappingMemento;
import org.hibernate.query.results.ResultSetMapping;
import org.hibernate.query.sqm.sql.internal.DomainResultProducer;
import org.jboss.logging.Logger;
@ -34,16 +33,16 @@ public static void resolveResultSetMappings(
Class[] resultSetMappingClasses,
ResultSetMapping resultSetMapping,
Consumer<String> querySpaceConsumer,
SessionFactoryImplementor sessionFactory) {
ResultSetMappingResolutionContext context) {
if ( ! ArrayHelper.isEmpty( resultSetMappingNames ) ) {
// cannot specify both
if ( ! ArrayHelper.isEmpty( resultSetMappingClasses ) ) {
throw new IllegalArgumentException( "Cannot specify both result-set mapping names and classes" );
}
resolveResultSetMappingNames( resultSetMappingNames, resultSetMapping, querySpaceConsumer, sessionFactory );
resolveResultSetMappingNames( resultSetMappingNames, resultSetMapping, querySpaceConsumer, context );
}
else if ( ! ArrayHelper.isEmpty( resultSetMappingClasses ) ) {
resolveResultSetMappingClasses( resultSetMappingClasses, resultSetMapping, querySpaceConsumer, sessionFactory );
resolveResultSetMappingClasses( resultSetMappingClasses, resultSetMapping, querySpaceConsumer, context );
}
// otherwise, nothing to resolve
@ -53,15 +52,15 @@ public static void resolveResultSetMappingNames(
String[] resultSetMappingNames,
ResultSetMapping resultSetMapping,
Consumer<String> querySpaceConsumer,
SessionFactoryImplementor sessionFactory) {
final NamedQueryRepository namedQueryRepository = sessionFactory.getQueryEngine().getNamedQueryRepository();
ResultSetMappingResolutionContext context) {
final NamedQueryRepository namedQueryRepository = context.getSessionFactory().getQueryEngine().getNamedQueryRepository();
for ( String resultSetMappingName : resultSetMappingNames ) {
final NamedResultSetMappingMemento memento = namedQueryRepository.getResultSetMappingMemento( resultSetMappingName );
memento.resolve(
resultSetMapping,
querySpaceConsumer,
sessionFactory
context
);
}
}
@ -70,7 +69,7 @@ public static void resolveResultSetMappingClasses(
Class[] resultSetMappingClasses,
ResultSetMapping resultSetMapping,
Consumer<String> querySpaceConsumer,
SessionFactoryImplementor sessionFactory) {
ResultSetMappingResolutionContext context) {
throw new NotYetImplementedFor6Exception( Util.class );
// final DomainMetamodel domainModel = sessionFactory.getDomainModel();

View File

@ -118,6 +118,19 @@ public interface NativeQuery<T> extends Query<T>, SynchronizeableQuery {
*/
<C> NativeQuery<T> addScalar(String columnAlias, Class<C> relationalJavaType, AttributeConverter<?,C> converter);
/**
* Declare a scalar query result with an explicit conversion
*
* @param jdbcJavaType The Java type expected by the converter as its "relational model" type.
* @param domainJavaType The Java type expected by the converter as its "object model" type.
* @param converter The conversion to apply. Consumes the JDBC value based on `relationalJavaType`.
*
* @return {@code this}, for method chaining
*
* @since 6.0
*/
<O,R> NativeQuery<T> addScalar(String columnAlias, Class<O> domainJavaType, Class<R> jdbcJavaType, AttributeConverter<O,R> converter);
/**
* Declare a scalar query result with an explicit conversion
*
@ -132,6 +145,25 @@ public interface NativeQuery<T> extends Query<T>, SynchronizeableQuery {
*/
<C> NativeQuery<T> addScalar(String columnAlias, Class<C> relationalJavaType, Class<? extends AttributeConverter<?,C>> converter);
/**
* Declare a scalar query result with an explicit conversion
*
* @param jdbcJavaType The Java type expected by the converter as its "relational model" type.
* @param domainJavaType The Java type expected by the converter as its "object model" type.
* @param converter The conversion to apply. Consumes the JDBC value based on `jdbcJavaType`.
*
* @return {@code this}, for method chaining
*
* @since 6.0
*/
<O,R> NativeQuery<T> addScalar(
String columnAlias,
Class<O> domainJavaType,
Class<R> jdbcJavaType,
Class<? extends AttributeConverter<O,R>> converter);
<J> InstantiationResultNode<J> addInstantiation(Class<J> targetJavaType);
/**
* Defines a result based on a specified attribute. Differs from adding a scalar in that
* any conversions or other semantics defined on the attribute are automatically applied
@ -321,6 +353,14 @@ interface ResultNode {
interface ReturnableResultNode extends ResultNode {
}
interface InstantiationResultNode<J> extends ReturnableResultNode {
default InstantiationResultNode<J> addBasicArgument(String columnAlias) {
return addBasicArgument( columnAlias, null );
}
InstantiationResultNode<J> addBasicArgument(String columnAlias, String argumentAlias);
}
/**
* Allows access to further control how properties within a root or join
* fetch are mapped back from the result set. Generally used in composite

View File

@ -0,0 +1,37 @@
/*
* 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.internal;
import java.util.function.Consumer;
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
import org.hibernate.query.results.FetchBuilder;
import org.hibernate.query.results.complete.CompleteFetchBuilderBasicPart;
/**
* Memento describing a basic-valued fetch. A basic-value cannot be
* de-referenced.
*
* @author Steve Ebersole
*/
public class BasicFetchMemento implements FetchMappingMemento {
private final BasicValuedModelPart fetchedAttribute;
private final String columnAlias;
public BasicFetchMemento(BasicValuedModelPart fetchedAttribute, String columnAlias) {
this.fetchedAttribute = fetchedAttribute;
this.columnAlias = columnAlias;
}
@Override
public FetchBuilder resolve(
Parent parent,
Consumer<String> querySpaceConsumer,
ResultSetMappingResolutionContext context) {
return new CompleteFetchBuilderBasicPart( fetchedAttribute, columnAlias );
}
}

View File

@ -0,0 +1,61 @@
/*
* 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.internal;
import java.util.Map;
import java.util.function.Consumer;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.ManagedMappingType;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.results.ResultBuilder;
/**
* @author Steve Ebersole
*/
public class EntityResultMappingMemento implements ResultMappingMemento, FetchMappingMemento.Parent {
private final NavigablePath navigablePath;
private final EntityMappingType entityDescriptor;
private final String discriminatorColumnAlias;
private final Map<String,FetchMappingMemento> fetchMementoMap;
public EntityResultMappingMemento(
EntityMappingType entityDescriptor,
String discriminatorColumnAlias,
Map<String, FetchMappingMemento> fetchMementoMap) {
this.navigablePath = new NavigablePath( entityDescriptor.getEntityName() );
this.entityDescriptor = entityDescriptor;
this.discriminatorColumnAlias = discriminatorColumnAlias;
this.fetchMementoMap = fetchMementoMap;
}
@Override
public NavigablePath getNavigablePath() {
return navigablePath;
}
@Override
public ManagedMappingType getMappingType() {
return entityDescriptor;
}
@Override
public ResultBuilder resolve(
Consumer<String> querySpaceConsumer,
ResultSetMappingResolutionContext context) {
throw new NotYetImplementedFor6Exception( getClass() );
// final Map<String, FetchBuilder> fetchBuilderMap = new HashMap<>();
// fetchMementoMap.forEach(
// (fetchableName, memento) -> fetchBuilderMap.put(
// fetchableName,
// memento.resolve( this, querySpaceConsumer, context )
// )
// );
// return new DynamicResultBuilderEntityStandard( entityDescriptor, null, discriminatorColumnAlias, fetchBuilderMap );
}
}

View File

@ -0,0 +1,35 @@
/*
* 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.internal;
import java.util.function.Consumer;
import org.hibernate.metamodel.mapping.ManagedMappingType;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.results.FetchBuilder;
/**
* @author Steve Ebersole
*/
public interface FetchMappingMemento {
interface Parent {
/**
* The path for the parent
*/
NavigablePath getNavigablePath();
/**
* The entity descriptor that is the base for this path/parent
*/
ManagedMappingType getMappingType();
}
/**
* Resolve the fetch-memento into the result-graph-node builder
*/
FetchBuilder resolve(Parent parent, Consumer<String> querySpaceConsumer, ResultSetMappingResolutionContext context);
}

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.internal;
import java.util.List;
import java.util.function.Consumer;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.query.results.ResultBuilder;
import org.hibernate.query.results.complete.CompleteResultBuilderInstantiation;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/**
* @author Steve Ebersole
*/
public class InstantiationResultMappingMemento implements ResultMappingMemento {
public static class ArgumentMemento {
private final ResultMappingMemento argumentMemento;
public ArgumentMemento(ResultMappingMemento argumentMemento) {
this.argumentMemento = argumentMemento;
}
public ResultBuilder resolve(Consumer<String> querySpaceConsumer, ResultSetMappingResolutionContext context) {
return argumentMemento.resolve( querySpaceConsumer, context );
}
}
private final JavaTypeDescriptor<?> instantiatedJtd;
private final List<ArgumentMemento> argumentMementos;
public InstantiationResultMappingMemento(
JavaTypeDescriptor<?> instantiatedJtd,
List<ArgumentMemento> argumentMementos) {
this.instantiatedJtd = instantiatedJtd;
this.argumentMementos = argumentMementos;
}
@Override
public ResultBuilder resolve(
Consumer<String> querySpaceConsumer,
ResultSetMappingResolutionContext context) {
final List<ResultBuilder> argumentBuilders = CollectionHelper.arrayList( argumentMementos.size() );
argumentMementos.forEach(
argumentMemento -> argumentBuilders.add(
argumentMemento.resolve( querySpaceConsumer, context )
)
);
return new CompleteResultBuilderInstantiation( instantiatedJtd, argumentBuilders );
}
}

View File

@ -153,9 +153,16 @@ public void prepare(
}
);
final ResultSetMappingResolutionContext resolutionContext = new ResultSetMappingResolutionContext() {
@Override
public SessionFactoryImplementor getSessionFactory() {
return sessionFactory;
}
};
bootMetamodel.visitNamedResultSetMappingDefinition(
namedResultSetMappingDefinition -> {
final NamedResultSetMappingMemento resolved = namedResultSetMappingDefinition.resolve( sessionFactory );
final NamedResultSetMappingMemento resolved = namedResultSetMappingDefinition.resolve( resolutionContext );
resultSetMappingMementoMap.put( namedResultSetMappingDefinition.getRegistrationName(), resolved );
}
);

View File

@ -6,17 +6,11 @@
*/
package org.hibernate.query.internal;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.named.NamedResultSetMappingMemento;
import org.hibernate.query.results.EntityResultBuilder;
import org.hibernate.query.results.InstantiationResultBuilder;
import org.hibernate.query.results.ResultBuilder;
import org.hibernate.query.results.ResultSetMapping;
import org.hibernate.query.results.ScalarResultBuilder;
/**
* Standard `NamedResultSetMappingMemento` implementation
@ -25,25 +19,13 @@
*/
public class NamedResultSetMappingMementoImpl implements NamedResultSetMappingMemento {
private final String name;
private final List<ResultBuilder> resultBuilders;
private final List<ResultMappingMemento> resultMappingMementos;
public NamedResultSetMappingMementoImpl(
String name,
List<EntityResultBuilder> entityResultBuilders,
List<InstantiationResultBuilder> instantiationResultBuilders,
List<ScalarResultBuilder> scalarResultBuilders,
SessionFactoryImplementor factory) {
List<ResultMappingMemento> resultMappingMementos) {
this.name = name;
final int totalNumberOfBuilders = entityResultBuilders.size()
+ instantiationResultBuilders.size()
+ scalarResultBuilders.size();
this.resultBuilders = new ArrayList<>( totalNumberOfBuilders );
resultBuilders.addAll( entityResultBuilders );
resultBuilders.addAll( instantiationResultBuilders );
resultBuilders.addAll( scalarResultBuilders );
this.resultMappingMementos = resultMappingMementos;
}
@Override
@ -55,7 +37,9 @@ public String getName() {
public void resolve(
ResultSetMapping resultSetMapping,
Consumer<String> querySpaceConsumer,
SessionFactoryImplementor sessionFactory) {
resultBuilders.forEach( resultSetMapping::addResultBuilder );
ResultSetMappingResolutionContext context) {
resultMappingMementos.forEach(
memento -> resultSetMapping.addResultBuilder( memento.resolve( querySpaceConsumer, context ) )
);
}
}

View File

@ -0,0 +1,18 @@
/*
* 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.internal;
import java.util.function.Consumer;
import org.hibernate.query.results.ResultBuilder;
/**
* @author Steve Ebersole
*/
public interface ResultMappingMemento {
ResultBuilder resolve(Consumer<String> querySpaceConsumer, ResultSetMappingResolutionContext context);
}

View File

@ -0,0 +1,18 @@
/*
* 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.internal;
import org.hibernate.engine.spi.SessionFactoryImplementor;
/**
* Context ("parameter object") used in resolving a {@link NamedResultSetMappingMementoImpl}
*
* @author Steve Ebersole
*/
public interface ResultSetMappingResolutionContext {
SessionFactoryImplementor getSessionFactory();
}

View File

@ -0,0 +1,105 @@
/*
* 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.internal;
import java.util.function.Consumer;
import javax.persistence.ColumnResult;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.results.ResultBuilder;
import org.hibernate.query.results.complete.CompleteResultBuilderBasicValuedStandard;
import org.hibernate.type.BasicType;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.java.spi.JavaTypeDescriptorRegistry;
import org.hibernate.type.spi.TypeConfiguration;
/**
* Implementation of ResultMappingMemento for scalar (basic) results.
*
* Ultimately a scalar result is defined as a column name and a BasicType with the following notes:<ul>
* <li>
* For JPA mappings, the column name is required. For `hbm.xml` mappings, it is optional (positional)
* </li>
* <li>
* Ultimately, when reading values, we need the {@link BasicType}. We know the BasicType in a few
* different ways:<ul>
* <li>
* If we know an explicit Type, that is used.
* </li>
* <li>
* If we do not know the Type, but do know the Java type then we determine the BasicType
* based on the reported SQL type and its known mapping to the specified Java type
* </li>
* <li>
* If we know neither, we use the reported SQL type and its recommended Java type to
* resolve the BasicType to use
* </li>
* </ul>
* </li>
* </ul>
*
* @author Steve Ebersole
*/
public class ScalarResultMappingMemento implements ResultMappingMemento {
public final String explicitColumnName;
private final BasicType<?> explicitType;
private final JavaTypeDescriptor<?> explicitJavaTypeDescriptor;
/**
* Creation of ScalarResultMappingMemento for JPA descriptor
*/
public ScalarResultMappingMemento(
ColumnResult definition,
ResultSetMappingResolutionContext context) {
this.explicitColumnName = definition.name();
final Class<?> definedType = definition.type();
if ( void.class == definedType ) {
explicitJavaTypeDescriptor = null;
}
else {
final SessionFactoryImplementor sessionFactory = context.getSessionFactory();
final TypeConfiguration typeConfiguration = sessionFactory.getTypeConfiguration();
final JavaTypeDescriptorRegistry jtdRegistry = typeConfiguration.getJavaTypeDescriptorRegistry();
this.explicitJavaTypeDescriptor = jtdRegistry.getDescriptor( definition.type() );
}
explicitType = null;
}
public ScalarResultMappingMemento(
String explicitColumnName,
BasicType<?> explicitType,
ResultSetMappingResolutionContext context) {
this.explicitColumnName = explicitColumnName;
this.explicitType = explicitType;
this.explicitJavaTypeDescriptor = explicitType != null
? explicitType.getJavaTypeDescriptor()
: null;
}
@Override
public ResultBuilder resolve(
Consumer<String> querySpaceConsumer,
ResultSetMappingResolutionContext context) {
return new CompleteResultBuilderBasicValuedStandard( this, context );
}
public String getExplicitColumnName() {
return explicitColumnName;
}
public BasicType<?> getExplicitType() {
return explicitType;
}
public JavaTypeDescriptor<?> getExplicitJavaTypeDescriptor() {
return explicitJavaTypeDescriptor;
}
}

View File

@ -9,7 +9,7 @@
import java.util.function.Consumer;
import org.hibernate.Incubating;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.internal.ResultSetMappingResolutionContext;
import org.hibernate.query.results.ResultSetMapping;
/**
@ -38,5 +38,8 @@ public interface NamedResultSetMappingMemento {
* each defined result and registering them with the passed `resultSetMapping`. Any known
* query spaces should be passed to the `querySpaceConsumer`
*/
void resolve(ResultSetMapping resultSetMapping, Consumer<String> querySpaceConsumer, SessionFactoryImplementor sessionFactory);
void resolve(
ResultSetMapping resultSetMapping,
Consumer<String> querySpaceConsumer,
ResultSetMappingResolutionContext context);
}

View File

@ -16,8 +16,17 @@
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.RuntimeMetamodels;
import org.hibernate.metamodel.mapping.AttributeMapping;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.metamodel.mapping.SingularAttributeMapping;
import org.hibernate.persister.entity.EntityPersister;
import org.hibernate.query.results.dynamic.DynamicResultBuilderAttribute;
import org.hibernate.query.results.dynamic.DynamicResultBuilderBasic;
import org.hibernate.query.results.dynamic.DynamicResultBuilderBasicConverted;
import org.hibernate.query.results.dynamic.DynamicResultBuilderBasicStandard;
import org.hibernate.query.results.dynamic.DynamicResultBuilderEntityCalculated;
import org.hibernate.query.results.dynamic.DynamicResultBuilderEntityStandard;
import org.hibernate.query.results.dynamic.DynamicResultBuilderInstantiation;
import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
import org.hibernate.type.BasicType;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
@ -25,53 +34,92 @@
* @author Steve Ebersole
*/
public class Builders {
public static ScalarResultBuilder scalar(String columnAlias) {
return new StandardScalarResultBuilder( columnAlias );
public static DynamicResultBuilderBasic scalar(String columnAlias) {
return scalar( columnAlias, columnAlias );
}
public static ScalarResultBuilder scalar(
String columnAlias,
BasicType<?> type) {
return new StandardScalarResultBuilder( columnAlias, type );
public static DynamicResultBuilderBasic scalar(String columnAlias, String resultAlias) {
return new DynamicResultBuilderBasicStandard( columnAlias, resultAlias );
}
public static ScalarResultBuilder scalar(
public static DynamicResultBuilderBasic scalar(String columnAlias, BasicType<?> type) {
return scalar( columnAlias, columnAlias, type );
}
public static DynamicResultBuilderBasic scalar(String columnAlias, String resultAlias, BasicType<?> type) {
return new DynamicResultBuilderBasicStandard( columnAlias, resultAlias, type );
}
public static DynamicResultBuilderBasic scalar(
String columnAlias,
Class<?> javaType,
SessionFactoryImplementor factory) {
return scalar( columnAlias, columnAlias, javaType, factory );
}
public static DynamicResultBuilderBasic scalar(
String columnAlias,
String resultAlias,
Class<?> javaType,
SessionFactoryImplementor factory) {
final JavaTypeDescriptor<?> javaTypeDescriptor = factory.getTypeConfiguration()
.getJavaTypeDescriptorRegistry()
.getDescriptor( javaType );
return new StandardScalarResultBuilder( columnAlias, javaTypeDescriptor );
return new DynamicResultBuilderBasicStandard( columnAlias, resultAlias, javaTypeDescriptor );
}
public static <C> ResultBuilder scalar(
public static <R> ResultBuilder converted(
String columnAlias,
Class<C> relationalJavaType,
AttributeConverter<?, C> converter,
Class<R> jdbcJavaType,
AttributeConverter<?, R> converter,
SessionFactoryImplementor sessionFactory) {
return ConvertedResultBuilder.from( columnAlias, relationalJavaType, converter, sessionFactory );
return converted( columnAlias, null, jdbcJavaType, converter, sessionFactory );
}
public static <C> ResultBuilder scalar(
public static <O,R> ResultBuilder converted(
String columnAlias,
Class<C> relationalJavaType,
Class<? extends AttributeConverter<?, C>> converterJavaType,
Class<O> domainJavaType,
Class<R> jdbcJavaType,
AttributeConverter<O, R> converter,
SessionFactoryImplementor sessionFactory) {
return ConvertedResultBuilder.from( columnAlias, relationalJavaType, converterJavaType, sessionFactory );
return new DynamicResultBuilderBasicConverted( columnAlias, domainJavaType, jdbcJavaType, converter, sessionFactory );
}
public static ScalarResultBuilder scalar(int position) {
public static <R> ResultBuilder converted(
String columnAlias,
Class<R> jdbcJavaType,
Class<? extends AttributeConverter<?, R>> converterJavaType,
SessionFactoryImplementor sessionFactory) {
return converted( columnAlias, null, jdbcJavaType, (Class) converterJavaType, sessionFactory );
}
public static <O,R> ResultBuilder converted(
String columnAlias,
Class<O> domainJavaType,
Class<R> jdbcJavaType,
Class<? extends AttributeConverter<O,R>> converterJavaType,
SessionFactoryImplementor sessionFactory) {
return new DynamicResultBuilderBasicConverted( columnAlias, domainJavaType, jdbcJavaType, converterJavaType, sessionFactory );
}
public static ResultBuilderBasicValued scalar(int position) {
// will be needed for interpreting legacy HBM <resultset/> mappings
throw new NotYetImplementedFor6Exception();
}
public static ScalarResultBuilder scalar(int position, BasicType<?> type) {
public static ResultBuilderBasicValued scalar(int position, BasicType<?> type) {
// will be needed for interpreting legacy HBM <resultset/> mappings
throw new NotYetImplementedFor6Exception();
}
public static <J> DynamicResultBuilderInstantiation<J> instantiation(Class<J> targetJavaType, SessionFactoryImplementor factory) {
final JavaTypeDescriptor<J> targetJtd = factory.getTypeConfiguration()
.getJavaTypeDescriptorRegistry()
.getDescriptor( targetJavaType );
return new DynamicResultBuilderInstantiation<>( targetJtd );
}
public static ResultBuilder attributeResult(
String columnAlias,
String entityName,
@ -97,7 +145,7 @@ public static ResultBuilder attributeResult(
if ( attributeMapping instanceof SingularAttributeMapping ) {
final SingularAttributeMapping singularAttributeMapping = (SingularAttributeMapping) attributeMapping;
return new AttributeResultBuilder( singularAttributeMapping, columnAlias, fullEntityName, attributePath );
return new DynamicResultBuilderAttribute( singularAttributeMapping, columnAlias, fullEntityName, attributePath );
}
throw new IllegalArgumentException(
@ -128,8 +176,14 @@ public static ResultBuilder attributeResult(String columnAlias, SingularAttribut
* @param entityName
* @return
*/
public static EntityResultBuilder entity(String tableAlias, String entityName) {
throw new NotYetImplementedFor6Exception( );
public static DynamicResultBuilderEntityStandard entity(
String tableAlias,
String entityName,
SessionFactoryImplementor sessionFactory) {
final RuntimeMetamodels runtimeMetamodels = sessionFactory.getRuntimeMetamodels();
final EntityMappingType entityMapping = runtimeMetamodels.getEntityMappingType( entityName );
return new DynamicResultBuilderEntityStandard( entityMapping, tableAlias );
}
/**
@ -140,25 +194,32 @@ public static EntityResultBuilder entity(String tableAlias, String entityName) {
* @see org.hibernate.query.NativeQuery#addEntity(String, Class)
* @see org.hibernate.query.NativeQuery#addEntity(String, String)
*/
public static CalculatedEntityResultBuilder entityCalculated(String tableAlias, String entityName) {
return entityCalculated( tableAlias, entityName, null );
public static DynamicResultBuilderEntityCalculated entityCalculated(
String tableAlias,
String entityName,
SessionFactoryImplementor sessionFactory) {
return entityCalculated( tableAlias, entityName, null,sessionFactory );
}
/**
* Creates a EntityResultBuilder that does not allow any further configuring of the mapping.
*
* @see #entityCalculated(String, String)
* @see #entityCalculated(String, String, SessionFactoryImplementor)
* @see org.hibernate.query.NativeQuery#addEntity(String, Class, LockMode)
* @see org.hibernate.query.NativeQuery#addEntity(String, String, LockMode)
*/
public static CalculatedEntityResultBuilder entityCalculated(
public static DynamicResultBuilderEntityCalculated entityCalculated(
String tableAlias,
String entityName,
LockMode explicitLockMode) {
return new CalculatedEntityResultBuilder( tableAlias, entityName, explicitLockMode );
LockMode explicitLockMode,
SessionFactoryImplementor sessionFactory) {
final RuntimeMetamodels runtimeMetamodels = sessionFactory.getRuntimeMetamodels();
final EntityMappingType entityMapping = runtimeMetamodels.getEntityMappingType( entityName );
return new DynamicResultBuilderEntityCalculated( entityMapping, tableAlias, explicitLockMode, sessionFactory );
}
public static LegacyFetchBuilder fetch(String tableAlias, String ownerTableAlias, String joinPropertyName) {
public static DynamicFetchBuilderLegacy fetch(String tableAlias, String ownerTableAlias, String joinPropertyName) {
throw new NotYetImplementedFor6Exception( );
}
}

View File

@ -1,46 +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.results;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
/**
* An entity DomainResult builder for cases when Hibernate implicitly
* calculates the mapping
*
* @author Steve Ebersole
*/
public class CalculatedEntityResultBuilder implements ResultBuilder {
private final String tableAlias;
private final String entityName;
private final LockMode explicitLockMode;
public CalculatedEntityResultBuilder(
String tableAlias,
String entityName,
LockMode explicitLockMode) {
this.tableAlias = tableAlias;
this.entityName = entityName;
this.explicitLockMode = explicitLockMode;
}
@Override
public DomainResult<?> buildReturn(
JdbcValuesMetadata jdbcResultsMetadata,
BiFunction<String, String, LegacyFetchBuilder> legacyFetchResolver,
Consumer<SqlSelection> sqlSelectionConsumer,
SessionFactoryImplementor sessionFactory) {
return null;
}
}

View File

@ -1,200 +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.results;
import java.util.Collections;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import javax.persistence.AttributeConverter;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.MappingModelExpressable;
import org.hibernate.resource.beans.spi.ManagedBean;
import org.hibernate.resource.beans.spi.ManagedBeanRegistry;
import org.hibernate.sql.ast.Clause;
import org.hibernate.sql.ast.SqlAstWalker;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.basic.BasicResult;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
import org.hibernate.type.descriptor.ValueBinder;
import org.hibernate.type.descriptor.ValueExtractor;
import org.hibernate.type.descriptor.converter.ConvertedValueExtractor;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.java.spi.JavaTypeDescriptorRegistry;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
import org.hibernate.type.spi.TypeConfiguration;
/**
* A ResultBuilder for explicitly converted scalar results
*
* @author Steve Ebersole
*/
public class ConvertedResultBuilder implements ScalarResultBuilder {
public static <C> ResultBuilder from(
String columnAlias,
Class<C> relationalJavaType,
AttributeConverter<?, C> converter,
SessionFactoryImplementor sessionFactory) {
final TypeConfiguration typeConfiguration = sessionFactory.getTypeConfiguration();
final JavaTypeDescriptorRegistry jtdRegistry = typeConfiguration.getJavaTypeDescriptorRegistry();
final JavaTypeDescriptor<C> relationJtd = jtdRegistry.getDescriptor( relationalJavaType );
return new ConvertedResultBuilder( columnAlias, relationJtd, converter );
}
public static <C> ResultBuilder from(
String columnAlias,
Class<C> relationalJavaType,
Class<? extends AttributeConverter<?, C>> converterJavaType,
SessionFactoryImplementor sessionFactory) {
final TypeConfiguration typeConfiguration = sessionFactory.getTypeConfiguration();
final JavaTypeDescriptorRegistry jtdRegistry = typeConfiguration.getJavaTypeDescriptorRegistry();
final JavaTypeDescriptor<C> relationJtd = jtdRegistry.getDescriptor( relationalJavaType );
final ManagedBeanRegistry beans = sessionFactory.getServiceRegistry().getService( ManagedBeanRegistry.class );
final ManagedBean<? extends AttributeConverter<?, C>> bean = beans.getBean( converterJavaType );
final AttributeConverter<?, C> converter = bean.getBeanInstance();
return new ConvertedResultBuilder( columnAlias, relationJtd, converter );
}
private final String columnAlias;
private final JavaTypeDescriptor<?> relationJtd;
private final AttributeConverter<?,?> converter;
public ConvertedResultBuilder(
String columnAlias,
JavaTypeDescriptor<?> relationJtd,
AttributeConverter<?, ?> converter) {
assert columnAlias != null;
this.columnAlias = columnAlias;
assert relationJtd != null;
this.relationJtd = relationJtd;
assert converter != null;
this.converter = converter;
}
@SuppressWarnings({"unchecked", "rawtypes"})
@Override
public DomainResult<?> buildReturn(
JdbcValuesMetadata jdbcResultsMetadata,
BiFunction<String, String, LegacyFetchBuilder> legacyFetchResolver,
Consumer<SqlSelection> sqlSelectionConsumer,
SessionFactoryImplementor sessionFactory) {
final int jdbcPosition = jdbcResultsMetadata.resolveColumnPosition( columnAlias );
final int valuesArrayPosition = jdbcPosition - 1;
final SqlTypeDescriptor std = jdbcResultsMetadata.resolveSqlTypeDescriptor( jdbcPosition );
final ConverterMapping<Object> converterMapping = new ConverterMapping(
relationJtd,
std,
new ConvertedValueExtractor( std.getExtractor( relationJtd ), converter )
);
final SqlSelectionImpl sqlSelection = new SqlSelectionImpl( valuesArrayPosition, converterMapping );
sqlSelectionConsumer.accept( sqlSelection );
return new BasicResult( valuesArrayPosition, columnAlias, converterMapping.getJavaTypeDescriptor() );
}
private static class ConverterMapping<T> implements MappingModelExpressable<T>, JdbcMapping {
private final JavaTypeDescriptor<T> jtd;
private final SqlTypeDescriptor std;
private final ValueExtractor<T> extractor;
public ConverterMapping(
JavaTypeDescriptor<T> jtd,
SqlTypeDescriptor std,
ValueExtractor<T> extractor) {
this.jtd = jtd;
this.std = std;
this.extractor = extractor;
}
@Override
public int getJdbcTypeCount(TypeConfiguration typeConfiguration) {
return 1;
}
@Override
public JavaTypeDescriptor<T> getJavaTypeDescriptor() {
return jtd;
}
@Override
public SqlTypeDescriptor getSqlTypeDescriptor() {
return std;
}
@Override
public ValueExtractor<T> getJdbcValueExtractor() {
return extractor;
}
@Override
public ValueBinder<?> getJdbcValueBinder() {
// this will never get used for binding values
throw new UnsupportedOperationException();
}
@Override
public List<JdbcMapping> getJdbcMappings(TypeConfiguration typeConfiguration) {
return Collections.singletonList( this );
}
@Override
public void visitJdbcTypes(
Consumer<JdbcMapping> action,
Clause clause,
TypeConfiguration typeConfiguration) {
action.accept( this );
}
}
@SuppressWarnings("rawtypes")
private static class SqlSelectionImpl implements SqlSelection {
private final int valuesArrayPosition;
private final ConverterMapping converterMapping;
public SqlSelectionImpl(
int valuesArrayPosition,
ConverterMapping converterMapping) {
this.valuesArrayPosition = valuesArrayPosition;
this.converterMapping = converterMapping;
}
@Override
public int getValuesArrayPosition() {
return valuesArrayPosition;
}
@Override
public ValueExtractor getJdbcValueExtractor() {
return converterMapping.getJdbcValueExtractor();
}
@Override
public MappingModelExpressable getExpressionType() {
return converterMapping;
}
@Override
public void accept(SqlAstWalker sqlAstWalker) {
throw new UnsupportedOperationException();
}
}
}

View File

@ -0,0 +1,83 @@
/*
* 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.results;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.FetchParent;
/**
* @author Steve Ebersole
*/
public class DomainResultCreationStateImpl implements DomainResultCreationState {
private final List<ResultBuilder> resultBuilders;
private final Map<String, Map<String, DynamicFetchBuilderLegacy>> legacyFetchBuilders;
private final SqlAstCreationStateImpl sqlAstCreationState;
private final FromClauseAccessImpl fromClauseAccess;
private final LegacyFetchResolverImpl legacyFetchResolver;
public DomainResultCreationStateImpl(
List<ResultBuilder> resultBuilders,
Map<String, Map<String, DynamicFetchBuilderLegacy>> legacyFetchBuilders,
SessionFactoryImplementor sessionFactory) {
this.resultBuilders = resultBuilders;
this.legacyFetchBuilders = legacyFetchBuilders;
this.fromClauseAccess = new FromClauseAccessImpl();
this.sqlAstCreationState = new SqlAstCreationStateImpl( fromClauseAccess, sessionFactory );
this.legacyFetchResolver = new LegacyFetchResolverImpl();
}
public FromClauseAccessImpl getFromClauseAccess() {
return fromClauseAccess;
}
@Override
public SqlAstCreationStateImpl getSqlAstCreationState() {
return sqlAstCreationState;
}
@FunctionalInterface
public interface LegacyFetchResolver {
DynamicFetchBuilderLegacy resolve(String ownerTableAlias, String fetchedPartPath);
}
private static class LegacyFetchResolverImpl implements LegacyFetchResolver {
private final Map<String,Map<String, DynamicFetchBuilderLegacy>> legacyFetchResolvers;
public LegacyFetchResolverImpl() {
this.legacyFetchResolvers = new HashMap<>();
}
@Override
public DynamicFetchBuilderLegacy resolve(String ownerTableAlias, String fetchedPartPath) {
final Map<String, DynamicFetchBuilderLegacy> fetchBuilders = legacyFetchResolvers.get( ownerTableAlias );
if ( fetchBuilders == null ) {
return null;
}
return fetchBuilders.get( fetchedPartPath );
}
}
public LegacyFetchResolver getLegacyFetchResolver() {
return legacyFetchResolver;
}
@Override
public List<Fetch> visitFetches(FetchParent fetchParent) {
throw new UnsupportedOperationException();
}
}

View File

@ -1,63 +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.results;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.NativeQuery;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
/**
* @author Steve Ebersole
*/
public class EntityResultBuilder
extends AbstractPropertyContainer<EntityResultBuilder>
implements ResultBuilder, NativeQuery.RootReturn {
private final String entityName;
private final String tableAlias;
private LockMode lockMode;
private String discriminatorColumnAlias;
public EntityResultBuilder(String entityName, String tableAlias) {
this.entityName = entityName;
this.tableAlias = tableAlias;
}
@Override
protected String getPropertyBase() {
return entityName;
}
@Override
public DomainResult<?> buildReturn(
JdbcValuesMetadata jdbcResultsMetadata,
BiFunction<String, String, LegacyFetchBuilder> legacyFetchResolver,
Consumer<SqlSelection> sqlSelectionConsumer,
SessionFactoryImplementor sessionFactory) {
throw new NotYetImplementedFor6Exception( getClass() );
}
@Override
public EntityResultBuilder setLockMode(LockMode lockMode) {
this.lockMode = lockMode;
return this;
}
@Override
public EntityResultBuilder setDiscriminatorAlias(String columnAlias) {
this.discriminatorColumnAlias = columnAlias;
return this;
}
}

View File

@ -6,13 +6,15 @@
*/
package org.hibernate.query.results;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import org.hibernate.Incubating;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.NativeQuery;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
@ -21,13 +23,16 @@
* Responsible for building a single {@link DomainResult} instance as part of
* the overall mapping of native / procedure query results.
*
* @apiNote By definition a fetch is a reference to the fetched ModelPart
* @author Steve Ebersole
*/
@Incubating
public interface FetchBuilder extends NativeQuery.ReturnProperty {
public interface FetchBuilder {
Fetch buildFetch(
FetchParent parent,
JdbcValuesMetadata jdbcResultsMetadata,
NavigablePath fetchPath, JdbcValuesMetadata jdbcResultsMetadata,
BiFunction<String, String, DynamicFetchBuilderLegacy> legacyFetchResolver,
Consumer<SqlSelection> sqlSelectionConsumer,
SessionFactoryImplementor sessionFactory);
DomainResultCreationState domainResultCreationState);
}

View File

@ -0,0 +1,85 @@
/*
* 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.results;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.spi.FromClauseAccess;
import org.hibernate.sql.ast.tree.from.TableGroup;
/**
* @author Steve Ebersole
*/
public class FromClauseAccessImpl implements FromClauseAccess {
private List<TableGroup> rootTableGroups;
private Map<String, TableGroup> tableGroupBySqlAlias;
private Map<NavigablePath, TableGroup> tableGroupByPath;
public FromClauseAccessImpl() {
}
public List<TableGroup> getRootTableGroups() {
return rootTableGroups;
}
public TableGroup getByAlias(String alias) {
final TableGroup byAlias = findByAlias( alias );
if ( byAlias == null ) {
throw new IllegalArgumentException( "Could not resolve TableGroup by alias [" + alias + "]" );
}
return byAlias;
}
public TableGroup findByAlias(String alias) {
if ( tableGroupBySqlAlias != null ) {
final TableGroup tableGroup = tableGroupBySqlAlias.get( alias );
if ( tableGroup != null ) {
return tableGroup;
}
}
if ( rootTableGroups != null && rootTableGroups.size() == 1 ) {
return rootTableGroups.get( 0 );
}
return null;
}
@Override
public TableGroup findTableGroup(NavigablePath navigablePath) {
if ( tableGroupByPath != null ) {
final TableGroup tableGroup = tableGroupByPath.get( navigablePath );
if ( tableGroup != null ) {
return tableGroup;
}
}
if ( rootTableGroups != null && rootTableGroups.size() == 1 ) {
return rootTableGroups.get( 0 );
}
return null;
}
@Override
public void registerTableGroup(NavigablePath navigablePath, TableGroup tableGroup) {
if ( tableGroupByPath == null ) {
tableGroupByPath = new HashMap<>();
}
tableGroupByPath.put( navigablePath, tableGroup );
if ( tableGroup.getGroupAlias() != null ) {
if ( tableGroupBySqlAlias == null ) {
tableGroupBySqlAlias = new HashMap<>();
}
tableGroupBySqlAlias.put( tableGroup.getGroupAlias(), tableGroup );
}
}
}

View File

@ -1,27 +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.results;
/**
* @author Steve Ebersole
*/
public interface PropertyContainer {
/**
* Add a simple property-to-one-column mapping.
*/
PropertyContainer addProperty(String propertyName, String columnAlias);
/**
* Add a property mapped to multiple columns
*/
PropertyContainer addProperty(String propertyName, String... columnAliases);
/**
* Add a property whose columns can later be defined using {@link FetchBuilder#addColumnAlias}
*/
FetchBuilder addProperty(String propertyName);
}

View File

@ -10,9 +10,10 @@
import java.util.function.Consumer;
import org.hibernate.Incubating;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
/**
@ -23,9 +24,10 @@
*/
@Incubating
public interface ResultBuilder {
DomainResult<?> buildReturn(
DomainResult<?> buildResult(
JdbcValuesMetadata jdbcResultsMetadata,
BiFunction<String,String,LegacyFetchBuilder> legacyFetchResolver,
int resultPosition,
BiFunction<String, String, DynamicFetchBuilderLegacy> legacyFetchResolver,
Consumer<SqlSelection> sqlSelectionConsumer,
SessionFactoryImplementor sessionFactory);
DomainResultCreationState domainResultCreationState);
}

View File

@ -0,0 +1,31 @@
/*
* 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.results;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.basic.BasicResult;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
/**
* Nominal extension to ResultBuilder for cases involving scalar results
*
* @author Steve Ebersole
*/
public interface ResultBuilderBasicValued extends ResultBuilder {
@Override
BasicResult<?> buildResult(
JdbcValuesMetadata jdbcResultsMetadata,
int resultPosition,
BiFunction<String, String, DynamicFetchBuilderLegacy> legacyFetchResolver,
Consumer<SqlSelection> sqlSelectionConsumer,
DomainResultCreationState domainResultCreationState);
}

View File

@ -6,30 +6,26 @@
*/
package org.hibernate.query.results;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.NativeQuery;
import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.entity.EntityResult;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
/**
* Specialization of ResultBuilder for building an EntityResult
*
* @author Steve Ebersole
*/
public class StandardFetchBuilderImpl implements FetchBuilder {
public interface ResultBuilderEntityValued extends ResultBuilder {
@Override
public Fetch buildFetch(
FetchParent parent,
EntityResult buildResult(
JdbcValuesMetadata jdbcResultsMetadata,
int resultPosition,
BiFunction<String, String, DynamicFetchBuilderLegacy> legacyFetchResolver,
Consumer<SqlSelection> sqlSelectionConsumer,
SessionFactoryImplementor sessionFactory) {
return null;
}
@Override
public NativeQuery.ReturnProperty addColumnAlias(String columnAlias) {
return null;
}
DomainResultCreationState domainResultCreationState);
}

View File

@ -11,5 +11,5 @@
*
* @author Steve Ebersole
*/
public interface InstantiationResultBuilder extends ResultBuilder {
public interface ResultBuilderInstantiationValued extends ResultBuilder {
}

View File

@ -10,6 +10,7 @@
import org.hibernate.Incubating;
import org.hibernate.query.named.NamedResultSetMappingMemento;
import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMappingProducer;
/**
@ -17,13 +18,20 @@
* or {@link org.hibernate.procedure.ProcedureCall} / {@link javax.persistence.StoredProcedureQuery}
* instances.
*
* Collects builders for results and fetches and manages resolving them via JdbcValuesMappingProducer
*
* @see org.hibernate.query.NativeQuery#addScalar
* @see org.hibernate.query.NativeQuery#addEntity
* @see org.hibernate.query.NativeQuery#addJoin
* @see org.hibernate.query.NativeQuery#addFetch
* @see org.hibernate.query.NativeQuery#addRoot
* Can be defined<ul>
* <li>
* statically via {@link javax.persistence.SqlResultSetMapping} or `hbm.xml` mapping
* </li>
* <li>
* dynamically via Hibernate-specific APIs:<ul>
* <li>{@link org.hibernate.query.NativeQuery#addScalar}</li>
* <li>{@link org.hibernate.query.NativeQuery#addEntity}</li>
* <li>{@link org.hibernate.query.NativeQuery#addJoin}</li>
* <li>{@link org.hibernate.query.NativeQuery#addFetch}</li>
* <li>{@link org.hibernate.query.NativeQuery#addRoot}</li>
* </ul>
* </li>
* </ul>
*
* @author Steve Ebersole
*/
@ -34,7 +42,7 @@ public interface ResultSetMapping extends JdbcValuesMappingProducer {
void visitResultBuilders(BiConsumer<Integer, ResultBuilder> resultBuilderConsumer);
void addResultBuilder(ResultBuilder resultBuilder);
void addLegacyFetchBuilder(LegacyFetchBuilder fetchBuilder);
void addLegacyFetchBuilder(DynamicFetchBuilderLegacy fetchBuilder);
NamedResultSetMappingMemento toMemento(String name);
}

View File

@ -17,7 +17,9 @@
import org.hibernate.Internal;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.mapping.BasicValuedMapping;
import org.hibernate.query.named.NamedResultSetMappingMemento;
import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.basic.BasicResult;
@ -35,7 +37,7 @@
@Internal
public class ResultSetMappingImpl implements ResultSetMapping {
private List<ResultBuilder> resultBuilders;
private Map<String, Map<String,LegacyFetchBuilder>> legacyFetchBuilders;
private Map<String, Map<String, DynamicFetchBuilderLegacy>> legacyFetchBuilders;
@Override
public int getNumberOfResultBuilders() {
@ -62,8 +64,8 @@ public void addResultBuilder(ResultBuilder resultBuilder) {
}
@Override
public void addLegacyFetchBuilder(LegacyFetchBuilder fetchBuilder) {
final Map<String, LegacyFetchBuilder> existingFetchBuildersByOwner;
public void addLegacyFetchBuilder(DynamicFetchBuilderLegacy fetchBuilder) {
final Map<String, DynamicFetchBuilderLegacy> existingFetchBuildersByOwner;
if ( legacyFetchBuilders == null ) {
legacyFetchBuilders = new HashMap<>();
@ -73,7 +75,7 @@ public void addLegacyFetchBuilder(LegacyFetchBuilder fetchBuilder) {
existingFetchBuildersByOwner = legacyFetchBuilders.get( fetchBuilder.getOwnerAlias() );
}
final Map<String, LegacyFetchBuilder> fetchBuildersByOwner;
final Map<String, DynamicFetchBuilderLegacy> fetchBuildersByOwner;
if ( existingFetchBuildersByOwner == null ) {
fetchBuildersByOwner = new HashMap<>();
legacyFetchBuilders.put( fetchBuilder.getOwnerAlias(), fetchBuildersByOwner );
@ -82,7 +84,7 @@ public void addLegacyFetchBuilder(LegacyFetchBuilder fetchBuilder) {
fetchBuildersByOwner = existingFetchBuildersByOwner;
}
final LegacyFetchBuilder previousBuilder = fetchBuildersByOwner.put( fetchBuilder.getFetchedAttributeName(), fetchBuilder );
final DynamicFetchBuilderLegacy previousBuilder = fetchBuildersByOwner.put( fetchBuilder.getFetchableName(), fetchBuilder );
if ( previousBuilder != null ) {
// todo (6.0) : error? log? nothing?
}
@ -92,7 +94,6 @@ public void addLegacyFetchBuilder(LegacyFetchBuilder fetchBuilder) {
public JdbcValuesMapping resolve(
JdbcValuesMetadata jdbcResultsMetadata,
SessionFactoryImplementor sessionFactory) {
final List<SqlSelection> sqlSelections = new ArrayList<>( jdbcResultsMetadata.getColumnCount() );
final int numberOfResults;
@ -103,8 +104,15 @@ public JdbcValuesMapping resolve(
numberOfResults = resultBuilders.size();
}
final List<SqlSelection> sqlSelections = new ArrayList<>( jdbcResultsMetadata.getColumnCount() );
final List<DomainResult<?>> domainResults = new ArrayList<>( numberOfResults );
final DomainResultCreationStateImpl creationState = new DomainResultCreationStateImpl(
resultBuilders,
legacyFetchBuilders,
sessionFactory
);
for ( int i = 0; i < numberOfResults; i++ ) {
final ResultBuilder resultBuilder = resultBuilders != null
? resultBuilders.get( i )
@ -120,23 +128,23 @@ public JdbcValuesMapping resolve(
);
}
else {
domainResult = resultBuilder.buildReturn(
domainResult = resultBuilder.buildResult(
jdbcResultsMetadata,
(ownerAlias, fetchName) -> {
domainResults.size(),
(entityName, fetchableName) -> {
if ( legacyFetchBuilders == null ) {
return null;
}
final Map<String, LegacyFetchBuilder> fetchBuildersForOwner = legacyFetchBuilders.get(
ownerAlias );
if ( fetchBuildersForOwner == null ) {
final Map<String, DynamicFetchBuilderLegacy> fetchBuilderMap = legacyFetchBuilders.get( entityName );
if ( fetchBuilderMap == null ) {
return null;
}
return fetchBuildersForOwner.get( fetchName );
return fetchBuilderMap.get( fetchableName );
},
sqlSelections::add,
sessionFactory
creationState
);
}
domainResults.add( domainResult );
@ -164,7 +172,7 @@ private DomainResult<?> makeImplicitDomainResult(
final String name = jdbcResultsMetadata.resolveColumnName( jdbcPosition );
final SqlSelectionImpl sqlSelection = new SqlSelectionImpl( valuesArrayPosition, jdbcMapping );
final SqlSelectionImpl sqlSelection = new SqlSelectionImpl( valuesArrayPosition, (BasicValuedMapping) jdbcMapping );
sqlSelectionConsumer.accept( sqlSelection );
return new BasicResult( valuesArrayPosition, name, jdbcMapping.getJavaTypeDescriptor() );

View File

@ -0,0 +1,51 @@
/*
* 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.results;
import org.hibernate.sql.results.graph.DomainResultCreationState;
/**
* @author Steve Ebersole
*/
public class ResultsHelper {
public static int jdbcPositionToValuesArrayPosition(int jdbcPosition) {
return jdbcPosition - 1;
}
public static int valuesArrayPositionToJdbcPosition(int valuesArrayPosition) {
return valuesArrayPosition + 1;
}
public static DomainResultCreationStateImpl impl(DomainResultCreationState creationState) {
return unwrap( creationState );
}
public static FromClauseAccessImpl extractFromClauseAccess(DomainResultCreationState creationState) {
return unwrap( creationState ).getFromClauseAccess();
}
public static SqlAstCreationStateImpl extractSqlAstCreationState(DomainResultCreationState creationState) {
return unwrap( creationState ).getSqlAstCreationState();
}
public static SqlAstProcessingStateImpl extractSqlAstProcessingState(DomainResultCreationState creationState) {
return unwrap( creationState ).getSqlAstCreationState().getCurrentProcessingState();
}
private static DomainResultCreationStateImpl unwrap(DomainResultCreationState creationState) {
if ( creationState instanceof DomainResultCreationStateImpl ) {
return ( (DomainResultCreationStateImpl) creationState );
}
throw new IllegalArgumentException(
"Passed DomainResultCreationState not an instance of org.hibernate.query.results.DomainResultCreationStateImpl"
);
}
private ResultsHelper() {
}
}

View File

@ -0,0 +1,65 @@
/*
* 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.results;
import org.hibernate.LockMode;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.sql.ast.spi.FromClauseAccess;
import org.hibernate.sql.ast.spi.SqlAliasBaseGenerator;
import org.hibernate.sql.ast.spi.SqlAstCreationContext;
import org.hibernate.sql.ast.spi.SqlAstCreationState;
/**
* SqlAstCreationState implementation for result-set mapping handling
*
* @author Steve Ebersole
*/
public class SqlAstCreationStateImpl implements SqlAstCreationState {
private final SessionFactoryImplementor sessionFactory;
private final FromClauseAccessImpl fromClauseAccess;
private final SqlAstProcessingStateImpl processingState;
public SqlAstCreationStateImpl(
FromClauseAccessImpl fromClauseAccess,
SessionFactoryImplementor sessionFactory) {
this.sessionFactory = sessionFactory;
this.fromClauseAccess = fromClauseAccess;
this.processingState = new SqlAstProcessingStateImpl( this, fromClauseAccess );
}
@Override
public SqlAstCreationContext getCreationContext() {
return sessionFactory;
}
@Override
public SqlAstProcessingStateImpl getCurrentProcessingState() {
return processingState;
}
@Override
public SqlAstProcessingStateImpl getSqlExpressionResolver() {
return processingState;
}
@Override
public FromClauseAccessImpl getFromClauseAccess() {
return fromClauseAccess;
}
@Override
public SqlAliasBaseGenerator getSqlAliasBaseGenerator() {
return stem -> {
throw new UnsupportedOperationException();
};
}
@Override
public LockMode determineLockMode(String identificationVariable) {
return null;
}
}

View File

@ -0,0 +1,98 @@
/*
* 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.results;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
import org.hibernate.sql.ast.spi.FromClauseAccess;
import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.sql.ast.spi.SqlAstProcessingState;
import org.hibernate.sql.ast.spi.SqlExpressionResolver;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.expression.ColumnReference;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.spi.TypeConfiguration;
/**
* @author Steve Ebersole
*/
public class SqlAstProcessingStateImpl implements SqlAstProcessingState, SqlExpressionResolver {
private final SqlAstCreationState sqlAstCreationState;
private final FromClauseAccessImpl fromClauseAccess;
private final Map<String,SqlSelectionImpl> sqlSelectionMap = new HashMap<>();
public SqlAstProcessingStateImpl(
SqlAstCreationState sqlAstCreationState,
FromClauseAccessImpl fromClauseAccess) {
this.sqlAstCreationState = sqlAstCreationState;
this.fromClauseAccess = fromClauseAccess;
}
@Override
public SqlAstProcessingState getParentState() {
// none
return null;
}
@Override
public SqlExpressionResolver getSqlExpressionResolver() {
return this;
}
@Override
public SqlAstCreationState getSqlAstCreationState() {
return sqlAstCreationState;
}
public int getNumberOfProcessedSelections() {
return sqlSelectionMap.size();
}
@Override
public Expression resolveSqlExpression(
String key,
Function<SqlAstProcessingState, Expression> creator) {
final SqlSelectionImpl existing = sqlSelectionMap.get( key );
if ( existing != null ) {
return existing;
}
final Expression created = creator.apply( this );
if ( created instanceof SqlSelectionImpl ) {
sqlSelectionMap.put( key, (SqlSelectionImpl) created );
}
else if ( created instanceof ColumnReference ) {
final ColumnReference columnReference = (ColumnReference) created;
final SqlSelectionImpl sqlSelection = new SqlSelectionImpl(
sqlSelectionMap.size() + 1,
columnReference.getJdbcMapping()
);
sqlSelectionMap.put( key, sqlSelection );
}
return created;
}
@Override
public SqlSelection resolveSqlSelection(
Expression expression,
JavaTypeDescriptor javaTypeDescriptor,
TypeConfiguration typeConfiguration) {
assert expression instanceof SqlSelectionImpl;
return (SqlSelection) expression;
}
public FromClauseAccess getFromClauseAccess() {
return fromClauseAccess;
}
}

View File

@ -7,28 +7,51 @@
package org.hibernate.query.results;
import org.hibernate.metamodel.mapping.BasicValuedMapping;
import org.hibernate.metamodel.mapping.JdbcMapping;
import org.hibernate.metamodel.mapping.MappingModelExpressable;
import org.hibernate.sql.ast.SqlAstWalker;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.expression.Expression;
import org.hibernate.type.descriptor.ValueExtractor;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.spi.TypeConfiguration;
/**
* SqlSelection for NativeQuery
* SqlSelection used in {@link ResultSetMapping} resolution. Doubles as its own
* {@link Expression} as well.
*
* @author Steve Ebersole
*/
public class SqlSelectionImpl implements SqlSelection {
public class SqlSelectionImpl implements SqlSelection, Expression {
private final int valuesArrayPosition;
private final BasicValuedMapping valueMapping;
private final JdbcMapping jdbcMapping;
public SqlSelectionImpl(int valuesArrayPosition, BasicValuedMapping valueMapping) {
this.valuesArrayPosition = valuesArrayPosition;
this.valueMapping = valueMapping;
this.jdbcMapping = valueMapping.getJdbcMapping();
}
public SqlSelectionImpl(int valuesArrayPosition, JdbcMapping jdbcMapping) {
this.valuesArrayPosition = valuesArrayPosition;
this.jdbcMapping = jdbcMapping;
this.valueMapping = null;
}
@Override
public ValueExtractor getJdbcValueExtractor() {
return valueMapping.getJdbcMapping().getJdbcValueExtractor();
return jdbcMapping.getJdbcValueExtractor();
}
@Override
public SqlSelection createSqlSelection(
int jdbcPosition,
int valuesArrayPosition,
JavaTypeDescriptor javaTypeDescriptor,
TypeConfiguration typeConfiguration) {
return this;
}
@Override

View File

@ -1,109 +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.results;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.basic.BasicResult;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
import org.hibernate.type.BasicType;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
import org.hibernate.type.spi.TypeConfiguration;
/**
* @see javax.persistence.ColumnResult
*
* @author Steve Ebersole
*/
public class StandardScalarResultBuilder implements ScalarResultBuilder {
private final String explicitName;
private final BasicType<?> explicitType;
private final JavaTypeDescriptor<?> explicitJavaTypeDescriptor;
public StandardScalarResultBuilder(String explicitName) {
assert explicitName != null;
this.explicitName = explicitName;
this.explicitType = null;
this.explicitJavaTypeDescriptor = null;
}
public StandardScalarResultBuilder(String explicitName, BasicType<?> explicitType) {
assert explicitName != null;
this.explicitName = explicitName;
assert explicitType != null;
this.explicitType = explicitType;
this.explicitJavaTypeDescriptor = null;
}
public StandardScalarResultBuilder(String explicitName, JavaTypeDescriptor<?> explicitJavaTypeDescriptor) {
assert explicitName != null;
this.explicitName = explicitName;
assert explicitJavaTypeDescriptor != null;
this.explicitJavaTypeDescriptor = explicitJavaTypeDescriptor;
this.explicitType = null;
}
StandardScalarResultBuilder(JavaTypeDescriptor<?> explicitJavaTypeDescriptor) {
assert explicitJavaTypeDescriptor != null;
this.explicitJavaTypeDescriptor = explicitJavaTypeDescriptor;
this.explicitName = null;
this.explicitType = null;
}
public String getExplicitName() {
return explicitName;
}
@Override
public DomainResult<?> buildReturn(
JdbcValuesMetadata jdbcResultsMetadata,
BiFunction<String, String, LegacyFetchBuilder> legacyFetchResolver,
Consumer<SqlSelection> sqlSelectionConsumer,
SessionFactoryImplementor sessionFactory) {
final int jdbcPosition = jdbcResultsMetadata.resolveColumnPosition( explicitName );
final int valuesArrayPosition = jdbcPosition - 1;
final BasicType<?> jdbcMapping;
if ( explicitType != null ) {
jdbcMapping = explicitType;
}
else if ( explicitJavaTypeDescriptor != null ) {
final TypeConfiguration typeConfiguration = sessionFactory.getTypeConfiguration();
final SqlTypeDescriptor sqlTypeDescriptor = jdbcResultsMetadata.resolveSqlTypeDescriptor( jdbcPosition );
jdbcMapping = typeConfiguration.getBasicTypeRegistry().resolve( explicitJavaTypeDescriptor, sqlTypeDescriptor );
}
else {
final TypeConfiguration typeConfiguration = sessionFactory.getTypeConfiguration();
final SqlTypeDescriptor sqlTypeDescriptor = jdbcResultsMetadata.resolveSqlTypeDescriptor( jdbcPosition );
final JavaTypeDescriptor<?> javaTypeDescriptor = sqlTypeDescriptor.getJdbcRecommendedJavaTypeMapping( typeConfiguration );
jdbcMapping = typeConfiguration.getBasicTypeRegistry().resolve( javaTypeDescriptor, sqlTypeDescriptor );
}
final SqlSelectionImpl sqlSelection = new SqlSelectionImpl( valuesArrayPosition, jdbcMapping );
sqlSelectionConsumer.accept( sqlSelection );
return new BasicResult( valuesArrayPosition, explicitName, jdbcMapping.getJavaTypeDescriptor() );
}
}

View File

@ -0,0 +1,152 @@
/*
* 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.results;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;
import java.util.function.Supplier;
import org.hibernate.LockMode;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.mapping.ModelPartContainer;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableGroupJoin;
import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.ast.tree.from.TableReferenceJoin;
/**
* A TableGroup created with regards to a SQL ResultSet mapping
*
* @author Steve Ebersole
*/
public class TableGroupImpl implements TableGroup {
private final NavigablePath navigablePath;
private final String alias;
private final TableReferenceImpl primaryTableReference;
private final ModelPartContainer container;
private final LockMode lockMode;
private Set<TableGroupJoin> tableGroupJoins;
public TableGroupImpl(
NavigablePath navigablePath,
String alias,
TableReferenceImpl primaryTableReference,
ModelPartContainer container,
LockMode lockMode) {
this.navigablePath = navigablePath;
this.alias = alias;
this.primaryTableReference = primaryTableReference;
this.container = container;
this.lockMode = lockMode;
}
@Override
public NavigablePath getNavigablePath() {
return navigablePath;
}
@Override
public String getGroupAlias() {
return alias;
}
@Override
public ModelPartContainer getModelPart() {
return container;
}
@Override
public ModelPartContainer getExpressionType() {
return getModelPart();
}
@Override
public LockMode getLockMode() {
return lockMode;
}
@Override
public Set<TableGroupJoin> getTableGroupJoins() {
return tableGroupJoins == null ? Collections.emptySet() : tableGroupJoins;
}
@Override
public boolean hasTableGroupJoins() {
return tableGroupJoins != null && ! tableGroupJoins.isEmpty();
}
@Override
public void setTableGroupJoins(Set<TableGroupJoin> joins) {
throw new UnsupportedOperationException();
}
@Override
public void addTableGroupJoin(TableGroupJoin join) {
}
@Override
public void visitTableGroupJoins(Consumer<TableGroupJoin> consumer) {
if ( tableGroupJoins == null ) {
return;
}
tableGroupJoins.forEach( consumer );
}
@Override
public void applyAffectedTableNames(Consumer<String> nameCollector) {
}
@Override
public TableReference getPrimaryTableReference() {
return primaryTableReference;
}
@Override
public List<TableReferenceJoin> getTableReferenceJoins() {
return Collections.emptyList();
}
@Override
public boolean isInnerJoinPossible() {
return false;
}
@Override
public TableReference resolveTableReference(
String tableExpression, Supplier<TableReference> creator) {
return primaryTableReference;
}
@Override
public TableReference resolveTableReference(String tableExpression) {
return primaryTableReference;
}
@Override
public TableReference getTableReference(String tableExpression) {
return primaryTableReference;
}
public static class TableReferenceImpl extends TableReference {
public TableReferenceImpl(
String tableExpression,
String identificationVariable,
boolean isOptional,
SessionFactoryImplementor sessionFactory) {
super( tableExpression, identificationVariable, isOptional, sessionFactory );
}
}
}

View File

@ -0,0 +1,18 @@
/*
* 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.results.complete;
import org.hibernate.query.results.FetchBuilder;
import org.hibernate.sql.results.graph.Fetchable;
/**
* @author Steve Ebersole
*/
public interface CompleteFetchBuilder extends FetchBuilder, ModelPartReference {
@Override
Fetchable getReferencedPart();
}

View File

@ -0,0 +1,111 @@
/*
* 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.results.complete;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.engine.FetchTiming;
import org.hibernate.metamodel.mapping.BasicValuedModelPart;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.results.DomainResultCreationStateImpl;
import org.hibernate.query.results.FromClauseAccessImpl;
import org.hibernate.query.results.SqlAstCreationStateImpl;
import org.hibernate.query.results.SqlAstProcessingStateImpl;
import org.hibernate.query.results.SqlSelectionImpl;
import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.ast.tree.from.TableReference;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
import static org.hibernate.query.results.ResultsHelper.impl;
import static org.hibernate.query.results.ResultsHelper.jdbcPositionToValuesArrayPosition;
import static org.hibernate.sql.ast.spi.SqlExpressionResolver.createColumnReferenceKey;
/**
* @author Steve Ebersole
*/
public class CompleteFetchBuilderBasicPart implements CompleteFetchBuilder {
private final BasicValuedModelPart referencedModelPart;
private final String columnName;
public CompleteFetchBuilderBasicPart(BasicValuedModelPart referencedModelPart, String columnName) {
this.referencedModelPart = referencedModelPart;
this.columnName = columnName;
}
@Override
public BasicValuedModelPart getReferencedPart() {
return referencedModelPart;
}
@Override
public Fetch buildFetch(
FetchParent parent,
NavigablePath fetchPath,
JdbcValuesMetadata jdbcResultsMetadata,
BiFunction<String, String, DynamicFetchBuilderLegacy> legacyFetchResolver,
Consumer<SqlSelection> sqlSelectionConsumer,
DomainResultCreationState domainResultCreationState) {
final DomainResultCreationStateImpl domainResultCreationStateImpl = impl( domainResultCreationState );
final SqlAstCreationStateImpl sqlAstCreationState = domainResultCreationStateImpl.getSqlAstCreationState();
final FromClauseAccessImpl fromClauseAccess = domainResultCreationStateImpl.getFromClauseAccess();
final SqlAstProcessingStateImpl sqlAstProcessingState = sqlAstCreationState.getCurrentProcessingState();
final String mappedTable = referencedModelPart.getContainingTableExpression();
final String mappedColumn = referencedModelPart.getMappedColumnExpression();
final TableGroup tableGroup = fromClauseAccess.getTableGroup( parent.getNavigablePath() );
final TableReference tableReference = tableGroup.getTableReference( mappedTable );
final String selectedAlias;
final int jdbcPosition;
if ( columnName == null ) {
jdbcPosition = sqlAstProcessingState.getNumberOfProcessedSelections();
selectedAlias = jdbcResultsMetadata.resolveColumnName( jdbcPosition );
}
else {
jdbcPosition = jdbcResultsMetadata.resolveColumnPosition( columnName );
selectedAlias = columnName;
}
final int valuesArrayPosition = jdbcPositionToValuesArrayPosition( jdbcPosition );
// we just care about the registration here. The ModelPart will find it later
sqlAstProcessingState.resolveSqlExpression(
createColumnReferenceKey( tableReference, mappedColumn ),
processingState -> new SqlSelectionImpl( valuesArrayPosition, referencedModelPart )
);
// final Expression expression = sqlAstProcessingState.resolveSqlExpression(
// createColumnReferenceKey( tableReference, mappedColumn ),
// processingState -> new SqlSelectionImpl( valuesArrayPosition, referencedModelPart )
// );
//
// final SqlSelection sqlSelection = sqlAstProcessingState.resolveSqlSelection(
// expression,
// referencedModelPart.getJavaTypeDescriptor(),
// sqlAstCreationState.getCreationContext().getSessionFactory().getTypeConfiguration()
// );
return referencedModelPart.generateFetch(
parent,
fetchPath,
FetchTiming.IMMEDIATE,
true,
LockMode.READ,
selectedAlias,
domainResultCreationState
);
}
}

View File

@ -4,10 +4,12 @@
* 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.results;
package org.hibernate.query.results.complete;
import org.hibernate.query.results.ResultBuilder;
/**
* @author Steve Ebersole
*/
public interface BuilderGraphNode {
public interface CompleteResultBuilder extends ResultBuilder {
}

View File

@ -4,12 +4,14 @@
* 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.results;
package org.hibernate.query.results.complete;
import org.hibernate.query.results.ResultBuilderBasicValued;
/**
* Nominal extension to ResultBuilder for cases involving scalar results
*
* @author Steve Ebersole
*/
public interface ScalarResultBuilder extends ResultBuilder {
public interface CompleteResultBuilderBasicValued extends CompleteResultBuilder, ResultBuilderBasicValued {
}

View File

@ -0,0 +1,103 @@
/*
* 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.results.complete;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.mapping.BasicValuedMapping;
import org.hibernate.query.internal.ResultSetMappingResolutionContext;
import org.hibernate.query.internal.ScalarResultMappingMemento;
import org.hibernate.query.results.ResultsHelper;
import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
import org.hibernate.query.results.SqlSelectionImpl;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.basic.BasicResult;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
import org.hibernate.type.BasicType;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
import org.hibernate.type.spi.TypeConfiguration;
/**
* ResultBuilder for scalar results defined via:<ul>
* <li>JPA {@link javax.persistence.ColumnResult}</li>
* <li>`<return-scalar/>` as part of a `<resultset/>` stanza in `hbm.xml`</li>
* </ul>
*
* @author Steve Ebersole
*/
public class CompleteResultBuilderBasicValuedStandard implements CompleteResultBuilderBasicValued {
private final String explicitColumnName;
private final BasicType<?> explicitType;
private final JavaTypeDescriptor<?> explicitJavaTypeDescriptor;
public CompleteResultBuilderBasicValuedStandard(
ScalarResultMappingMemento memento,
ResultSetMappingResolutionContext context) {
this.explicitColumnName = memento.getExplicitColumnName();
this.explicitType = memento.getExplicitType();
this.explicitJavaTypeDescriptor = memento.getExplicitJavaTypeDescriptor();
}
@Override
public BasicResult<?> buildResult(
JdbcValuesMetadata jdbcResultsMetadata,
int resultPosition,
BiFunction<String, String, DynamicFetchBuilderLegacy> legacyFetchResolver,
Consumer<SqlSelection> sqlSelectionConsumer,
DomainResultCreationState domainResultCreationState) {
final SessionFactoryImplementor sessionFactory = domainResultCreationState.getSqlAstCreationState()
.getCreationContext()
.getSessionFactory();
final int jdbcPosition;
final String columnName;
if ( explicitColumnName != null ) {
jdbcPosition = jdbcResultsMetadata.resolveColumnPosition( explicitColumnName );
columnName = explicitColumnName;
}
else {
jdbcPosition = resultPosition + 1;
columnName = jdbcResultsMetadata.resolveColumnName( jdbcPosition );
}
final int valuesArrayPosition = ResultsHelper.jdbcPositionToValuesArrayPosition( jdbcPosition );
final BasicType<?> basicType;
if ( explicitType != null ) {
basicType = explicitType;
}
else if ( explicitJavaTypeDescriptor != null ) {
final TypeConfiguration typeConfiguration = sessionFactory.getTypeConfiguration();
final SqlTypeDescriptor sqlTypeDescriptor = jdbcResultsMetadata.resolveSqlTypeDescriptor( jdbcPosition );
basicType = typeConfiguration.getBasicTypeRegistry().resolve( explicitJavaTypeDescriptor, sqlTypeDescriptor );
}
else {
final TypeConfiguration typeConfiguration = sessionFactory.getTypeConfiguration();
final SqlTypeDescriptor sqlTypeDescriptor = jdbcResultsMetadata.resolveSqlTypeDescriptor( jdbcPosition );
final JavaTypeDescriptor<?> javaTypeDescriptor = sqlTypeDescriptor.getJdbcRecommendedJavaTypeMapping( typeConfiguration );
basicType = typeConfiguration.getBasicTypeRegistry().resolve( javaTypeDescriptor, sqlTypeDescriptor );
}
final SqlSelectionImpl sqlSelection = new SqlSelectionImpl( valuesArrayPosition, (BasicValuedMapping) basicType );
sqlSelectionConsumer.accept( sqlSelection );
return new BasicResult<>( valuesArrayPosition, columnName, basicType.getJavaTypeDescriptor() );
}
}

View File

@ -0,0 +1,19 @@
/*
* 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.results.complete;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.query.results.ResultBuilderEntityValued;
/**
* @author Steve Ebersole
*/
public interface CompleteResultBuilderEntityValued
extends CompleteResultBuilder, ModelPartReference, ResultBuilderEntityValued {
@Override
EntityMappingType getReferencedPart();
}

View File

@ -4,30 +4,37 @@
* 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.results;
package org.hibernate.query.results.complete;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.DynamicInstantiationNature;
import org.hibernate.query.results.ResultBuilderInstantiationValued;
import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
import org.hibernate.query.results.ResultBuilder;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.instantiation.internal.ArgumentDomainResult;
import org.hibernate.sql.results.graph.instantiation.internal.DynamicInstantiationResultImpl;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/**
* ResultBuilder for dynamic instantiation results ({@link javax.persistence.ConstructorResult}
*
* @author Steve Ebersole
*/
public class StandardInstantiationResultBuilder implements InstantiationResultBuilder {
public class CompleteResultBuilderInstantiation
implements CompleteResultBuilder, ResultBuilderInstantiationValued {
private final JavaTypeDescriptor<?> javaTypeDescriptor;
private final List<ResultBuilder> argumentResultBuilders;
public StandardInstantiationResultBuilder(
public CompleteResultBuilderInstantiation(
JavaTypeDescriptor<?> javaTypeDescriptor,
List<ResultBuilder> argumentResultBuilders) {
this.javaTypeDescriptor = javaTypeDescriptor;
@ -35,22 +42,30 @@ public StandardInstantiationResultBuilder(
}
@Override
public DomainResult<?> buildReturn(
public DomainResult<?> buildResult(
JdbcValuesMetadata jdbcResultsMetadata,
BiFunction<String, String, LegacyFetchBuilder> legacyFetchResolver,
int resultPosition,
BiFunction<String, String, DynamicFetchBuilderLegacy> legacyFetchResolver,
Consumer<SqlSelection> sqlSelectionConsumer,
SessionFactoryImplementor sessionFactory) {
DomainResultCreationState domainResultCreationState) {
final List<ArgumentDomainResult<?>> argumentDomainResults = new ArrayList<>( argumentResultBuilders.size() );
argumentResultBuilders.forEach(
argumentResultBuilder -> argumentDomainResults.add(
new ArgumentDomainResult<>(
argumentResultBuilder.buildReturn( jdbcResultsMetadata, legacyFetchResolver, sqlSelectionConsumer, sessionFactory )
)
)
);
for ( int i = 0; i < argumentResultBuilders.size(); i++ ) {
final ResultBuilder argumentResultBuilder = argumentResultBuilders.get( i );
final ArgumentDomainResult<Object> argumentDomainResult = new ArgumentDomainResult<>(
argumentResultBuilder.buildResult(
jdbcResultsMetadata,
i,
legacyFetchResolver,
sqlSelectionConsumer,
domainResultCreationState
)
);
argumentDomainResults.add( argumentDomainResult );
}
//noinspection unchecked
return new DynamicInstantiationResultImpl(
null,
DynamicInstantiationNature.CLASS,

View File

@ -0,0 +1,26 @@
/*
* 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.results.complete;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.query.results.FetchBuilder;
import org.hibernate.query.results.ResultBuilder;
/**
* A {@link ResultBuilder} or {@link FetchBuilder} that refers to some part
* of the user's domain model
*
* @author Steve Ebersole
*/
public interface ModelPartReference {
/**
* The part of the domain model that is referenced
*/
ModelPart getReferencedPart();
}

View File

@ -0,0 +1,17 @@
/*
* 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
*/
/**
* Support for immutable result/fetch builder graph nodes built from static sources
* such as JPA's {@link javax.persistence.SqlResultSetMapping} or `hbm.xml` mapping
* `<resultset/>`.
*
* The differentiation from {@link org.hibernate.query.results.dynamic} is that here
* we have up-front knowledge of the complete mapping graph and can perform optimized
* resolution process
*/
package org.hibernate.query.results.complete;

View File

@ -4,25 +4,32 @@
* 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.results;
package org.hibernate.query.results.dynamic;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import org.hibernate.internal.util.collections.ArrayHelper;
import org.hibernate.query.results.FetchBuilder;
/**
* @author Steve Ebersole
*/
public abstract class AbstractPropertyContainer<T extends AbstractPropertyContainer<T>> implements PropertyContainer {
private Map<String,FetchBuilder> fetchBuilderMap;
public abstract class AbstractFetchBuilderContainer<T extends AbstractFetchBuilderContainer<T>>
implements DynamicFetchBuilderContainer {
private Map<String, DynamicFetchBuilder> fetchBuilderMap;
protected abstract String getPropertyBase();
@Override
public DynamicFetchBuilder findFetchBuilder(String fetchableName) {
return fetchBuilderMap == null ? null : fetchBuilderMap.get( fetchableName );
}
@Override
public T addProperty(String propertyName, String columnAlias) {
final FetchBuilder fetchBuilder = addProperty( propertyName );
final DynamicFetchBuilder fetchBuilder = addProperty( propertyName );
fetchBuilder.addColumnAlias( columnAlias );
return (T) this;
@ -30,14 +37,14 @@ public T addProperty(String propertyName, String columnAlias) {
@Override
public T addProperty(String propertyName, String... columnAliases) {
final FetchBuilder fetchBuilder = addProperty( propertyName );
final DynamicFetchBuilder fetchBuilder = addProperty( propertyName );
ArrayHelper.forEach( columnAliases, fetchBuilder::addColumnAlias );
return (T) this;
}
@Override
public FetchBuilder addProperty(String propertyName) {
public DynamicFetchBuilder addProperty(String propertyName) {
if ( fetchBuilderMap == null ) {
fetchBuilderMap = new HashMap<>();
}
@ -56,7 +63,11 @@ public FetchBuilder addProperty(String propertyName) {
}
}
final FetchBuilder fetchBuilder = new StandardFetchBuilderImpl();
final DynamicFetchBuilderStandard fetchBuilder = new DynamicFetchBuilderStandard(
this,
propertyName
);
fetchBuilderMap.put( propertyName, fetchBuilder );
return fetchBuilder;

View File

@ -4,15 +4,14 @@
* 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.results;
package org.hibernate.query.results.dynamic;
import org.hibernate.query.NativeQuery;
import org.hibernate.query.results.FetchBuilder;
import org.hibernate.sql.results.graph.Fetchable;
/**
* @author Steve Ebersole
*/
public interface LegacyFetchBuilder extends FetchBuilder, NativeQuery.FetchReturn {
String getOwnerAlias();
String getFetchAlias();
String getFetchedAttributeName();
public interface DynamicFetchBuilder extends FetchBuilder, NativeQuery.ReturnProperty {
}

View File

@ -0,0 +1,32 @@
/*
* 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.results.dynamic;
/**
* @author Steve Ebersole
*/
public interface DynamicFetchBuilderContainer {
/**
* Locate an explicit fetch definition for the named fetchable
*/
DynamicFetchBuilder findFetchBuilder(String fetchableName);
/**
* Add a property mapped to a single column.
*/
DynamicFetchBuilderContainer addProperty(String propertyName, String columnAlias);
/**
* Add a property mapped to multiple columns
*/
DynamicFetchBuilderContainer addProperty(String propertyName, String... columnAliases);
/**
* Add a property whose columns can later be defined using {@link DynamicFetchBuilder#addColumnAlias}
*/
DynamicFetchBuilder addProperty(String propertyName);
}

View File

@ -0,0 +1,98 @@
/*
* 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.results.dynamic;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.query.NativeQuery;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.results.FromClauseAccessImpl;
import org.hibernate.query.results.ResultsHelper;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
/**
* @author Steve Ebersole
*/
public class DynamicFetchBuilderLegacy implements DynamicFetchBuilder, NativeQuery.FetchReturn {
private final String tableAlias;
private final String ownerTableAlias;
private final String fetchableName;
private final List<String> columnNames;
public DynamicFetchBuilderLegacy(
String tableAlias,
String ownerTableAlias,
String fetchableName,
List<String> columnNames) {
this.tableAlias = tableAlias;
this.ownerTableAlias = ownerTableAlias;
this.fetchableName = fetchableName;
this.columnNames = columnNames;
}
public String getTableAlias() {
return tableAlias;
}
public String getOwnerAlias() {
return ownerTableAlias;
}
public String getFetchableName() {
return fetchableName;
}
@Override
public Fetch buildFetch(
FetchParent parent,
NavigablePath fetchPath,
JdbcValuesMetadata jdbcResultsMetadata,
BiFunction<String, String, DynamicFetchBuilderLegacy> legacyFetchResolver,
Consumer<SqlSelection> sqlSelectionConsumer,
DomainResultCreationState domainResultCreationState) {
final FromClauseAccessImpl fromClauseAccess = ResultsHelper.extractFromClauseAccess( domainResultCreationState );
final TableGroup ownerTableGroup = fromClauseAccess.findByAlias( ownerTableAlias );
// todo (6.0) : create the TableGroupJoin for the fetch and then build the fetch
throw new NotYetImplementedFor6Exception( getClass() );
}
@Override
public NativeQuery.ReturnProperty addColumnAlias(String columnAlias) {
columnNames.add( columnAlias );
return this;
}
@Override
public NativeQuery.FetchReturn setLockMode(LockMode lockMode) {
return null;
}
@Override
public NativeQuery.FetchReturn addProperty(String propertyName, String columnAlias) {
return null;
}
@Override
public NativeQuery.ReturnProperty addProperty(String propertyName) {
return null;
}
}

View File

@ -0,0 +1,66 @@
/*
* 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.results.dynamic;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.query.NativeQuery;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.results.FromClauseAccessImpl;
import org.hibernate.query.results.ResultsHelper;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.ast.tree.from.TableGroup;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
/**
* @author Steve Ebersole
*/
public class DynamicFetchBuilderStandard
implements DynamicFetchBuilder, NativeQuery.ReturnProperty {
private final DynamicFetchBuilderContainer container;
private final String fetchableName;
private final List<String> columnNames = new ArrayList<>();
public DynamicFetchBuilderStandard(
DynamicFetchBuilderContainer container,
String fetchableName) {
this.container = container;
this.fetchableName = fetchableName;
}
@Override
public Fetch buildFetch(
FetchParent parent,
NavigablePath fetchPath,
JdbcValuesMetadata jdbcResultsMetadata,
BiFunction<String, String, DynamicFetchBuilderLegacy> legacyFetchResolver,
Consumer<SqlSelection> sqlSelectionConsumer,
DomainResultCreationState domainResultCreationState) {
final FromClauseAccessImpl fromClauseAccess = ResultsHelper.extractFromClauseAccess( domainResultCreationState );
final TableGroup ownerTableGroup = fromClauseAccess.getTableGroup( parent.getNavigablePath() );
// todo (6.0) : create the TableGroupJoin for the fetch and then build the fetch
throw new NotYetImplementedFor6Exception( getClass() );
}
@Override
public NativeQuery.ReturnProperty addColumnAlias(String columnAlias) {
columnNames.add( columnAlias );
return this;
}
}

View File

@ -0,0 +1,25 @@
/*
* 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.results.dynamic;
import org.hibernate.query.NativeQuery;
import org.hibernate.query.results.ResultBuilder;
/**
* ResultBuilder specialization for results added through the Hibernate-specific
* {@link NativeQuery} result definition methods.
*
* @see NativeQuery#addScalar
* @see NativeQuery#addInstantiation
* @see NativeQuery#addAttributeResult
* @see NativeQuery#addEntity
* @see NativeQuery#addRoot
*
* @author Steve Ebersole
*/
public interface DynamicResultBuilder extends ResultBuilder, NativeQuery.ReturnableResultNode {
}

View File

@ -4,37 +4,33 @@
* 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.results;
package org.hibernate.query.results.dynamic;
import java.util.List;
import java.util.Locale;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.mapping.SingularAttributeMapping;
import org.hibernate.metamodel.mapping.internal.BasicValuedSingularAttributeMapping;
import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping;
import org.hibernate.sql.ast.spi.SqlAstCreationState;
import org.hibernate.query.results.SqlSelectionImpl;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.Fetch;
import org.hibernate.sql.results.graph.FetchParent;
import org.hibernate.sql.results.graph.basic.BasicResult;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
/**
* DynamicResultBuilder based on a named mapped attribute
*
* @author Steve Ebersole
*/
public class AttributeResultBuilder implements ResultBuilder {
public class DynamicResultBuilderAttribute implements DynamicResultBuilder {
private final BasicValuedSingularAttributeMapping attributeMapping;
private final String columnAlias;
private final String entityName;
private final String attributePath;
public AttributeResultBuilder(
public DynamicResultBuilderAttribute(
SingularAttributeMapping attributeMapping,
String columnAlias,
String entityName,
@ -59,14 +55,17 @@ public AttributeResultBuilder(
}
@Override
public DomainResult<?> buildReturn(
public DomainResult<?> buildResult(
JdbcValuesMetadata jdbcResultsMetadata,
BiFunction<String, String, LegacyFetchBuilder> legacyFetchResolver,
int resultPosition,
BiFunction<String, String, DynamicFetchBuilderLegacy> legacyFetchResolver,
Consumer<SqlSelection> sqlSelectionConsumer,
SessionFactoryImplementor sessionFactory) {
DomainResultCreationState domainResultCreationState) {
final int resultSetPosition = jdbcResultsMetadata.resolveColumnPosition( columnAlias );
final int valuesArrayPosition = resultSetPosition - 1;
// todo (6.0) : TableGroups + `attributeMapping#buldResult`
final SqlSelectionImpl sqlSelection = new SqlSelectionImpl( valuesArrayPosition, attributeMapping );
sqlSelectionConsumer.accept( sqlSelection );

View File

@ -0,0 +1,15 @@
/*
* 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.results.dynamic;
import org.hibernate.query.results.ResultBuilderBasicValued;
/**
* @author Steve Ebersole
*/
public interface DynamicResultBuilderBasic extends DynamicResultBuilder, ResultBuilderBasicValued {
}

View File

@ -0,0 +1,130 @@
/*
* 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.results.dynamic;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import javax.persistence.AttributeConverter;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.mapping.BasicValuedMapping;
import org.hibernate.metamodel.model.convert.internal.JpaAttributeConverterImpl;
import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
import org.hibernate.query.results.ResultsHelper;
import org.hibernate.query.results.SqlSelectionImpl;
import org.hibernate.resource.beans.spi.ManagedBean;
import org.hibernate.resource.beans.spi.ManagedBeanRegistry;
import org.hibernate.resource.beans.spi.ProvidedInstanceManagedBeanImpl;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.basic.BasicResult;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
import org.hibernate.type.BasicType;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.java.spi.JavaTypeDescriptorRegistry;
import org.hibernate.type.spi.TypeConfiguration;
/**
* A ResultBuilder for explicitly converted scalar results
*
* @author Steve Ebersole
*/
public class DynamicResultBuilderBasicConverted<O,R> implements DynamicResultBuilderBasic {
private final String columnAlias;
private final JavaTypeDescriptor<O> domainJtd;
private final JavaTypeDescriptor<R> jdbcJtd;
private final BasicValueConverter<O,R> basicValueConverter;
public DynamicResultBuilderBasicConverted(
String columnAlias,
Class<O> domainJavaType,
Class<R> jdbcJavaType,
AttributeConverter<O, R> converter,
SessionFactoryImplementor sessionFactory) {
final TypeConfiguration typeConfiguration = sessionFactory.getTypeConfiguration();
final JavaTypeDescriptorRegistry jtdRegistry = typeConfiguration.getJavaTypeDescriptorRegistry();
this.columnAlias = columnAlias;
this.domainJtd = jtdRegistry.getDescriptor( domainJavaType );
this.jdbcJtd = jtdRegistry.getDescriptor( jdbcJavaType );
final JavaTypeDescriptor<? extends AttributeConverter> converterJtd = jtdRegistry.getDescriptor( converter.getClass() );
final ManagedBean<? extends AttributeConverter<O,R>> bean = new ProvidedInstanceManagedBeanImpl<>( converter );
this.basicValueConverter = new JpaAttributeConverterImpl(
bean,
converterJtd,
domainJtd,
jdbcJtd
);
}
public DynamicResultBuilderBasicConverted(
String columnAlias,
Class<O> domainJavaType,
Class<R> jdbcJavaType,
Class<? extends AttributeConverter<O,R>> converterJavaType,
SessionFactoryImplementor sessionFactory) {
final ManagedBeanRegistry beans = sessionFactory.getServiceRegistry().getService( ManagedBeanRegistry.class );
final TypeConfiguration typeConfiguration = sessionFactory.getTypeConfiguration();
final JavaTypeDescriptorRegistry jtdRegistry = typeConfiguration.getJavaTypeDescriptorRegistry();
this.columnAlias = columnAlias;
this.domainJtd = jtdRegistry.getDescriptor( domainJavaType );
this.jdbcJtd = jtdRegistry.getDescriptor( jdbcJavaType );
final JavaTypeDescriptor<? extends AttributeConverter<O,R>> converterJtd = jtdRegistry.getDescriptor( converterJavaType );
final ManagedBean<? extends AttributeConverter<O,R>> bean = beans.getBean( converterJavaType );
this.basicValueConverter = new JpaAttributeConverterImpl(
bean,
converterJtd,
domainJtd,
jdbcJtd
);
}
@Override
public BasicResult<?> buildResult(
JdbcValuesMetadata jdbcResultsMetadata,
int resultPosition,
BiFunction<String, String, DynamicFetchBuilderLegacy> legacyFetchResolver,
Consumer<SqlSelection> sqlSelectionConsumer,
DomainResultCreationState domainResultCreationState) {
final int currentJdbcPosition = resultPosition + 1;
final int jdbcPosition;
if ( columnAlias != null ) {
jdbcPosition = jdbcResultsMetadata.resolveColumnPosition( columnAlias );
}
else {
jdbcPosition = currentJdbcPosition;
}
final TypeConfiguration typeConfiguration = domainResultCreationState.getSqlAstCreationState()
.getCreationContext()
.getSessionFactory()
.getTypeConfiguration();
final BasicType<?> basicType = typeConfiguration.getBasicTypeRegistry().resolve(
basicValueConverter.getRelationalJavaDescriptor(),
jdbcResultsMetadata.resolveSqlTypeDescriptor( jdbcPosition )
);
final int valuesArrayPosition = ResultsHelper.jdbcPositionToValuesArrayPosition( jdbcPosition );
final SqlSelectionImpl sqlSelection = new SqlSelectionImpl( valuesArrayPosition, (BasicValuedMapping) basicType );
sqlSelectionConsumer.accept( sqlSelection );
//noinspection unchecked
return new BasicResult( valuesArrayPosition, columnAlias, domainJtd, basicValueConverter );
}
}

View File

@ -0,0 +1,115 @@
/*
* 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.results.dynamic;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.mapping.BasicValuedMapping;
import org.hibernate.query.results.ResultsHelper;
import org.hibernate.query.results.SqlSelectionImpl;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.basic.BasicResult;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
import org.hibernate.type.BasicType;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
import org.hibernate.type.spi.TypeConfiguration;
/**
* Standard DynamicResultBuilder for basic values.
*
* @see org.hibernate.query.NativeQuery#addScalar
*
* @author Steve Ebersole
*/
public class DynamicResultBuilderBasicStandard implements DynamicResultBuilderBasic {
private final String columnName;
private final String resultAlias;
private final BasicType<?> explicitType;
private final JavaTypeDescriptor<?> explicitJavaTypeDescriptor;
public DynamicResultBuilderBasicStandard(String columnName, String resultAlias) {
assert columnName != null;
this.columnName = columnName;
this.resultAlias = resultAlias != null ? resultAlias : columnName;
this.explicitType = null;
this.explicitJavaTypeDescriptor = null;
}
public DynamicResultBuilderBasicStandard(String columnName, String resultAlias, JavaTypeDescriptor<?> explicitJavaTypeDescriptor) {
assert columnName != null;
this.columnName = columnName;
this.resultAlias = resultAlias != null ? resultAlias : columnName;
assert explicitJavaTypeDescriptor != null;
this.explicitJavaTypeDescriptor = explicitJavaTypeDescriptor;
this.explicitType = null;
}
public DynamicResultBuilderBasicStandard(String columnName, String resultAlias, BasicType<?> explicitType) {
assert columnName != null;
this.columnName = columnName;
this.resultAlias = resultAlias != null ? resultAlias : columnName;
assert explicitType != null;
this.explicitType = explicitType;
this.explicitJavaTypeDescriptor = null;
}
public String getColumnName() {
return columnName;
}
@Override
public BasicResult<?> buildResult(
JdbcValuesMetadata jdbcResultsMetadata,
int resultPosition,
BiFunction<String, String, DynamicFetchBuilderLegacy> legacyFetchResolver,
Consumer<SqlSelection> sqlSelectionConsumer,
DomainResultCreationState domainResultCreationState) {
final SessionFactoryImplementor sessionFactory = domainResultCreationState.getSqlAstCreationState()
.getCreationContext()
.getSessionFactory();
final int jdbcPosition = jdbcResultsMetadata.resolveColumnPosition( columnName );
final int valuesArrayPosition = ResultsHelper.jdbcPositionToValuesArrayPosition( jdbcPosition );
final BasicType<?> basicType;
if ( explicitType != null ) {
basicType = explicitType;
}
else if ( explicitJavaTypeDescriptor != null ) {
final TypeConfiguration typeConfiguration = sessionFactory.getTypeConfiguration();
final SqlTypeDescriptor sqlTypeDescriptor = jdbcResultsMetadata.resolveSqlTypeDescriptor( jdbcPosition );
basicType = typeConfiguration.getBasicTypeRegistry().resolve( explicitJavaTypeDescriptor, sqlTypeDescriptor );
}
else {
final TypeConfiguration typeConfiguration = sessionFactory.getTypeConfiguration();
final SqlTypeDescriptor sqlTypeDescriptor = jdbcResultsMetadata.resolveSqlTypeDescriptor( jdbcPosition );
final JavaTypeDescriptor<?> javaTypeDescriptor = sqlTypeDescriptor.getJdbcRecommendedJavaTypeMapping( typeConfiguration );
basicType = typeConfiguration.getBasicTypeRegistry().resolve( javaTypeDescriptor, sqlTypeDescriptor );
}
final SqlSelectionImpl sqlSelection = new SqlSelectionImpl( valuesArrayPosition, (BasicValuedMapping) basicType );
sqlSelectionConsumer.accept( sqlSelection );
return new BasicResult<>( valuesArrayPosition, resultAlias, explicitJavaTypeDescriptor );
}
}

View File

@ -0,0 +1,29 @@
/*
* 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.results.dynamic;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import org.hibernate.query.results.ResultBuilderEntityValued;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.entity.EntityResult;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
/**
* @author Steve Ebersole
*/
public interface DynamicResultBuilderEntity extends DynamicResultBuilder, ResultBuilderEntityValued {
@Override
EntityResult buildResult(
JdbcValuesMetadata jdbcResultsMetadata,
int resultPosition,
BiFunction<String, String, DynamicFetchBuilderLegacy> legacyFetchResolver,
Consumer<SqlSelection> sqlSelectionConsumer,
DomainResultCreationState domainResultCreationState);
}

View File

@ -0,0 +1,85 @@
/*
* 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.results.dynamic;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.query.NavigablePath;
import org.hibernate.query.results.FromClauseAccessImpl;
import org.hibernate.query.results.ResultsHelper;
import org.hibernate.query.results.TableGroupImpl;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.entity.EntityResult;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
/**
* An entity-valued DynamicResultBuilder for cases when the user has not supplied
* specific column -> attribute mappings. Hibernate uses the column names mapped
* by the entity mapping itself to read the entity values.
*
* @author Steve Ebersole
*/
public class DynamicResultBuilderEntityCalculated implements DynamicResultBuilderEntity {
private final NavigablePath navigablePath;
private final EntityMappingType entityMapping;
private final String tableAlias;
private final LockMode explicitLockMode;
private final SessionFactoryImplementor sessionFactory;
public DynamicResultBuilderEntityCalculated(
EntityMappingType entityMapping,
String tableAlias,
LockMode explicitLockMode,
SessionFactoryImplementor sessionFactory) {
this.entityMapping = entityMapping;
this.navigablePath = new NavigablePath( entityMapping.getEntityName() );
this.tableAlias = tableAlias;
this.explicitLockMode = explicitLockMode;
this.sessionFactory = sessionFactory;
}
@Override
public EntityResult buildResult(
JdbcValuesMetadata jdbcResultsMetadata,
int resultPosition,
BiFunction<String, String, DynamicFetchBuilderLegacy> legacyFetchResolver,
Consumer<SqlSelection> sqlSelectionConsumer,
DomainResultCreationState domainResultCreationState) {
final FromClauseAccessImpl fromClauseAccess = ResultsHelper.extractFromClauseAccess( domainResultCreationState );
TableGroupImpl.TableReferenceImpl tableReference = new TableGroupImpl.TableReferenceImpl(
entityMapping.getEntityName(),
tableAlias,
false,
sessionFactory
);
final TableGroupImpl tableGroup = new TableGroupImpl(
navigablePath,
tableAlias,
tableReference,
entityMapping,
explicitLockMode
);
fromClauseAccess.registerTableGroup( navigablePath, tableGroup );
return (EntityResult) entityMapping.createDomainResult(
navigablePath,
tableGroup,
tableAlias,
domainResultCreationState
);
}
}

View File

@ -0,0 +1,133 @@
/*
* 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.results.dynamic;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import org.hibernate.LockMode;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.metamodel.mapping.EntityMappingType;
import org.hibernate.query.NativeQuery;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.entity.EntityResult;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
/**
* @author Steve Ebersole
*/
public class DynamicResultBuilderEntityStandard
extends AbstractFetchBuilderContainer<DynamicResultBuilderEntityStandard>
implements DynamicResultBuilderEntity, NativeQuery.RootReturn {
private final NavigablePath navigablePath;
private final EntityMappingType entityMapping;
private final String tableAlias;
private LockMode lockMode;
private String discriminatorColumnName;
public DynamicResultBuilderEntityStandard(EntityMappingType entityMapping, String tableAlias) {
this( entityMapping, tableAlias, null );
}
public DynamicResultBuilderEntityStandard(
EntityMappingType entityMapping,
String tableAlias,
String discriminatorColumnName) {
this.navigablePath = new NavigablePath( entityMapping.getEntityName() );
this.entityMapping = entityMapping;
this.tableAlias = tableAlias;
this.discriminatorColumnName = discriminatorColumnName;
}
public EntityMappingType getEntityMapping() {
return entityMapping;
}
@Override
protected String getPropertyBase() {
return entityMapping.getEntityName();
}
@Override
public EntityResult buildResult(
JdbcValuesMetadata jdbcResultsMetadata,
int resultPosition,
BiFunction<String, String, DynamicFetchBuilderLegacy> legacyFetchResolver,
Consumer<SqlSelection> sqlSelectionConsumer,
DomainResultCreationState domainResultCreationState) {
// final FromClauseAccessImpl fromClauseAccess = ResultsHelper.extractFromClauseAccess( domainResultCreationState );
// final TableGroup tableGroup = fromClauseAccess.resolveTableGroup(
// navigablePath,
// np -> {
// final TableGroupImpl.TableReferenceImpl tableReference = new TableGroupImpl.TableReferenceImpl(
// entityMapping.getEntityName(),
// tableAlias,
// false,
// domainResultCreationState.getSqlAstCreationState().getCreationContext().getSessionFactory()
// );
// return new TableGroupImpl( navigablePath, tableAlias, tableReference, entityMapping, lockMode );
// }
// );
//
// return new EntityResultImpl(
// entityMapping,
// tableAlias,
// lockMode,
// jdbcResultsMetadata,
// sqlSelectionConsumer,
// () -> {
// if ( discriminatorColumnName == null ) {
// return null;
// }
//
// final int jdbcPosition;
// try {
// jdbcPosition = jdbcResultsMetadata.resolveColumnPosition( discriminatorColumnName );
// }
// catch (Exception e) {
// return null;
// }
//
// final int valuesArrayPosition = jdbcPosition - 1;
//
// final SqlSelection discriminatorSqlSelection = new SqlSelectionImpl(
// valuesArrayPosition,
// entityMapping.getDiscriminatorMapping()
// );
//
// sqlSelectionConsumer.accept( discriminatorSqlSelection );
//
// return discriminatorSqlSelection;
// },
// // fetchableName -> fetchBuilders.get( fetchableName ),
// fetchableName -> null,
// legacyFetchResolver,
// domainResultCreationState
// );
throw new NotYetImplementedFor6Exception( getClass() );
}
@Override
public DynamicResultBuilderEntityStandard setLockMode(LockMode lockMode) {
this.lockMode = lockMode;
return this;
}
@Override
public DynamicResultBuilderEntityStandard setDiscriminatorAlias(String columnName) {
this.discriminatorColumnName = columnName;
return this;
}
}

View File

@ -0,0 +1,93 @@
/*
* 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.results.dynamic;
import java.util.ArrayList;
import java.util.List;
import java.util.function.BiFunction;
import java.util.function.Consumer;
import org.hibernate.query.DynamicInstantiationNature;
import org.hibernate.query.NativeQuery;
import org.hibernate.query.results.Builders;
import org.hibernate.query.results.ResultBuilderInstantiationValued;
import org.hibernate.sql.ast.spi.SqlSelection;
import org.hibernate.sql.results.graph.DomainResult;
import org.hibernate.sql.results.graph.DomainResultCreationState;
import org.hibernate.sql.results.graph.instantiation.internal.ArgumentDomainResult;
import org.hibernate.sql.results.graph.instantiation.internal.DynamicInstantiationResultImpl;
import org.hibernate.sql.results.jdbc.spi.JdbcValuesMetadata;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/**
* @author Steve Ebersole
*/
public class DynamicResultBuilderInstantiation<J>
implements DynamicResultBuilder, ResultBuilderInstantiationValued, NativeQuery.InstantiationResultNode<J> {
private static class InstantiationArgument {
private final DynamicResultBuilder argumentBuilder;
private final String resultAlias;
public InstantiationArgument(DynamicResultBuilder argumentBuilder, String resultAlias) {
this.argumentBuilder = argumentBuilder;
this.resultAlias = resultAlias;
}
}
private final JavaTypeDescriptor<J> javaTypeDescriptor;
private final List<InstantiationArgument> argumentResultBuilders = new ArrayList<>();
public DynamicResultBuilderInstantiation(JavaTypeDescriptor<J> javaTypeDescriptor) {
this.javaTypeDescriptor = javaTypeDescriptor;
}
@Override
public NativeQuery.InstantiationResultNode<J> addBasicArgument(String columnAlias, String argumentAlias) {
argumentResultBuilders.add(
new InstantiationArgument( Builders.scalar( columnAlias ), argumentAlias )
);
return this;
}
@Override
public DomainResult<?> buildResult(
JdbcValuesMetadata jdbcResultsMetadata,
int resultPosition,
BiFunction<String, String, DynamicFetchBuilderLegacy> legacyFetchResolver,
Consumer<SqlSelection> sqlSelectionConsumer,
DomainResultCreationState domainResultCreationState) {
if ( argumentResultBuilders.isEmpty() ) {
throw new IllegalStateException( "DynamicResultBuilderInstantiation defined no arguments" );
}
final List<ArgumentDomainResult<?>> argumentDomainResults = new ArrayList<>( argumentResultBuilders.size() );
for ( int i = 0; i < argumentResultBuilders.size(); i++ ) {
final InstantiationArgument argument = argumentResultBuilders.get( i );
final ArgumentDomainResult<Object> argumentDomainResult = new ArgumentDomainResult<>(
argument.argumentBuilder.buildResult(
jdbcResultsMetadata,
i,
legacyFetchResolver,
sqlSelectionConsumer,
domainResultCreationState
)
);
argumentDomainResults.add( argumentDomainResult );
}
return new DynamicInstantiationResultImpl(
null,
DynamicInstantiationNature.CLASS,
javaTypeDescriptor,
argumentDomainResults
);
}
}

View File

@ -0,0 +1,18 @@
/*
* 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
*/
/**
* Support for mutable result/fetch builder graphs nodes built dynamically via
* Hibernate's {@link org.hibernate.query.NativeQuery} APIs
*
* @see org.hibernate.query.NativeQuery#addScalar
* @see org.hibernate.query.NativeQuery#addEntity
* @see org.hibernate.query.NativeQuery#addJoin
* @see org.hibernate.query.NativeQuery#addFetch
* @see org.hibernate.query.NativeQuery#addRoot
*/
package org.hibernate.query.results.dynamic;

View File

@ -9,7 +9,14 @@
* Support for defining result-set mappings used in {@link org.hibernate.query.NativeQuery}
* and {@link org.hibernate.procedure.ProcedureCall} / {@link javax.persistence.StoredProcedureQuery}.
* These result-set mappings are used to map the values in the JDBC {@link java.sql.ResultSet}
* into "domain results" (see {@link org.hibernate.sql.results.graph.DomainResult}).
* into the query result graph.
*
* NOTE : Handling the different sources of results and fetches is split into 2 packages
* for performance reasons. The classes in {@link org.hibernate.query.results.complete}
* represent result/fetch definitions that are completely known up-front and are faster to
* resolve. The definitions in {@link org.hibernate.query.results.dynamic} are built incrementally
* via Hibernate's {@link org.hibernate.query.NativeQuery} contract need to resolve themselves
* against other dynamic result/fetch definitions and therefore take more resources to resolve
*
* @see org.hibernate.query.results.ResultSetMapping
*

View File

@ -58,12 +58,14 @@
import org.hibernate.query.internal.ParameterMetadataImpl;
import org.hibernate.query.internal.QueryOptionsImpl;
import org.hibernate.query.internal.QueryParameterBindingsImpl;
import org.hibernate.query.internal.ResultSetMappingResolutionContext;
import org.hibernate.query.named.NamedResultSetMappingMemento;
import org.hibernate.query.results.Builders;
import org.hibernate.query.results.EntityResultBuilder;
import org.hibernate.query.results.LegacyFetchBuilder;
import org.hibernate.query.results.ResultBuilder;
import org.hibernate.query.results.ResultSetMappingImpl;
import org.hibernate.query.results.dynamic.DynamicResultBuilderEntityStandard;
import org.hibernate.query.results.dynamic.DynamicResultBuilderInstantiation;
import org.hibernate.query.results.dynamic.DynamicFetchBuilderLegacy;
import org.hibernate.query.spi.AbstractQuery;
import org.hibernate.query.spi.MutableQueryOptions;
import org.hibernate.query.spi.NonSelectQueryPlan;
@ -96,7 +98,7 @@
@SuppressWarnings("WeakerAccess")
public class NativeQueryImpl<R>
extends AbstractQuery<R>
implements NativeQueryImplementor<R>, ExecutionContext {
implements NativeQueryImplementor<R>, ExecutionContext, ResultSetMappingResolutionContext {
private final String sqlString;
private final ParameterMetadataImplementor parameterMetadata;
@ -159,7 +161,7 @@ public NativeQueryImpl(
.getQueryEngine()
.getNamedQueryRepository()
.getResultSetMappingMemento( resultSetMappingName )
.resolve( resultSetMapping, (s) -> {}, getSessionFactory() );
.resolve( resultSetMapping, (s) -> {}, this );
}
public NativeQueryImpl(
@ -169,7 +171,7 @@ public NativeQueryImpl(
super( session );
this.sqlString = sqlString;
resultSetMappingMemento.resolve( resultSetMapping, (s) -> {}, getSessionFactory() );
resultSetMappingMemento.resolve( resultSetMapping, (s) -> {}, this );
final ParameterInterpretation parameterInterpretation = resolveParameterInterpretation( session );
@ -518,9 +520,18 @@ public NativeQueryImplementor<R> addScalar(String columnAlias, Class<?> javaType
@Override
public <C> NativeQueryImplementor<R> addScalar(
String columnAlias,
Class<C> relationalJavaType,
Class<C> jdbcJavaType,
AttributeConverter<?, C> converter) {
return registerBuilder( Builders.scalar( columnAlias, relationalJavaType, converter, getSessionFactory() ) );
return registerBuilder( Builders.converted( columnAlias, jdbcJavaType, converter, getSessionFactory() ) );
}
@Override
public <O, J> NativeQueryImplementor<R> addScalar(
String columnAlias,
Class<O> domainJavaType,
Class<J> jdbcJavaType,
AttributeConverter<O, J> converter) {
return registerBuilder( Builders.converted( columnAlias, domainJavaType, jdbcJavaType, converter, getSessionFactory() ) );
}
@Override
@ -528,7 +539,26 @@ public <C> NativeQueryImplementor<R> addScalar(
String columnAlias,
Class<C> relationalJavaType,
Class<? extends AttributeConverter<?, C>> converter) {
return registerBuilder( Builders.scalar( columnAlias, relationalJavaType, converter, getSessionFactory() ) );
return registerBuilder( Builders.converted( columnAlias, relationalJavaType, converter, getSessionFactory() ) );
}
@Override
public <O, J> NativeQueryImplementor<R> addScalar(
String columnAlias,
Class<O> domainJavaType,
Class<J> jdbcJavaType,
Class<? extends AttributeConverter<O, J>> converterJavaType) {
return registerBuilder( Builders.converted( columnAlias, domainJavaType, jdbcJavaType, converterJavaType, getSessionFactory() ) );
}
@Override
public <J> InstantiationResultNode<J> addInstantiation(Class<J> targetJavaType) {
final DynamicResultBuilderInstantiation<J> builder = Builders.instantiation(
targetJavaType,
getSessionFactory()
);
registerBuilder( builder );
return builder;
}
@Override
@ -557,17 +587,18 @@ public NativeQueryImplementor<R> addAttributeResult(
}
@Override
public EntityResultBuilder addRoot(String tableAlias, String entityName) {
final EntityResultBuilder resultBuilder = Builders.entity(
public DynamicResultBuilderEntityStandard addRoot(String tableAlias, String entityName) {
final DynamicResultBuilderEntityStandard resultBuilder = Builders.entity(
tableAlias,
entityName
entityName,
getSessionFactory()
);
resultSetMapping.addResultBuilder( resultBuilder );
return resultBuilder;
}
@Override
public EntityResultBuilder addRoot(String tableAlias, Class entityType) {
public DynamicResultBuilderEntityStandard addRoot(String tableAlias, Class entityType) {
return addRoot( tableAlias, entityType.getName() );
}
@ -578,13 +609,13 @@ public NativeQueryImplementor<R> addEntity(String entityName) {
@Override
public NativeQueryImplementor<R> addEntity(String tableAlias, String entityName) {
registerBuilder( Builders.entityCalculated( tableAlias, entityName ) );
registerBuilder( Builders.entityCalculated( tableAlias, entityName, getSessionFactory() ) );
return this;
}
@Override
public NativeQueryImplementor<R> addEntity(String tableAlias, String entityName, LockMode lockMode) {
registerBuilder( Builders.entityCalculated( tableAlias, entityName, lockMode ) );
registerBuilder( Builders.entityCalculated( tableAlias, entityName, lockMode, getSessionFactory() ) );
return this;
}
@ -605,7 +636,7 @@ public NativeQueryImplementor<R> addEntity(String tableAlias, Class entityClass,
@Override
public FetchReturn addFetch(String tableAlias, String ownerTableAlias, String joinPropertyName) {
final LegacyFetchBuilder fetchBuilder = Builders.fetch( tableAlias, ownerTableAlias, joinPropertyName );
final DynamicFetchBuilderLegacy fetchBuilder = Builders.fetch( tableAlias, ownerTableAlias, joinPropertyName );
resultSetMapping.addLegacyFetchBuilder( fetchBuilder );
return fetchBuilder;
}

View File

@ -34,7 +34,7 @@
import org.hibernate.query.ResultListTransformer;
import org.hibernate.query.TupleTransformer;
import org.hibernate.query.named.NameableQuery;
import org.hibernate.query.results.EntityResultBuilder;
import org.hibernate.query.results.dynamic.DynamicResultBuilderEntityStandard;
import org.hibernate.query.spi.QueryImplementor;
/**
@ -63,9 +63,19 @@ public interface NativeQueryImplementor<R> extends QueryImplementor<R>, NativeQu
@Override
<C> NativeQueryImplementor<R> addScalar(String columnAlias, Class<C> relationalJavaType, AttributeConverter<?,C> converter);
@Override
<O, J> NativeQueryImplementor<R> addScalar(String columnAlias, Class<O> domainJavaType, Class<J> jdbcJavaType, AttributeConverter<O, J> converter);
@Override
<C> NativeQueryImplementor<R> addScalar(String columnAlias, Class<C> relationalJavaType, Class<? extends AttributeConverter<?,C>> converter);
@Override
<O, J> NativeQueryImplementor<R> addScalar(
String columnAlias,
Class<O> domainJavaType,
Class<J> jdbcJavaType,
Class<? extends AttributeConverter<O, J>> converter);
@Override
NativeQueryImplementor<R> addAttributeResult(String columnAlias, Class<?> entityJavaType, String attributePath);
@ -76,7 +86,7 @@ public interface NativeQueryImplementor<R> extends QueryImplementor<R>, NativeQu
NativeQueryImplementor<R> addAttributeResult(String columnAlias, SingularAttribute<?, ?> attribute);
@Override
EntityResultBuilder addRoot(String tableAlias, String entityName);
DynamicResultBuilderEntityStandard addRoot(String tableAlias, String entityName);
@Override
NativeQueryImplementor<R> addEntity(String entityName);

View File

@ -87,9 +87,7 @@ public Expression resolveSqlExpression(
expressionMap.put( key, expression );
}
final Expression result = normalize( expression );
return result;
return expression;
}
@SuppressWarnings("WeakerAccess")

View File

@ -8,12 +8,10 @@
import java.util.List;
import org.hibernate.LockMode;
import org.hibernate.NotYetImplementedFor6Exception;
import org.hibernate.metamodel.mapping.AssociationKey;
import org.hibernate.metamodel.mapping.ModelPart;
import org.hibernate.query.NavigablePath;
import org.hibernate.sql.results.jdbc.spi.JdbcValues;
import org.hibernate.sql.ast.spi.SqlAliasBaseManager;
import org.hibernate.sql.ast.spi.SqlAstCreationState;

View File

@ -23,6 +23,7 @@
* @author Steve Ebersole
*/
public class EntityResultImpl extends AbstractEntityResultGraphNode implements EntityResult {
private final String resultVariable;
public EntityResultImpl(

View File

@ -28,5 +28,7 @@ public interface JdbcValuesMappingProducer {
* {@link org.hibernate.sql.results.graph.DomainResult} and
* {@link org.hibernate.sql.results.graph.Fetch}
*/
JdbcValuesMapping resolve(JdbcValuesMetadata jdbcResultsMetadata, SessionFactoryImplementor sessionFactory);
JdbcValuesMapping resolve(
JdbcValuesMetadata jdbcResultsMetadata,
SessionFactoryImplementor sessionFactory);
}

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.type.descriptor;
import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
/**
* @author Steve Ebersole
*/
public class EmptyJdbcValueExtractor implements ValueExtractor {
/**
* Singleton access
*/
public static final EmptyJdbcValueExtractor INSTANCE = new EmptyJdbcValueExtractor();
@Override
public Object extract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException {
return null;
}
@Override
public Object extract(CallableStatement statement, int paramIndex, WrapperOptions options) throws SQLException {
return null;
}
@Override
public Object extract(CallableStatement statement, String paramName, WrapperOptions options) throws SQLException {
return null;
}
}

View File

@ -9,7 +9,6 @@
import java.sql.CallableStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import javax.persistence.AttributeConverter;
import javax.persistence.PersistenceException;

View File

@ -9,6 +9,8 @@
import javax.persistence.ColumnResult;
import javax.persistence.ConstructorResult;
import javax.persistence.Entity;
import javax.persistence.EntityResult;
import javax.persistence.FieldResult;
import javax.persistence.Id;
import javax.persistence.SqlResultSetMapping;
@ -37,6 +39,16 @@
}
)
)
@SqlResultSetMapping(
name = "entity",
entities = @EntityResult(
entityClass = SimpleEntityWithNamedMappings.class,
fields = {
@FieldResult( name = "id", column = "id" ),
@FieldResult( name = "name", column = "name" )
}
)
)
public class SimpleEntityWithNamedMappings {
@Id
private Integer id;

View File

@ -6,6 +6,8 @@
*/
package org.hibernate.orm.test.query.named.resultmapping;
import org.hibernate.engine.spi.SessionFactoryImplementor;
import org.hibernate.query.internal.ResultSetMappingResolutionContext;
import org.hibernate.query.named.NamedQueryRepository;
import org.hibernate.query.named.NamedResultSetMappingMemento;
import org.hibernate.query.results.ResultSetMapping;
@ -33,7 +35,15 @@ public void testMappingResolution(SessionFactoryScope sessionFactoryScope) {
final NamedResultSetMappingMemento mappingMemento = namedQueryRepository.getResultSetMappingMemento( "name" );
final ResultSetMapping mapping = new ResultSetMappingImpl();
mappingMemento.resolve( mapping, querySpace -> {}, sessionFactoryScope.getSessionFactory() );
final ResultSetMappingResolutionContext resolutionContext = new ResultSetMappingResolutionContext() {
@Override
public SessionFactoryImplementor getSessionFactory() {
return sessionFactoryScope.getSessionFactory();
}
};
mappingMemento.resolve( mapping, querySpace -> {}, resolutionContext );
assertThat( mapping.getNumberOfResultBuilders(), is( 1 ) );
}

View File

@ -11,6 +11,7 @@
import org.hibernate.query.named.NamedResultSetMappingMemento;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.FailureExpected;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.AfterEach;
@ -27,6 +28,7 @@
@DomainModel( annotatedClasses = SimpleEntityWithNamedMappings.class )
@SessionFactory
public class UsageTests {
// select a.{*}
@Test
public void testSimpleScalarMapping(SessionFactoryScope scope) {
scope.inTransaction(
@ -75,6 +77,34 @@ public void testSimpleInstantiationOfScalars(SessionFactoryScope scope) {
);
}
@Test
@FailureExpected( reason = "Entity result mappings not yet implemented" )
public void testSimpleEntityResultMapping(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
// make sure it is in the repository
final NamedResultSetMappingMemento mappingMemento = session.getSessionFactory()
.getQueryEngine()
.getNamedQueryRepository()
.getResultSetMappingMemento( "entity" );
assertThat( mappingMemento, notNullValue() );
// apply it to a native-query
final String qryString = "select id, name from SimpleEntityWithNamedMappings";
final List<SimpleEntityWithNamedMappings> results
= session.createNativeQuery( qryString, "entity" ).list();
assertThat( results.size(), is( 1 ) );
final SimpleEntityWithNamedMappings entity = results.get( 0 );
assertThat( entity.getId(), is( 1 ) );
assertThat( entity.getName(), is( "test" ) );
// todo (6.0) : should also try executing the ProcedureCall once that functionality is implemented
session.createStoredProcedureCall( "abc", "entity" );
}
);
}
@BeforeEach
public void prepareData(SessionFactoryScope scope) {
scope.inTransaction(

View File

@ -17,6 +17,7 @@
import org.hibernate.metamodel.mapping.internal.BasicValuedSingularAttributeMapping;
import org.hibernate.metamodel.model.convert.spi.BasicValueConverter;
import org.hibernate.metamodel.model.convert.spi.JpaAttributeConverter;
import org.hibernate.query.NativeQuery;
import org.hibernate.query.sql.spi.NativeQueryImplementor;
import org.hibernate.testing.orm.domain.StandardDomainModel;
@ -71,6 +72,25 @@ public void fullyImplicitTest(SessionFactoryScope scope) {
}
);
}
@Test
public void fullyImplicitTest2(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
final String sql = "select count(theString) from EntityOfBasics";
final NativeQueryImplementor<?> query = session.createNativeQuery( sql );
final List<?> results = query.list();
assertThat( results.size(), is( 1 ) );
final Object result = results.get( 0 );
assertThat( result, instanceOf( Long.class ) );
assertThat( result, is( 1L ) );
}
);
}
@Test
public void explicitOrderTest(SessionFactoryScope scope) {
scope.inTransaction(
@ -174,6 +194,7 @@ public void explicitConversionTest(SessionFactoryScope scope) {
final NativeQueryImplementor<?> query = session.createNativeQuery( sql );
query.addScalar(
"converted_gender",
EntityOfBasics.Gender.class,
Character.class,
new EntityOfBasics.GenderConverter()
);
@ -194,6 +215,7 @@ public void explicitConversionTest(SessionFactoryScope scope) {
final NativeQueryImplementor<?> query = session.createNativeQuery( sql );
query.addScalar(
"converted_gender",
EntityOfBasics.Gender.class,
Character.class,
EntityOfBasics.GenderConverter.class
);
@ -296,4 +318,35 @@ public void cleanUpData(SessionFactoryScope scope) {
session -> session.createQuery( "delete EntityOfBasics" ).executeUpdate()
);
}
public static class DTO {
private Integer key;
private String text;
public DTO(Integer key, String text) {
this.key = key;
this.text = text;
}
}
public static class Bean {
private Integer key;
private String text;
public Integer getKey() {
return key;
}
public void setKey(Integer key) {
this.key = key;
}
public String getText() {
return text;
}
public void setText(String text) {
this.text = text;
}
}
}