HHH-9059 - JPA 2.1 @NamedStoredProcedureQuery binding in metamodel

This commit is contained in:
Steve Ebersole 2014-03-18 09:58:03 -05:00
parent 83d2e46ba4
commit 4933a266f2
10 changed files with 634 additions and 79 deletions

View File

@ -31,6 +31,7 @@ import java.io.Serializable;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
@ -101,6 +102,7 @@ import org.hibernate.engine.profile.Fetch;
import org.hibernate.engine.profile.FetchProfile;
import org.hibernate.engine.query.spi.QueryPlanCache;
import org.hibernate.engine.query.spi.ReturnMetadata;
import org.hibernate.engine.query.spi.sql.NativeSQLQueryReturn;
import org.hibernate.engine.spi.ActionQueue;
import org.hibernate.engine.spi.CacheImplementor;
import org.hibernate.engine.spi.FilterDefinition;
@ -122,6 +124,7 @@ import org.hibernate.integrator.spi.IntegratorService;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.metadata.ClassMetadata;
import org.hibernate.metadata.CollectionMetadata;
import org.hibernate.metamodel.NamedStoredProcedureQueryDefinition;
import org.hibernate.metamodel.spi.MetadataImplementor;
import org.hibernate.metamodel.spi.binding.EntityBinding;
import org.hibernate.metamodel.spi.binding.PluralAttributeBinding;
@ -131,6 +134,8 @@ import org.hibernate.persister.entity.Loadable;
import org.hibernate.persister.entity.Queryable;
import org.hibernate.persister.spi.PersisterFactory;
import org.hibernate.procedure.ProcedureCallMemento;
import org.hibernate.procedure.internal.ProcedureCallMementoImpl;
import org.hibernate.procedure.internal.Util;
import org.hibernate.proxy.EntityNotFoundDelegate;
import org.hibernate.service.spi.ServiceRegistryImplementor;
import org.hibernate.service.spi.SessionFactoryServiceRegistry;
@ -643,18 +648,6 @@ public final class SessionFactoryImpl
// }
// }
private Map<String, ProcedureCallMemento> toProcedureCallMementos(
Map<String, NamedProcedureCallDefinition> definitions,
Map<String, ResultSetMappingDefinition> resultSetMappingMap) {
final Map<String, ProcedureCallMemento> rtn = new HashMap<String, ProcedureCallMemento>();
if ( definitions != null ) {
for (String name : definitions.keySet()){
rtn.put( name, definitions.get( name ).toMemento( this, resultSetMappingMap ));
}
}
return rtn;
}
private JdbcConnectionAccess buildLocalConnectionAccess() {
return new JdbcConnectionAccess() {
@Override
@ -946,7 +939,10 @@ public final class SessionFactoryImpl
metadata.getNamedQueryDefinitions(),
metadata.getNamedNativeQueryDefinitions(),
metadata.getResultSetMappingDefinitions().values(),
new HashMap<String, ProcedureCallMemento>( )
toProcedureCallMementos(
metadata.getNamedStoredProcedureQueryDefinitions(),
metadata.getResultSetMappingDefinitions()
)
);
imports = new HashMap<String,String>();
@ -1076,6 +1072,133 @@ public final class SessionFactoryImpl
);
}
private Map<String, ProcedureCallMemento> toProcedureCallMementos(
Map<String, NamedProcedureCallDefinition> definitions,
Map<String, ResultSetMappingDefinition> resultSetMappingMap) {
final Map<String, ProcedureCallMemento> rtn = new HashMap<String, ProcedureCallMemento>();
if ( definitions != null ) {
for (String name : definitions.keySet()){
rtn.put( name, definitions.get( name ).toMemento( this, resultSetMappingMap ));
}
}
return rtn;
}
private Map<String, ProcedureCallMemento> toProcedureCallMementos(
Collection<NamedStoredProcedureQueryDefinition> procedureQueryDefinitions,
Map<String, ResultSetMappingDefinition> resultSetMappingDefinitions) {
final Map<String, ProcedureCallMemento> rtn = new HashMap<String, ProcedureCallMemento>();
if ( procedureQueryDefinitions != null ) {
for (NamedStoredProcedureQueryDefinition definition : procedureQueryDefinitions ) {
rtn.put(
definition.getName(),
toMemento( definition, resultSetMappingDefinitions )
);
}
}
return rtn;
}
private ProcedureCallMemento toMemento(
NamedStoredProcedureQueryDefinition definition,
final Map<String, ResultSetMappingDefinition> resultSetMappingDefinitions) {
final List<NativeSQLQueryReturn> collectedQueryReturns = new ArrayList<NativeSQLQueryReturn>();
final Set<String> collectedQuerySpaces = new HashSet<String>();
final boolean specifiesResultClasses = definition.getClassNames().size() > 0;
final boolean specifiesResultSetMappings = definition.getResultSetMappingNames().size() > 0;
final ClassLoaderService cls = getServiceRegistry().getService( ClassLoaderService.class );
if ( specifiesResultClasses ) {
final Class[] classes = new Class[ definition.getClassNames().size() ];
List<String> classNames = definition.getClassNames();
for ( int i = 0, classNamesSize = classNames.size(); i < classNamesSize; i++ ) {
classes[i] = cls.classForName( classNames.get( i ) );
}
Util.resolveResultClasses(
new Util.ResultClassesResolutionContext() {
@Override
public SessionFactoryImplementor getSessionFactory() {
return SessionFactoryImpl.this;
}
@Override
public void addQueryReturns(NativeSQLQueryReturn... queryReturns) {
Collections.addAll( collectedQueryReturns, queryReturns );
}
@Override
public void addQuerySpaces(String... spaces) {
Collections.addAll( collectedQuerySpaces, spaces );
}
},
classes
);
}
else if ( specifiesResultSetMappings ) {
Util.resolveResultSetMappings(
new Util.ResultSetMappingResolutionContext() {
@Override
public SessionFactoryImplementor getSessionFactory() {
return SessionFactoryImpl.this;
}
@Override
public ResultSetMappingDefinition findResultSetMapping(String name) {
return resultSetMappingDefinitions.get( name );
}
@Override
public void addQueryReturns(NativeSQLQueryReturn... queryReturns) {
Collections.addAll( collectedQueryReturns, queryReturns );
}
@Override
public void addQuerySpaces(String... spaces) {
Collections.addAll( collectedQuerySpaces, spaces );
}
},
definition.getResultSetMappingNames()
);
}
return new ProcedureCallMementoImpl(
definition.getName(),
collectedQueryReturns.toArray( new NativeSQLQueryReturn[ collectedQueryReturns.size() ] ),
definition.getParameterStrategy(),
toParameterMementos( definition.getParameters(), cls ),
collectedQuerySpaces,
definition.getQueryHints()
);
}
private List<ProcedureCallMementoImpl.ParameterMemento> toParameterMementos(
List<NamedStoredProcedureQueryDefinition.Parameter> parameters,
ClassLoaderService cls) {
final List<ProcedureCallMementoImpl.ParameterMemento> mementos = new ArrayList<ProcedureCallMementoImpl.ParameterMemento>();
for ( int i = 0, parametersSize = parameters.size(); i < parametersSize; i++ ) {
NamedStoredProcedureQueryDefinition.Parameter definition = parameters.get( i );
mementos.add( toParameterMemento( i+1, definition, cls ) );
}
return mementos;
}
private ProcedureCallMementoImpl.ParameterMemento toParameterMemento(
int position,
NamedStoredProcedureQueryDefinition.Parameter definition,
ClassLoaderService cls) {
return new ProcedureCallMementoImpl.ParameterMemento(
position,
name,
definition.getMode(),
cls.classForName( definition.getJavaType() ),
getTypeResolver().heuristicType( definition.getJavaType() )
);
}
@SuppressWarnings( {"unchecked"} )
private static Properties createPropertiesFromMap(Map map) {
Properties properties = new Properties();

View File

@ -23,8 +23,11 @@
*/
package org.hibernate.metamodel;
import java.util.Collection;
import java.util.Map;
import javax.persistence.NamedStoredProcedureQuery;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.annotations.NamedEntityGraphDefinition;
import org.hibernate.engine.ResultSetMappingDefinition;
@ -74,15 +77,17 @@ public interface Metadata {
Iterable<PluralAttributeBinding> getCollectionBindings();
Iterable<EntityBinding> getEntityBindings();
Iterable<TypeDefinition> getTypeDefinitions();
Iterable<NamedQueryDefinition> getNamedQueryDefinitions();
Iterable<NamedSQLQueryDefinition> getNamedNativeQueryDefinitions();
Iterable<FetchProfile> getFetchProfiles();
Map<Identifier, SecondaryTable> getSecondaryTables();
Map<String, FilterDefinition> getFilterDefinitions();
Map<String, NamedEntityGraphDefinition> getNamedEntityGraphs();
Map<String, ResultSetMappingDefinition> getResultSetMappingDefinitions();
Map<String,String> getImports();
NamedSQLQueryDefinition getNamedNativeQuery(String name);
Iterable<NamedQueryDefinition> getNamedQueryDefinitions();
Iterable<NamedSQLQueryDefinition> getNamedNativeQueryDefinitions();
Collection<NamedStoredProcedureQueryDefinition> getNamedStoredProcedureQueryDefinitions();
Map<String, ResultSetMappingDefinition> getResultSetMappingDefinitions();
}

View File

@ -0,0 +1,204 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2014, Red Hat Inc. or third-party contributors as
* indicated by the @author tags or express copyright attribution
* statements applied by the authors. All third-party contributions are
* distributed under license by Red Hat Inc.
*
* This copyrighted material is made available to anyone wishing to use, modify,
* copy, or redistribute it subject to the terms and conditions of the GNU
* Lesser General Public License, as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
* for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this distribution; if not, write to:
* Free Software Foundation, Inc.
* 51 Franklin Street, Fifth Floor
* Boston, MA 02110-1301 USA
*/
package org.hibernate.metamodel;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.persistence.ParameterMode;
import org.hibernate.MappingException;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.procedure.spi.ParameterStrategy;
/**
* Models the information about a {@link javax.persistence.NamedStoredProcedureQuery}
*
* @author Steve Ebersole
*/
public class NamedStoredProcedureQueryDefinition {
private final String name;
private final String procedureName;
private final ParameterStrategy parameterStrategy;
private final List<Parameter> parameters;
private final Map<String,Object> queryHints;
private final List<String> classNames;
private final List<String> resultSetMappingNames;
private NamedStoredProcedureQueryDefinition(
String name,
String procedureName,
ParameterStrategy parameterStrategy,
List<Parameter> parameters,
Map<String, Object> queryHints,
List<String> classNames,
List<String> resultSetMappingNames) {
if ( name == null ) {
throw new IllegalArgumentException( "Name cannot be null" );
}
if ( procedureName == null ) {
throw new IllegalArgumentException( "Procedure-name cannot be null" );
}
final boolean specifiesResultClasses = classNames.size() > 0;
final boolean specifiesResultSetMappings = resultSetMappingNames.size() > 0;
if ( specifiesResultClasses && specifiesResultSetMappings ) {
throw new MappingException(
String.format(
"NamedStoredProcedureQuery [" + name + "] specified both resultClasses and resultSetMappings",
name
)
);
}
this.name = name;
this.procedureName = procedureName;
this.parameterStrategy = parameterStrategy;
this.parameters = Collections.unmodifiableList( parameters );
this.queryHints = Collections.unmodifiableMap( queryHints );
this.classNames = Collections.unmodifiableList( classNames );
this.resultSetMappingNames = Collections.unmodifiableList( resultSetMappingNames );
}
public String getName() {
return name;
}
public String getProcedureName() {
return procedureName;
}
public ParameterStrategy getParameterStrategy() {
return parameterStrategy;
}
public List<Parameter> getParameters() {
return parameters;
}
public Map<String, Object> getQueryHints() {
return queryHints;
}
public List<String> getClassNames() {
return classNames;
}
public List<String> getResultSetMappingNames() {
return resultSetMappingNames;
}
public static class Parameter {
private final String name;
private final ParameterMode mode;
private final String javaType;
private Parameter(String name, ParameterMode mode, String javaType) {
this.name = name;
this.mode = mode;
this.javaType = javaType;
}
public String getName() {
return name;
}
public ParameterMode getMode() {
return mode;
}
public String getJavaType() {
return javaType;
}
}
public static class Builder {
private final String name;
private final String procedureName;
private final List<Parameter> parameters = new ArrayList<Parameter>();
private final Map<String, Object> queryHints = new HashMap<String, Object>();
private final List<String> classNames = new ArrayList<String>();
private final List<String> resultSetMappingNames = new ArrayList<String>();
private ParameterStrategy parameterStrategy = ParameterStrategy.UNKNOWN;
public Builder(String name, String procedureName) {
this.name = name;
this.procedureName = procedureName;
}
public void addParameter(String name, ParameterMode mode, String javaType) {
final ParameterStrategy incomingParameterStrategy;
if ( StringHelper.isNotEmpty( name ) ) {
incomingParameterStrategy = ParameterStrategy.NAMED;
}
else {
incomingParameterStrategy = ParameterStrategy.POSITIONAL;
}
if ( parameterStrategy == ParameterStrategy.UNKNOWN ) {
parameterStrategy = incomingParameterStrategy;
}
else {
if ( parameterStrategy != incomingParameterStrategy ) {
throw new IllegalArgumentException(
"Attempt to mix named and position parameters for " +
"@NamedStoredProcedureQuery(name=" + name + ")"
);
}
}
parameters.add( new Parameter( name, mode, javaType ) );
}
public void addHint(String hintKey, String value) {
queryHints.put( hintKey, value );
}
public void addResultClassName(String name) {
classNames.add( name );
}
public void addResultSetMappingName(String name) {
resultSetMappingNames.add( name );
}
public NamedStoredProcedureQueryDefinition buildDefinition() {
return new NamedStoredProcedureQueryDefinition(
name,
procedureName,
parameterStrategy,
parameters,
queryHints,
classNames,
resultSetMappingNames
);
}
}
}

View File

@ -24,6 +24,7 @@
package org.hibernate.metamodel.internal;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
@ -57,6 +58,7 @@ import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.metamodel.MetadataSourceProcessingOrder;
import org.hibernate.metamodel.MetadataSources;
import org.hibernate.metamodel.NamedStoredProcedureQueryDefinition;
import org.hibernate.metamodel.SessionFactoryBuilder;
import org.hibernate.metamodel.internal.binder.Binder;
import org.hibernate.metamodel.reflite.internal.JavaTypeDescriptorRepositoryImpl;
@ -709,16 +711,28 @@ public class MetadataBuildingProcess {
private final Map<String, TypeDefinition> typeDefinitionMap = new HashMap<String, TypeDefinition>();
private final Map<String, FilterDefinition> filterDefinitionMap = new HashMap<String, FilterDefinition>();
private final Map<String, EntityBinding> entityBindingMap = new HashMap<String, EntityBinding>();
private final Map<String, PluralAttributeBinding> collectionBindingMap = new HashMap<String, PluralAttributeBinding>();
private final Map<String, FetchProfile> fetchProfiles = new HashMap<String, FetchProfile>();
private final Map<String, String> imports = new HashMap<String, String>();
private final Map<String, IdentifierGeneratorDefinition> idGenerators = new HashMap<String, IdentifierGeneratorDefinition>();
private final Map<String, NamedQueryDefinition> namedQueryDefs = new HashMap<String, NamedQueryDefinition>();
private final Map<String, NamedSQLQueryDefinition> namedNativeQueryDefs = new HashMap<String, NamedSQLQueryDefinition>();
private final Map<String, ResultSetMappingDefinition> resultSetMappings = new HashMap<String, ResultSetMappingDefinition>();
private final Map<String, NamedEntityGraphDefinition> namedEntityGraphMap = new HashMap<String, NamedEntityGraphDefinition>( );
private final Map<Identifier, SecondaryTable> secondaryTableMap = new HashMap<Identifier, SecondaryTable>();
private final Map<String, EntityBinding> entityBindingMap =
new HashMap<String, EntityBinding>();
private final Map<String, PluralAttributeBinding> collectionBindingMap =
new HashMap<String, PluralAttributeBinding>();
private final Map<String, FetchProfile> fetchProfiles =
new HashMap<String, FetchProfile>();
private final Map<String, String> imports =
new HashMap<String, String>();
private final Map<String, IdentifierGeneratorDefinition> idGenerators =
new HashMap<String, IdentifierGeneratorDefinition>();
private final Map<String, NamedQueryDefinition> namedQueryDefs =
new HashMap<String, NamedQueryDefinition>();
private final Map<String, NamedSQLQueryDefinition> namedNativeQueryDefs =
new HashMap<String, NamedSQLQueryDefinition>();
private final Map<String, NamedStoredProcedureQueryDefinition> namedStoredProcedureQueryDefinitionMap =
new HashMap<String, NamedStoredProcedureQueryDefinition>();
private final Map<String, ResultSetMappingDefinition> resultSetMappings =
new HashMap<String, ResultSetMappingDefinition>();
private final Map<String, NamedEntityGraphDefinition> namedEntityGraphMap =
new HashMap<String, NamedEntityGraphDefinition>( );
private final Map<Identifier, SecondaryTable> secondaryTableMap =
new HashMap<Identifier, SecondaryTable>();
public InFlightMetadataCollectorImpl(MetadataBuildingOptions options, TypeResolver typeResolver) {
this.options = options;
@ -964,6 +978,21 @@ public class MetadataBuildingProcess {
}
}
@Override
public void addNamedStoredProcedureQueryDefinition(NamedStoredProcedureQueryDefinition definition) {
if ( definition == null ) {
throw new IllegalArgumentException( "Named query definition is null" );
}
namedStoredProcedureQueryDefinitionMap.put( definition.getName(), definition );
}
@Override
public Collection<NamedStoredProcedureQueryDefinition> getNamedStoredProcedureQueryDefinitions() {
return namedStoredProcedureQueryDefinitionMap.values();
}
public NamedQueryDefinition getNamedQuery(String name) {
if ( name == null ) {
throw new IllegalArgumentException( "null is not a valid query name" );
@ -1171,6 +1200,7 @@ public class MetadataBuildingProcess {
idGenerators,
namedQueryDefs,
namedNativeQueryDefs,
namedStoredProcedureQueryDefinitionMap,
resultSetMappings,
namedEntityGraphMap,
secondaryTableMap

View File

@ -24,6 +24,7 @@
package org.hibernate.metamodel.internal;
import java.io.Serializable;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
@ -37,6 +38,7 @@ import org.hibernate.engine.spi.FilterDefinition;
import org.hibernate.engine.spi.NamedQueryDefinition;
import org.hibernate.engine.spi.NamedSQLQueryDefinition;
import org.hibernate.id.factory.IdentifierGeneratorFactory;
import org.hibernate.metamodel.NamedStoredProcedureQueryDefinition;
import org.hibernate.metamodel.SessionFactoryBuilder;
import org.hibernate.metamodel.spi.MetadataImplementor;
import org.hibernate.metamodel.spi.binding.AttributeBinding;
@ -74,6 +76,7 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
private final Map<String, IdentifierGeneratorDefinition> idGenerators = new HashMap<String, IdentifierGeneratorDefinition>();
private final Map<String, NamedQueryDefinition> namedQueryDefs = new HashMap<String, NamedQueryDefinition>();
private final Map<String, NamedSQLQueryDefinition> namedNativeQueryDefs = new HashMap<String, NamedSQLQueryDefinition>();
private final Map<String, NamedStoredProcedureQueryDefinition> namedStoredProcedureQueryDefinitionMap = new HashMap<String, NamedStoredProcedureQueryDefinition>();
private final Map<String, ResultSetMappingDefinition> resultSetMappings = new HashMap<String, ResultSetMappingDefinition>();
private final Map<String, NamedEntityGraphDefinition> namedEntityGraphMap = new HashMap<String, NamedEntityGraphDefinition>( );
private final Map<Identifier, SecondaryTable> secondaryTableMap = new HashMap<Identifier, SecondaryTable>( );
@ -92,6 +95,7 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
Map<String, IdentifierGeneratorDefinition> idGenerators,
Map<String, NamedQueryDefinition> namedQueryDefs,
Map<String, NamedSQLQueryDefinition> namedNativeQueryDefs,
Map<String, NamedStoredProcedureQueryDefinition> namedStoredProcedureQueryDefinitionMap,
Map<String, ResultSetMappingDefinition> resultSetMappings,
Map<String, NamedEntityGraphDefinition> namedEntityGraphMap,
Map<Identifier, SecondaryTable> secondaryTableMap) {
@ -130,6 +134,9 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
if ( resultSetMappings != null ) {
this.resultSetMappings.putAll( resultSetMappings );
}
if ( namedStoredProcedureQueryDefinitionMap != null ) {
this.namedStoredProcedureQueryDefinitionMap.putAll( namedStoredProcedureQueryDefinitionMap );
}
if ( namedEntityGraphMap != null ) {
this.namedEntityGraphMap.putAll( namedEntityGraphMap );
}
@ -191,6 +198,11 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
return namedNativeQueryDefs.values();
}
@Override
public Collection<NamedStoredProcedureQueryDefinition> getNamedStoredProcedureQueryDefinitions() {
return namedStoredProcedureQueryDefinitionMap.values();
}
@Override
public Iterable<NamedQueryDefinition> getNamedQueryDefinitions() {
return namedQueryDefs.values();

View File

@ -26,10 +26,7 @@ package org.hibernate.metamodel.source.internal.annotations.global;
import java.util.Collection;
import java.util.HashMap;
import javax.persistence.LockModeType;
import javax.persistence.NamedNativeQueries;
import javax.persistence.NamedNativeQuery;
import javax.persistence.NamedQueries;
import javax.persistence.NamedQuery;
import javax.persistence.ParameterMode;
import org.hibernate.AnnotationException;
import org.hibernate.AssertionFailure;
@ -46,9 +43,11 @@ import org.hibernate.engine.query.spi.sql.NativeSQLQueryRootReturn;
import org.hibernate.engine.spi.NamedQueryDefinitionBuilder;
import org.hibernate.engine.spi.NamedSQLQueryDefinition;
import org.hibernate.engine.spi.NamedSQLQueryDefinitionBuilder;
import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.LockModeConverter;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.metamodel.NamedStoredProcedureQueryDefinition;
import org.hibernate.metamodel.source.internal.annotations.AnnotationBindingContext;
import org.hibernate.metamodel.source.internal.annotations.util.HibernateDotNames;
import org.hibernate.metamodel.source.internal.annotations.util.JPADotNames;
@ -56,70 +55,89 @@ import org.hibernate.metamodel.source.internal.annotations.util.JandexHelper;
import org.jboss.jandex.AnnotationInstance;
import org.jboss.jandex.AnnotationValue;
import org.jboss.logging.Logger;
/**
* Binds {@link NamedQuery}, {@link NamedQueries}, {@link NamedNativeQuery}, {@link NamedNativeQueries},
* {@link org.hibernate.annotations.NamedQuery}, {@link org.hibernate.annotations.NamedQueries},
* {@link org.hibernate.annotations.NamedNativeQuery}, and {@link org.hibernate.annotations.NamedNativeQueries}.
* Handles processing of named queries defined via:<ul>
* <li>
* {@link javax.persistence.NamedQuery} (and
* {@link javax.persistence.NamedQueries})
* </li>
* <li>
* {@link javax.persistence.NamedNativeQuery} (and
* {@link javax.persistence.NamedNativeQueries})
* </li>
* <li>
* {@link javax.persistence.NamedStoredProcedureQuery} (and
* {@link javax.persistence.NamedStoredProcedureQueries})
* </li>
* <li>
* {@link org.hibernate.annotations.NamedQuery} (and
* {@link org.hibernate.annotations.NamedQueries})
* </li>
* <li>
* {@link org.hibernate.annotations.NamedNativeQuery} (and
* {@link org.hibernate.annotations.NamedNativeQueries})
* </li>
* </ul>
*
* @author Hardy Ferentschik
* @author Steve Ebersole
*/
public class QueryProcessor {
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( QueryProcessor.class );
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
CoreMessageLogger.class,
QueryProcessor.class.getName()
);
/**
* Disallow direct instantiation
*/
private QueryProcessor() {
}
/**
* Binds all {@link NamedQuery}, {@link NamedQueries}, {@link NamedNativeQuery}, {@link NamedNativeQueries},
* {@link org.hibernate.annotations.NamedQuery}, {@link org.hibernate.annotations.NamedQueries},
* {@link org.hibernate.annotations.NamedNativeQuery}, and {@link org.hibernate.annotations.NamedNativeQueries}
* annotations to the supplied metadata.
* Main entry point into named query processing
*
* @param bindingContext the context for annotation binding
*/
public static void bind(AnnotationBindingContext bindingContext) {
final ClassLoaderService classLoaderService = bindingContext.getBuildingOptions().getServiceRegistry().getService( ClassLoaderService.class );
Collection<AnnotationInstance> annotations = JandexHelper.getAnnotations(
Collection<AnnotationInstance> annotations = JandexHelper.collectionAnnotations(
bindingContext.getIndex(),
JPADotNames.NAMED_QUERY,
JPADotNames.NAMED_QUERIES,
classLoaderService
JPADotNames.NAMED_QUERIES
);
for ( AnnotationInstance query : annotations ) {
bindNamedQuery( bindingContext, query );
}
annotations = JandexHelper.getAnnotations(
annotations = JandexHelper.collectionAnnotations(
bindingContext.getIndex(),
JPADotNames.NAMED_NATIVE_QUERY,
JPADotNames.NAMED_NATIVE_QUERIES,
classLoaderService
JPADotNames.NAMED_NATIVE_QUERIES
);
for ( AnnotationInstance query : annotations ) {
bindNamedNativeQuery( query, bindingContext );
}
annotations = JandexHelper.getAnnotations(
annotations = JandexHelper.collectionAnnotations(
bindingContext.getIndex(),
JPADotNames.NAMED_STORED_PROCEDURE_QUERY,
JPADotNames.NAMED_STORED_PROCEDURE_QUERIES
);
for ( AnnotationInstance query : annotations ) {
bindNamedStoredProcedureQuery( query, bindingContext );
}
annotations = JandexHelper.collectionAnnotations(
bindingContext.getIndex(),
HibernateDotNames.NAMED_QUERY,
HibernateDotNames.NAMED_QUERIES,
classLoaderService
HibernateDotNames.NAMED_QUERIES
);
for ( AnnotationInstance query : annotations ) {
bindNamedQuery( bindingContext, query );
}
annotations = JandexHelper.getAnnotations(
annotations = JandexHelper.collectionAnnotations(
bindingContext.getIndex(),
HibernateDotNames.NAMED_NATIVE_QUERY,
HibernateDotNames.NAMED_NATIVE_QUERIES,
classLoaderService
HibernateDotNames.NAMED_NATIVE_QUERIES
);
for ( AnnotationInstance query : annotations ) {
bindNamedNativeQuery( query, bindingContext );
@ -353,6 +371,98 @@ public class QueryProcessor {
LOG.debugf( "Binding named native query: %s => %s", name, query );
}
private static void bindNamedStoredProcedureQuery(
AnnotationInstance query,
AnnotationBindingContext bindingContext) {
final String name = query.value( "name" ).asString();
final String procedureName = query.value( "procedureName" ).asString();
LOG.debugf( "Starting binding of @NamedStoredProcedureQuery(name=%s, procedureName=%s)", name, procedureName );
NamedStoredProcedureQueryDefinition.Builder builder = new NamedStoredProcedureQueryDefinition.Builder(
name,
procedureName
);
final AnnotationInstance[] parameterAnnotations = JandexHelper.extractAnnotationsValue(
query,
"parameters"
);
if ( parameterAnnotations != null && parameterAnnotations.length > 0 ) {
for ( AnnotationInstance parameterAnnotation : parameterAnnotations ) {
final AnnotationValue pNameValue = parameterAnnotation.value( "name" );
final String pName;
if ( pNameValue == null ) {
pName = null;
}
else {
pName = StringHelper.nullIfEmpty( pNameValue.asString() );
}
final AnnotationValue pModeValue = parameterAnnotation.value( "mode" );
final ParameterMode pMode;
if ( pModeValue == null ) {
pMode = ParameterMode.IN;
}
else {
final String pModeName = StringHelper.nullIfEmpty( pModeValue.asEnum() );
if ( pModeName == null ) {
pMode = ParameterMode.IN;
}
else {
pMode = ParameterMode.valueOf( pModeName );
}
}
final AnnotationValue javaTypeValue = parameterAnnotation.value( "type" );
final String pJavaType;
if ( javaTypeValue == null ) {
pJavaType = null;
}
else {
pJavaType = StringHelper.nullIfEmpty( javaTypeValue.asString() );
}
builder.addParameter( pName, pMode, pJavaType );
}
}
final AnnotationInstance[] hintAnnotations = JandexHelper.extractAnnotationsValue(
query,
"hints"
);
if ( hintAnnotations != null && hintAnnotations.length > 0 ) {
for ( AnnotationInstance hintAnnotation : hintAnnotations ) {
builder.addHint(
hintAnnotation.value( "name" ).asString(),
hintAnnotation.value( "value" ).asString()
);
}
}
final AnnotationValue resultClassesValue = query.value( "resultClasses" );
if ( resultClassesValue != null ) {
final String[] resultClassNames = resultClassesValue.asStringArray();
if ( resultClassNames != null ) {
for ( String resultClassName : resultClassNames ) {
builder.addResultClassName( resultClassName );
}
}
}
final AnnotationValue resultSetMappingsValue = query.value( "resultSetMappings" );
if ( resultSetMappingsValue != null ) {
final String[] resultSetMappingNames = resultSetMappingsValue.asStringArray();
if ( resultSetMappingNames != null ) {
for ( String resultSetMappingName : resultSetMappingNames ) {
builder.addResultSetMappingName( resultSetMappingName );
}
}
}
bindingContext.getMetadataCollector().addNamedStoredProcedureQueryDefinition(
builder.buildDefinition()
);
}
private static boolean getBoolean(AnnotationInstance[] hints, String element, String query, AnnotationBindingContext bindingContext) {
String val = getString( hints, element, bindingContext );
if ( val == null || val.equalsIgnoreCase( "false" ) ) {

View File

@ -44,6 +44,7 @@ import org.hibernate.HibernateException;
import org.hibernate.MappingException;
import org.hibernate.boot.registry.classloading.spi.ClassLoaderService;
import org.hibernate.internal.util.type.PrimitiveWrapperHelper;
import org.hibernate.metamodel.spi.BindingContext;
import org.hibernate.service.ServiceRegistry;
import org.jboss.jandex.AnnotationInstance;
@ -65,33 +66,39 @@ import org.jboss.jandex.Type;
*/
public class JandexHelper {
private static final Map<String, Object> DEFAULT_VALUES_BY_ELEMENT = new HashMap<String, Object>();
public static final DotName OBJECT = DotName.createSimple( Object.class.getName() );
// todo : consider making JandexHelper non-static (looked up from context) and caching the ClassLoaderService as instance state
private JandexHelper() {
}
/**
* Retrieves a jandex annotation element value. If the value is {@code null}, the default value specified in the
* annotation class is retrieved instead.
* <p>
* <p/>
* The following types are supported:<ul>
* <li>Byte</li>
* <li>Short</li>
* <li>Integer</li>
* <li>Character</li>
* <li>Float</li>
* <li>Double</li>
* <li>Long</li>
* <li>Boolean</li>
* <li>String</li>
* <li>AnnotationInstance</li>
* </ul>
* There are two special cases. {@code Class} parameters should be retrieved as strings (and then can later be
* loaded) and enumerated values should be retrieved via {@link #getEnumValue}.
* </p>
*
* @param annotation the annotation containing the element with the supplied name
* @param element the name of the element value to be retrieve
* @param type the type of element to retrieve. The following types are supported:
* <ul>
* <li>Byte</li>
* <li>Short</li>
* <li>Integer</li>
* <li>Character</li>
* <li>Float</li>
* <li>Double</li>
* <li>Long</li>
* <li>Boolean</li>
* <li>String</li>
* <li>AnnotationInstance</li>
* @param classLoaderService ClassLoaderService
* @param annotation The annotation containing the attribute whose value we are to extract
* @param attributeName The name of the attribute whose value we are to extract
* @param type The type we are to return the extracted value in; see the list of supported types above.
* @param classLoaderService The ClassLoaderService; used to resolve default
* values defined on the annotation class.
*
* @return the value if not {@code null}, else the default value if not
* {@code null}, else {@code null}.
@ -100,7 +107,10 @@ public class JandexHelper {
* when retrieving the value.
*/
@SuppressWarnings("unchecked")
public static <T> T getValue(AnnotationInstance annotation, String element, Class<T> type,
public static <T> T getValue(
AnnotationInstance annotation,
String attributeName,
Class<T> type,
ClassLoaderService classLoaderService) throws AssertionFailure {
if ( Class.class.equals( type ) ) {
throw new AssertionFailure(
@ -108,26 +118,41 @@ public class JandexHelper {
);
}
// todo : we should seriously consider mapping type to appropriate AnnotationValue.asXYZ calls
if ( type.isPrimitive() ) {
type = PrimitiveWrapperHelper.getDescriptorByPrimitiveType( type ).getWrapperClass();
}
// try getting the untyped value from Jandex
AnnotationValue annotationValue = annotation.value( element );
AnnotationValue annotationValue = annotation.value( attributeName );
try {
// Jandex only reads stuff that is actually in the bytecode. If
// an annotation usage does not include a defaulted attribute,
// Jandex reports the missing attribute inclusion as the returned
// AnnotationValue being {@code null} (quite nice actually).
//
// todo : couldn't null here indicate that the attributeName does
// not name an existing attribute on the annotation?
if ( annotationValue != null ) {
// the attribute was included in the annotation usage, so extract
// its typed value and return it
return explicitAnnotationParameter( annotationValue, type );
}
else {
return defaultAnnotationParameter( getDefaultValue( annotation, element, classLoaderService ), type );
// Here the attribute was left off. So we look at the
// annotation class to see what its default value is.
return defaultAnnotationParameter(
getDefaultValue( annotation, attributeName, classLoaderService ),
type
);
}
}
catch ( ClassCastException e ) {
throw new AssertionFailure(
String.format(
"the annotation property [%s] of annotation [@%s] is not of type %s",
element,
attributeName,
annotation.name(),
type.getName()
)
@ -135,6 +160,23 @@ public class JandexHelper {
}
}
public static Collection<AnnotationInstance> collectionAnnotations(
final IndexView indexView,
final DotName singularDotName,
final DotName pluralDotName) {
final List<AnnotationInstance> results = new ArrayList<AnnotationInstance>();
results.addAll( indexView.getAnnotations( singularDotName ) );
final Collection<AnnotationInstance> pluralAnnotations = indexView.getAnnotations( pluralDotName );
for ( AnnotationInstance plural : pluralAnnotations ) {
final AnnotationInstance[] singulars = extractAnnotationsValue( plural, "value" );
results.addAll( Arrays.asList( singulars ) );
}
return results;
}
/**
* Simplified form of {@link #getValue} for dealing with extracting
* an annotation attribute value which is itself an annotation
@ -665,4 +707,5 @@ public class JandexHelper {
}
return targetName;
}
}

View File

@ -31,6 +31,7 @@ import org.hibernate.engine.spi.Mapping;
import org.hibernate.engine.spi.NamedQueryDefinition;
import org.hibernate.engine.spi.NamedSQLQueryDefinition;
import org.hibernate.metamodel.Metadata;
import org.hibernate.metamodel.NamedStoredProcedureQueryDefinition;
import org.hibernate.metamodel.spi.binding.EntityBinding;
import org.hibernate.metamodel.spi.binding.FetchProfile;
import org.hibernate.metamodel.spi.binding.IdentifierGeneratorDefinition;
@ -38,6 +39,7 @@ import org.hibernate.metamodel.spi.binding.PluralAttributeBinding;
import org.hibernate.metamodel.spi.binding.SecondaryTable;
import org.hibernate.metamodel.spi.binding.TypeDefinition;
import org.hibernate.metamodel.spi.relational.Database;
import org.hibernate.procedure.ProcedureCallMemento;
import org.hibernate.type.TypeResolver;
/**
@ -77,6 +79,8 @@ public interface InFlightMetadataCollector extends Mapping, Metadata {
void addNamedQuery(NamedQueryDefinition def);
void addNamedStoredProcedureQueryDefinition(NamedStoredProcedureQueryDefinition definition);
void addResultSetMapping(ResultSetMappingDefinition resultSetMappingDefinition);
@Deprecated

View File

@ -23,6 +23,7 @@
*/
package org.hibernate.procedure.internal;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
@ -148,6 +149,31 @@ public class Util {
}
}
/**
* Resolve the given result set mapping names
*
* @param context The context for the resolution. See {@link ResultSetMappingResolutionContext}
* @param resultSetMappingNames The names of the result-set-mappings to resolve
*/
public static void resolveResultSetMappings(ResultSetMappingResolutionContext context, Collection<String> resultSetMappingNames) {
for ( String resultSetMappingName : resultSetMappingNames ) {
log.tracef( "Starting attempt resolve named result-set-mapping : %s", resultSetMappingName );
final ResultSetMappingDefinition mapping = context.findResultSetMapping( resultSetMappingName );
if ( mapping == null ) {
throw new UnknownSqlResultSetMappingException( "Unknown SqlResultSetMapping [" + resultSetMappingName + "]" );
}
log.tracef( "Found result-set-mapping : %s", mapping.traceLoggableFormat() );
context.addQueryReturns( mapping.getQueryReturns() );
final SQLQueryReturnProcessor processor =
new SQLQueryReturnProcessor( mapping.getQueryReturns(), context.getSessionFactory() );
final SQLQueryReturnProcessor.ResultAliasContext processResult = processor.process();
context.addQuerySpaces( processResult.collectQuerySpaces() );
}
}
/**
* Context for resolving result-class definitions
*/

View File

@ -173,7 +173,6 @@ public class JpaTckUsageTest extends BaseUnitTestCase {
}
@Test
@FailureExpectedWithNewMetamodel( jiraKey = "HHH-9059" )
public void testSettingInParamDefinedOnNamedStoredProcedureQuery() {
EntityManager em = entityManagerFactory.createEntityManager();
em.getTransaction().begin();
@ -192,7 +191,6 @@ public class JpaTckUsageTest extends BaseUnitTestCase {
}
@Test
@FailureExpectedWithNewMetamodel( jiraKey = "HHH-9059" )
public void testSettingNonExistingParams() {
EntityManager em = entityManagerFactory.createEntityManager();