Skip to content

Commit b75d9d7

Browse files
dreab8sebersole
authored andcommitted
HHH-19388 - Process <database-object> in mapping.xml
1 parent 6a4e990 commit b75d9d7

File tree

10 files changed

+204
-3
lines changed

10 files changed

+204
-3
lines changed

hibernate-core/src/main/java/org/hibernate/boot/model/internal/AnnotationBinder.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,10 @@ public static void bindDefaults(MetadataBuildingContext context) {
118118
bindNamedStoredProcedureQuery( queryRegistration.configuration(), context, true );
119119
} );
120120

121+
globalRegistrations.getDatabaseObjectRegistrations().forEach( databaseObjectRegistration ->
122+
AuxiliaryDatabaseObjectBinder.processAuxiliaryDatabaseObject( context, databaseObjectRegistration )
123+
);
124+
121125
}
122126

123127
private static ModelsContext modelsContext(MetadataBuildingContext context) {
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.boot.model.internal;
6+
7+
import org.hibernate.MappingException;
8+
import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject;
9+
import org.hibernate.boot.model.relational.SimpleAuxiliaryDatabaseObject;
10+
import org.hibernate.boot.models.spi.DatabaseObjectRegistration;
11+
import org.hibernate.boot.models.spi.DialectScopeRegistration;
12+
import org.hibernate.boot.registry.classloading.spi.ClassLoadingException;
13+
import org.hibernate.boot.spi.MetadataBuildingContext;
14+
import org.hibernate.models.internal.util.StringHelper;
15+
16+
public class AuxiliaryDatabaseObjectBinder {
17+
public static void processAuxiliaryDatabaseObject(
18+
MetadataBuildingContext context,
19+
DatabaseObjectRegistration databaseObjectRegistration) {
20+
final AuxiliaryDatabaseObject auxDbObject;
21+
22+
if ( StringHelper.isNotEmpty( databaseObjectRegistration.definition()) ) {
23+
try {
24+
auxDbObject = (AuxiliaryDatabaseObject)
25+
context.getBootstrapContext().getClassLoaderService()
26+
.classForName( databaseObjectRegistration.definition() )
27+
.getConstructor()
28+
.newInstance();
29+
}
30+
catch (ClassLoadingException cle) {
31+
throw cle;
32+
}
33+
catch (Exception e) {
34+
throw new MappingException(
35+
String.format(
36+
"Unable to instantiate custom AuxiliaryDatabaseObject class [%s]",
37+
databaseObjectRegistration.definition()
38+
)
39+
);
40+
}
41+
}
42+
else {
43+
auxDbObject = new SimpleAuxiliaryDatabaseObject(
44+
context.getMetadataCollector().getDatabase().getDefaultNamespace(),
45+
databaseObjectRegistration.create(),
46+
databaseObjectRegistration.drop(),
47+
null
48+
);
49+
}
50+
51+
if ( !databaseObjectRegistration.dialectScopes().isEmpty() ) {
52+
if ( auxDbObject instanceof AuxiliaryDatabaseObject.Expandable expandable ) {
53+
for ( DialectScopeRegistration dialectScopeRegistration : databaseObjectRegistration.dialectScopes() ) {
54+
expandable.addDialectScope( dialectScopeRegistration.name() );
55+
}
56+
}
57+
else {
58+
// error? warn?
59+
}
60+
}
61+
62+
context.getMetadataCollector().getDatabase().addAuxiliaryDatabaseObject( auxDbObject );
63+
}
64+
65+
}

hibernate-core/src/main/java/org/hibernate/boot/models/internal/DomainModelCategorizationCollector.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ public void apply(JaxbEntityMappingsImpl jaxbRoot, XmlDocumentContext xmlDocumen
8585

8686
getGlobalRegistrations().collectQueryReferences( jaxbRoot, xmlDocumentContext );
8787

88+
getGlobalRegistrations().collectDataBaseObject( jaxbRoot.getDatabaseObjects() );
8889
// todo (7.0) : named graphs?
8990
}
9091

hibernate-core/src/main/java/org/hibernate/boot/models/internal/GlobalRegistrationsImpl.java

Lines changed: 41 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@
2424
import org.hibernate.boot.jaxb.mapping.spi.JaxbConfigurationParameterImpl;
2525
import org.hibernate.boot.jaxb.mapping.spi.JaxbConverterImpl;
2626
import org.hibernate.boot.jaxb.mapping.spi.JaxbConverterRegistrationImpl;
27+
import org.hibernate.boot.jaxb.mapping.spi.JaxbDatabaseObjectImpl;
28+
import org.hibernate.boot.jaxb.mapping.spi.JaxbDatabaseObjectScopeImpl;
2729
import org.hibernate.boot.jaxb.mapping.spi.JaxbEmbeddableInstantiatorRegistrationImpl;
2830
import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityListenerImpl;
2931
import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappingsImpl;
@@ -53,6 +55,8 @@
5355
import org.hibernate.boot.models.spi.CompositeUserTypeRegistration;
5456
import org.hibernate.boot.models.spi.ConversionRegistration;
5557
import org.hibernate.boot.models.spi.ConverterRegistration;
58+
import org.hibernate.boot.models.spi.DatabaseObjectRegistration;
59+
import org.hibernate.boot.models.spi.DialectScopeRegistration;
5660
import org.hibernate.boot.models.spi.EmbeddableInstantiatorRegistration;
5761
import org.hibernate.boot.models.spi.FilterDefRegistration;
5862
import org.hibernate.boot.models.spi.GenericGeneratorRegistration;
@@ -144,6 +148,8 @@ public class GlobalRegistrationsImpl implements GlobalRegistrations, GlobalRegis
144148
private Map<String, NamedNativeQueryRegistration> namedNativeQueryRegistrations;
145149
private Map<String, NamedStoredProcedureQueryRegistration> namedStoredProcedureQueryRegistrations;
146150

151+
private List<DatabaseObjectRegistration> databaseObjectRegistrations;
152+
147153
public GlobalRegistrationsImpl(ModelsContext sourceModelContext, BootstrapContext bootstrapContext) {
148154
this.sourceModelContext = sourceModelContext;
149155
this.bootstrapContext = bootstrapContext;
@@ -242,9 +248,13 @@ public Map<String, NamedNativeQueryRegistration> getNamedNativeQueryRegistration
242248

243249
@Override
244250
public Map<String, NamedStoredProcedureQueryRegistration> getNamedStoredProcedureQueryRegistrations() {
245-
return namedStoredProcedureQueryRegistrations== null ? emptyMap() : namedStoredProcedureQueryRegistrations;
251+
return namedStoredProcedureQueryRegistrations == null ? emptyMap() : namedStoredProcedureQueryRegistrations;
246252
}
247253

254+
@Override
255+
public List<DatabaseObjectRegistration> getDatabaseObjectRegistrations() {
256+
return databaseObjectRegistrations == null ? emptyList() : databaseObjectRegistrations;
257+
}
248258

249259
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
250260
// JavaTypeRegistration
@@ -1314,4 +1324,34 @@ private List<QueryHint> extractQueryHints(JaxbQueryHintContainer jaxbQuery) {
13141324
}
13151325
return hints;
13161326
}
1327+
1328+
public void collectDataBaseObject(List<JaxbDatabaseObjectImpl> databaseObjects) {
1329+
if ( isEmpty( databaseObjects ) ) {
1330+
return;
1331+
}
1332+
1333+
if ( databaseObjectRegistrations == null ) {
1334+
databaseObjectRegistrations = new ArrayList<>();
1335+
}
1336+
1337+
for ( JaxbDatabaseObjectImpl jaxbDatabaseObject : databaseObjects ) {
1338+
final JaxbDatabaseObjectImpl.JaxbDefinitionImpl definition = jaxbDatabaseObject.getDefinition();
1339+
final List<JaxbDatabaseObjectScopeImpl> dialectScopes = jaxbDatabaseObject.getDialectScopes();
1340+
final List<DialectScopeRegistration> scopeRegistrations = new ArrayList<>(dialectScopes.size());
1341+
for ( JaxbDatabaseObjectScopeImpl dialectScope : dialectScopes ) {
1342+
scopeRegistrations.add(
1343+
new DialectScopeRegistration(
1344+
dialectScope.getName(),
1345+
dialectScope.getContent(),
1346+
dialectScope.getMinimumVersion(),
1347+
dialectScope.getMaximumVersion() )
1348+
);
1349+
}
1350+
databaseObjectRegistrations.add( new DatabaseObjectRegistration(
1351+
jaxbDatabaseObject.getCreate(),
1352+
jaxbDatabaseObject.getDrop(),
1353+
definition != null ? definition.getClazz() : null,
1354+
scopeRegistrations ) );
1355+
}
1356+
}
13171357
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.boot.models.spi;
6+
7+
import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject;
8+
9+
import java.util.List;
10+
11+
/**
12+
* Models an auxiliary database object in the boot mapping model
13+
*
14+
* @param create The create command
15+
* @param drop The drop command
16+
* @param definition (optional) Name of the {@link AuxiliaryDatabaseObject} implementation to use.
17+
* @param dialectScopes Allows scoping the object to specific dialects.
18+
*
19+
* @see AuxiliaryDatabaseObject
20+
*
21+
* @author Andrea Boriero
22+
*/
23+
public record DatabaseObjectRegistration(
24+
String create,
25+
String drop,
26+
String definition,
27+
List<DialectScopeRegistration> dialectScopes ) {
28+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.boot.models.spi;
6+
7+
public record DialectScopeRegistration(String name, String content, String minimumVersion, String maximumVersion) {
8+
}

hibernate-core/src/main/java/org/hibernate/boot/models/spi/GlobalRegistrations.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,8 @@ public interface GlobalRegistrations {
5252

5353
Map<String, NamedStoredProcedureQueryRegistration> getNamedStoredProcedureQueryRegistrations();
5454

55+
List<DatabaseObjectRegistration> getDatabaseObjectRegistrations();
56+
5557
// todo : named entity graphs
5658

5759
<T> T as(Class<T> type);

hibernate-core/src/test/java/org/hibernate/orm/test/boot/database/qualfiedTableNaming/DefaultCatalogAndSchemaTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -215,8 +215,8 @@ public void initSessionFactory() {
215215
metadataSources.addInputStream( getClass().getResourceAsStream( "implicit-file-level-catalog-and-schema.hbm.xml" ) );
216216
metadataSources.addInputStream( getClass().getResourceAsStream( "no-file-level-catalog-and-schema.orm.xml" ) );
217217
metadataSources.addInputStream( getClass().getResourceAsStream( "no-file-level-catalog-and-schema.hbm.xml" ) );
218-
metadataSources.addInputStream( getClass().getResourceAsStream( "database-object-using-catalog-placeholder.hbm.xml" ) );
219-
metadataSources.addInputStream( getClass().getResourceAsStream( "database-object-using-schema-placeholder.hbm.xml" ) );
218+
metadataSources.addInputStream( getClass().getResourceAsStream( "database-object-using-catalog-placeholder.orm.xml" ) );
219+
metadataSources.addInputStream( getClass().getResourceAsStream( "database-object-using-schema-placeholder.orm.xml" ) );
220220
if ( configuredXmlMappingPath != null ) {
221221
metadataSources.addInputStream( getClass().getResourceAsStream( configuredXmlMappingPath ) );
222222
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
~ SPDX-License-Identifier: Apache-2.0
4+
~ Copyright Red Hat Inc. and Hibernate Authors
5+
-->
6+
<entity-mappings xmlns="http://www.hibernate.org/xsd/orm/mapping"
7+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
8+
version="7.0">
9+
<database-object>
10+
<!-- Note this code does not actually get executed.
11+
We just generate the script and check that ${catalog} gets replaced correctly.
12+
So the actual language used here does not need to be compatible with the DB dialect under test.
13+
-->
14+
<create>
15+
CREATE OR REPLACE FUNCTION ${catalog}.catalogPrefixedAuxObject()
16+
RETURNS varchar AS
17+
$BODY$
18+
BEGIN
19+
SELECT 'test';
20+
END;
21+
$BODY$
22+
LANGUAGE plpgsql
23+
</create>
24+
<drop>DROP FUNCTION ${catalog}.catalogPrefixedAuxObject()</drop>
25+
</database-object>
26+
</entity-mappings>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!--
3+
~ SPDX-License-Identifier: Apache-2.0
4+
~ Copyright Red Hat Inc. and Hibernate Authors
5+
-->
6+
<entity-mappings xmlns="http://www.hibernate.org/xsd/orm/mapping"
7+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
8+
version="7.0">
9+
<database-object>
10+
<!-- Note this code does not actually get executed.
11+
We just generate the script and check that ${schema} gets replaced correctly.
12+
So the actual language used here does not need to be compatible with the DB dialect under test.
13+
-->
14+
<create>
15+
CREATE OR REPLACE FUNCTION ${schema}.schemaPrefixedAuxObject()
16+
RETURNS varchar AS
17+
$BODY$
18+
BEGIN
19+
SELECT 'test';
20+
END;
21+
$BODY$
22+
LANGUAGE plpgsql
23+
</create>
24+
<drop>DROP FUNCTION ${schema}.schemaPrefixedAuxObject()</drop>
25+
26+
</database-object>
27+
</entity-mappings>

0 commit comments

Comments
 (0)