From 7258cb98f47afafa8d6a70954613188cb3d25e78 Mon Sep 17 00:00:00 2001 From: JPAV Date: Mon, 9 May 2011 11:26:00 -0500 Subject: [PATCH] HHH-6132: Created binders for several global configurations and updated metadata appropriately. --- .../org/hibernate/annotations/QueryHints.java | 44 ++ .../metamodel/binding/FetchProfile.java | 167 +++---- .../metamodel/binding/IdGenerator.java | 69 ++- .../hibernate/metamodel/binding/TypeDef.java | 29 +- .../source/annotations/AnnotationBinder.java | 16 +- .../global/FetchProfileBinder.java | 89 ++-- .../annotations/global/FilterDefBinder.java | 80 ++++ .../annotations/global/IdGeneratorBinder.java | 161 +++++++ .../annotations/global/QueryBinder.java | 219 ++++++++- .../annotations/global/TableBinder.java | 154 +++---- .../annotations/global/TypeDefBinder.java | 94 ++++ .../source/annotations/util/JandexHelper.java | 429 +++++++++++------- .../source/hbm/HibernateMappingBinder.java | 16 +- .../source/internal/MetadataImpl.java | 74 +-- .../source/spi/MetadataImplementor.java | 3 +- .../annotations/util/JandexHelperTest.java | 51 +++ 16 files changed, 1207 insertions(+), 488 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/annotations/QueryHints.java create mode 100644 hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/global/FilterDefBinder.java create mode 100644 hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/global/IdGeneratorBinder.java create mode 100644 hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/global/TypeDefBinder.java diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/QueryHints.java b/hibernate-core/src/main/java/org/hibernate/annotations/QueryHints.java new file mode 100644 index 0000000000..19635cd12c --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/annotations/QueryHints.java @@ -0,0 +1,44 @@ +/* + * 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.annotations; + +/** + * + */ +public class QueryHints { + + public static final String CACHE_MODE = "org.hibernate.cacheMode"; + public static final String CACHE_REGION = "org.hibernate.cacheRegion"; + public static final String CACHEABLE = "org.hibernate.cacheable"; + public static final String CALLABLE = "org.hibernate.callable"; + public static final String COMMENT = "org.hibernate.comment"; + public static final String FETCH_SIZE = "org.hibernate.fetchSize"; + public static final String FLUSH_MODE = "org.hibernate.flushMode"; + public static final String READ_ONLY = "org.hibernate.readOnly"; + public static final String TIMEOUT_HIBERNATE = "org.hibernate.timeout"; + public static final String TIMEOUT_JPA = "javax.persistence.query.timeout"; + + private QueryHints() { + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/binding/FetchProfile.java b/hibernate-core/src/main/java/org/hibernate/metamodel/binding/FetchProfile.java index 1136f2615c..31b6d5dbc5 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/binding/FetchProfile.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/binding/FetchProfile.java @@ -22,122 +22,93 @@ * Boston, MA 02110-1301 USA */ package org.hibernate.metamodel.binding; -import java.util.LinkedHashSet; -import org.hibernate.mapping.MetadataSource; +import java.util.Collections; +import java.util.Set; /** - * A fetch profile allows a user to dynamically modify the fetching strategy used for particular associations at - * runtime, whereas that information was historically only statically defined in the metadata. + * A fetch profile allows a user to dynamically modify the fetching strategy used for particular associations at runtime, whereas + * that information was historically only statically defined in the metadata. *

* This class represent the data as it is defined in their metadata. * * @author Steve Ebersole - * * @see org.hibernate.engine.profile.FetchProfile */ public class FetchProfile { - private final String name; - private final MetadataSource source; - private LinkedHashSet fetches = new LinkedHashSet(); - /** - * Create a fetch profile representation. - * - * @param name The name of the fetch profile. - * @param source The source of the fetch profile (where was it defined). - */ - public FetchProfile(String name, MetadataSource source) { - this.name = name; - this.source = source; - } + private final String name; + private final Set fetches; - /** - * Retrieve the name of the fetch profile. - * - * @return The profile name - */ - public String getName() { - return name; - } + /** + * Create a fetch profile representation. + * + * @param name The name of the fetch profile. + * @param fetches + */ + public FetchProfile( String name, + Set fetches ) { + this.name = name; + this.fetches = fetches; + } - /** - * Retrieve the fetch profile source. - * - * @return The profile source. - */ - public MetadataSource getSource() { - return source; - } + /** + * Retrieve the name of the fetch profile. + * + * @return The profile name + */ + public String getName() { + return name; + } - /** - * Retrieve the fetches associated with this profile - * - * @return The fetches associated with this profile. - */ - public LinkedHashSet getFetches() { - return fetches; - } + /** + * Retrieve the fetches associated with this profile + * + * @return The fetches associated with this profile. + */ + public Set getFetches() { + return Collections.unmodifiableSet(fetches); + } - /** - * Adds a fetch to this profile. - * - * @param entity The entity which contains the association to be fetched - * @param association The association to fetch - * @param style The style of fetch t apply - */ - public void addFetch(String entity, String association, String style) { - fetches.add( new Fetch( entity, association, style ) ); - } + /** + * Adds a fetch to this profile. + * + * @param entity The entity which contains the association to be fetched + * @param association The association to fetch + * @param style The style of fetch t apply + */ + public void addFetch( String entity, + String association, + String style ) { + fetches.add(new Fetch(entity, association, style)); + } - /** - * {@inheritDoc} - */ - public boolean equals(Object o) { - if ( this == o ) { - return true; - } - if ( o == null || getClass() != o.getClass() ) { - return false; - } + /** + * Defines an individual association fetch within the given profile. + */ + public static class Fetch { + private final String entity; + private final String association; + private final String style; - FetchProfile that = (FetchProfile) o; + public Fetch( String entity, + String association, + String style ) { + this.entity = entity; + this.association = association; + this.style = style; + } - return name.equals( that.name ); - } + public String getEntity() { + return entity; + } - /** - * {@inheritDoc} - */ - public int hashCode() { - return name.hashCode(); - } + public String getAssociation() { + return association; + } - - /** - * Defines an individual association fetch within the given profile. - */ - public static class Fetch { - private final String entity; - private final String association; - private final String style; - - public Fetch(String entity, String association, String style) { - this.entity = entity; - this.association = association; - this.style = style; - } - - public String getEntity() { - return entity; - } - - public String getAssociation() { - return association; - } - - public String getStyle() { - return style; - } - } + public String getStyle() { + return style; + } + } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/binding/IdGenerator.java b/hibernate-core/src/main/java/org/hibernate/metamodel/binding/IdGenerator.java index faeb9ca7ab..151a0c68f5 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/binding/IdGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/binding/IdGenerator.java @@ -22,52 +22,47 @@ * Boston, MA 02110-1301 USA */ package org.hibernate.metamodel.binding; + import java.io.Serializable; -import java.util.Properties; +import java.util.Collections; +import java.util.Map; /** - * Identifier generator container, - * Useful to keep named generator in annotations + * Identifier generator container, Useful to keep named generator in annotations * * @author Emmanuel Bernard */ public class IdGenerator implements Serializable { - private String name; - private String identifierGeneratorStrategy; - private Properties params = new Properties(); + private final String name; + private final String strategy; + private final Map parameters; + public IdGenerator( String name, + String strategy, + Map parameters ) { + this.name = name; + this.strategy = strategy; + this.parameters = parameters; + } - /** - * @return identifier generator strategy - */ - public String getIdentifierGeneratorStrategy() { - return identifierGeneratorStrategy; - } + /** + * @return identifier generator strategy + */ + public String getStrategy() { + return strategy; + } - /** - * @return generator name - */ - public String getName() { - return name; - } - - /** - * @return generator configuration parameters - */ - public Properties getParams() { - return params; - } - - public void setIdentifierGeneratorStrategy(String string) { - identifierGeneratorStrategy = string; - } - - public void setName(String string) { - name = string; - } - - public void addParam(String key, String value) { - params.setProperty( key, value ); - } + /** + * @return generator name + */ + public String getName() { + return name; + } + /** + * @return generator configuration parameters + */ + public Map getParameters() { + return Collections.unmodifiableMap(parameters); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/binding/TypeDef.java b/hibernate-core/src/main/java/org/hibernate/metamodel/binding/TypeDef.java index df746ea001..6378a046b2 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/binding/TypeDef.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/binding/TypeDef.java @@ -22,27 +22,30 @@ * Boston, MA 02110-1301 USA */ package org.hibernate.metamodel.binding; + import java.io.Serializable; -import java.util.Properties; +import java.util.Collections; +import java.util.Map; /** * Placeholder for typedef information */ public class TypeDef implements Serializable { - private String typeClass; - private Properties parameters; + private final String typeClass; + private final Map parameters; - public TypeDef(String typeClass, Properties parameters) { - this.typeClass = typeClass; - this.parameters = parameters; - } + public TypeDef( String typeClass, + Map parameters ) { + this.typeClass = typeClass; + this.parameters = parameters; + } - public Properties getParameters() { - return parameters; - } - public String getTypeClass() { - return typeClass; - } + public Map getParameters() { + return Collections.unmodifiableMap(parameters); + } + public String getTypeClass() { + return typeClass; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/AnnotationBinder.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/AnnotationBinder.java index 56ecb82edd..25630f1afc 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/AnnotationBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/AnnotationBinder.java @@ -32,6 +32,10 @@ import org.slf4j.LoggerFactory; import org.hibernate.metamodel.source.annotations.entity.ConfiguredClass; import org.hibernate.metamodel.source.annotations.entity.ConfiguredClassHierarchy; import org.hibernate.metamodel.source.annotations.entity.EntityBinder; +import org.hibernate.metamodel.source.annotations.global.FilterDefBinder; +import org.hibernate.metamodel.source.annotations.global.IdGeneratorBinder; +import org.hibernate.metamodel.source.annotations.global.QueryBinder; +import org.hibernate.metamodel.source.annotations.global.TypeDefBinder; import org.hibernate.metamodel.source.annotations.global.FetchProfileBinder; import org.hibernate.metamodel.source.annotations.global.TableBinder; import org.hibernate.metamodel.source.annotations.util.ConfiguredClassHierarchyBuilder; @@ -45,7 +49,9 @@ import org.hibernate.metamodel.source.internal.MetadataImpl; * @author Hardy Ferentschik */ public class AnnotationBinder { - private static final Logger log = LoggerFactory.getLogger( AnnotationBinder.class ); + + private static final Logger LOG = LoggerFactory.getLogger( AnnotationBinder.class ); + private final MetadataImpl metadata; private final Index index; @@ -64,7 +70,8 @@ public class AnnotationBinder { * Binds global configuration data prior to entity binding. This includes generators and type definitions. */ private void preEntityBindings() { - FetchProfileBinder.bind( metadata, index ); + TypeDefBinder.bind(metadata, index); + IdGeneratorBinder.bind(metadata, index); } /** @@ -79,7 +86,7 @@ public class AnnotationBinder { // now we process each hierarchy one at the time for ( ConfiguredClassHierarchy hierarchy : hierarchies ) { for ( ConfiguredClass configuredClass : hierarchy ) { - log.info( "Binding entity from annotated class: {}", configuredClass.getName() ); + LOG.info( "Binding entity from annotated class: {}", configuredClass.getName() ); EntityBinder entityBinder = new EntityBinder( metadata, configuredClass ); entityBinder.bind(); } @@ -92,6 +99,9 @@ public class AnnotationBinder { */ private void postEntityBindings() { TableBinder.bind( metadata, index ); + FetchProfileBinder.bind( metadata, index ); + QueryBinder.bind(metadata, index); + FilterDefBinder.bind(metadata, index); } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/global/FetchProfileBinder.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/global/FetchProfileBinder.java index 92e8b8679f..8e6681d169 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/global/FetchProfileBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/global/FetchProfileBinder.java @@ -23,17 +23,17 @@ */ package org.hibernate.metamodel.source.annotations.global; -import java.util.Arrays; -import java.util.List; - +import java.util.HashSet; +import java.util.Set; import org.jboss.jandex.AnnotationInstance; import org.jboss.jandex.Index; - import org.hibernate.MappingException; import org.hibernate.annotations.FetchMode; -import org.hibernate.mapping.MetadataSource; +import org.hibernate.annotations.FetchProfiles; import org.hibernate.metamodel.binding.FetchProfile; +import org.hibernate.metamodel.binding.FetchProfile.Fetch; import org.hibernate.metamodel.source.annotations.HibernateDotNames; +import org.hibernate.metamodel.source.annotations.util.JandexHelper; import org.hibernate.metamodel.source.internal.MetadataImpl; /** @@ -42,51 +42,42 @@ import org.hibernate.metamodel.source.internal.MetadataImpl; * @author Hardy Ferentschik */ public class FetchProfileBinder { - private FetchProfileBinder() { - } - /** - * Binds all {@link org.hibernate.annotations.FetchProfiles} and {@link org.hibernate.annotations.FetchProfile} - * annotations to the specified meta data instance. - * - * @param meta the global metadata - * @param index the annotation index repository - */ - // TODO how to handle fetch profiles defined in hbm and annotations. Which overrides which? - // TODO verify that association exists. See former VerifyFetchProfileReferenceSecondPass - public static void bind(MetadataImpl meta, Index index) { - // check @FetchProfiles - List fetchProfilesAnnotations = index.getAnnotations( HibernateDotNames.FETCH_PROFILES ); - for ( AnnotationInstance fetchProfilesAnnotation : fetchProfilesAnnotations ) { - AnnotationInstance fetchProfiles[] = fetchProfilesAnnotation.value().asNestedArray(); - bindFetchProfileAnnotations( meta, Arrays.asList( fetchProfiles ) ); - } + /** + * Binds all {@link FetchProfiles} and {@link org.hibernate.annotations.FetchProfile} annotations to the supplied metadata. + * + * @param metadata the global metadata + * @param jandex the jandex index + */ + // TODO verify that association exists. See former VerifyFetchProfileReferenceSecondPass + public static void bind( MetadataImpl metadata, + Index jandex ) { + for (AnnotationInstance fetchProfile : jandex.getAnnotations(HibernateDotNames.FETCH_PROFILE)) { + bind(metadata, jandex, fetchProfile); + } + for (AnnotationInstance fetchProfiles : jandex.getAnnotations(HibernateDotNames.FETCH_PROFILES)) { + for (AnnotationInstance fetchProfile : JandexHelper.getValueAsArray(fetchProfiles, "value")) { + bind(metadata, jandex, fetchProfile); + } + } + } - // check @FetchProfile - List fetchProfileAnnotations = index.getAnnotations( HibernateDotNames.FETCH_PROFILE ); - bindFetchProfileAnnotations( meta, fetchProfileAnnotations ); - } + private static void bind( MetadataImpl metadata, + Index jandex, + AnnotationInstance fetchProfile ) { + String name = JandexHelper.getValueAsString(jandex, fetchProfile, "name"); + Set fetches = new HashSet(); + for (AnnotationInstance override : JandexHelper.getValueAsArray(fetchProfile, "fetchOverrides")) { + FetchMode fetchMode = JandexHelper.getValueAsEnum(jandex, override, "mode", FetchMode.class); + if (!fetchMode.equals(org.hibernate.annotations.FetchMode.JOIN)) throw new MappingException( + "Only FetchMode.JOIN is currently supported"); + fetches.add(new Fetch(JandexHelper.getValueAsString(jandex, override, "entity"), + JandexHelper.getValueAsString(jandex, override, "association"), + fetchMode.toString().toLowerCase())); + } + metadata.addFetchProfile(new FetchProfile(name, fetches)); + } - private static void bindFetchProfileAnnotations(MetadataImpl meta, List fetchProfileAnnotations) { - for ( AnnotationInstance fetchProfileAnnotation : fetchProfileAnnotations ) { - String name = fetchProfileAnnotation.value( "name" ).asString(); - FetchProfile profile = meta.findOrCreateFetchProfile( name, MetadataSource.ANNOTATIONS ); - - AnnotationInstance overrides[] = fetchProfileAnnotation.value( "fetchOverrides" ).asNestedArray(); - for ( AnnotationInstance overrideAnnotation : overrides ) { - FetchMode fetchMode = Enum.valueOf( FetchMode.class, overrideAnnotation.value( "mode" ).asEnum() ); - if ( !fetchMode.equals( org.hibernate.annotations.FetchMode.JOIN ) ) { - throw new MappingException( "Only FetchMode.JOIN is currently supported" ); - } - - String entityClassName = overrideAnnotation.value( "entity" ).asClass().name().toString(); - String associationName = overrideAnnotation.value( "association" ).asString(); - profile.addFetch( - entityClassName, associationName, fetchMode.toString().toLowerCase() - ); - } - } - } + private FetchProfileBinder() { + } } - - diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/global/FilterDefBinder.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/global/FilterDefBinder.java new file mode 100644 index 0000000000..d95801292e --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/global/FilterDefBinder.java @@ -0,0 +1,80 @@ +/* + * 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.source.annotations.global; + +import java.util.HashMap; +import java.util.Map; +import org.hibernate.annotations.FilterDef; +import org.hibernate.annotations.FilterDefs; +import org.hibernate.engine.spi.FilterDefinition; +import org.hibernate.internal.CoreMessageLogger; +import org.hibernate.metamodel.source.annotations.HibernateDotNames; +import org.hibernate.metamodel.source.annotations.util.JandexHelper; +import org.hibernate.metamodel.source.internal.MetadataImpl; +import org.hibernate.type.Type; +import org.jboss.jandex.AnnotationInstance; +import org.jboss.jandex.Index; +import org.jboss.logging.Logger; + +/** + * + */ +public class FilterDefBinder { + + private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, FilterDefBinder.class.getName()); + + /** + * Binds all {@link FilterDefs} and {@link FilterDef} annotations to the supplied metadata. + * + * @param metadata the global metadata + * @param jandex the jandex index + */ + public static void bind( MetadataImpl metadata, + Index jandex ) { + for (AnnotationInstance filterDef : jandex.getAnnotations(HibernateDotNames.FILTER_DEF)) { + bind(metadata, jandex, filterDef); + } + for (AnnotationInstance filterDefs : jandex.getAnnotations(HibernateDotNames.FILTER_DEFS)) { + for (AnnotationInstance filterDef : JandexHelper.getValueAsArray(filterDefs, "value")) { + bind(metadata, jandex, filterDef); + } + } + } + + private static void bind( MetadataImpl metadata, + Index jandex, + AnnotationInstance filterDef ) { + String name = JandexHelper.getValueAsString(jandex, filterDef, "name"); + Map prms = new HashMap(); + for (AnnotationInstance prm : JandexHelper.getValueAsArray(filterDef, "parameters")) { + prms.put(JandexHelper.getValueAsString(jandex, prm, "name"), + metadata.typeResolver().heuristicType(JandexHelper.getValueAsString(jandex, prm, "type"))); + } + metadata.addFilterDef(new FilterDefinition(name, JandexHelper.getValueAsString(jandex, filterDef, "defaultCondition"), prms)); + LOG.debugf("Binding filter definition: %s", name); + } + + private FilterDefBinder() { + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/global/IdGeneratorBinder.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/global/IdGeneratorBinder.java new file mode 100644 index 0000000000..6ce3fb2e9e --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/global/IdGeneratorBinder.java @@ -0,0 +1,161 @@ +/* + * 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.source.annotations.global; + +import java.util.HashMap; +import java.util.Map; +import javax.persistence.SequenceGenerator; +import org.hibernate.annotations.GenericGenerator; +import org.hibernate.annotations.GenericGenerators; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.id.MultipleHiLoPerTableGenerator; +import org.hibernate.id.PersistentIdentifierGenerator; +import org.hibernate.id.SequenceHiLoGenerator; +import org.hibernate.id.TableHiLoGenerator; +import org.hibernate.id.enhanced.SequenceStyleGenerator; +import org.hibernate.id.enhanced.TableGenerator; +import org.hibernate.internal.CoreMessageLogger; +import org.hibernate.internal.util.StringHelper; +import org.hibernate.metamodel.binding.IdGenerator; +import org.hibernate.metamodel.source.annotations.HibernateDotNames; +import org.hibernate.metamodel.source.annotations.JPADotNames; +import org.hibernate.metamodel.source.annotations.util.JandexHelper; +import org.hibernate.metamodel.source.internal.MetadataImpl; +import org.jboss.jandex.AnnotationInstance; +import org.jboss.jandex.Index; +import org.jboss.logging.Logger; + +/** + * + */ +public class IdGeneratorBinder { + + private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, IdGeneratorBinder.class.getName()); + + private static void addStringParameter( Index index, + AnnotationInstance annotation, + String element, + Map parameters, + String parameter ) { + String string = JandexHelper.getValueAsString(index, annotation, element); + if (StringHelper.isNotEmpty(string)) parameters.put(parameter, string); + } + + /** + * Binds all {@link SequenceGenerator}, {@link javax.persistence.TableGenerator}, {@link GenericGenerator}, and { + * {@link GenericGenerators} annotations to the supplied metadata. + * + * @param metadata the global metadata + * @param jandex the jandex index + */ + public static void bind( MetadataImpl metadata, + Index jandex ) { + for (AnnotationInstance generator : jandex.getAnnotations(JPADotNames.SEQUENCE_GENERATOR)) { + bindSequenceGenerator(metadata, jandex, generator); + } + for (AnnotationInstance generator : jandex.getAnnotations(JPADotNames.TABLE_GENERATOR)) { + bindTableGenerator(metadata, jandex, generator); + } + for (AnnotationInstance generator : jandex.getAnnotations(HibernateDotNames.GENERIC_GENERATOR)) { + bindGenericGenerator(metadata, jandex, generator); + } + for (AnnotationInstance generators : jandex.getAnnotations(HibernateDotNames.GENERIC_GENERATORS)) { + for (AnnotationInstance generator : JandexHelper.getValueAsArray(generators, "value")) { + bindGenericGenerator(metadata, jandex, generator); + } + } + } + + private static void bindGenericGenerator( MetadataImpl metadata, + Index jandex, + AnnotationInstance generator ) { + String name = JandexHelper.getValueAsString(jandex, generator, "name"); + Map prms = new HashMap(); + for (AnnotationInstance prm : JandexHelper.getValueAsArray(generator, "parameters")) { + prms.put(JandexHelper.getValueAsString(jandex, prm, "name"), JandexHelper.getValueAsString(jandex, prm, "value")); + } + metadata.addIdGenerator(new IdGenerator(name, JandexHelper.getValueAsString(jandex, generator, "strategy"), prms)); + LOG.tracef("Add generic generator with name: %s", name); + } + + private static void bindSequenceGenerator( MetadataImpl metadata, + Index jandex, + AnnotationInstance generator ) { + String name = JandexHelper.getValueAsString(jandex, generator, "name"); + String strategy; + Map prms = new HashMap(); + addStringParameter(jandex, generator, "sequenceName", prms, SequenceStyleGenerator.SEQUENCE_PARAM); + if (metadata.getOptions().useNewIdentifierGenerators()) { + strategy = SequenceStyleGenerator.class.getName(); + addStringParameter(jandex, generator, "catalog", prms, PersistentIdentifierGenerator.CATALOG); + addStringParameter(jandex, generator, "schema", prms, PersistentIdentifierGenerator.SCHEMA); + prms.put(SequenceStyleGenerator.INCREMENT_PARAM, + String.valueOf(JandexHelper.getValueAsInt(jandex, generator, "allocationSize"))); + prms.put(SequenceStyleGenerator.INITIAL_PARAM, + String.valueOf(JandexHelper.getValueAsInt(jandex, generator, "initialValue"))); + } else { + strategy = "seqhilo"; + if (JandexHelper.getValueAsInt(jandex, generator, "initialValue") != 1) LOG.unsupportedInitialValue(AvailableSettings.USE_NEW_ID_GENERATOR_MAPPINGS); + prms.put(SequenceHiLoGenerator.MAX_LO, + String.valueOf(JandexHelper.getValueAsInt(jandex, generator, "allocationSize") - 1)); + } + metadata.addIdGenerator(new IdGenerator(name, strategy, prms)); + LOG.tracef("Add sequence generator with name: %s", name); + } + + private static void bindTableGenerator( MetadataImpl metadata, + Index jandex, + AnnotationInstance generator ) { + String name = JandexHelper.getValueAsString(jandex, generator, "name"); + String strategy; + Map prms = new HashMap(); + addStringParameter(jandex, generator, "catalog", prms, PersistentIdentifierGenerator.CATALOG); + addStringParameter(jandex, generator, "schema", prms, PersistentIdentifierGenerator.SCHEMA); + if (metadata.getOptions().useNewIdentifierGenerators()) { + strategy = TableGenerator.class.getName(); + prms.put(TableGenerator.CONFIG_PREFER_SEGMENT_PER_ENTITY, "true"); + addStringParameter(jandex, generator, "table", prms, TableGenerator.TABLE_PARAM); + addStringParameter(jandex, generator, "pkColumnName", prms, TableGenerator.SEGMENT_COLUMN_PARAM); + addStringParameter(jandex, generator, "pkColumnValue", prms, TableGenerator.SEGMENT_VALUE_PARAM); + addStringParameter(jandex, generator, "valueColumnName", prms, TableGenerator.VALUE_COLUMN_PARAM); + prms.put(TableGenerator.INCREMENT_PARAM, + String.valueOf(JandexHelper.getValueAsInt(jandex, generator, "allocationSize"))); + prms.put(TableGenerator.INITIAL_PARAM, + String.valueOf(JandexHelper.getValueAsInt(jandex, generator, "initialValue") + 1)); + } else { + strategy = MultipleHiLoPerTableGenerator.class.getName(); + addStringParameter(jandex, generator, "table", prms, MultipleHiLoPerTableGenerator.ID_TABLE); + addStringParameter(jandex, generator, "pkColumnName", prms, MultipleHiLoPerTableGenerator.PK_COLUMN_NAME); + addStringParameter(jandex, generator, "pkColumnValue", prms, MultipleHiLoPerTableGenerator.PK_VALUE_NAME); + addStringParameter(jandex, generator, "valueColumnName", prms, MultipleHiLoPerTableGenerator.VALUE_COLUMN_NAME); + prms.put(TableHiLoGenerator.MAX_LO, String.valueOf(JandexHelper.getValueAsInt(jandex, generator, "allocationSize") - 1)); + } + if (JandexHelper.getValueAsArray(generator, "uniqueConstraints").length > 0) LOG.ignoringTableGeneratorConstraints(name); + metadata.addIdGenerator(new IdGenerator(name, strategy, prms)); + LOG.tracef("Add table generator with name: %s", name); + } + + private IdGeneratorBinder() { + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/global/QueryBinder.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/global/QueryBinder.java index bb8c291976..a3b6636177 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/global/QueryBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/global/QueryBinder.java @@ -23,22 +23,221 @@ */ package org.hibernate.metamodel.source.annotations.global; -import org.jboss.jandex.Index; - +import java.util.HashMap; +import javax.persistence.NamedNativeQueries; +import javax.persistence.NamedNativeQuery; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import org.hibernate.AnnotationException; +import org.hibernate.CacheMode; +import org.hibernate.FlushMode; +import org.hibernate.LockMode; +import org.hibernate.annotations.QueryHints; +import org.hibernate.cfg.NotYetImplementedException; +import org.hibernate.engine.query.spi.sql.NativeSQLQueryRootReturn; +import org.hibernate.engine.spi.NamedQueryDefinition; +import org.hibernate.engine.spi.NamedSQLQueryDefinition; +import org.hibernate.internal.CoreMessageLogger; +import org.hibernate.internal.util.StringHelper; +import org.hibernate.metamodel.source.annotations.HibernateDotNames; +import org.hibernate.metamodel.source.annotations.JPADotNames; +import org.hibernate.metamodel.source.annotations.util.JandexHelper; import org.hibernate.metamodel.source.internal.MetadataImpl; +import org.jboss.jandex.AnnotationInstance; +import org.jboss.jandex.Index; +import org.jboss.logging.Logger; /** * @author Hardy Ferentschik */ public class QueryBinder { - private QueryBinder() { - } - public static void bindNamedQuery(MetadataImpl meta, Index index) { - } + private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, QueryBinder.class.getName()); - public static void bindNativeNamedQuery(MetadataImpl meta, Index index) { - } + /** + * 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. + * + * @param metadata the global metadata + * @param jandex the jandex index + */ + public static void bind( MetadataImpl metadata, + Index jandex ) { + for (AnnotationInstance query : jandex.getAnnotations(JPADotNames.NAMED_QUERY)) { + bindNamedQuery(metadata, jandex, query); + } + for (AnnotationInstance queries : jandex.getAnnotations(JPADotNames.NAMED_QUERIES)) { + for (AnnotationInstance query : JandexHelper.getValueAsArray(queries, "value")) { + bindNamedQuery(metadata, jandex, query); + } + } + for (AnnotationInstance query : jandex.getAnnotations(JPADotNames.NAMED_NATIVE_QUERY)) { + bindNamedNativeQuery(metadata, jandex, query); + } + for (AnnotationInstance queries : jandex.getAnnotations(JPADotNames.NAMED_NATIVE_QUERIES)) { + for (AnnotationInstance query : JandexHelper.getValueAsArray(queries, "value")) { + bindNamedNativeQuery(metadata, jandex, query); + } + } + for (AnnotationInstance query : jandex.getAnnotations(HibernateDotNames.NAMED_QUERY)) { + bindNamedQuery(metadata, jandex, query); + } + for (AnnotationInstance queries : jandex.getAnnotations(HibernateDotNames.NAMED_QUERIES)) { + for (AnnotationInstance query : JandexHelper.getValueAsArray(queries, "value")) { + bindNamedQuery(metadata, jandex, query); + } + } + for (AnnotationInstance query : jandex.getAnnotations(HibernateDotNames.NAMED_NATIVE_QUERY)) { + bindNamedNativeQuery(metadata, jandex, query); + } + for (AnnotationInstance queries : jandex.getAnnotations(HibernateDotNames.NAMED_NATIVE_QUERIES)) { + for (AnnotationInstance query : JandexHelper.getValueAsArray(queries, "value")) { + bindNamedNativeQuery(metadata, jandex, query); + } + } + } + + private static void bindNamedQuery( MetadataImpl metadata, + Index jandex, + AnnotationInstance annotation ) { + String name = JandexHelper.getValueAsString(jandex, annotation, "name"); + if (StringHelper.isEmpty(name)) throw new AnnotationException( + "A named query must have a name when used in class or package level"); + String query = JandexHelper.getValueAsString(jandex, annotation, "query"); + AnnotationInstance[] hints = JandexHelper.getValueAsArray(annotation, "hints"); + String cacheRegion = getString(jandex, hints, QueryHints.CACHE_REGION); + if (StringHelper.isEmpty(cacheRegion)) cacheRegion = null; + Integer timeout = getTimeout(jandex, hints, query); + if (timeout != null && timeout < 0) timeout = null; + Integer fetchSize = getInteger(jandex, hints, QueryHints.FETCH_SIZE, name); + if (fetchSize != null && fetchSize < 0) fetchSize = null; + String comment = getString(jandex, hints, QueryHints.COMMENT); + if (StringHelper.isEmpty(comment)) comment = null; + metadata.addNamedQuery(name, + new NamedQueryDefinition(query, getBoolean(jandex, hints, QueryHints.CACHEABLE, name), cacheRegion, + timeout, fetchSize, + getFlushMode(jandex, hints, QueryHints.FLUSH_MODE, name), + getCacheMode(jandex, hints, QueryHints.CACHE_MODE, name), + getBoolean(jandex, hints, QueryHints.READ_ONLY, name), comment, null)); + LOG.debugf("Binding named query: %s => %s", name, query); + } + + private static void bindNamedNativeQuery( MetadataImpl metadata, + Index jandex, + AnnotationInstance annotation ) { + String name = JandexHelper.getValueAsString(jandex, annotation, "name"); + if (StringHelper.isEmpty(name)) throw new AnnotationException( + "A named native query must have a name when used in class or package level"); + String query = JandexHelper.getValueAsString(jandex, annotation, "query"); + String resultSetMapping = JandexHelper.getValueAsString(jandex, annotation, "resultSetMapping"); + AnnotationInstance[] hints = JandexHelper.getValueAsArray(annotation, "hints"); + boolean cacheable = getBoolean(jandex, hints, "org.hibernate.cacheable", name); + String cacheRegion = getString(jandex, hints, QueryHints.CACHE_REGION); + if (StringHelper.isEmpty(cacheRegion)) cacheRegion = null; + Integer timeout = getTimeout(jandex, hints, query); + if (timeout != null && timeout < 0) timeout = null; + Integer fetchSize = getInteger(jandex, hints, QueryHints.FETCH_SIZE, name); + if (fetchSize != null && fetchSize < 0) fetchSize = null; + FlushMode flushMode = getFlushMode(jandex, hints, QueryHints.FLUSH_MODE, name); + CacheMode cacheMode = getCacheMode(jandex, hints, QueryHints.CACHE_MODE, name); + boolean readOnly = getBoolean(jandex, hints, QueryHints.READ_ONLY, name); + String comment = getString(jandex, hints, QueryHints.COMMENT); + if (StringHelper.isEmpty(comment)) comment = null; + boolean callable = getBoolean(jandex, hints, QueryHints.CALLABLE, name); + NamedSQLQueryDefinition def; + if (StringHelper.isNotEmpty(resultSetMapping)) def = new NamedSQLQueryDefinition(query, resultSetMapping, null, cacheable, + cacheRegion, timeout, fetchSize, + flushMode, cacheMode, readOnly, comment, + null, callable); + else { + String resultClass = JandexHelper.getValueAsString(jandex, annotation, "resultClass"); + if (void.class.equals(resultClass)) throw new NotYetImplementedException( + "Pure native scalar queries are not yet supported"); + def = new NamedSQLQueryDefinition(query, new NativeSQLQueryRootReturn[] {new NativeSQLQueryRootReturn("alias1", + resultClass, + new HashMap(), + LockMode.READ)}, + null, cacheable, cacheRegion, timeout, fetchSize, flushMode, cacheMode, readOnly, + comment, null, callable); + + } + metadata.addNamedNativeQuery(name, def); + LOG.debugf("Binding named native query: %s => %s", name, query); + } + + private static boolean getBoolean( Index jandex, + AnnotationInstance[] hints, + String element, + String query ) { + String val = getString(jandex, hints, element); + if (val == null || val.equalsIgnoreCase("false")) return false; + if (val.equalsIgnoreCase("true")) return true; + throw new AnnotationException("Not a boolean in hint: " + query + ":" + element); + } + + private static CacheMode getCacheMode( Index jandex, + AnnotationInstance[] hints, + String element, + String query ) { + String val = getString(jandex, hints, element); + if (val == null) return null; + if (val.equalsIgnoreCase(CacheMode.GET.toString())) return CacheMode.GET; + if (val.equalsIgnoreCase(CacheMode.IGNORE.toString())) return CacheMode.IGNORE; + 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( Index jandex, + AnnotationInstance[] hints, + String element, + String query ) { + String val = getString(jandex, hints, element); + if (val == null) return null; + if (val.equalsIgnoreCase(FlushMode.ALWAYS.toString())) return FlushMode.ALWAYS; + 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 throw new AnnotationException("Unknown FlushMode in hint: " + query + ":" + element); + + } + + private static Integer getInteger( Index jandex, + AnnotationInstance[] hints, + String element, + String query ) { + String val = getString(jandex, hints, element); + if (val == null) return null; + try { + return Integer.decode(val); + } catch (NumberFormatException nfe) { + throw new AnnotationException("Not an integer in hint: " + query + ":" + element, nfe); + } + } + + private static String getString( Index jandex, + AnnotationInstance[] hints, + String element ) { + for (AnnotationInstance hint : hints) { + if (element.equals(JandexHelper.getValue(jandex, hint, "name"))) return JandexHelper.getValueAsString(jandex, + hint, + "value"); + } + return null; + } + + private static Integer getTimeout( Index jandex, + AnnotationInstance[] hints, + String query ) { + Integer timeout = getInteger(jandex, hints, QueryHints.TIMEOUT_JPA, query); + if (timeout == null) return getInteger(jandex, hints, QueryHints.TIMEOUT_HIBERNATE, query); // timeout is already in seconds + return new Integer((int)Math.round(timeout.doubleValue() / 1000.0)); // convert milliseconds to seconds + } + + private QueryBinder() { + } } - - diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/global/TableBinder.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/global/TableBinder.java index ed0eb386d6..d009eee9a0 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/global/TableBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/global/TableBinder.java @@ -23,21 +23,19 @@ */ package org.hibernate.metamodel.source.annotations.global; -import java.util.Arrays; -import java.util.List; - import org.jboss.jandex.AnnotationInstance; import org.jboss.jandex.Index; import org.jboss.logging.Logger; - import org.hibernate.AnnotationException; import org.hibernate.internal.CoreMessageLogger; +import org.hibernate.internal.util.StringHelper; import org.hibernate.metamodel.relational.Column; import org.hibernate.metamodel.relational.ObjectName; import org.hibernate.metamodel.relational.Schema; import org.hibernate.metamodel.relational.SimpleValue; import org.hibernate.metamodel.relational.Table; import org.hibernate.metamodel.source.annotations.HibernateDotNames; +import org.hibernate.metamodel.source.annotations.util.JandexHelper; import org.hibernate.metamodel.source.internal.MetadataImpl; /** @@ -46,93 +44,77 @@ import org.hibernate.metamodel.source.internal.MetadataImpl; * @author Hardy Ferentschik */ public class TableBinder { - private static final CoreMessageLogger LOG = Logger.getMessageLogger( - CoreMessageLogger.class, TableBinder.class.getName() - ); - private TableBinder() { - } + private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, TableBinder.class.getName()); - /** - * Binds {@link org.hibernate.annotations.Tables} and {@link org.hibernate.annotations.Table} - * annotations to the specified meta data instance. - * - * @param meta the global metadata - * @param index the annotation index repository - */ - public static void bind(MetadataImpl meta, Index index) { - // check @o.h.a.Tables - List tablesAnnotations = index.getAnnotations( HibernateDotNames.TABLES ); - for ( AnnotationInstance tableAnnotation : tablesAnnotations ) { - AnnotationInstance tables[] = tableAnnotation.value().asNestedArray(); - bindTablesAnnotation( meta, Arrays.asList( tables ) ); - } + /** + * Binds {@link org.hibernate.annotations.Tables} and {@link org.hibernate.annotations.Table} annotations to the supplied + * metadata. + * + * @param metadata the global metadata + * @param jandex the annotation index repository + */ + public static void bind( MetadataImpl metadata, + Index jandex ) { + for (AnnotationInstance tableAnnotation : jandex.getAnnotations(HibernateDotNames.TABLE)) { + bind(metadata, jandex, tableAnnotation); + } + for (AnnotationInstance tables : jandex.getAnnotations(HibernateDotNames.TABLES)) { + for (AnnotationInstance table : JandexHelper.getValueAsArray(tables, "value")) { + bind(metadata, jandex, table); + } + } + } - // check @o.h.a.Table - List tableAnnotations = index.getAnnotations( HibernateDotNames.TABLE ); - bindTablesAnnotation( meta, tableAnnotations ); - } + private static void bind( MetadataImpl metadata, + Index jandex, + AnnotationInstance tableAnnotation ) { + String tableName = JandexHelper.getValueAsString(jandex, tableAnnotation, "appliesTo"); + ObjectName objectName = new ObjectName(tableName); + Schema schema = metadata.getDatabase().getSchema(objectName.getSchema(), objectName.getCatalog()); + Table table = schema.getTable(objectName.getName()); + if (table != null) bindHibernateTableAnnotation(jandex, table, tableAnnotation); + } - private static void bindTablesAnnotation(MetadataImpl meta, List tableAnnotations) { - for ( AnnotationInstance tableAnnotation : tableAnnotations ) { - String tableName = tableAnnotation.value( "appliesTo" ).asString(); - ObjectName objectName = new ObjectName( tableName ); - Schema schema = meta.getDatabase().getSchema( objectName.getSchema(), objectName.getCatalog() ); - Table table = schema.getTable( objectName.getName() ); - if ( table == null ) { - continue; - } - bindHibernateTableAnnotation( table, tableAnnotation ); - } - } + private static void bindHibernateTableAnnotation( Index jandex, + Table table, + AnnotationInstance tableAnnotation ) { + for (AnnotationInstance indexAnnotation : JandexHelper.getValueAsArray(tableAnnotation, "indexes")) { + bindIndexAnnotation(jandex, table, indexAnnotation); + } + String comment = JandexHelper.getValueAsString(jandex, tableAnnotation, "comment"); + if (StringHelper.isNotEmpty(comment)) table.addComment(comment.trim()); + } - private static void bindHibernateTableAnnotation(Table table, AnnotationInstance tableAnnotation) { - if ( tableAnnotation.value( "indexes" ) != null ) { - AnnotationInstance[] indexAnnotations = tableAnnotation.value( "indexes" ).asNestedArray(); - for ( AnnotationInstance indexAnnotation : indexAnnotations ) { - bindIndexAnnotation( table, indexAnnotation ); - } - } + private static void bindIndexAnnotation( Index jandex, + Table table, + AnnotationInstance indexAnnotation ) { + String indexName = JandexHelper.getValueAsString(jandex, indexAnnotation, "appliesTo"); + String[] columnNames = (String[])JandexHelper.getValue(jandex, indexAnnotation, "columnNames"); + if (columnNames == null) { + LOG.noColumnsSpecifiedForIndex(indexName, table.toLoggableString()); + return; + } + org.hibernate.metamodel.relational.Index index = table.getOrCreateIndex(indexName); + for (String columnName : columnNames) { + Column column = findColumn(table, columnName); + if (column == null) throw new AnnotationException("@Index references a unknown column: " + columnName); + index.addColumn(column); + } + } - if ( tableAnnotation.value( "comment" ) != null ) { - table.addComment( tableAnnotation.value( "comment" ).asString().trim() ); - } + private static Column findColumn( Table table, + String columnName ) { + Column column = null; + for (SimpleValue value : table.values()) { + if (value instanceof Column && ((Column)value).getName().equals(columnName)) { + column = (Column)value; + break; + } + } + return column; + } - - - } - - private static void bindIndexAnnotation(Table table, AnnotationInstance indexAnnotation) { - String indexName = indexAnnotation.value( "name" ).asString(); - if ( indexAnnotation.value( "columnNames" ) == null ) { - LOG.noColumnsSpecifiedForIndex( indexName, table.toLoggableString() ); - return; - } - - org.hibernate.metamodel.relational.Index index = table.getOrCreateIndex( indexName ); - - String[] columnNames = indexAnnotation.value( "columnNames" ).asStringArray(); - for ( String columnName : columnNames ) { - Column column = findColumn( table, columnName ); - if ( column == null ) { - throw new AnnotationException( - "@Index references a unknown column: " + columnName - ); - } - index.addColumn( column ); - } - } - - private static Column findColumn(Table table, String columnName) { - Column column = null; - for ( SimpleValue value : table.values() ) { - if ( value instanceof Column && ( (Column) value ).getName().equals( columnName ) ) { - column = (Column) value; - break; - } - } - return column; - } + private TableBinder() { + } } - - diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/global/TypeDefBinder.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/global/TypeDefBinder.java new file mode 100644 index 0000000000..f53fe497e4 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/global/TypeDefBinder.java @@ -0,0 +1,94 @@ +/* + * 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.source.annotations.global; + +import java.util.HashMap; +import java.util.Map; +import org.hibernate.AnnotationException; +import org.hibernate.annotations.TypeDefs; +import org.hibernate.internal.CoreMessageLogger; +import org.hibernate.internal.util.StringHelper; +import org.hibernate.metamodel.binding.TypeDef; +import org.hibernate.metamodel.source.annotations.HibernateDotNames; +import org.hibernate.metamodel.source.annotations.util.JandexHelper; +import org.hibernate.metamodel.source.internal.MetadataImpl; +import org.jboss.jandex.AnnotationInstance; +import org.jboss.jandex.Index; +import org.jboss.logging.Logger; + +/** + * + */ +public class TypeDefBinder { + + private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, TypeDefBinder.class.getName()); + + /** + * Binds all {@link org.hibernate.annotations.TypeDef} and {@link TypeDefs} annotations to the supplied metadata. + * + * @param metadata the global metadata + * @param jandex the jandex jandex + */ + public static void bind( MetadataImpl metadata, + Index jandex ) { + for (AnnotationInstance typeDef : jandex.getAnnotations(HibernateDotNames.TYPE_DEF)) { + bind(metadata, jandex, typeDef); + } + for (AnnotationInstance typeDefs : jandex.getAnnotations(HibernateDotNames.TYPE_DEFS)) { + for (AnnotationInstance typeDef : JandexHelper.getValueAsArray(typeDefs, "value")) { + bind(metadata, jandex, typeDef); + } + } + } + + private static void bind( String name, + String typeClass, + Map prms, + MetadataImpl metadata ) { + LOG.debugf("Binding type definition: %s", name); + metadata.addTypeDef(name, new TypeDef(typeClass, prms)); + } + + private static void bind( MetadataImpl metadata, + Index jandex, + AnnotationInstance typeDef ) { + String name = JandexHelper.getValueAsString(jandex, typeDef, "name"); + String defaultForType = JandexHelper.getValueAsString(jandex, typeDef, "defaultForType"); + String typeClass = JandexHelper.getValueAsString(jandex, typeDef, "typeClass"); + boolean noName = StringHelper.isEmpty(name); + boolean noDefaultForType = defaultForType == null || defaultForType.equals(void.class.getName()); + if (noName && noDefaultForType) throw new AnnotationException( + "Either name or defaultForType (or both) attribute should be set in TypeDef having typeClass " + + typeClass); + Map prms = new HashMap(); + for (AnnotationInstance prm : JandexHelper.getValueAsArray(typeDef, "parameters")) { + prms.put(JandexHelper.getValueAsString(jandex, prm, "name"), JandexHelper.getValueAsString(jandex, prm, "value")); + } + if (!noName) bind(name, typeClass, prms, metadata); + if (!noDefaultForType) bind(defaultForType, typeClass, prms, metadata); + } + + private TypeDefBinder() { + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/util/JandexHelper.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/util/JandexHelper.java index 0b1d9e6e54..452f3c65f8 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/util/JandexHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/annotations/util/JandexHelper.java @@ -33,6 +33,7 @@ import java.util.Map; import org.jboss.jandex.AnnotationInstance; import org.jboss.jandex.AnnotationTarget; +import org.jboss.jandex.AnnotationValue; import org.jboss.jandex.ClassInfo; import org.jboss.jandex.DotName; import org.jboss.jandex.FieldInfo; @@ -40,6 +41,7 @@ import org.jboss.jandex.Index; import org.jboss.jandex.Indexer; import org.jboss.jandex.MethodInfo; +import org.hibernate.AnnotationException; import org.hibernate.AssertionFailure; import org.hibernate.HibernateException; import org.hibernate.service.classloading.spi.ClassLoaderService; @@ -50,172 +52,285 @@ import org.hibernate.service.classloading.spi.ClassLoaderService; * @author Hardy Ferentschik */ public class JandexHelper { - private JandexHelper() { - } - /** - * Expects a method or field annotation target and returns the property name for this target - * - * @param target the annotation target - * - * @return the property name of the target. For a field it is the field name and for a method name it is - * the method name stripped of 'is', 'has' or 'get' - */ - public static String getPropertyName(AnnotationTarget target) { - if ( !( target instanceof MethodInfo || target instanceof FieldInfo ) ) { - throw new AssertionFailure( "Unexpected annotation target " + target.toString() ); - } + private static final AnnotationInstance[] EMPTY_ANNOTATIONS_ARRAY = new AnnotationInstance[0]; - if ( target instanceof FieldInfo ) { - return ( (FieldInfo) target ).name(); - } - else { - String methodName = ( (MethodInfo) target ).name(); - if ( methodName.startsWith( "is" ) ) { - methodName = Introspector.decapitalize( methodName.substring( 2 ) ); - } - else if ( methodName.startsWith( "has" ) ) { - methodName = Introspector.decapitalize( methodName.substring( 3 ) ); - } - else if ( methodName.startsWith( "get" ) ) { - methodName = Introspector.decapitalize( methodName.substring( 3 ) ); - } - else { - throw new AssertionFailure( "Expected a method following the Java Bean notation" ); - } - return methodName; - } - } + private static final Map DEFAULT_VALUES_BY_ELEMENT = new HashMap(); - /** - * @param classInfo the class info from which to retrieve the annotation instance - * @param annotationName the annotation to retrieve from the class info - * - * @return the single annotation defined on the class or {@code null} in case the annotation is not specified at all - * - * @throws org.hibernate.AssertionFailure in case there is there is more than one annotation of this type. - */ - public static AnnotationInstance getSingleAnnotation(ClassInfo classInfo, DotName annotationName) - throws AssertionFailure { - return getSingleAnnotation( classInfo.annotations(), annotationName ); - } + private static Object getDefaultValue( Index index, + AnnotationInstance annotation, + String element ) { + String name = annotation.name().toString(); + String fqElement = name + '.' + element; + Object val = DEFAULT_VALUES_BY_ELEMENT.get(fqElement); + if (val != null) return val; + try { + val = Index.class.getClassLoader().loadClass(name).getMethod(element).getDefaultValue(); + DEFAULT_VALUES_BY_ELEMENT.put(fqElement, val); + return val == null ? null : val; + } catch (RuntimeException error) { + throw error; + } catch (Exception error) { + throw new AnnotationException(error); + } + } - /** - * @param annotations List of annotation instances keyed against their dot name. - * @param annotationName the annotation to retrieve from map - * - * @return the single annotation of the specified dot name or {@code null} in case the annotation is not specified at all - * - * @throws org.hibernate.AssertionFailure in case there is there is more than one annotation of this type. - */ - public static AnnotationInstance getSingleAnnotation(Map> annotations, DotName annotationName) - throws AssertionFailure { - List annotationList = annotations.get( annotationName ); - if ( annotationList == null ) { - return null; - } - else if ( annotationList.size() == 1 ) { - return annotationList.get( 0 ); - } - else { - throw new AssertionFailure( - "Found more than one instance of the annotation " - + annotationList.get( 0 ).name().toString() - + ". Expected was one." - ); - } - } + /** + * Expects a method or field annotation target and returns the property name for this target + * + * @param target the annotation target + * + * @return the property name of the target. For a field it is the field name and for a method name it is + * the method name stripped of 'is', 'has' or 'get' + */ + public static String getPropertyName(AnnotationTarget target) { + if ( !( target instanceof MethodInfo || target instanceof FieldInfo ) ) { + throw new AssertionFailure( "Unexpected annotation target " + target.toString() ); + } - /** - * Creates a jandex index for the specified classes - * - * @param classLoaderService class loader service - * @param classes the classes to index - * - * @return an annotation repository w/ all the annotation discovered in the specified classes - */ - public static Index indexForClass(ClassLoaderService classLoaderService, Class... classes) { - Indexer indexer = new Indexer(); - for ( Class clazz : classes ) { - InputStream stream = classLoaderService.locateResourceStream( - clazz.getName().replace( '.', '/' ) + ".class" - ); - try { - indexer.index( stream ); - } - catch ( IOException e ) { - StringBuilder builder = new StringBuilder(); - builder.append( "[" ); - int count = 0; - for ( Class c : classes ) { - builder.append( c.getName() ); - if ( count < classes.length - 1 ) { - builder.append( "," ); - } - count++; - } - builder.append( "]" ); - throw new HibernateException( "Unable to create annotation index for " + builder.toString() ); - } - } - return indexer.complete(); - } + if ( target instanceof FieldInfo ) { + return ( (FieldInfo) target ).name(); + } + else { + String methodName = ( (MethodInfo) target ).name(); + if ( methodName.startsWith( "is" ) ) { + methodName = Introspector.decapitalize( methodName.substring( 2 ) ); + } + else if ( methodName.startsWith( "has" ) ) { + methodName = Introspector.decapitalize( methodName.substring( 3 ) ); + } + else if ( methodName.startsWith( "get" ) ) { + methodName = Introspector.decapitalize( methodName.substring( 3 ) ); + } + else { + throw new AssertionFailure( "Expected a method following the Java Bean notation" ); + } + return methodName; + } + } - public static Map> getMemberAnnotations(ClassInfo classInfo, String name) { - if ( classInfo == null ) { - throw new IllegalArgumentException( "classInfo cannot be null" ); - } + /** + * @param classInfo the class info from which to retrieve the annotation instance + * @param annotationName the annotation to retrieve from the class info + * + * @return the single annotation defined on the class or {@code null} in case the annotation is not specified at all + * + * @throws org.hibernate.AssertionFailure in case there is there is more than one annotation of this type. + */ + public static AnnotationInstance getSingleAnnotation(ClassInfo classInfo, DotName annotationName) + throws AssertionFailure { + return getSingleAnnotation( classInfo.annotations(), annotationName ); + } - if ( name == null ) { - throw new IllegalArgumentException( "name cannot be null" ); - } + /** + * @param annotations List of annotation instances keyed against their dot name. + * @param annotationName the annotation to retrieve from map + * + * @return the single annotation of the specified dot name or {@code null} in case the annotation is not specified at all + * + * @throws org.hibernate.AssertionFailure in case there is there is more than one annotation of this type. + */ + public static AnnotationInstance getSingleAnnotation(Map> annotations, DotName annotationName) + throws AssertionFailure { + List annotationList = annotations.get( annotationName ); + if ( annotationList == null ) { + return null; + } + else if ( annotationList.size() == 1 ) { + return annotationList.get( 0 ); + } + else { + throw new AssertionFailure( + "Found more than one instance of the annotation " + + annotationList.get( 0 ).name().toString() + + ". Expected was one." + ); + } + } - Map> annotations = new HashMap>(); - for ( List annotationList : classInfo.annotations().values() ) { - for ( AnnotationInstance instance : annotationList ) { - String targetName = null; - if ( instance.target() instanceof FieldInfo ) { - targetName = ( (FieldInfo) instance.target() ).name(); - } - else if ( instance.target() instanceof MethodInfo ) { - targetName = ( (MethodInfo) instance.target() ).name(); - } - if ( targetName != null && name.equals( targetName ) ) { - addAnnotationToMap( instance, annotations ); - } - } - } - return annotations; - } + /** + * Retrieves a jandex annotation element value. If the value is null, the default value specified in the + * annotation class is retrieved instead. Note, {@link #getValueAsEnum(Index, AnnotationInstance, String, Class)} must be + * called to retrieve an enumerated value, and {@link #getValueAsArray(AnnotationInstance, String)} must be called to retrieve + * an object array (other than a String array). + * + * @param index the jandex index containing the supplied annotation + * @param annotation the annotation containing the element with the supplied name + * @param element the name of the element value to be retrieve + * @return the value if not null, else the default value if not + * null, else null. + */ + public static Object getValue( Index index, + AnnotationInstance annotation, + String element ) { + AnnotationValue val = annotation.value(element); + if (val == null) return getDefaultValue(index, annotation, element); + return val.asNested(); + } - public static Map> getTypeAnnotations(ClassInfo classInfo) { - if ( classInfo == null ) { - throw new IllegalArgumentException( "classInfo cannot be null" ); - } + /** + * Retrieves a jandex annotation element array. Note, {@link #getValue(Index, AnnotationInstance, String)} may be + * called to retrieve a String array (or a non-array value). + * + * @param annotation the jandex annotation containing the element with the supplied name + * @param element the name of the element array + * @return the element array if not null, else an empty array + */ + public static AnnotationInstance[] getValueAsArray( AnnotationInstance annotation, + String element ) { + AnnotationValue val = annotation.value(element); + return val == null ? EMPTY_ANNOTATIONS_ARRAY : val.asNestedArray(); + } - Map> annotations = new HashMap>(); - for ( List annotationList : classInfo.annotations().values() ) { - for ( AnnotationInstance instance : annotationList ) { - if ( instance.target() instanceof ClassInfo ) { - addAnnotationToMap( instance, annotations ); - } - } - } - return annotations; - } + /** + * Retrieves a jandex annotation element value, converting it to the supplied enumerated type. If the value is + * null, the default value specified in the annotation class is retrieved instead. + * + * @param an enumerated type + * @param index the jandex index containing the supplied annotation + * @param annotation the annotation containing the enumerated element with the supplied name + * @param element the name of the enumerated element value to be retrieve + * @param type the type to which to convert the value before being returned + * @return the value converted to the supplied enumerated type if the value is not null, else the default value if + * not null, else null. + * @see #getValue(Index, AnnotationInstance, String) + */ + public static > T getValueAsEnum( Index index, + AnnotationInstance annotation, + String element, + Class type ) { + AnnotationValue val = annotation.value(element); + if (val == null) return (T)getDefaultValue(index, annotation, element); + return Enum.valueOf(type, val.asEnum()); + } - private static void addAnnotationToMap(AnnotationInstance instance, Map> annotations) { - DotName dotName = instance.name(); - List list; - if ( annotations.containsKey( dotName ) ) { - list = annotations.get( dotName ); - } - else { - list = new ArrayList(); - annotations.put( dotName, list ); - } - list.add( instance ); - } + /** + * Retrieves a jandex annotation element value as an Integer. If the value is null, the default value specified in + * the annotation class is retrieved instead. + * + * @param index the jandex index containing the supplied annotation + * @param annotation the annotation containing the element with the supplied name + * @param element the name of the element value to be retrieve + * @return the value converted to an int if the value is not null, else the default value if not + * null, else 0. + */ + public static int getValueAsInt( Index index, + AnnotationInstance annotation, + String element ) { + AnnotationValue val = annotation.value(element); + if (val == null) return (Integer)getDefaultValue(index, annotation, element); + return val.asInt(); + } + + /** + * Retrieves a jandex annotation element value as a String. If the value is null, the default value specified in + * the annotation class is retrieved instead. + * + * @param index the jandex index containing the supplied annotation + * @param annotation the annotation containing the element with the supplied name + * @param element the name of the element value to be retrieve + * @return the value converted to a String if the value is not null, else the default value if not + * null, else null. + */ + public static String getValueAsString( Index index, + AnnotationInstance annotation, + String element ) { + AnnotationValue val = annotation.value(element); + if (val == null) return (String)getDefaultValue(index, annotation, element); + return val.asString(); + } + + /** + * Creates a jandex index for the specified classes + * + * @param classLoaderService class loader service + * @param classes the classes to index + * + * @return an annotation repository w/ all the annotation discovered in the specified classes + */ + public static Index indexForClass(ClassLoaderService classLoaderService, Class... classes) { + Indexer indexer = new Indexer(); + for ( Class clazz : classes ) { + InputStream stream = classLoaderService.locateResourceStream( + clazz.getName().replace( '.', '/' ) + ".class" + ); + try { + indexer.index( stream ); + } + catch ( IOException e ) { + StringBuilder builder = new StringBuilder(); + builder.append( "[" ); + int count = 0; + for ( Class c : classes ) { + builder.append( c.getName() ); + if ( count < classes.length - 1 ) { + builder.append( "," ); + } + count++; + } + builder.append( "]" ); + throw new HibernateException( "Unable to create annotation index for " + builder.toString() ); + } + } + return indexer.complete(); + } + + public static Map> getMemberAnnotations(ClassInfo classInfo, String name) { + if ( classInfo == null ) { + throw new IllegalArgumentException( "classInfo cannot be null" ); + } + + if ( name == null ) { + throw new IllegalArgumentException( "name cannot be null" ); + } + + Map> annotations = new HashMap>(); + for ( List annotationList : classInfo.annotations().values() ) { + for ( AnnotationInstance instance : annotationList ) { + String targetName = null; + if ( instance.target() instanceof FieldInfo ) { + targetName = ( (FieldInfo) instance.target() ).name(); + } + else if ( instance.target() instanceof MethodInfo ) { + targetName = ( (MethodInfo) instance.target() ).name(); + } + if ( targetName != null && name.equals( targetName ) ) { + addAnnotationToMap( instance, annotations ); + } + } + } + return annotations; + } + + public static Map> getTypeAnnotations(ClassInfo classInfo) { + if ( classInfo == null ) { + throw new IllegalArgumentException( "classInfo cannot be null" ); + } + + Map> annotations = new HashMap>(); + for ( List annotationList : classInfo.annotations().values() ) { + for ( AnnotationInstance instance : annotationList ) { + if ( instance.target() instanceof ClassInfo ) { + addAnnotationToMap( instance, annotations ); + } + } + } + return annotations; + } + + private static void addAnnotationToMap(AnnotationInstance instance, Map> annotations) { + DotName dotName = instance.name(); + List list; + if ( annotations.containsKey( dotName ) ) { + list = annotations.get( dotName ); + } + else { + list = new ArrayList(); + annotations.put( dotName, list ); + } + list.add( instance ); + } + + private JandexHelper() { + } } - - diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/HibernateMappingBinder.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/HibernateMappingBinder.java index 9a9b43dbac..419cbf39f5 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/HibernateMappingBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/hbm/HibernateMappingBinder.java @@ -23,18 +23,19 @@ */ package org.hibernate.metamodel.source.hbm; +import java.util.HashSet; import java.util.List; import java.util.Map; - +import java.util.Set; import org.dom4j.Attribute; - import org.hibernate.MappingException; import org.hibernate.cfg.NamingStrategy; import org.hibernate.internal.util.StringHelper; -import org.hibernate.mapping.MetadataSource; +import org.hibernate.metamodel.binding.FetchProfile; +import org.hibernate.metamodel.binding.FetchProfile.Fetch; import org.hibernate.metamodel.domain.MetaAttribute; import org.hibernate.metamodel.source.Origin; -import org.hibernate.metamodel.source.internal.JaxbRoot; +import org.hibernate.metamodel.source.hbm.util.MappingHelper; import org.hibernate.metamodel.source.hbm.xml.mapping.XMLFetchProfileElement; import org.hibernate.metamodel.source.hbm.xml.mapping.XMLFetchProfileElement.XMLFetch; import org.hibernate.metamodel.source.hbm.xml.mapping.XMLHibernateMapping; @@ -45,7 +46,7 @@ import org.hibernate.metamodel.source.hbm.xml.mapping.XMLQueryElement; import org.hibernate.metamodel.source.hbm.xml.mapping.XMLSqlQueryElement; import org.hibernate.metamodel.source.hbm.xml.mapping.XMLSubclassElement; import org.hibernate.metamodel.source.hbm.xml.mapping.XMLUnionSubclassElement; -import org.hibernate.metamodel.source.hbm.util.MappingHelper; +import org.hibernate.metamodel.source.internal.JaxbRoot; import org.hibernate.service.ServiceRegistry; /** @@ -225,14 +226,15 @@ public class HibernateMappingBinder implements MappingDefaults { protected void parseFetchProfiles(List fetchProfiles, String containingEntityName) { for ( XMLFetchProfileElement fetchProfile : fetchProfiles ) { String profileName = fetchProfile.getName(); - org.hibernate.metamodel.binding.FetchProfile profile = hibernateXmlBinder.getMetadata().findOrCreateFetchProfile( profileName, MetadataSource.HBM ); + Set fetches = new HashSet(); for ( XMLFetch fetch : fetchProfile.getFetch() ) { String entityName = fetch.getEntity() == null ? containingEntityName : fetch.getEntity(); if ( entityName == null ) { throw new MappingException( "could not determine entity for fetch-profile fetch [" + profileName + "]:[" + fetch.getAssociation() + "]" ); } - profile.addFetch( entityName, fetch.getAssociation(), fetch.getStyle() ); + fetches.add(new Fetch(entityName, fetch.getAssociation(), fetch.getStyle())); } + hibernateXmlBinder.getMetadata().addFetchProfile( new FetchProfile(profileName, fetches)); } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/MetadataImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/MetadataImpl.java index 54b2b39597..1089c00de8 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/MetadataImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/internal/MetadataImpl.java @@ -30,21 +30,21 @@ import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; - import org.jboss.jandex.Index; import org.jboss.jandex.Indexer; import org.jboss.logging.Logger; - import org.hibernate.DuplicateMappingException; import org.hibernate.HibernateException; import org.hibernate.SessionFactory; +import org.hibernate.engine.spi.FilterDefinition; +import org.hibernate.engine.spi.NamedQueryDefinition; +import org.hibernate.engine.spi.NamedSQLQueryDefinition; import org.hibernate.internal.CoreMessageLogger; -import org.hibernate.mapping.MetadataSource; -import org.hibernate.metamodel.Metadata; import org.hibernate.metamodel.MetadataSources; import org.hibernate.metamodel.SourceProcessingOrder; import org.hibernate.metamodel.binding.EntityBinding; import org.hibernate.metamodel.binding.FetchProfile; +import org.hibernate.metamodel.binding.IdGenerator; import org.hibernate.metamodel.binding.PluralAttributeBinding; import org.hibernate.metamodel.binding.TypeDef; import org.hibernate.metamodel.relational.Database; @@ -56,6 +56,7 @@ import org.hibernate.metamodel.source.hbm.xml.mapping.XMLHibernateMapping; import org.hibernate.metamodel.source.spi.MetadataImplementor; import org.hibernate.service.BasicServiceRegistry; import org.hibernate.service.classloading.spi.ClassLoaderService; +import org.hibernate.type.TypeResolver; /** * Container for configuration data collected during binding the metamodel. @@ -63,15 +64,15 @@ import org.hibernate.service.classloading.spi.ClassLoaderService; * @author Steve Ebersole * @author Hardy Ferentschik */ -public class MetadataImpl implements Metadata, MetadataImplementor, Serializable { - private static final CoreMessageLogger LOG = Logger.getMessageLogger( - CoreMessageLogger.class, MetadataImpl.class.getName() - ); +public class MetadataImpl implements MetadataImplementor, Serializable { + + private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, MetadataImpl.class.getName()); private final BasicServiceRegistry serviceRegistry; private final Options options; private final Database database = new Database(); + private TypeResolver typeResolver = new TypeResolver(); /** * Maps the fully qualified class name of an entity to its entity binding @@ -79,8 +80,12 @@ public class MetadataImpl implements Metadata, MetadataImplementor, Serializable private Map entityBindingMap = new HashMap(); private Map collectionBindingMap = new HashMap(); private Map fetchProfiles = new HashMap(); - private Map typeDefs = new HashMap(); private Map imports; + private Map typeDefs = new HashMap(); + private Map idGenerators = new HashMap(); + private Map namedQueryDefs = new HashMap(); + private Map namedNativeQueryDefs = new HashMap(); + private Map filterDefs = new HashMap(); public MetadataImpl(MetadataSources metadataSources, Options options) { this.serviceRegistry = metadataSources.getServiceRegistry(); @@ -99,6 +104,33 @@ public class MetadataImpl implements Metadata, MetadataImplementor, Serializable new EntityReferenceResolver( this ).resolve(); } + public void addFetchProfile( FetchProfile profile ) { + fetchProfiles.put(profile.getName(), profile); + } + + public void addFilterDef( FilterDefinition def ) { + filterDefs.put(def.getFilterName(), def); + } + + public void addIdGenerator( IdGenerator generator ) { + idGenerators.put(generator.getName(), generator); + } + + public void addNamedNativeQuery( String name, + NamedSQLQueryDefinition def ) { + namedNativeQueryDefs.put(name, def); + } + + public void addNamedQuery( String name, + NamedQueryDefinition def ) { + namedQueryDefs.put(name, def); + } + + public void addTypeDef(String name, TypeDef typeDef) { + // TODO - should we check whether the typedef already exists? Log it? Exception? (HF) + typeDefs.put( name, typeDef ); + } + private void applyHibernateMappings(MetadataSources metadataSources, List processedEntityNames) { final HibernateXmlBinder hibernateXmlBinder = new HibernateXmlBinder( this ); for ( JaxbRoot jaxbRoot : metadataSources.getJaxbRootList() ) { @@ -223,25 +255,15 @@ public class MetadataImpl implements Metadata, MetadataImplementor, Serializable } } - public Iterable getFetchProfiles() { - return fetchProfiles.values(); - } - - public void addTypeDef(String name, TypeDef typeDef) { - // TODO - should we check whether the typedef already exists? Log it? Exception? (HF) - typeDefs.put( name, typeDef ); - } - public TypeDef getTypeDef(String name) { return typeDefs.get( name ); } - public FetchProfile findOrCreateFetchProfile(String profileName, MetadataSource source) { - FetchProfile profile = fetchProfiles.get( profileName ); - if ( profile == null ) { - profile = new FetchProfile( profileName, source ); - fetchProfiles.put( profileName, profile ); - } - return profile; - } + public Iterable getFetchProfiles() { + return fetchProfiles.values(); + } + + public TypeResolver typeResolver() { + return typeResolver; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/source/spi/MetadataImplementor.java b/hibernate-core/src/main/java/org/hibernate/metamodel/source/spi/MetadataImplementor.java index 291f4bf888..2b254004fb 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/source/spi/MetadataImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/source/spi/MetadataImplementor.java @@ -23,7 +23,6 @@ */ package org.hibernate.metamodel.source.spi; -import org.hibernate.mapping.MetadataSource; import org.hibernate.metamodel.Metadata; import org.hibernate.metamodel.binding.EntityBinding; import org.hibernate.metamodel.binding.FetchProfile; @@ -47,5 +46,5 @@ public interface MetadataImplementor extends Metadata { public void addCollection(PluralAttributeBinding collectionBinding); - public FetchProfile findOrCreateFetchProfile(String profileName, MetadataSource hbm); + public void addFetchProfile( FetchProfile profile ); } diff --git a/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/util/JandexHelperTest.java b/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/util/JandexHelperTest.java index 4aba7db158..90378a102d 100644 --- a/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/util/JandexHelperTest.java +++ b/hibernate-core/src/test/java/org/hibernate/metamodel/source/annotations/util/JandexHelperTest.java @@ -23,10 +23,17 @@ */ package org.hibernate.metamodel.source.annotations.util; +import static org.hamcrest.core.Is.is; + +import static org.junit.Assert.assertThat; + import java.util.List; import java.util.Map; import javax.persistence.Basic; import javax.persistence.Column; +import javax.persistence.LockModeType; +import javax.persistence.NamedQuery; +import javax.persistence.SequenceGenerator; import org.jboss.jandex.AnnotationInstance; import org.jboss.jandex.ClassInfo; @@ -36,6 +43,7 @@ import org.junit.After; import org.junit.Before; import org.junit.Test; +import org.hibernate.metamodel.source.annotations.JPADotNames; import org.hibernate.service.ServiceRegistryBuilder; import org.hibernate.service.classloading.spi.ClassLoaderService; import org.hibernate.service.internal.BasicServiceRegistryImpl; @@ -88,6 +96,49 @@ public class JandexHelperTest extends BaseUnitTestCase { memberAnnotations = JandexHelper.getMemberAnnotations( classInfo, "fubar" ); assertTrue( "there should be no annotations in fubar", memberAnnotations.isEmpty() ); } + + @Test + public void shouldRetrieveDefaultOfUnspecifiedAnnotationElement() { + + @NamedQuery(name="foo", query="bar") + @SequenceGenerator(name="fu") + class Foo { + } + + Index index = JandexHelper.indexForClass(classLoaderService, Foo.class); + for (AnnotationInstance query : index.getAnnotations( JPADotNames.NAMED_QUERY)) { + assertThat(JandexHelper.getValueAsEnum(index, query, "lockMode", LockModeType.class), is(LockModeType.NONE)); + } + for (AnnotationInstance generator : index.getAnnotations( JPADotNames.SEQUENCE_GENERATOR)) { + assertThat(JandexHelper.getValueAsInt(index, generator, "allocationSize"), is(50)); + } + } + + @Test + public void shouldRetrieveValueOfAnnotationElement() { + + @NamedQuery(name="foo", query="bar") + class Foo { + } + + Index index = JandexHelper.indexForClass(classLoaderService, Foo.class); + for (AnnotationInstance query : index.getAnnotations( JPADotNames.NAMED_QUERY)) { + assertThat(JandexHelper.getValueAsString(index, query, "name"), is("foo")); + } + } + + @Test + public void shouldRetrieveValueOfEnumeratedAnnotationElement() { + + @NamedQuery(name="foo", query="bar", lockMode=LockModeType.OPTIMISTIC) + class Foo { + } + + Index index = JandexHelper.indexForClass(classLoaderService, Foo.class); + for (AnnotationInstance query : index.getAnnotations( JPADotNames.NAMED_QUERY)) { + assertThat(JandexHelper.getValueAsEnum(index, query, "lockMode", LockModeType.class), is(LockModeType.OPTIMISTIC)); + } + } }