HHH-6491 Binding @SqlResultSetMapping

This commit is contained in:
Strong Liu 2012-06-28 23:45:27 +08:00
parent 1679b1d3fc
commit c1e40df164
15 changed files with 335 additions and 109 deletions

View File

@ -107,12 +107,12 @@ public class ResultsetMappingSecondPass implements QuerySecondPass {
int dotIndex = name.lastIndexOf( '.' );
String reducedName = name.substring( 0, dotIndex );
Iterator parentPropIter = getSubPropertyIterator( pc, reducedName );
List followers = getFollowers( parentPropIter, reducedName, name );
List<String> followers = getFollowers( parentPropIter, reducedName, name );
int index = propertyNames.size();
int followersSize = followers.size();
for (int loop = 0; loop < followersSize; loop++) {
String follower = (String) followers.get( loop );
String follower = followers.get( loop );
int currentIndex = getIndexOfFirstMatchingProperty( propertyNames, follower );
index = currentIndex != -1 && currentIndex < index ? currentIndex : index;
}
@ -123,8 +123,8 @@ public class ResultsetMappingSecondPass implements QuerySecondPass {
Set<String> uniqueReturnProperty = new HashSet<String>();
Map<String, ArrayList<String>> propertyResultsTmp = new HashMap<String, ArrayList<String>>();
for ( Object property : properties ) {
final FieldResult propertyresult = ( FieldResult ) property;
for ( FieldResult property : properties ) {
final FieldResult propertyresult = property;
final String name = propertyresult.name();
if ( "class".equals( name ) ) {
throw new MappingException(
@ -132,13 +132,12 @@ public class ResultsetMappingSecondPass implements QuerySecondPass {
);
}
if ( uniqueReturnProperty.contains( name ) ) {
if ( !uniqueReturnProperty.add( name ) ) {
throw new MappingException(
"duplicate @FieldResult for property " + name +
" on @Entity " + entity.entityClass().getName() + " in " + ann.name()
);
}
uniqueReturnProperty.add( name );
final String quotingNormalizedColumnName = mappings.getObjectNameNormalizer()
.normalizeIdentifierQuoting( propertyresult.column() );
@ -167,10 +166,6 @@ public class ResultsetMappingSecondPass implements QuerySecondPass {
propertyResults.put( "class", new String[] { quotingNormalizedName } );
}
if ( propertyResults.isEmpty() ) {
propertyResults = java.util.Collections.emptyMap();
}
NativeSQLQueryRootReturn result = new NativeSQLQueryRootReturn(
"alias" + entityAliasIndex++,
entity.entityClass().getName(),
@ -202,7 +197,7 @@ public class ResultsetMappingSecondPass implements QuerySecondPass {
@SuppressWarnings({ "unchecked" })
private List getFollowers(Iterator parentPropIter, String reducedName, String name) {
boolean hasFollowers = false;
List followers = new ArrayList();
List<String> followers = new ArrayList<String>();
while ( parentPropIter.hasNext() ) {
String currentPropertyName = ( (Property) parentPropIter.next() ).getName();
String currentName = reducedName + '.' + currentPropertyName;

View File

@ -30,6 +30,7 @@ import java.util.Map;
import org.hibernate.HibernateException;
import org.hibernate.LockMode;
import org.hibernate.internal.util.collections.CollectionHelper;
/**
* Represents the base information for a non-scalar return defined as part of
@ -40,7 +41,7 @@ import org.hibernate.LockMode;
public abstract class NativeSQLQueryNonScalarReturn implements NativeSQLQueryReturn, Serializable {
private final String alias;
private final LockMode lockMode;
private final Map<String,String[]> propertyResults = new HashMap<String,String[]>();
private final Map<String,String[]> propertyResults;
private final int hashCode;
/**
@ -50,15 +51,14 @@ public abstract class NativeSQLQueryNonScalarReturn implements NativeSQLQueryRet
* @param propertyResults Any user-supplied column->property mappings
* @param lockMode The lock mode to apply to the return.
*/
protected NativeSQLQueryNonScalarReturn(String alias, Map<String,String[]> propertyResults, LockMode lockMode) {
protected NativeSQLQueryNonScalarReturn(String alias, Map<String, String[]> propertyResults, LockMode lockMode) {
this.alias = alias;
if ( alias == null ) {
throw new HibernateException("alias must be specified");
throw new HibernateException( "alias must be specified" );
}
this.lockMode = lockMode;
if ( propertyResults != null ) {
this.propertyResults.putAll( propertyResults );
}
this.propertyResults = CollectionHelper.isEmpty( propertyResults ) ? Collections.<String, String[]>emptyMap()
: Collections.unmodifiableMap(new HashMap<String, String[]>( propertyResults ));
this.hashCode = determineHashCode();
}
@ -86,7 +86,7 @@ public abstract class NativeSQLQueryNonScalarReturn implements NativeSQLQueryRet
* @return The property mappings.
*/
public Map<String,String[]> getPropertyResultsMap() {
return Collections.unmodifiableMap( propertyResults );
return propertyResults;
}
public int hashCode() {

View File

@ -52,6 +52,7 @@ import org.hibernate.engine.spi.NamedSQLQueryDefinition;
import org.hibernate.engine.spi.QueryParameters;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.internal.util.collections.CollectionHelper;
import org.hibernate.type.Type;
/**
@ -62,7 +63,7 @@ import org.hibernate.type.Type;
*/
public class SQLQueryImpl extends AbstractQueryImpl implements SQLQuery {
private List<NativeSQLQueryReturn> queryReturns;
private NativeSQLQueryReturn[] queryReturns;
private List<ReturnBuilder> queryReturnBuilders;
private boolean autoDiscoverTypes;
@ -88,13 +89,13 @@ public class SQLQueryImpl extends AbstractQueryImpl implements SQLQuery {
queryDef.getResultSetRef()
);
}
this.queryReturns = Arrays.asList( definition.getQueryReturns() );
this.queryReturns = definition.getQueryReturns();
}
else if ( queryDef.getQueryReturns() != null && queryDef.getQueryReturns().length > 0 ) {
this.queryReturns = Arrays.asList( queryDef.getQueryReturns() );
this.queryReturns = queryDef.getQueryReturns();
}
else {
this.queryReturns = new ArrayList<NativeSQLQueryReturn>();
this.queryReturns = new NativeSQLQueryReturn[]{};
}
this.querySpaces = queryDef.getQuerySpaces();
@ -112,14 +113,14 @@ public class SQLQueryImpl extends AbstractQueryImpl implements SQLQuery {
ParameterMetadata parameterMetadata) {
// TODO : this constructor form is *only* used from constructor directly below us; can it go away?
super( sql, flushMode, session, parameterMetadata );
queryReturns = new ArrayList<NativeSQLQueryReturn>( returnAliases.length );
this.queryReturns = new NativeSQLQueryReturn[returnAliases.length];
for ( int i=0; i<returnAliases.length; i++ ) {
NativeSQLQueryRootReturn ret = new NativeSQLQueryRootReturn(
returnAliases[i],
returnClasses[i].getName(),
lockModes==null ? LockMode.NONE : lockModes[i]
);
queryReturns.add(ret);
queryReturns[i] = ret;
}
this.querySpaces = querySpaces;
this.callable = false;
@ -136,13 +137,13 @@ public class SQLQueryImpl extends AbstractQueryImpl implements SQLQuery {
SQLQueryImpl(String sql, SessionImplementor session, ParameterMetadata parameterMetadata) {
super( sql, null, session, parameterMetadata );
queryReturns = new ArrayList<NativeSQLQueryReturn>();
queryReturns = new NativeSQLQueryReturn[0];
querySpaces = null;
callable = false;
}
private NativeSQLQueryReturn[] getQueryReturns() {
return queryReturns.toArray( new NativeSQLQueryReturn[queryReturns.size()] );
return queryReturns;
}
public List list() throws HibernateException {
@ -208,13 +209,12 @@ public class SQLQueryImpl extends AbstractQueryImpl implements SQLQuery {
// some preparation work.
prepare();
verifyParameters( callable );
boolean noReturns = queryReturns==null || queryReturns.isEmpty();
if ( noReturns ) {
this.autoDiscoverTypes = noReturns;
if ( CollectionHelper.isEmpty( queryReturns ) ) {
this.autoDiscoverTypes = true;
}
else {
for ( NativeSQLQueryReturn queryReturn : queryReturns ) {
if ( queryReturn instanceof NativeSQLQueryScalarReturn ) {
for ( final NativeSQLQueryReturn queryReturn : queryReturns ) {
if ( NativeSQLQueryScalarReturn.class.isInstance( queryReturn ) ) {
NativeSQLQueryScalarReturn scalar = (NativeSQLQueryScalarReturn) queryReturn;
if ( scalar.getType() == null ) {
autoDiscoverTypes = true;
@ -229,12 +229,12 @@ public class SQLQueryImpl extends AbstractQueryImpl implements SQLQuery {
if ( queryReturnBuilders != null ) {
if ( ! queryReturnBuilders.isEmpty() ) {
if ( queryReturns != null ) {
queryReturns.clear();
queryReturns = null;
}
queryReturns = new ArrayList<NativeSQLQueryReturn>();
for ( ReturnBuilder builder : queryReturnBuilders ) {
queryReturns.add( builder.buildReturn() );
int size = queryReturnBuilders.size();
queryReturns = new NativeSQLQueryReturn[size];
for(int i=0;i<size;i++){
queryReturns[i] = queryReturnBuilders.get( i ).buildReturn();
}
queryReturnBuilders.clear();
}
@ -251,11 +251,11 @@ public class SQLQueryImpl extends AbstractQueryImpl implements SQLQuery {
public Type[] getReturnTypes() throws HibernateException {
throw new UnsupportedOperationException("not yet implemented for SQL queries");
}
@Override
public Query setLockMode(String alias, LockMode lockMode) {
throw new UnsupportedOperationException("cannot set the lock mode for a native SQL query");
}
@Override
public Query setLockOptions(LockOptions lockOptions) {
throw new UnsupportedOperationException("cannot set lock options for a native SQL query");
}
@ -265,7 +265,7 @@ public class SQLQueryImpl extends AbstractQueryImpl implements SQLQuery {
//we never need to apply locks to the SQL
return null;
}
@Override
public SQLQuery addScalar(final String columnAlias, final Type type) {
if ( queryReturnBuilders == null ) {
queryReturnBuilders = new ArrayList<ReturnBuilder>();
@ -351,22 +351,22 @@ public class SQLQueryImpl extends AbstractQueryImpl implements SQLQuery {
final String joinedPropertyName = path.substring( loc+1 );
return addFetch( tableAlias, ownerTableAlias, joinedPropertyName );
}
@Override
public SQLQuery addJoin(String alias, String path, LockMode lockMode) {
createFetchJoin( alias, path ).setLockMode( lockMode );
return this;
}
@Override
public SQLQuery setResultSetMapping(String name) {
ResultSetMappingDefinition mapping = session.getFactory().getResultSetMapping( name );
if ( mapping == null ) {
throw new MappingException( "Unknown SqlResultSetMapping [" + name + "]" );
}
NativeSQLQueryReturn[] returns = mapping.getQueryReturns();
queryReturns.addAll( Arrays.asList( returns ) );
queryReturns = mapping.getQueryReturns();
return this;
}
@Override
public SQLQuery addSynchronizedQuerySpace(String querySpace) {
if ( querySpaces == null ) {
querySpaces = new ArrayList<String>();
@ -374,11 +374,11 @@ public class SQLQueryImpl extends AbstractQueryImpl implements SQLQuery {
querySpaces.add( querySpace );
return this;
}
@Override
public SQLQuery addSynchronizedEntityName(String entityName) {
return addQuerySpaces( getSession().getFactory().getEntityPersister( entityName ).getQuerySpaces() );
}
@Override
public SQLQuery addSynchronizedEntityClass(Class entityClass) {
return addQuerySpaces( getSession().getFactory().getEntityPersister( entityClass.getName() ).getQuerySpaces() );
}
@ -392,7 +392,7 @@ public class SQLQueryImpl extends AbstractQueryImpl implements SQLQuery {
}
return this;
}
@Override
public int executeUpdate() throws HibernateException {
Map namedParams = getNamedParams();
before();

View File

@ -863,9 +863,7 @@ public final class SessionFactoryImpl
namedSqlQueries.put( namedNativeQueryDefinition.getName(), namedNativeQueryDefinition );
}
sqlResultSetMappings = new HashMap<String, ResultSetMappingDefinition>();
for( ResultSetMappingDefinition resultSetMappingDefinition : metadata.getResultSetMappingDefinitions() ) {
sqlResultSetMappings.put( resultSetMappingDefinition.getName(), resultSetMappingDefinition );
}
sqlResultSetMappings.putAll( metadata.getResultSetMappingDefinitions() );
imports = new HashMap<String,String>();
for ( Map.Entry<String,String> importEntry : metadata.getImports() ) {
imports.put( importEntry.getKey(), importEntry.getValue() );

View File

@ -146,4 +146,10 @@ public final class CollectionHelper {
public static boolean isNotEmpty(Map map) {
return !isEmpty( map );
}
public static boolean isEmpty(Object[] objs){
return objs == null || objs.length ==0;
}
public static boolean isNotEmpty(Object[] objs){
return !isEmpty( objs );
}
}

View File

@ -107,7 +107,7 @@ public interface Metadata {
public Iterable<NamedSQLQueryDefinition> getNamedNativeQueryDefinitions();
public Iterable<ResultSetMappingDefinition> getResultSetMappingDefinitions();
public Map<String, ResultSetMappingDefinition> getResultSetMappingDefinitions();
public Iterable<Map.Entry<String, String>> getImports();

View File

@ -186,18 +186,7 @@ public class Binder {
this.metadata = metadata;
this.identifierGeneratorFactory = identifierGeneratorFactory;
this.typeHelper = new HibernateTypeHelper( this, metadata );
this.nameNormalizer = new ObjectNameNormalizer() {
@Override
protected NamingStrategy getNamingStrategy() {
return metadata.getNamingStrategy();
}
@Override
protected boolean isUseQuotedIdentifiersGlobally() {
return metadata.isGloballyQuotedIdentifiers();
}
};
this.nameNormalizer = metadata.getObjectNameNormalizer();
}
private AttributeBinding attributeBinding( final String entityName, final String attributeName ) {

View File

@ -36,6 +36,7 @@ import org.hibernate.SessionFactory;
import org.hibernate.cache.spi.RegionFactory;
import org.hibernate.cache.spi.access.AccessType;
import org.hibernate.cfg.NamingStrategy;
import org.hibernate.cfg.ObjectNameNormalizer;
import org.hibernate.engine.ResultSetMappingDefinition;
import org.hibernate.engine.spi.FilterDefinition;
import org.hibernate.engine.spi.NamedQueryDefinition;
@ -100,6 +101,7 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
private final Database database;
private final MappingDefaults mappingDefaults;
private final ObjectNameNormalizer nameNormalizer;
private Map<String, TypeDefinition> typeDefinitionMap = new HashMap<String, TypeDefinition>();
private Map<String, FilterDefinition> filterDefinitionMap = new HashMap<String, FilterDefinition>();
@ -122,6 +124,18 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
this.database = new Database( options );
this.mappingDefaults = new MappingDefaultsImpl();
this.nameNormalizer = new ObjectNameNormalizer() {
@Override
protected NamingStrategy getNamingStrategy() {
return MetadataImpl.this.getNamingStrategy();
}
@Override
protected boolean isUseQuotedIdentifiersGlobally() {
return MetadataImpl.this.isGloballyQuotedIdentifiers();
}
};
final MetadataSourceProcessor[] metadataSourceProcessors;
if ( options.getMetadataSourceProcessingOrder() == MetadataSourceProcessingOrder.HBM_FIRST ) {
@ -186,6 +200,11 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
}
}
@Override
public ObjectNameNormalizer getObjectNameNormalizer() {
return nameNormalizer;
}
@Override
public void addTypeDefinition(TypeDefinition typeDefinition) {
if ( typeDefinition == null ) {
@ -345,12 +364,19 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
if ( resultSetMappingDefinition == null || resultSetMappingDefinition.getName() == null ) {
throw new IllegalArgumentException( "Result-set mapping object or name is null: " + resultSetMappingDefinition );
}
resultSetMappings.put( resultSetMappingDefinition.getName(), resultSetMappingDefinition );
ResultSetMappingDefinition old = resultSetMappings.put(
resultSetMappingDefinition.getName(),
resultSetMappingDefinition
);
if ( old != null ) {
LOG.warn( "Duplicated @SqlResultSetMappings with same name["+ resultSetMappingDefinition.getName() +"] found" );
//todo mapping exception??
}
}
@Override
public Iterable<ResultSetMappingDefinition> getResultSetMappingDefinitions() {
return resultSetMappings.values();
public Map<String, ResultSetMappingDefinition> getResultSetMappingDefinitions() {
return resultSetMappings;
}
private ClassLoaderService classLoaderService() {
@ -425,11 +451,11 @@ public class MetadataImpl implements MetadataImplementor, Serializable {
throw new AssertionFailure( "Entity binding has no root: " + entityName );
}
@Override
public Iterable<EntityBinding> getEntityBindings() {
return entityBindingMap.values();
}
@Override
public void addEntity(EntityBinding entityBinding) {
final String entityName = entityBinding.getEntity().getName();
if ( entityBindingMap.containsKey( entityName ) ) {

View File

@ -41,6 +41,7 @@ import org.hibernate.metamodel.MetadataSources;
import org.hibernate.metamodel.internal.MetadataImpl;
import org.hibernate.metamodel.internal.source.annotations.global.FetchProfileProcessor;
import org.hibernate.metamodel.internal.source.annotations.global.QueryProcessor;
import org.hibernate.metamodel.internal.source.annotations.global.SqlResultSetProcessor;
import org.hibernate.metamodel.internal.source.annotations.global.TableProcessor;
import org.hibernate.metamodel.internal.source.annotations.util.HibernateDotNames;
import org.hibernate.metamodel.internal.source.annotations.util.JPADotNames;
@ -178,6 +179,7 @@ public class AnnotationMetadataSourceProcessorImpl implements MetadataSourceProc
TableProcessor.bind( bindingContext );
FetchProfileProcessor.bind( bindingContext );
QueryProcessor.bind( bindingContext );
SqlResultSetProcessor.bind( bindingContext );
}
private Index parseAndUpdateIndex(List<JaxbRoot<JaxbEntityMappings>> mappings, Index annotationIndex) {

View File

@ -279,22 +279,12 @@ public class QueryProcessor {
if ( val == null ) {
return null;
}
if ( val.equalsIgnoreCase( CacheMode.GET.toString() ) ) {
return CacheMode.GET;
try {
return CacheMode.valueOf( val.toUpperCase() );
}
if ( val.equalsIgnoreCase( CacheMode.IGNORE.toString() ) ) {
return CacheMode.IGNORE;
catch ( IllegalArgumentException e ) {
throw new AnnotationException( "Unknown CacheMode in hint: " + query + ":" + element );
}
if ( val.equalsIgnoreCase( CacheMode.NORMAL.toString() ) ) {
return CacheMode.NORMAL;
}
if ( val.equalsIgnoreCase( CacheMode.PUT.toString() ) ) {
return CacheMode.PUT;
}
if ( val.equalsIgnoreCase( CacheMode.REFRESH.toString() ) ) {
return CacheMode.REFRESH;
}
throw new AnnotationException( "Unknown CacheMode in hint: " + query + ":" + element );
}
private static FlushMode getFlushMode(AnnotationInstance[] hints, String element, String query) {
@ -302,22 +292,10 @@ public class QueryProcessor {
if ( val == null ) {
return null;
}
if ( val.equalsIgnoreCase( FlushMode.ALWAYS.toString() ) ) {
return FlushMode.ALWAYS;
try {
return FlushMode.valueOf( val.toUpperCase() );
}
else if ( val.equalsIgnoreCase( FlushMode.AUTO.toString() ) ) {
return FlushMode.AUTO;
}
else if ( val.equalsIgnoreCase( FlushMode.COMMIT.toString() ) ) {
return FlushMode.COMMIT;
}
else if ( val.equalsIgnoreCase( FlushMode.NEVER.toString() ) ) {
return FlushMode.MANUAL;
}
else if ( val.equalsIgnoreCase( FlushMode.MANUAL.toString() ) ) {
return FlushMode.MANUAL;
}
else {
catch ( IllegalArgumentException e ) {
throw new AnnotationException( "Unknown FlushMode in hint: " + query + ":" + element );
}
}

View File

@ -0,0 +1,218 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* Copyright (c) 2011, 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.internal.source.annotations.global;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.jboss.jandex.AnnotationInstance;
import org.jboss.logging.Logger;
import org.hibernate.LockMode;
import org.hibernate.MappingException;
import org.hibernate.engine.ResultSetMappingDefinition;
import org.hibernate.engine.query.spi.sql.NativeSQLQueryRootReturn;
import org.hibernate.engine.query.spi.sql.NativeSQLQueryScalarReturn;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.metamodel.internal.source.annotations.AnnotationBindingContext;
import org.hibernate.metamodel.internal.source.annotations.util.JPADotNames;
import org.hibernate.metamodel.internal.source.annotations.util.JandexHelper;
import org.hibernate.metamodel.spi.binding.AttributeBinding;
import org.hibernate.metamodel.spi.binding.CompositeAttributeBinding;
import org.hibernate.metamodel.spi.binding.EntityBinding;
import org.hibernate.metamodel.spi.binding.ManyToOneAttributeBinding;
import org.hibernate.metamodel.spi.binding.SingularAssociationAttributeBinding;
/**
* Binds <ul>
* <li>{@link javax.persistence.SqlResultSetMapping}</li>
* <li>{@link javax.persistence.SqlResultSetMappings}</li>
* <li>{@link javax.persistence.EntityResult}</li>
* <li>{@link javax.persistence.FieldResult}</li>
* <li>{@link javax.persistence.ColumnResult}</li>
* </ul>
*
* @author Strong Liu <stliu@hibernate.org>
*/
public class SqlResultSetProcessor {
private static final CoreMessageLogger LOG = Logger.getMessageLogger(
CoreMessageLogger.class,
QueryProcessor.class.getName()
);
private SqlResultSetProcessor() {
}
public static void bind(final AnnotationBindingContext bindingContext) {
List<AnnotationInstance> annotations = bindingContext.getIndex()
.getAnnotations( JPADotNames.SQL_RESULT_SET_MAPPING );
for ( final AnnotationInstance sqlResultSetMappingAnnotationInstance : annotations ) {
bindSqlResultSetMapping( bindingContext, sqlResultSetMappingAnnotationInstance );
}
annotations = bindingContext.getIndex().getAnnotations( JPADotNames.SQL_RESULT_SET_MAPPINGS );
for ( final AnnotationInstance sqlResultSetMappingsAnnotationInstance : annotations ) {
for ( AnnotationInstance annotationInstance : JandexHelper.getValue(
sqlResultSetMappingsAnnotationInstance,
"value",
AnnotationInstance[].class
) ) {
bindSqlResultSetMapping( bindingContext, annotationInstance );
}
}
}
private static int entityAliasIndex = 0;
private static void bindSqlResultSetMapping(final AnnotationBindingContext bindingContext, final AnnotationInstance annotation) {
entityAliasIndex = 0;
final String name = JandexHelper.getValue( annotation, "name", String.class );
final ResultSetMappingDefinition definition = new ResultSetMappingDefinition( name );
for ( final AnnotationInstance entityResult : JandexHelper.getValue(
annotation,
"entities",
AnnotationInstance[].class
) ) {
bindEntityResult( bindingContext, entityResult, definition );
}
for ( final AnnotationInstance columnResult : JandexHelper.getValue(
annotation,
"columns",
AnnotationInstance[].class
) ) {
bindColumnResult( bindingContext, columnResult, definition );
}
bindingContext.getMetadataImplementor().addResultSetMapping( definition );
}
private static void bindEntityResult(final AnnotationBindingContext bindingContext,
final AnnotationInstance entityResult,
final ResultSetMappingDefinition definition) {
final Class entityClass = JandexHelper.getValue( entityResult, "entityClass", Class.class );
final String className = entityClass.getName();
//todo look up the whole entitybindings to find the right one seems stupid, but there is no way to look entitybinding
//by class name, since with hbm, hibernate actually supports map one class to multi entities.
final Iterable<EntityBinding> entityBindings = bindingContext.getMetadataImplementor().getEntityBindings();
EntityBinding targetEntityBinding = null;
for ( final EntityBinding entityBinding : entityBindings ) {
if ( className.equals( entityBinding.getEntity().getClass() ) ) {
targetEntityBinding = entityBinding;
break;
}
}
if ( targetEntityBinding == null ) {
throw new MappingException(
String.format(
"Entity[%s] not found in SqlResultMapping[%s]",
className,
definition.getName()
)
);
}
final String discriminatorColumn = JandexHelper.getValue( entityResult, "discriminatorColumn", String.class );
final Map<String, String[]> propertyResults = new HashMap<String, String[]>();
if ( StringHelper.isNotEmpty( discriminatorColumn ) ) {
final String quotingNormalizedName = bindingContext.getMetadataImplementor()
.getObjectNameNormalizer()
.normalizeIdentifierQuoting(
discriminatorColumn
);
propertyResults.put( "class", new String[] { quotingNormalizedName } );
}
for ( final AnnotationInstance fieldResult : JandexHelper.getValue(
entityResult,
"fields",
AnnotationInstance[].class
) ) {
bindFieldResult( bindingContext, targetEntityBinding, fieldResult, definition );
}
final NativeSQLQueryRootReturn result = new NativeSQLQueryRootReturn(
"alias" + entityAliasIndex++,
targetEntityBinding.getEntity().getName(),
propertyResults,
LockMode.READ
);
definition.addQueryReturn( result );
}
private static void bindFieldResult(final AnnotationBindingContext bindingContext,
final EntityBinding entityBinding,
final AnnotationInstance fieldResult,
final ResultSetMappingDefinition definition) {
final String name = JandexHelper.getValue( fieldResult, "name", String.class );
final String column = JandexHelper.getValue( fieldResult, "column", String.class );
final String quotingNormalizedColumnName = bindingContext.getMetadataImplementor().getObjectNameNormalizer()
.normalizeIdentifierQuoting( column );
if ( name.indexOf( '.' ) == -1 ) {
}
else {
int dotIndex = name.lastIndexOf( '.' );
String reducedName = name.substring( 0, dotIndex );
AttributeBinding attributeBinding = entityBinding.locateAttributeBinding( reducedName );
if ( CompositeAttributeBinding.class.isInstance( attributeBinding ) ) {
CompositeAttributeBinding compositeAttributeBinding = CompositeAttributeBinding.class.cast(
attributeBinding
);
compositeAttributeBinding.attributeBindings();
}
else if ( ManyToOneAttributeBinding.class.isInstance( attributeBinding ) ) {
ManyToOneAttributeBinding manyToOneAttributeBinding = ManyToOneAttributeBinding.class.cast(
attributeBinding
);
EntityBinding referencedEntityBinding = manyToOneAttributeBinding.getReferencedEntityBinding();
Set<SingularAssociationAttributeBinding> referencingAttributeBindings = manyToOneAttributeBinding.getEntityReferencingAttributeBindings();
//todo see org.hibernate.cfg.annotations.ResultsetMappingSecondPass#getSubPropertyIterator
}
else {
throw new MappingException( "dotted notation reference neither a component nor a many/one to one" );
}
}
}
private static void bindColumnResult(final AnnotationBindingContext bindingContext,
final AnnotationInstance columnResult,
final ResultSetMappingDefinition definition) {
final String name = JandexHelper.getValue( columnResult, "name", String.class );
final String normalizedName = bindingContext.getMetadataImplementor()
.getObjectNameNormalizer()
.normalizeIdentifierQuoting( name );
definition.addQueryReturn( new NativeSQLQueryScalarReturn( normalizedName, null ) );
}
}

View File

@ -121,7 +121,10 @@ public class TableProcessor {
private static Column findColumn(Table table, String columnName) {
Column column = null;
for ( Value value : table.values() ) {
if ( value instanceof Column && ( (Column) value ).getColumnName().getName().equals( columnName ) ) {
if ( Column.class.isInstance( value ) && Column.class.cast( value )
.getColumnName()
.getName()
.equals( columnName ) ) {
column = (Column) value;
break;
}

View File

@ -27,6 +27,7 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.Set;
import org.hibernate.internal.util.Value;
import org.hibernate.metamodel.spi.domain.Attribute;
import org.hibernate.metamodel.spi.source.MetaAttributeContext;
@ -48,6 +49,7 @@ public abstract class AbstractAttributeBinding implements AttributeBinding {
private boolean isAlternateUniqueKey;
private final MetaAttributeContext metaAttributeContext;
private final Value<String> roleHolder;
protected AbstractAttributeBinding(
AttributeBindingContainer container,
@ -60,6 +62,14 @@ public abstract class AbstractAttributeBinding implements AttributeBinding {
this.propertyAccessorName = propertyAccessorName;
this.includedInOptimisticLocking = includedInOptimisticLocking;
this.metaAttributeContext = metaAttributeContext;
this.roleHolder = new Value<String>(
new Value.DeferredInitializer<String>() {
@Override
public String initialize() {
return getContainer().getPathBase() + '.' + getAttribute().getName();
}
}
);
}
@Override
@ -73,7 +83,7 @@ public abstract class AbstractAttributeBinding implements AttributeBinding {
}
protected String getRole() {
return getContainer().getPathBase() + '.' + getAttribute().getName();
return roleHolder.getValue();
}
@Override

View File

@ -160,18 +160,17 @@ public class ManyToOneAttributeBinding
@Override
public FetchMode getFetchMode() {
if ( fetchStyle == FetchStyle.JOIN ) {
return FetchMode.JOIN;
switch ( fetchStyle ){
case JOIN:
return FetchMode.JOIN;
case SELECT:
return FetchMode.SELECT;
case BATCH:
// we need the subsequent select...
return FetchMode.SELECT;
default:
throw new AssertionFailure( "Unexpected fetch style : " + fetchStyle.name() );
}
else if ( fetchStyle == FetchStyle.SELECT ) {
return FetchMode.SELECT;
}
else if ( fetchStyle == FetchStyle.BATCH ) {
// we need the subsequent select...
return FetchMode.SELECT;
}
throw new AssertionFailure( "Unexpected fetch style : " + fetchStyle.name() );
}
@Override

View File

@ -23,6 +23,7 @@
*/
package org.hibernate.metamodel.spi.source;
import org.hibernate.cfg.ObjectNameNormalizer;
import org.hibernate.engine.ResultSetMappingDefinition;
import org.hibernate.engine.spi.FilterDefinition;
import org.hibernate.engine.spi.Mapping;
@ -47,6 +48,8 @@ public interface MetadataImplementor extends Metadata, BindingContext, Mapping {
public TypeResolver getTypeResolver();
public ObjectNameNormalizer getObjectNameNormalizer();
public void addImport(String entityName, String entityName1);
public void addEntity(EntityBinding entityBinding);
@ -69,7 +72,6 @@ public interface MetadataImplementor extends Metadata, BindingContext, Mapping {
public void addResultSetMapping(ResultSetMappingDefinition resultSetMappingDefinition);
// todo : this needs to move to AnnotationBindingContext
public void setGloballyQuotedIdentifiers(boolean b);
public MetaAttributeContext getGlobalMetaAttributeContext();