HHH-14922 Delay applying the implicit catalog/schema until schema management tool or session factory creation

This is necessary if we want the default catalog/schema to take
precedence, since the default catalog/schema is applied late,
on schema management tool or session factory creation.
This commit is contained in:
Yoann Rodière 2021-11-10 09:55:56 +01:00
parent 9b47fcdfa8
commit 795d5cd4e9
15 changed files with 147 additions and 126 deletions

View File

@ -35,7 +35,7 @@ public class Database {
private final ServiceRegistry serviceRegistry;
private final PhysicalNamingStrategy physicalNamingStrategy;
private Namespace implicitNamespace;
private Namespace.Name physicalImplicitNamespaceName;
private List<InitCommand> initCommands;
public Database(MetadataBuildingOptions buildingOptions) {
@ -48,11 +48,16 @@ public class Database {
this.physicalNamingStrategy = buildingOptions.getPhysicalNamingStrategy();
this.dialect = determineDialect( buildingOptions );
this.implicitNamespace = makeNamespace(
new Namespace.Name(
toIdentifier( buildingOptions.getMappingDefaults().getImplicitCatalogName() ),
toIdentifier( buildingOptions.getMappingDefaults().getImplicitSchemaName() )
)
setImplicitNamespaceName(
toIdentifier( buildingOptions.getMappingDefaults().getImplicitCatalogName() ),
toIdentifier( buildingOptions.getMappingDefaults().getImplicitSchemaName() )
);
}
private void setImplicitNamespaceName(Identifier catalogName, Identifier schemaName) {
this.physicalImplicitNamespaceName = new Namespace.Name(
physicalNamingStrategy.toPhysicalCatalogName( catalogName, jdbcEnvironment ),
physicalNamingStrategy.toPhysicalSchemaName( schemaName, jdbcEnvironment )
);
}
@ -108,15 +113,25 @@ public class Database {
return namespaceMap.values();
}
/**
* @return The default namespace, with a {@code null} catalog and schema
* which will have to be interpreted with defaults at runtime.
* @see SqlStringGenerationContext
*/
public Namespace getDefaultNamespace() {
return implicitNamespace;
return locateNamespace( null, null );
}
/**
* @return The implicit name of the default namespace, with a {@code null} catalog and schema
* which will have to be interpreted with defaults at runtime.
* @see SqlStringGenerationContext
*/
public Namespace.Name getPhysicalImplicitNamespaceName() {
return physicalImplicitNamespaceName;
}
public Namespace locateNamespace(Identifier catalogName, Identifier schemaName) {
if ( catalogName == null && schemaName == null ) {
return getDefaultNamespace();
}
final Namespace.Name name = new Namespace.Name( catalogName, schemaName );
Namespace namespace = namespaceMap.get( name );
if ( namespace == null ) {
@ -126,17 +141,8 @@ public class Database {
}
public Namespace adjustDefaultNamespace(Identifier catalogName, Identifier schemaName) {
final Namespace.Name name = new Namespace.Name( catalogName, schemaName );
if ( implicitNamespace.getName().equals( name ) ) {
return implicitNamespace;
}
Namespace namespace = namespaceMap.get( name );
if ( namespace == null ) {
namespace = makeNamespace( name );
}
implicitNamespace = namespace;
return implicitNamespace;
setImplicitNamespaceName( catalogName, schemaName );
return locateNamespace( catalogName, schemaName );
}
public Namespace adjustDefaultNamespace(String implicitCatalogName, String implicitSchemaName) {

View File

@ -36,6 +36,12 @@ public interface SqlStringGenerationContext {
*/
Identifier getDefaultCatalog();
/**
* @param explicitCatalogOrNull An explicitly configured catalog, or {@code null}.
* @return The given identifier if non-{@code null}, or the default catalog otherwise.
*/
Identifier catalogWithDefault(Identifier explicitCatalogOrNull);
/**
* @return The default schema, used for table/sequence names that do not explicitly mention a schema.
* May be {@code null}.
@ -44,6 +50,12 @@ public interface SqlStringGenerationContext {
*/
Identifier getDefaultSchema();
/**
* @param explicitSchemaOrNull An explicitly configured schema, or {@code null}.
* @return The given identifier if non-{@code null}, or the default schema otherwise.
*/
Identifier schemaWithDefault(Identifier explicitSchemaOrNull);
/**
* Render a formatted a table name
*

View File

@ -47,7 +47,7 @@ public class SqlStringGenerationContextImpl
*/
public static SqlStringGenerationContext fromExplicit(JdbcEnvironment jdbcEnvironment,
Database database, String defaultCatalog, String defaultSchema) {
Namespace.Name implicitNamespaceName = database.getDefaultNamespace().getPhysicalName();
Namespace.Name implicitNamespaceName = database.getPhysicalImplicitNamespaceName();
IdentifierHelper identifierHelper = jdbcEnvironment.getIdentifierHelper();
NameQualifierSupport nameQualifierSupport = jdbcEnvironment.getNameQualifierSupport();
Identifier actualDefaultCatalog = null;
@ -107,11 +107,48 @@ public class SqlStringGenerationContextImpl
return defaultCatalog;
}
@Override
public Identifier catalogWithDefault(Identifier explicitCatalogOrNull) {
return explicitCatalogOrNull != null ? explicitCatalogOrNull : defaultCatalog;
}
@Override
public Identifier getDefaultSchema() {
return defaultSchema;
}
@Override
public Identifier schemaWithDefault(Identifier explicitSchemaOrNull) {
return explicitSchemaOrNull != null ? explicitSchemaOrNull : defaultSchema;
}
private QualifiedTableName withDefaults(QualifiedTableName name) {
if ( name.getCatalogName() == null && defaultCatalog != null
|| name.getSchemaName() == null && defaultSchema != null ) {
return new QualifiedTableName( catalogWithDefault( name.getCatalogName() ),
schemaWithDefault( name.getSchemaName() ), name.getTableName() );
}
return name;
}
private QualifiedSequenceName withDefaults(QualifiedSequenceName name) {
if ( name.getCatalogName() == null && defaultCatalog != null
|| name.getSchemaName() == null && defaultSchema != null ) {
return new QualifiedSequenceName( catalogWithDefault( name.getCatalogName() ),
schemaWithDefault( name.getSchemaName() ), name.getSequenceName() );
}
return name;
}
private QualifiedName withDefaults(QualifiedName name) {
if ( name.getCatalogName() == null && defaultCatalog != null
|| name.getSchemaName() == null && defaultSchema != null ) {
return new QualifiedSequenceName( catalogWithDefault( name.getCatalogName() ),
schemaWithDefault( name.getSchemaName() ), name.getObjectName() );
}
return name;
}
@Override
public String format(QualifiedTableName qualifiedName) {
return qualifiedObjectNameFormatter.format( withDefaults( qualifiedName ), dialect );
@ -127,37 +164,6 @@ public class SqlStringGenerationContextImpl
return qualifiedObjectNameFormatter.format( withDefaults( qualifiedName ), dialect );
}
private QualifiedTableName withDefaults(QualifiedTableName name) {
if ( name.getCatalogName() == null && defaultCatalog != null
|| name.getSchemaName() == null && defaultSchema != null ) {
return new QualifiedTableName( withDefault( name.getCatalogName(), defaultCatalog ),
withDefault( name.getSchemaName(), defaultSchema ), name.getTableName() );
}
return name;
}
private QualifiedSequenceName withDefaults(QualifiedSequenceName name) {
if ( name.getCatalogName() == null && defaultCatalog != null
|| name.getSchemaName() == null && defaultSchema != null ) {
return new QualifiedSequenceName( withDefault( name.getCatalogName(), defaultCatalog ),
withDefault( name.getSchemaName(), defaultSchema ), name.getSequenceName() );
}
return name;
}
private QualifiedName withDefaults(QualifiedName name) {
if ( name.getCatalogName() == null && defaultCatalog != null
|| name.getSchemaName() == null && defaultSchema != null ) {
return new QualifiedSequenceName( withDefault( name.getCatalogName(), defaultCatalog ),
withDefault( name.getSchemaName(), defaultSchema ), name.getObjectName() );
}
return name;
}
private static Identifier withDefault(Identifier value, Identifier defaultValue) {
return value != null ? value : defaultValue;
}
@Override
public String formatWithoutCatalog(QualifiedSequenceName qualifiedName) {
QualifiedSequenceName nameToFormat;

View File

@ -804,15 +804,6 @@ public class ModelBinder {
// YUCK! but cannot think of a clean way to do this given the string-config based scheme
params.put( PersistentIdentifierGenerator.IDENTIFIER_NORMALIZER, objectNameNormalizer);
String implicitSchemaName = metadataBuildingContext.getMappingDefaults().getImplicitSchemaName();
if ( implicitSchemaName != null ) {
params.setProperty( PersistentIdentifierGenerator.SCHEMA, implicitSchemaName );
}
String implicitCatalogName = metadataBuildingContext.getMappingDefaults().getImplicitCatalogName();
if ( implicitCatalogName != null ) {
params.setProperty( PersistentIdentifierGenerator.CATALOG, implicitCatalogName );
}
params.putAll( generator.getParameters() );
identifierValue.setIdentifierGeneratorProperties( params );
@ -2966,7 +2957,7 @@ public class ModelBinder {
return database.toIdentifier( tableSpecSource.getExplicitSchemaName() );
}
else {
return database.toIdentifier( metadataBuildingContext.getMappingDefaults().getImplicitSchemaName() );
return null;
}
}

View File

@ -149,7 +149,6 @@ import org.hibernate.cfg.annotations.TableBinder;
import org.hibernate.cfg.internal.NullableDiscriminatorColumnSecondPass;
import org.hibernate.engine.OptimisticLockStyle;
import org.hibernate.engine.spi.FilterDefinition;
import org.hibernate.id.PersistentIdentifierGenerator;
import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.StringHelper;
import org.hibernate.jpa.event.internal.CallbackDefinitionResolverLegacyImpl;
@ -467,20 +466,6 @@ public final class AnnotationBinder {
IdentifierGeneratorDefinition.Builder definitionBuilder = new IdentifierGeneratorDefinition.Builder();
if ( context.getMappingDefaults().getImplicitSchemaName() != null ) {
definitionBuilder.addParam(
PersistentIdentifierGenerator.SCHEMA,
context.getMappingDefaults().getImplicitSchemaName()
);
}
if ( context.getMappingDefaults().getImplicitCatalogName() != null ) {
definitionBuilder.addParam(
PersistentIdentifierGenerator.CATALOG,
context.getMappingDefaults().getImplicitCatalogName()
);
}
if ( generatorAnn instanceof TableGenerator ) {
context.getBuildingOptions().getIdGenerationTypeInterpreter().interpretTableGenerator(
(TableGenerator) generatorAnn,

View File

@ -525,15 +525,6 @@ public class BinderHelper {
PersistentIdentifierGenerator.TABLE, table.getName()
);
final String implicitCatalogName = buildingContext.getBuildingOptions().getMappingDefaults().getImplicitCatalogName();
if ( implicitCatalogName != null ) {
params.put( PersistentIdentifierGenerator.CATALOG, implicitCatalogName );
}
final String implicitSchemaName = buildingContext.getBuildingOptions().getMappingDefaults().getImplicitSchemaName();
if ( implicitSchemaName != null ) {
params.put( PersistentIdentifierGenerator.SCHEMA, implicitSchemaName );
}
if ( id.getColumnSpan() == 1 ) {
params.setProperty(
PersistentIdentifierGenerator.PK,

View File

@ -50,8 +50,8 @@ public final class Settings {
public Settings(SessionFactoryOptions sessionFactoryOptions, Metadata metadata) {
this(
sessionFactoryOptions,
extractName( metadata.getDatabase().getDefaultNamespace().getName().getCatalog() ),
extractName( metadata.getDatabase().getDefaultNamespace().getName().getSchema() )
extractName( metadata.getDatabase().getPhysicalImplicitNamespaceName().getCatalog() ),
extractName( metadata.getDatabase().getPhysicalImplicitNamespaceName().getSchema() )
);
}

View File

@ -477,10 +477,10 @@ public class TableBinder {
String subselect,
InFlightMetadataCollector.EntityTableXref denormalizedSuperTableXref) {
schema = BinderHelper.isEmptyOrNullAnnotationValue( schema )
? buildingContext.getBuildingOptions().getMappingDefaults().getImplicitSchemaName()
? null
: schema;
catalog = BinderHelper.isEmptyOrNullAnnotationValue( catalog )
? buildingContext.getBuildingOptions().getMappingDefaults().getImplicitCatalogName()
? null
: catalog;
final Table table;

View File

@ -407,7 +407,9 @@ public class JPAXMLOverriddenAnnotationReader implements AnnotationReader {
*/
private void initAnnotations() {
if ( annotations == null ) {
XMLContext.Default defaults = xmlContext.getDefault( className );
// We don't want the global catalog and schema here: they are applied much later,
// when SQL gets rendered.
XMLContext.Default defaults = xmlContext.getDefaultWithoutGlobalCatalogAndSchema( className );
if ( className != null && propertyName == null ) {
//is a class
ManagedType managedTypeOverride = xmlContext.getManagedTypeOverride( className );

View File

@ -94,7 +94,7 @@ public final class JPAXMLOverriddenMetadataProvider implements MetadataProvider
else {
if ( defaults == null ) {
defaults = new HashMap<>();
XMLContext.Default xmlDefaults = xmlContext.getDefault( null );
XMLContext.Default xmlDefaults = xmlContext.getDefaultWithGlobalCatalogAndSchema();
defaults.put( "schema", xmlDefaults.getSchema() );
defaults.put( "catalog", xmlDefaults.getCatalog() );

View File

@ -124,12 +124,12 @@ public class XMLContext implements Serializable {
managedTypeOverride.put( className, element );
Default mergedDefaults = new Default();
// Apply entity mapping defaults
mergedDefaults.override( defaults );
mergedDefaults.overrideWithCatalogAndSchema( defaults );
// ... then apply entity settings
Default fileDefaults = new Default();
fileDefaults.setMetadataComplete( element.isMetadataComplete() );
fileDefaults.setAccess( element.getAccess() );
mergedDefaults.override( fileDefaults );
mergedDefaults.overrideWithCatalogAndSchema( fileDefaults );
// ... and we get the merged defaults for that entity
defaultsOverride.put( className, mergedDefaults );
@ -196,16 +196,22 @@ public class XMLContext implements Serializable {
return buildSafeClassName( className, defaults.getPackageName() );
}
public Default getDefault(String className) {
public Default getDefaultWithoutGlobalCatalogAndSchema(String className) {
Default xmlDefault = new Default();
xmlDefault.override( globalDefaults );
xmlDefault.overrideWithoutCatalogAndSchema( globalDefaults );
if ( className != null ) {
Default entityMappingOverriding = defaultsOverride.get( className );
xmlDefault.override( entityMappingOverriding );
xmlDefault.overrideWithCatalogAndSchema( entityMappingOverriding );
}
return xmlDefault;
}
public Default getDefaultWithGlobalCatalogAndSchema() {
Default xmlDefault = new Default();
xmlDefault.overrideWithCatalogAndSchema( globalDefaults );
return xmlDefault;
}
public ManagedType getManagedTypeOverride(String className) {
return managedTypeOverride.get( className );
}
@ -292,7 +298,19 @@ public class XMLContext implements Serializable {
this.cascadePersist = cascadePersist;
}
public void override(Default globalDefault) {
public void overrideWithCatalogAndSchema(Default override) {
overrideWithoutCatalogAndSchema( override );
if ( override != null ) {
if ( override.getSchema() != null ) {
schema = override.getSchema();
}
if ( override.getCatalog() != null ) {
catalog = override.getCatalog();
}
}
}
public void overrideWithoutCatalogAndSchema(Default globalDefault) {
if ( globalDefault != null ) {
if ( globalDefault.getAccess() != null ) {
access = globalDefault.getAccess();
@ -300,12 +318,6 @@ public class XMLContext implements Serializable {
if ( globalDefault.getPackageName() != null ) {
packageName = globalDefault.getPackageName();
}
if ( globalDefault.getSchema() != null ) {
schema = globalDefault.getSchema();
}
if ( globalDefault.getCatalog() != null ) {
catalog = globalDefault.getCatalog();
}
if ( globalDefault.getDelimitedIdentifier() != null ) {
delimitedIdentifier = globalDefault.getDelimitedIdentifier();
}

View File

@ -32,6 +32,7 @@ import org.hibernate.tool.schema.spi.SchemaManagementTool;
public class DatabaseInformationImpl
implements DatabaseInformation, ExtractionContext.DatabaseObjectAccess {
private final JdbcEnvironment jdbcEnvironment;
private final SqlStringGenerationContext sqlStringGenerationContext;
private final ExtractionContext extractionContext;
private final InformationExtractor extractor;
@ -44,6 +45,7 @@ public class DatabaseInformationImpl
DdlTransactionIsolator ddlTransactionIsolator,
SchemaManagementTool tool) throws SQLException {
this.jdbcEnvironment = jdbcEnvironment;
this.sqlStringGenerationContext = sqlStringGenerationContext;
this.extractionContext = tool.getExtractionTool().createExtractionContext(
serviceRegistry,
jdbcEnvironment,
@ -78,12 +80,13 @@ public class DatabaseInformationImpl
@Override
public boolean catalogExists(Identifier catalog) {
return extractor.catalogExists( catalog );
return extractor.catalogExists( sqlStringGenerationContext.catalogWithDefault( catalog ) );
}
@Override
public boolean schemaExists(Namespace.Name namespace) {
return extractor.schemaExists( namespace.getCatalog(), namespace.getSchema() );
return extractor.schemaExists( sqlStringGenerationContext.catalogWithDefault( namespace.getCatalog() ),
sqlStringGenerationContext.schemaWithDefault( namespace.getSchema() ) );
}
@Override
@ -108,15 +111,16 @@ public class DatabaseInformationImpl
}
return extractor.getTable(
tableName.getCatalogName(),
tableName.getSchemaName(),
sqlStringGenerationContext.catalogWithDefault( tableName.getCatalogName() ),
sqlStringGenerationContext.schemaWithDefault( tableName.getSchemaName() ),
tableName.getTableName()
);
}
@Override
public NameSpaceTablesInformation getTablesInformation(Namespace namespace) {
return extractor.getTables( namespace.getPhysicalName().getCatalog(), namespace.getPhysicalName().getSchema() );
return extractor.getTables( sqlStringGenerationContext.catalogWithDefault( namespace.getPhysicalName().getCatalog() ),
sqlStringGenerationContext.schemaWithDefault( namespace.getPhysicalName().getSchema() ) );
}
@Override

View File

@ -235,7 +235,8 @@ public class SchemaCreatorImpl implements SchemaCreator {
if ( tryToCreateCatalogs ) {
final Identifier catalogLogicalName = namespace.getName().getCatalog();
final Identifier catalogPhysicalName = namespace.getPhysicalName().getCatalog();
final Identifier catalogPhysicalName =
sqlStringGenerationContext.catalogWithDefault( namespace.getPhysicalName().getCatalog() );
if ( catalogPhysicalName != null && !exportedCatalogs.contains( catalogLogicalName ) ) {
applySqlStrings(
@ -248,9 +249,11 @@ public class SchemaCreatorImpl implements SchemaCreator {
}
}
if ( tryToCreateSchemas && namespace.getPhysicalName().getSchema() != null ) {
final Identifier schemaPhysicalName =
sqlStringGenerationContext.schemaWithDefault( namespace.getPhysicalName().getSchema() );
if ( tryToCreateSchemas && schemaPhysicalName != null ) {
applySqlStrings(
dialect.getCreateSchemaCommand( namespace.getPhysicalName().getSchema().render( dialect ) ),
dialect.getCreateSchemaCommand( schemaPhysicalName.render( dialect ) ),
formatter,
options,
targets

View File

@ -11,6 +11,7 @@ import org.junit.Test;
import org.hibernate.Session;
import org.hibernate.Transaction;
import org.hibernate.boot.model.relational.SqlStringGenerationContext;
import org.hibernate.cfg.Configuration;
import org.hibernate.dialect.H2Dialect;
import org.hibernate.id.IdentifierGenerator;
@ -54,9 +55,10 @@ public class HibernateSequenceTest extends BaseCoreFunctionalTestCase {
IdentifierGenerator generator = persister.getIdentifierGenerator();
Assert.assertTrue( SequenceStyleGenerator.class.isInstance( generator ) );
SequenceStyleGenerator seqGenerator = (SequenceStyleGenerator) generator;
SqlStringGenerationContext sqlStringGenerationContext = sessionFactory().getSqlStringGenerationContext();
Assert.assertEquals(
SCHEMA_NAME + "." + SequenceStyleGenerator.DEF_SEQUENCE_NAME,
seqGenerator.getDatabaseStructure().getPhysicalName().render()
sqlStringGenerationContext.format( seqGenerator.getDatabaseStructure().getPhysicalName() )
);
}

View File

@ -64,7 +64,9 @@ public class JPAXMLOverriddenAnnotationReaderTest extends BaseUnitTestCase {
);
assertNotNull( reader.getAnnotation( Table.class ) );
assertEquals( "@Table not overridden", "tbl_admin", reader.getAnnotation( Table.class ).name() );
assertEquals( "Default schema not overridden", "myschema", reader.getAnnotation( Table.class ).schema() );
// The default schema is assigned later, when we generate SQL.
// See DefaultCatalogAndSchemaTest.
assertEquals( "Default schema overridden too soon", "", reader.getAnnotation( Table.class ).schema() );
assertEquals(
"Proper @Table.uniqueConstraints", 2,
reader.getAnnotation( Table.class ).uniqueConstraints()[0].columnNames().length
@ -88,7 +90,9 @@ public class JPAXMLOverriddenAnnotationReaderTest extends BaseUnitTestCase {
assertEquals( "default fails", 50, reader.getAnnotation( SequenceGenerator.class ).allocationSize() );
assertNotNull( "TableOverriding not working", reader.getAnnotation( TableGenerator.class ) );
assertEquals( "wrong tble name", "tablehilo", reader.getAnnotation( TableGenerator.class ).table() );
assertEquals( "no schema overriding", "myschema", reader.getAnnotation( TableGenerator.class ).schema() );
// The default schema is assigned later, when we generate SQL.
// See DefaultCatalogAndSchemaTest.
assertEquals( "Default schema overridden too soon", "", reader.getAnnotation( TableGenerator.class ).schema() );
reader = new JPAXMLOverriddenAnnotationReader( Match.class, context, bootstrapContext );
assertNotNull( reader.getAnnotation( Table.class ) );
@ -98,10 +102,14 @@ public class JPAXMLOverriddenAnnotationReaderTest extends BaseUnitTestCase {
assertEquals(
"Java annotation not taken into account", "matchschema", reader.getAnnotation( Table.class ).schema()
);
assertEquals( "Overriding not taken into account", "mycatalog", reader.getAnnotation( Table.class ).catalog() );
// The default schema is assigned later, when we generate SQL.
// See DefaultCatalogAndSchemaTest.
assertEquals( "Default catalog overridden too soon", "", reader.getAnnotation( Table.class ).catalog() );
assertNotNull( "SecondaryTable swallowed", reader.getAnnotation( SecondaryTables.class ) );
// The default schema is assigned later, when we generate SQL.
// See DefaultCatalogAndSchemaTest.
assertEquals(
"Default schema not taken into account", "myschema",
"Default schema not taken into account", "",
reader.getAnnotation( SecondaryTables.class ).value()[0].schema()
);
assertNotNull( reader.getAnnotation( Inheritance.class ) );
@ -194,15 +202,14 @@ public class JPAXMLOverriddenAnnotationReaderTest extends BaseUnitTestCase {
assertEquals(
"Metadata complete should ignore java annotations", "", reader.getAnnotation( Entity.class ).name()
);
assertNotNull( reader.getAnnotation( Table.class ) );
assertEquals( "@Table should not be used", "", reader.getAnnotation( Table.class ).name() );
assertEquals( "Default schema not overriden", "myschema", reader.getAnnotation( Table.class ).schema() );
// The default schema is assigned later, when we generate SQL.
// See DefaultCatalogAndSchemaTest.
assertNull( "Default schema overridden too soon", reader.getAnnotation( Table.class ) );
reader = new JPAXMLOverriddenAnnotationReader( Match.class, context, bootstrapContext );
assertNotNull( reader.getAnnotation( Table.class ) );
assertEquals( "@Table should not be used", "", reader.getAnnotation( Table.class ).name() );
assertEquals( "Overriding not taken into account", "myschema", reader.getAnnotation( Table.class ).schema() );
assertEquals( "Overriding not taken into account", "mycatalog", reader.getAnnotation( Table.class ).catalog() );
// The default schema is assigned later, when we generate SQL.
// See DefaultCatalogAndSchemaTest.
assertNull( "Default schema overridden too soon", reader.getAnnotation( Table.class ) );
assertNull( "Ignore Java annotation", reader.getAnnotation( SecondaryTable.class ) );
assertNull( "Ignore Java annotation", reader.getAnnotation( SecondaryTables.class ) );
assertNull( "Ignore Java annotation", reader.getAnnotation( Inheritance.class ) );