org.hibernate.boot.model.source.internal.hbm.NamedQueryBinder Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hibernate-core Show documentation
Show all versions of hibernate-core Show documentation
Hibernate's core ORM functionality
/*
* 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 .
*/
package org.hibernate.boot.model.source.internal.hbm;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import javax.xml.bind.JAXBElement;
import org.hibernate.MappingException;
import org.hibernate.boot.jaxb.hbm.internal.ImplicitResultSetMappingDefinition;
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmNamedNativeQueryType;
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmNamedQueryType;
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmNativeQueryCollectionLoadReturnType;
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmNativeQueryJoinReturnType;
import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmNativeQueryReturnType;
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.cfg.SecondPass;
import org.hibernate.engine.ResultSetMappingDefinition;
import org.hibernate.engine.query.spi.sql.NativeSQLQueryReturn;
import org.hibernate.engine.spi.NamedQueryDefinitionBuilder;
import org.hibernate.engine.spi.NamedSQLQueryDefinition;
import org.hibernate.engine.spi.NamedSQLQueryDefinitionBuilder;
import org.hibernate.internal.util.StringHelper;
/**
* @author Steve Ebersole
*/
public class NamedQueryBinder {
public static void processNamedQuery(
HbmLocalMetadataBuildingContext context,
JaxbHbmNamedQueryType namedQueryBinding) {
processNamedQuery( context, namedQueryBinding, "" );
}
public static void processNamedQuery(
HbmLocalMetadataBuildingContext context,
JaxbHbmNamedQueryType namedQueryBinding,
String prefix) {
String query = null;
java.util.Map parameterTypeMap = null;
for ( Object content : namedQueryBinding.getContent() ) {
if ( String.class.isInstance( content ) ) {
String trimmed = ((String)content).trim();
if (!"".equals(trimmed)) {
query = trimmed;
}
}
else {
final JaxbHbmQueryParamType paramTypeBinding =
(JaxbHbmQueryParamType)((JAXBElement)content).getValue();
if ( parameterTypeMap == null ) {
parameterTypeMap = new HashMap();
}
parameterTypeMap.put( paramTypeBinding.getName(), paramTypeBinding.getType() );
}
}
if ( query == null ) {
throw new org.hibernate.boot.MappingException(
String.format(
"Named query [%s] did not specify query string",
namedQueryBinding.getName()
),
context.getOrigin()
);
}
context.getMetadataCollector().addNamedQuery(
new NamedQueryDefinitionBuilder()
.setName( prefix + namedQueryBinding.getName() )
.setQuery( query )
.setComment( namedQueryBinding.getComment() )
.setCacheable( namedQueryBinding.isCacheable() )
.setCacheMode( namedQueryBinding.getCacheMode() )
.setCacheRegion( namedQueryBinding.getCacheRegion() )
.setTimeout( namedQueryBinding.getTimeout() )
.setReadOnly( namedQueryBinding.isReadOnly() )
.setFlushMode( namedQueryBinding.getFlushMode() )
.setFetchSize( namedQueryBinding.getFetchSize() )
.setParameterTypes( parameterTypeMap )
.createNamedQueryDefinition()
);
}
public static void processNamedNativeQuery(
HbmLocalMetadataBuildingContext context,
JaxbHbmNamedNativeQueryType namedQueryBinding) {
processNamedNativeQuery( context, namedQueryBinding, "" );
}
public static void processNamedNativeQuery(
final HbmLocalMetadataBuildingContext context,
JaxbHbmNamedNativeQueryType namedQueryBinding,
String prefix) {
final String queryName = prefix + namedQueryBinding.getName();
final NamedSQLQueryDefinitionBuilder builder = new NamedSQLQueryDefinitionBuilder()
.setName( queryName )
.setComment( namedQueryBinding.getComment() )
.setCacheable( namedQueryBinding.isCacheable() )
.setCacheMode( namedQueryBinding.getCacheMode() )
.setCacheRegion( namedQueryBinding.getCacheRegion() )
.setTimeout( namedQueryBinding.getTimeout() )
.setReadOnly( namedQueryBinding.isReadOnly() )
.setFlushMode( namedQueryBinding.getFlushMode() )
.setFetchSize( namedQueryBinding.getFetchSize() )
.setCallable( namedQueryBinding.isCallable() )
.setResultSetRef( namedQueryBinding.getResultsetRef() );
final ImplicitResultSetMappingDefinition.Builder implicitResultSetMappingBuilder
= new ImplicitResultSetMappingDefinition.Builder( queryName );
boolean foundQuery = false;
for ( Object content : namedQueryBinding.getContent() ) {
final boolean wasQuery = processNamedQueryContentItem(
content,
builder,
implicitResultSetMappingBuilder,
namedQueryBinding,
context
);
if ( wasQuery ) {
foundQuery = true;
}
}
if ( !foundQuery ) {
throw new org.hibernate.boot.MappingException(
String.format(
"Named native query [%s] did not specify query string",
namedQueryBinding.getName()
),
context.getOrigin()
);
}
if ( implicitResultSetMappingBuilder.hasAnyReturns() ) {
if ( StringHelper.isNotEmpty( namedQueryBinding.getResultsetRef() ) ) {
throw new org.hibernate.boot.MappingException(
String.format(
"Named native query [%s] specified both a resultset-ref and an inline mapping of results",
namedQueryBinding.getName()
),
context.getOrigin()
);
}
// Building a ResultSet mapping needs access to entity bindings for any entity
// returns it defines. But binding for those entities may have not been
// completed yet. For "normal" ResultSet mappings, this is already handled by
// the fact that MetadataSourceProcessor#processResultSetMappings() is called
// after all entity hierarchies have been processed. However, here we are in
// the middle of processing named-queries (either top-level or entity-level)
// and have no guarantee that any entity bindings we may need here are bound.
// So we add the second-pass to bind the implicit resultSet mapping.
//
// It is possible to know here whether the second-pass is needed or whether we
// can immediately bind the ResultSet mapping.
// todo : consider implementing this (^^) checking
final ImplicitResultSetMappingDefinition implicitResultSetMappingDefinition = implicitResultSetMappingBuilder.build();
builder.setResultSetRef( implicitResultSetMappingDefinition.getName() );
context.getMetadataCollector().addSecondPass(
new SecondPass() {
@Override
public void doSecondPass(Map persistentClasses) throws MappingException {
final ResultSetMappingDefinition resultSetMappingDefinition =
ResultSetMappingBinder.bind( implicitResultSetMappingDefinition, context );
context.getMetadataCollector().addResultSetMapping( resultSetMappingDefinition );
NativeSQLQueryReturn[] newQueryReturns = resultSetMappingDefinition.getQueryReturns();
final NamedSQLQueryDefinition queryDefinition =
context.getMetadataCollector().getNamedNativeQueryDefinition( queryName );
if ( queryDefinition != null ) {
queryDefinition.addQueryReturns( newQueryReturns );
}
}
}
);
}
context.getMetadataCollector().addNamedNativeQuery( builder.createNamedQueryDefinition() );
}
private static boolean processNamedQueryContentItem(
Object content,
NamedSQLQueryDefinitionBuilder builder,
ImplicitResultSetMappingDefinition.Builder implicitResultSetMappingBuilder,
JaxbHbmNamedNativeQueryType namedQueryBinding,
HbmLocalMetadataBuildingContext context) {
if ( String.class.isInstance( content ) ) {
// Especially when the query string is wrapped in CDATA we will get
// "extra" Strings here containing just spaces and/or newlines. This
// bit tries to account for them.
final String contentString = StringHelper.nullIfEmpty( ( (String) content ).trim() );
if ( contentString != null ) {
builder.setQuery( (String) content );
return true;
}
else {
return false;
}
}
else if ( JAXBElement.class.isInstance( content ) ) {
return processNamedQueryContentItem(
( (JAXBElement) content ).getValue(),
builder,
implicitResultSetMappingBuilder,
namedQueryBinding,
context
);
}
if ( JaxbHbmQueryParamType.class.isInstance( content ) ) {
final JaxbHbmQueryParamType paramTypeBinding = (JaxbHbmQueryParamType) content;
builder.addParameterType( paramTypeBinding.getName(), paramTypeBinding.getType() );
}
else if ( JaxbHbmSynchronizeType.class.isInstance( content ) ) {
final JaxbHbmSynchronizeType synchronizedSpace = (JaxbHbmSynchronizeType) content;
builder.addSynchronizedQuerySpace( synchronizedSpace.getTable() );
}
else if ( JaxbHbmNativeQueryScalarReturnType.class.isInstance( content ) ) {
implicitResultSetMappingBuilder.addReturn( (JaxbHbmNativeQueryScalarReturnType) content );
}
else if ( JaxbHbmNativeQueryReturnType.class.isInstance( content ) ) {
implicitResultSetMappingBuilder.addReturn( (JaxbHbmNativeQueryReturnType) content );
}
else if ( JaxbHbmNativeQueryJoinReturnType.class.isInstance( content ) ) {
implicitResultSetMappingBuilder.addReturn( (JaxbHbmNativeQueryJoinReturnType) content );
}
else if ( JaxbHbmNativeQueryCollectionLoadReturnType.class.isInstance( content ) ) {
implicitResultSetMappingBuilder.addReturn( (JaxbHbmNativeQueryCollectionLoadReturnType) content );
}
else {
throw new org.hibernate.boot.MappingException(
String.format(
Locale.ENGLISH,
"Encountered unexpected content type [%s] for named native query [%s] : [%s]",
content.getClass().getName(),
namedQueryBinding.getName(),
content.toString()
),
context.getOrigin()
);
}
return false;
}
}