From f0a81898dc02a32a305f83836090b970234f4873 Mon Sep 17 00:00:00 2001 From: Karel Maesen Date: Wed, 3 Feb 2021 22:16:17 +0100 Subject: [PATCH 001/644] HHH-14442 Upgrade geolatte-geom to 1.6.1 --- gradle/libraries.gradle | 2 +- hibernate-spatial/.gitignore | 1 + hibernate-spatial/.sdkmanrc | 4 ++++ .../resources/hibernate.properties | 2 +- .../resources/hibernate.properties | 2 +- .../resources/hibernate.properties | 2 +- .../databases/postgispg96/matrix.gradle | 2 +- .../resources/hibernate.properties | 6 ++--- .../resources/hibernate.properties | 23 ------------------- .../sqlserver2012_spatial/matrix.gradle | 11 --------- .../matrix.gradle | 0 .../resources/hibernate.properties | 0 .../testing/GeolatteGeometryEquality.java | 4 ++-- .../src/test/resources/hibernate.properties | 8 +++---- 14 files changed, 17 insertions(+), 50 deletions(-) create mode 100644 hibernate-spatial/.gitignore create mode 100644 hibernate-spatial/.sdkmanrc delete mode 100644 hibernate-spatial/databases/sqlserver2008_spatial/resources/hibernate.properties delete mode 100644 hibernate-spatial/databases/sqlserver2012_spatial/matrix.gradle rename hibernate-spatial/databases/{sqlserver2008_spatial => sqlserver2017_spatial}/matrix.gradle (100%) rename hibernate-spatial/databases/{sqlserver2012_spatial => sqlserver2017_spatial}/resources/hibernate.properties (100%) diff --git a/gradle/libraries.gradle b/gradle/libraries.gradle index dc6b9754e29d..c57070452381 100644 --- a/gradle/libraries.gradle +++ b/gradle/libraries.gradle @@ -29,7 +29,7 @@ ext { assertjVersion = '3.14.0' - geolatteVersion = '1.4.0' + geolatteVersion = '1.6.1' shrinkwrapVersion = '1.2.6' shrinkwrapDescriptorsVersion = '2.0.0' diff --git a/hibernate-spatial/.gitignore b/hibernate-spatial/.gitignore new file mode 100644 index 000000000000..e0b3904e6bb7 --- /dev/null +++ b/hibernate-spatial/.gitignore @@ -0,0 +1 @@ +.sdkmanrc diff --git a/hibernate-spatial/.sdkmanrc b/hibernate-spatial/.sdkmanrc new file mode 100644 index 000000000000..92d04b893ed2 --- /dev/null +++ b/hibernate-spatial/.sdkmanrc @@ -0,0 +1,4 @@ +# Enable auto-env through the sdkman_auto_env config +# Add key=value pairs of SDKs to use below +java=8.0.252.hs-adpt + diff --git a/hibernate-spatial/databases/oracle12c_connection_finder/resources/hibernate.properties b/hibernate-spatial/databases/oracle12c_connection_finder/resources/hibernate.properties index d71e6c8d3f63..706924c75130 100644 --- a/hibernate-spatial/databases/oracle12c_connection_finder/resources/hibernate.properties +++ b/hibernate-spatial/databases/oracle12c_connection_finder/resources/hibernate.properties @@ -7,7 +7,7 @@ hibernate.dialect org.hibernate.spatial.dialect.oracle.OracleSpatial10gDialect hibernate.connection.driver_class oracle.jdbc.OracleDriver -hibernate.connection.url jdbc:oracle:thin:@localhost:1521:ORCLCDB +hibernate.connection.url jdbc:oracle:thin:@localhost:1521:ORCL hibernate.connection.username C##hibernate hibernate.connection.password hibernate diff --git a/hibernate-spatial/databases/oracle12c_spatial/resources/hibernate.properties b/hibernate-spatial/databases/oracle12c_spatial/resources/hibernate.properties index ddb680a8e8e8..a58739e453d6 100644 --- a/hibernate-spatial/databases/oracle12c_spatial/resources/hibernate.properties +++ b/hibernate-spatial/databases/oracle12c_spatial/resources/hibernate.properties @@ -7,7 +7,7 @@ hibernate.dialect org.hibernate.spatial.dialect.oracle.OracleSpatial10gDialect hibernate.connection.driver_class oracle.jdbc.OracleDriver -hibernate.connection.url jdbc:oracle:thin:@localhost:1521:ORCLCDB +hibernate.connection.url jdbc:oracle:thin:@localhost:1521:ORCL hibernate.connection.username C##hibernate hibernate.connection.password hibernate diff --git a/hibernate-spatial/databases/oracle12c_spatial_native/resources/hibernate.properties b/hibernate-spatial/databases/oracle12c_spatial_native/resources/hibernate.properties index 6c7104093f99..77b55a1c2ce5 100644 --- a/hibernate-spatial/databases/oracle12c_spatial_native/resources/hibernate.properties +++ b/hibernate-spatial/databases/oracle12c_spatial_native/resources/hibernate.properties @@ -7,7 +7,7 @@ hibernate.dialect org.hibernate.spatial.dialect.oracle.OracleSpatialSDO10gDialect hibernate.connection.driver_class oracle.jdbc.OracleDriver -hibernate.connection.url jdbc:oracle:thin:@localhost:1521:ORCLCDB +hibernate.connection.url jdbc:oracle:thin:@localhost:1521:ORCL hibernate.connection.username C##hibernate hibernate.connection.password hibernate diff --git a/hibernate-spatial/databases/postgispg96/matrix.gradle b/hibernate-spatial/databases/postgispg96/matrix.gradle index 3b243402a5a3..5059cb9072d0 100644 --- a/hibernate-spatial/databases/postgispg96/matrix.gradle +++ b/hibernate-spatial/databases/postgispg96/matrix.gradle @@ -4,4 +4,4 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -jdbcDependency "postgresql:postgresql:8.4-701.jdbc4" \ No newline at end of file +jdbcDependency 'org.postgresql:postgresql:42.2.2' \ No newline at end of file diff --git a/hibernate-spatial/databases/postgispg96/resources/hibernate.properties b/hibernate-spatial/databases/postgispg96/resources/hibernate.properties index 7071e5a31e56..4d1aa4760601 100644 --- a/hibernate-spatial/databases/postgispg96/resources/hibernate.properties +++ b/hibernate-spatial/databases/postgispg96/resources/hibernate.properties @@ -5,16 +5,14 @@ # See the lgpl.txt file in the root directory or . # -hibernate.test.new_metadata_mappings = true + hibernate.dialect org.hibernate.spatial.dialect.postgis.PostgisPG95Dialect hibernate.connection.driver_class org.postgresql.Driver -hibernate.connection.url jdbc:postgresql://localhost:9432 +hibernate.connection.url jdbc:postgresql://localhost:9432/ hibernate.connection.username hibern8 hibernate.connection.password hibern8 -hibernate.connection.pool_size 5 - hibernate.show_sql true hibernate.format_sql true diff --git a/hibernate-spatial/databases/sqlserver2008_spatial/resources/hibernate.properties b/hibernate-spatial/databases/sqlserver2008_spatial/resources/hibernate.properties deleted file mode 100644 index 0dd46f339640..000000000000 --- a/hibernate-spatial/databases/sqlserver2008_spatial/resources/hibernate.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Hibernate, Relational Persistence for Idiomatic Java -# -# License: GNU Lesser General Public License (LGPL), version 2.1 or later. -# See the lgpl.txt file in the root directory or . -# - -hibernate.dialect org.hibernate.spatial.dialect.sqlserver.SqlServer2008SpatialDialect -hibernate.connection.driver_class com.microsoft.sqlserver.jdbc.SQLServerDriver -hibernate.connection.url jdbc:sqlserver://localhost:1433;databaseName=TestDb -hibernate.connection.username hibern8 -hibernate.connection.password langpaswoord123A%1 - - -hibernate.connection.pool_size 5 - -hibernate.show_sql true -hibernate.format_sql true - -hibernate.max_fetch_depth 5 - -hibernate.cache.region_prefix hibernate.test -hibernate.cache.region.factory_class org.hibernate.testing.cache.CachingRegionFactory diff --git a/hibernate-spatial/databases/sqlserver2012_spatial/matrix.gradle b/hibernate-spatial/databases/sqlserver2012_spatial/matrix.gradle deleted file mode 100644 index 21ac5e6da194..000000000000 --- a/hibernate-spatial/databases/sqlserver2012_spatial/matrix.gradle +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -repositories { - mavenLocal( ) -} - -jdbcDependency 'com.microsoft.sqlserver:mssql-jdbc:6.4.0.jre8' diff --git a/hibernate-spatial/databases/sqlserver2008_spatial/matrix.gradle b/hibernate-spatial/databases/sqlserver2017_spatial/matrix.gradle similarity index 100% rename from hibernate-spatial/databases/sqlserver2008_spatial/matrix.gradle rename to hibernate-spatial/databases/sqlserver2017_spatial/matrix.gradle diff --git a/hibernate-spatial/databases/sqlserver2012_spatial/resources/hibernate.properties b/hibernate-spatial/databases/sqlserver2017_spatial/resources/hibernate.properties similarity index 100% rename from hibernate-spatial/databases/sqlserver2012_spatial/resources/hibernate.properties rename to hibernate-spatial/databases/sqlserver2017_spatial/resources/hibernate.properties diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/GeolatteGeometryEquality.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/GeolatteGeometryEquality.java index 8ae2b5ca38c9..3b58d2aea1b6 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/GeolatteGeometryEquality.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/GeolatteGeometryEquality.java @@ -1,7 +1,7 @@ package org.hibernate.spatial.testing; import org.geolatte.geom.Geometry; -import org.geolatte.geom.GeometryPointEquality; +import org.geolatte.geom.GeometryPositionEquality; import org.geolatte.geom.Position; /** @@ -12,7 +12,7 @@ public class GeolatteGeometryEquality

implements GeometryEqu private final org.geolatte.geom.GeometryEquality delegate; public GeolatteGeometryEquality() { - this( new GeometryPointEquality() ); + this( new GeometryPositionEquality() ); } public GeolatteGeometryEquality(org.geolatte.geom.GeometryEquality delegate) { diff --git a/hibernate-spatial/src/test/resources/hibernate.properties b/hibernate-spatial/src/test/resources/hibernate.properties index abef2d2a22fd..12af9edae928 100644 --- a/hibernate-spatial/src/test/resources/hibernate.properties +++ b/hibernate-spatial/src/test/resources/hibernate.properties @@ -6,8 +6,6 @@ # # Default unit/integration test config. -hibernate.test.new_metadata_mappings = true -hibernate.connection.pool_size 5 hibernate.show_sql true @@ -30,9 +28,9 @@ hibernate.connection.password @jdbc.pass@ # #hibernate.dialect org.hibernate.spatial.dialect.postgis.PostgisPG95Dialect #hibernate.connection.driver_class org.postgresql.Driver -#hibernate.connection.url jdbc:postgresql://localhost:5432/hibbrtru -#hibernate.connection.username hibbrtru -#hibernate.connection.password hibbrtru +#hibernate.connection.url jdbc:postgresql://localhost:9432/ +#hibernate.connection.username hibern8 +#hibernate.connection.password hibern8 ## ## GeoDb (H2 spatial extension) From 650a703e1c1b0c42cff41ddaf82303673e8c0ce9 Mon Sep 17 00:00:00 2001 From: Karel Maesen Date: Sat, 6 Feb 2021 15:56:55 +0100 Subject: [PATCH 002/644] HHH-14442 Fix checkstyle errors --- .../JTSGeometryJavaTypeDescriptor.java | 5 +- .../dialect/db2/DB2SpatialDialect.java | 36 +-- .../spatial/dialect/h2geodb/GeoDBDialect.java | 3 +- .../dialect/hana/HANASpatialUtils.java | 20 +- .../dialect/mysql/MySQLSpatialDialect.java | 6 +- .../dialect/oracle/OracleSDOSupport.java | 14 +- .../dialect/postgis/PostgisFunctions.java | 7 +- .../hana/TestHANASpatialFunctions.java | 243 +++++++++++++----- .../dialect/postgis/PostgisUnmarshalTest.java | 6 +- .../AbstractTestStoreRetrieve.java | 10 +- .../spatial/integration/DecodeUtil.java | 7 + .../spatial/integration/GeomEntityLike.java | 7 + .../TestGeolatteSpatialPredicates.java | 2 +- .../integration/TestJTSSpatialPredicates.java | 2 +- .../integration/TestSpatialFunctions.java | 4 +- .../integration/TestSpatialRestrictions.java | 9 +- .../integration/geolatte/GeomEntity.java | 6 +- .../TestStoreRetrieveUsingGeolatte.java | 2 +- .../integration/jts/JtsGeomEntity.java | 6 +- .../testing/AbstractExpectationsFactory.java | 28 +- .../spatial/testing/DataSourceUtils.java | 5 +- .../testing/GeolatteGeometryEquality.java | 7 + .../spatial/testing/GeometryEquality.java | 7 + .../spatial/testing/NativeSQLStatement.java | 4 +- .../testing/SQLExpressionTemplate.java | 2 +- .../testing/SpatialFunctionalTestCase.java | 9 +- .../hibernate/spatial/testing/TestData.java | 2 - .../spatial/testing/TestSupportFactories.java | 2 +- .../testing/converter/GeometryConverter.java | 4 +- .../converter/GeometryConverterTest.java | 8 +- .../spatial/testing/converter/MyEntity.java | 2 +- .../dialects/db2/DB2DataSourceUtils.java | 21 +- .../dialects/db2/DB2ExpectationsFactory.java | 21 +- .../dialects/db2/DB2ExpressionTemplate.java | 21 +- .../testing/dialects/db2/DB2TestSupport.java | 24 +- .../h2geodb/GeoDBDataSourceUtils.java | 2 +- .../hana/HANAExpectationsFactory.java | 169 +++++++++--- .../mysql/MySQL8ExpectationsFactory.java | 1 - .../src/test/resources/db2/setup_db.sql | 44 ++-- .../resources/db2/test-db2nozm-data-set.xml | 12 +- .../db2/test-db2nozm-only-polygon.xml | 7 +- .../resources/hana/test-hana-data-set.xml | 8 +- .../src/test/resources/hibernate.properties | 34 +-- .../src/test/resources/log4j.properties | 3 - .../mysql/test-mysql-functions-data-set.xml | 12 +- .../mysql/test-mysql8-functions-data-set.xml | 12 +- ....oracle.OracleSpatial10gDialect.properties | 1 - .../test-sdo-geometry-data-set-2D.xml | 3 +- .../oracle10g/test-sdo-geometry-data-set.xml | 12 +- .../test/resources/postgis-functions-test.xml | 3 +- .../create-sqlserver-test-schema.sql | 7 +- ...ibernate-spatial-sqlserver-test.properties | 12 +- .../src/test/resources/test-data-set.xml | 21 +- 53 files changed, 555 insertions(+), 370 deletions(-) diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/JTSGeometryJavaTypeDescriptor.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/JTSGeometryJavaTypeDescriptor.java index 94a70359e405..0ffcde4699e6 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/JTSGeometryJavaTypeDescriptor.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/JTSGeometryJavaTypeDescriptor.java @@ -7,10 +7,11 @@ package org.hibernate.spatial; +import java.util.Locale; + import org.hibernate.type.descriptor.WrapperOptions; import org.hibernate.type.descriptor.java.AbstractTypeDescriptor; import org.hibernate.type.descriptor.java.JavaTypeDescriptor; -import org.hibernate.type.descriptor.java.JavaTypeDescriptorRegistry; import org.locationtech.jts.geom.Geometry; import org.locationtech.jts.io.ParseException; @@ -49,7 +50,7 @@ public Geometry fromString(String string) { return reader.read( string ); } catch (ParseException e) { - throw new RuntimeException( String.format( "Can't parse string %s as WKT", string ) ); + throw new RuntimeException( String.format( Locale.ENGLISH, "Can't parse string %s as WKT", string ) ); } } diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/db2/DB2SpatialDialect.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/db2/DB2SpatialDialect.java index 263b946efddb..a7d1c79e2631 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/db2/DB2SpatialDialect.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/db2/DB2SpatialDialect.java @@ -29,8 +29,6 @@ import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.Type; -import static java.lang.String.format; - /** * @author David Adler, Adtech Geospatial * creation-date: 5/22/2014 @@ -228,24 +226,11 @@ private void registerSpatialFunctions() { ) ); // Register non-SFS functions listed in Hibernate Spatial - registerFunction( "dwithin", new DWithinFunction()); - -// // The srid parameter needs to be explicitly cast to INTEGER to avoid a -245 SQLCODE, -// // ambiguous parameter. -// registerFunction( "transform", new SQLFunctionTemplate( -// geolatteGemetryType, -// "DB2GSE.ST_Transform(?1, CAST (?2 AS INTEGER))" -// ) ); + registerFunction( "dwithin", new DWithinFunction() ); registerFunction( "geomFromText", new StandardSQLFunction( "DB2GSE.ST_GeomFromText" ) ); - -// // Register spatial aggregate function -// registerFunction( "extent", new SQLFunctionTemplate( -// geolatteGemetryType, -// "db2gse.ST_GetAggrResult(MAX(db2gse.st_BuildMBRAggr(?1)))" -// ) ); } @Override @@ -271,7 +256,7 @@ public String getIsEmptySQL(String columnName, boolean isEmpty) { @Override public String getSpatialAggregateSQL(String columnName, int type) { switch ( type ) { - case SpatialAggregate.EXTENT: // same as extent function above??? + case SpatialAggregate.EXTENT: return "db2gse.ST_GetAggrResult(MAX(db2gse.st_BuildMBRAggr(" + columnName + ")))"; case SpatialAggregate.UNION: return "db2gse.ST_GetAggrResult(MAX(db2gse.st_BuildUnionAggr(" + columnName + ")))"; @@ -304,7 +289,8 @@ public String getSpatialRelateSQL(String columnName, int spatialRelation) { if ( spatialRelation != SpatialRelation.DISJOINT ) { return " db2gse." + relationName + "(" + columnName + ", ?) = 1 SELECTIVITY .0001"; } - else { // SELECTIVITY not supported for ST_Disjoint UDF + else { + // SELECTIVITY not supported for ST_Disjoint UDF return " db2gse." + relationName + "(" + columnName + ", ?) = 1"; } } @@ -328,17 +314,17 @@ public boolean supportsFiltering() { private static class DWithinFunction extends StandardSQLFunction { public DWithinFunction() { - super( "db2gse.ST_Dwithin" , StandardBasicTypes.NUMERIC_BOOLEAN); + super( "db2gse.ST_Dwithin", StandardBasicTypes.NUMERIC_BOOLEAN ); } public String render(Type firstArgumentType, final List args, final SessionFactoryImplementor factory) { StringBuilder sb = new StringBuilder( "db2gse.ST_Intersects( " ); - sb.append( (String)args.get(0) ) // - .append(", db2gse.ST_Buffer(") - .append((String)args.get(1) ) - .append(", ") - .append((String)args.get(2) ) - .append(", 'METER'))"); + sb.append( (String) args.get( 0 ) ) + .append( ", db2gse.ST_Buffer(" ) + .append( (String) args.get( 1 ) ) + .append( ", " ) + .append( (String) args.get( 2 ) ) + .append( ", 'METER'))" ); return sb.toString(); } diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/h2geodb/GeoDBDialect.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/h2geodb/GeoDBDialect.java index 4c4df78cad1c..800456a2b6aa 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/h2geodb/GeoDBDialect.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/h2geodb/GeoDBDialect.java @@ -8,6 +8,7 @@ package org.hibernate.spatial.dialect.h2geodb; import java.util.List; +import java.util.Locale; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -177,7 +178,7 @@ public String render( Type firstArgumentType, List arguments, SessionFactoryImplementor sessionFactory) { int argumentCount = arguments.size(); if ( argumentCount != 2 ) { - throw new QueryException( String.format( "2 arguments expected, received %d", argumentCount ) ); + throw new QueryException( String.format( Locale.ENGLISH,"2 arguments expected, received %d", argumentCount ) ); } return Stream.of( diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/hana/HANASpatialUtils.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/hana/HANASpatialUtils.java index a764e2d84838..ed7fd99ab5f2 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/hana/HANASpatialUtils.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/hana/HANASpatialUtils.java @@ -11,6 +11,7 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.Locale; import org.geolatte.geom.ByteBuffer; import org.geolatte.geom.ByteOrder; @@ -23,6 +24,10 @@ public class HANASpatialUtils { private static final int POSTGIS_SRID_FLAG = 0x20000000; + private HANASpatialUtils(){ + //prevent instantiation of Utility class + } + @SuppressWarnings("resource") public static Geometry toGeometry(ResultSet rs, String name) throws SQLException { ByteBuffer buffer = toByteBuffer( rs.getObject( name ) ); @@ -36,7 +41,7 @@ public static Geometry toGeometry(ResultSet rs, String name) throws SQLExcept String columnName = null; for ( int i = 1; i <= rs.getMetaData().getColumnCount(); i++ ) { if ( name.equals( rs.getMetaData().getColumnLabel( i ) ) || - name.toUpperCase().equals( rs.getMetaData().getColumnLabel( i ) ) ) { + name.toUpperCase( Locale.ENGLISH ).equals( rs.getMetaData().getColumnLabel( i ) ) ) { tableName = rs.getMetaData().getTableName( i ); columnName = rs.getMetaData().getColumnName( i ); } @@ -80,17 +85,20 @@ public static Geometry toGeometry(ResultSet rs, String name) throws SQLExcept } private static ByteBuffer addCrsId(byte[] wkb, byte orderByte, int typeCode, int crsId) { - ByteBuffer buffer = ByteBuffer.allocate( wkb.length + 4 ); // original capacity + 4 bytes for the CRS ID + // original capacity + 4 bytes for the CRS ID + ByteBuffer buffer = ByteBuffer.allocate( wkb.length + 4 ); buffer.setByteOrder( ByteOrder.valueOf( orderByte ) ); - buffer.put( orderByte ); // write byte order + // write byte order + buffer.put( orderByte ); - buffer.putUInt( typeCode | POSTGIS_SRID_FLAG ); // set SRID flag + // set SRID flag + buffer.putUInt( typeCode | POSTGIS_SRID_FLAG ); - buffer.putInt( crsId ); // write CRS ID + // write CRS ID + buffer.putInt( crsId ); // write remaining data - for ( int i = 5; i < wkb.length; i++ ) { buffer.put( wkb[i] ); } diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/mysql/MySQLSpatialDialect.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/mysql/MySQLSpatialDialect.java index e8c8645f8695..a4de19944f5a 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/mysql/MySQLSpatialDialect.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/mysql/MySQLSpatialDialect.java @@ -6,6 +6,7 @@ */ package org.hibernate.spatial.dialect.mysql; +import java.util.Locale; import java.util.Map; import org.hibernate.boot.model.TypeContributions; @@ -93,7 +94,10 @@ public String getSpatialAggregateSQL(String columnName, int aggregation) { @Override public String getDWithinSQL(String columnName) { - throw new UnsupportedOperationException( String.format( "Mysql doesn't support the Dwithin function" ) ); + throw new UnsupportedOperationException( String.format( + Locale.ENGLISH, + "Mysql doesn't support the Dwithin function" + ) ); } @Override diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/OracleSDOSupport.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/OracleSDOSupport.java index 0026a0f60099..7c94cbea4954 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/OracleSDOSupport.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/OracleSDOSupport.java @@ -42,11 +42,10 @@ class OracleSDOSupport implements SpatialDialect, Serializable, WithCustomJPAFil OracleSpatial10gDialect.class.getName() ); - private final boolean isOgcStrict; + private final SpatialFunctionsRegistry sdoFunctions; OracleSDOSupport(boolean isOgcStrict) { - this.isOgcStrict = isOgcStrict; this.sdoFunctions = new OracleSpatialFunctions( isOgcStrict, this ); } @@ -262,7 +261,7 @@ public String getSpatialAggregateSQL(String columnName, int aggregation) { aggregateFunction.append( "SDOAGGRTYPE(" ); } aggregateFunction.append( columnName ); - // TODO tolerance must by configurable + // Can we make tolerance configurable if ( sa.isAggregateType() ) { aggregateFunction.append( ", " ).append( .001 ).append( ")" ); } @@ -292,7 +291,7 @@ public String getDWithinSQL(String columnName) { */ @Override public String getHavingSridSQL(String columnName) { - return String.format( " (MDSYS.ST_GEOMETRY(%s).ST_SRID() = ?)", columnName , Locale.US); + return String.format( Locale.ENGLISH, " (MDSYS.ST_GEOMETRY(%s).ST_SRID() = ?)", columnName ); } /** @@ -306,7 +305,12 @@ public String getHavingSridSQL(String columnName) { */ @Override public String getIsEmptySQL(String columnName, boolean isEmpty) { - return String.format( "( MDSYS.ST_GEOMETRY(%s).ST_ISEMPTY() = %d )", columnName, isEmpty ? 1 : 0 , Locale.US); + return String.format( + Locale.ENGLISH, + "( MDSYS.ST_GEOMETRY(%s).ST_ISEMPTY() = %d )", + columnName, + isEmpty ? 1 : 0 + ); } /** diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisFunctions.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisFunctions.java index 0c3c08eb1909..77d3c79f8649 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisFunctions.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisFunctions.java @@ -7,6 +7,7 @@ package org.hibernate.spatial.dialect.postgis; import java.util.List; +import java.util.Locale; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -226,7 +227,11 @@ public String render( Type firstArgumentType, List arguments, SessionFactoryImplementor sessionFactory) { int argumentCount = arguments.size(); if ( argumentCount != 2 ) { - throw new QueryException( String.format( "2 arguments expected, received %d", argumentCount ) ); + throw new QueryException( String.format( + Locale.ENGLISH, + "2 arguments expected, received %d", + argumentCount + ) ); } return Stream.of( diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/hana/TestHANASpatialFunctions.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/hana/TestHANASpatialFunctions.java index 6e551362fbdc..068c4033b058 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/hana/TestHANASpatialFunctions.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/hana/TestHANASpatialFunctions.java @@ -1,17 +1,28 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ + package org.hibernate.spatial.dialect.hana; import static java.lang.String.format; import java.sql.SQLException; import java.util.HashMap; +import java.util.Locale; import java.util.Map; import org.hibernate.cfg.Configuration; import org.hibernate.spatial.HSMessageLogger; import org.hibernate.spatial.integration.TestSpatialFunctions; import org.hibernate.spatial.testing.dialects.hana.HANAExpectationsFactory; + import org.hibernate.testing.RequiresDialect; + import org.jboss.logging.Logger; + import org.junit.Test; import org.locationtech.jts.geom.Geometry; @@ -24,7 +35,8 @@ public class TestHANASpatialFunctions extends TestSpatialFunctions { private static final HSMessageLogger LOG = Logger.getMessageLogger( HSMessageLogger.class, - TestHANASpatialFunctions.class.getName() ); + TestHANASpatialFunctions.class.getName() + ); protected HANAExpectationsFactory hanaExpectationsFactory; @@ -52,8 +64,10 @@ public void test_alphashape_on_geolatte() throws SQLException { public void alphashape(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getAlphaShape( 1 ); String hql = format( + Locale.ENGLISH, "SELECT id, alphashape(geom, 1) FROM org.hibernate.spatial.integration.%s.GeomEntity where geometrytype(geom) in ('ST_Point', 'ST_MultiPoint')", - pckg ); + pckg + ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -71,7 +85,8 @@ public void area(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getArea(); String hql = format( "SELECT id, area(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where geometrytype(geom) in ('ST_Polygon', 'ST_MultiPolygon')", - pckg ); + pckg + ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -151,7 +166,10 @@ public void test_assvgaggr_on_geolatte() throws SQLException { public void assvgaggr(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getAsSVGAggr(); - String hql = format( "SELECT cast(count(g) as int), assvgaggr(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity g", pckg ); + String hql = format( + "SELECT cast(count(g) as int), assvgaggr(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity g", + pckg + ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -199,7 +217,10 @@ public void test_convexhullaggr_on_geolatte() throws SQLException { public void convexhullaggr(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getConvexHullAggr(); - String hql = format( "SELECT cast(count(g) as int), convexhullaggr(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity g", pckg ); + String hql = format( + "SELECT cast(count(g) as int), convexhullaggr(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity g", + pckg + ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -215,7 +236,10 @@ public void test_centroid_on_geolatte() throws SQLException { public void centroid(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getCentroid(); - String hql = format( "SELECT id, centroid(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity g where geometrytype(geom) = 'ST_Polygon'", pckg ); + String hql = format( + "SELECT id, centroid(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity g where geometrytype(geom) = 'ST_Polygon'", + pckg + ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -249,7 +273,9 @@ public void coveredby(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getCoveredBy( expectationsFactory.getTestPolygon() ); String hql = format( "SELECT id, coveredby(geom, :filter) FROM org.hibernate.spatial.integration.%s.GeomEntity where coveredby(geom, :filter) = true and srid(geom) = %d", - pckg, expectationsFactory.getTestSrid() ); + pckg, + expectationsFactory.getTestSrid() + ); Map params = createQueryParams( "filter", expectationsFactory.getTestPolygon() ); retrieveHQLResultsAndCompare( dbexpected, hql, params, pckg ); } @@ -268,7 +294,9 @@ public void covers(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getCovers( expectationsFactory.getTestPolygon() ); String hql = format( "SELECT id, covers(geom, :filter) FROM org.hibernate.spatial.integration.%s.GeomEntity where covers(geom, :filter) = true and srid(geom) = %d", - pckg, expectationsFactory.getTestSrid() ); + pckg, + expectationsFactory.getTestSrid() + ); Map params = createQueryParams( "filter", expectationsFactory.getTestPolygon() ); retrieveHQLResultsAndCompare( dbexpected, hql, params, pckg ); } @@ -285,8 +313,10 @@ public void test_endpoint_on_geolatte() throws SQLException { public void endpoint(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getEndPoint(); - String hql = format( "SELECT id, endpoint(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity g where geometrytype(geom) = 'ST_LineString'", - pckg ); + String hql = format( + "SELECT id, endpoint(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity g where geometrytype(geom) = 'ST_LineString'", + pckg + ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -302,7 +332,10 @@ public void test_envelopeaggr_on_geolatte() throws SQLException { public void envelopeaggr(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getEnvelopeAggr(); - String hql = format( "SELECT cast(count(g) as int), envelopeaggr(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity g", pckg ); + String hql = format( + "SELECT cast(count(g) as int), envelopeaggr(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity g", + pckg + ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -318,8 +351,10 @@ public void test_exteriorring_on_geolatte() throws SQLException { public void exteriorring(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getExteriorRing(); - String hql = format( "SELECT id, exteriorring(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity g where geometrytype(geom) = 'ST_Polygon'", - pckg ); + String hql = format( + "SELECT id, exteriorring(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity g where geometrytype(geom) = 'ST_Polygon'", + pckg + ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -337,8 +372,11 @@ public void geomfromewkb(String pckg) throws SQLException { WKBWriter writer = new WKBWriter( 2, true ); byte[] ewkb = writer.write( expectationsFactory.getTestPolygon() ); Map dbexpected = hanaExpectationsFactory.getGeomFromEWKB( ewkb ); - String hql = format( "SELECT 1, cast(geomfromewkb(:param) as %s) FROM org.hibernate.spatial.integration.%s.GeomEntity g", - getGeometryTypeFromPackage( pckg ), pckg ); + String hql = format( + "SELECT 1, cast(geomfromewkb(:param) as %s) FROM org.hibernate.spatial.integration.%s.GeomEntity g", + getGeometryTypeFromPackage( pckg ), + pckg + ); Map params = createQueryParams( "param", ewkb ); retrieveHQLResultsAndCompare( dbexpected, hql, params, pckg ); } @@ -357,8 +395,11 @@ public void geomfromewkt(String pckg) throws SQLException { WKTWriter writer = new WKTWriter(); String ewkt = "SRID=" + expectationsFactory.getTestSrid() + ";" + writer.write( expectationsFactory.getTestPolygon() ); Map dbexpected = hanaExpectationsFactory.getGeomFromEWKT( ewkt ); - String hql = format( "SELECT 1, cast(geomfromewkt(:param) as %s) FROM org.hibernate.spatial.integration.%s.GeomEntity g", - getGeometryTypeFromPackage( pckg ), pckg ); + String hql = format( + "SELECT 1, cast(geomfromewkt(:param) as %s) FROM org.hibernate.spatial.integration.%s.GeomEntity g", + getGeometryTypeFromPackage( pckg ), + pckg + ); Map params = createQueryParams( "param", ewkt ); retrieveHQLResultsAndCompare( dbexpected, hql, params, pckg ); } @@ -376,8 +417,11 @@ public void test_geomfromtext_on_geolatte() throws SQLException { public void geomfromtext(String pckg) throws SQLException { String text = expectationsFactory.getTestPolygon().toText(); Map dbexpected = hanaExpectationsFactory.getGeomFromText( text ); - String hql = format( "SELECT 1, cast(geomfromtext(:param) as %s) FROM org.hibernate.spatial.integration.%s.GeomEntity g", - getGeometryTypeFromPackage( pckg ), pckg ); + String hql = format( + "SELECT 1, cast(geomfromtext(:param) as %s) FROM org.hibernate.spatial.integration.%s.GeomEntity g", + getGeometryTypeFromPackage( pckg ), + pckg + ); Map params = createQueryParams( "param", text ); retrieveHQLResultsAndCompare( dbexpected, hql, params, pckg ); } @@ -396,8 +440,11 @@ public void geomfromwkb(String pckg) throws SQLException { WKBWriter writer = new WKBWriter( 2, false ); byte[] wkb = writer.write( expectationsFactory.getTestPolygon() ); Map dbexpected = hanaExpectationsFactory.getGeomFromWKB( wkb ); - String hql = format( "SELECT 1, cast(geomfromwkb(:param) as %s) FROM org.hibernate.spatial.integration.%s.GeomEntity g", - getGeometryTypeFromPackage( pckg ), pckg ); + String hql = format( + "SELECT 1, cast(geomfromwkb(:param) as %s) FROM org.hibernate.spatial.integration.%s.GeomEntity g", + getGeometryTypeFromPackage( pckg ), + pckg + ); Map params = createQueryParams( "param", wkb ); retrieveHQLResultsAndCompare( dbexpected, hql, params, pckg ); } @@ -416,8 +463,11 @@ public void geomfromwkt(String pckg) throws SQLException { WKTWriter writer = new WKTWriter(); String wkt = writer.write( expectationsFactory.getTestPolygon() ); Map dbexpected = hanaExpectationsFactory.getGeomFromWKT( wkt ); - String hql = format( "SELECT 1, cast(geomfromwkt(:param) as %s) FROM org.hibernate.spatial.integration.%s.GeomEntity g", - getGeometryTypeFromPackage( pckg ), pckg ); + String hql = format( + "SELECT 1, cast(geomfromwkt(:param) as %s) FROM org.hibernate.spatial.integration.%s.GeomEntity g", + getGeometryTypeFromPackage( pckg ), + pckg + ); Map params = createQueryParams( "param", wkt ); retrieveHQLResultsAndCompare( dbexpected, hql, params, pckg ); } @@ -436,7 +486,9 @@ public void geometryn(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getGeometryN( 1 ); String hql = format( "SELECT id, cast(geometryn(geom, :n) as %s) FROM org.hibernate.spatial.integration.%s.GeomEntity g where geometrytype(geom) = 'ST_GeometryCollection'", - getGeometryTypeFromPackage( pckg ), pckg ); + getGeometryTypeFromPackage( pckg ), + pckg + ); Map params = createQueryParams( "n", 1 ); retrieveHQLResultsAndCompare( dbexpected, hql, params, pckg ); } @@ -455,7 +507,9 @@ public void interiorringn(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getInteriorRingN( 1 ); String hql = format( "SELECT id, cast(interiorringn(geom, :n) as %s) FROM org.hibernate.spatial.integration.%s.GeomEntity g where geometrytype(geom) = 'ST_Polygon'", - getGeometryTypeFromPackage( pckg ), pckg ); + getGeometryTypeFromPackage( pckg ), + pckg + ); Map params = createQueryParams( "n", 1 ); retrieveHQLResultsAndCompare( dbexpected, hql, params, pckg ); } @@ -472,7 +526,10 @@ public void test_intersectionaggr_on_geolatte() throws SQLException { public void intersectionaggr(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getIntersectionAggr(); - String hql = format( "SELECT cast(count(g) as int), intersectionaggr(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity g", pckg ); + String hql = format( + "SELECT cast(count(g) as int), intersectionaggr(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity g", + pckg + ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -487,11 +544,15 @@ public void test_intersectsrect_on_geolatte() throws SQLException { } public void intersectsrect(String pckg) throws SQLException { - Map dbexpected = hanaExpectationsFactory.getIntersectsRect( (Point) expectationsFactory.getTestPoint().reverse(), - expectationsFactory.getTestPoint() ); + Map dbexpected = hanaExpectationsFactory.getIntersectsRect( + (Point) expectationsFactory.getTestPoint().reverse(), + expectationsFactory.getTestPoint() + ); String hql = format( "SELECT id, intersectsrect(geom, :pmin, :pmax) FROM org.hibernate.spatial.integration.%s.GeomEntity where intersectsrect(geom, :pmin, :pmax) = true and srid(geom) = %d", - pckg, expectationsFactory.getTestSrid() ); + pckg, + expectationsFactory.getTestSrid() + ); Map params = createQueryParams( "pmin", expectationsFactory.getTestPoint().reverse() ); params.put( "pmax", expectationsFactory.getTestPoint() ); retrieveHQLResultsAndCompare( dbexpected, hql, params, pckg ); @@ -511,7 +572,9 @@ public void is3d(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getIs3D(); String hql = format( "SELECT id, is3d(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where is3d(geom) = true and srid(geom) = %d", - pckg, expectationsFactory.getTestSrid() ); + pckg, + expectationsFactory.getTestSrid() + ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -529,7 +592,9 @@ public void isclosed(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getIsClosed(); String hql = format( "SELECT id, isclosed(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where geometrytype(geom) in ('ST_LineString', 'ST_MultiLineString') and isclosed(geom) = true and srid(geom) = %d", - pckg, expectationsFactory.getTestSrid() ); + pckg, + expectationsFactory.getTestSrid() + ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -547,7 +612,9 @@ public void ismeasured(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getIsMeasured(); String hql = format( "SELECT id, ismeasured(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where ismeasured(geom) = true and srid(geom) = %d", - pckg, expectationsFactory.getTestSrid() ); + pckg, + expectationsFactory.getTestSrid() + ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -565,7 +632,9 @@ public void isring(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getIsRing(); String hql = format( "SELECT id, isring(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where geometrytype(geom) in ('ST_LineString') and srid(geom) = %d", - pckg, expectationsFactory.getTestSrid() ); + pckg, + expectationsFactory.getTestSrid() + ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -583,7 +652,9 @@ public void isvalid(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getIsValid(); String hql = format( "SELECT id, isvalid(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where isvalid(geom) = true and srid(geom) = %d", - pckg, expectationsFactory.getTestSrid() ); + pckg, + expectationsFactory.getTestSrid() + ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -601,7 +672,9 @@ public void length(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getLength(); String hql = format( "SELECT id, length(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where geometrytype(geom) in ('ST_LineString', 'ST_MultiLineString') and srid(geom) = %d", - pckg, expectationsFactory.getTestSrid() ); + pckg, + expectationsFactory.getTestSrid() + ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -619,7 +692,9 @@ public void m(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getM(); String hql = format( "SELECT id, m(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where geometrytype(geom) in ('ST_Point') and srid(geom) = %d", - pckg, expectationsFactory.getTestSrid() ); + pckg, + expectationsFactory.getTestSrid() + ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -637,7 +712,8 @@ public void mmax(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getMMax(); String hql = format( "SELECT id, mmax(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where srid(geom) = %d", - pckg, expectationsFactory.getTestSrid() ); + pckg, expectationsFactory.getTestSrid() + ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -655,7 +731,8 @@ public void mmin(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getMMin(); String hql = format( "SELECT id, mmin(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where srid(geom) = %d", - pckg, expectationsFactory.getTestSrid() ); + pckg, expectationsFactory.getTestSrid() + ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -673,7 +750,9 @@ public void numgeometries(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getNumGeometries(); String hql = format( "SELECT id, numgeometries(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where geometrytype(geom) in ('ST_GeometryCollection') and srid(geom) = %d", - pckg, expectationsFactory.getTestSrid() ); + pckg, + expectationsFactory.getTestSrid() + ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -691,7 +770,9 @@ public void numinteriorring(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getNumInteriorRing(); String hql = format( "SELECT id, numinteriorring(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where geometrytype(geom) in ('ST_Polygon') and srid(geom) = %d", - pckg, expectationsFactory.getTestSrid() ); + pckg, + expectationsFactory.getTestSrid() + ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -709,7 +790,9 @@ public void numinteriorrings(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getNumInteriorRings(); String hql = format( "SELECT id, numinteriorrings(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where geometrytype(geom) in ('ST_Polygon') and srid(geom) = %d", - pckg, expectationsFactory.getTestSrid() ); + pckg, + expectationsFactory.getTestSrid() + ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -727,7 +810,9 @@ public void numpoints(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getNumPoints(); String hql = format( "SELECT id, numpoints(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where geometrytype(geom) in ('ST_LineString') and srid(geom) = %d", - pckg, expectationsFactory.getTestSrid() ); + pckg, + expectationsFactory.getTestSrid() + ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -745,7 +830,9 @@ public void orderingequals(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getOrderingEquals( expectationsFactory.getTestPolygon() ); String hql = format( "SELECT id, orderingequals(geom, :filter) FROM org.hibernate.spatial.integration.%s.GeomEntity where orderingequals(geom, :filter) = true and srid(geom) = %d", - pckg, expectationsFactory.getTestSrid() ); + pckg, + expectationsFactory.getTestSrid() + ); Map params = createQueryParams( "filter", expectationsFactory.getTestPolygon() ); retrieveHQLResultsAndCompare( dbexpected, hql, params, pckg ); } @@ -764,7 +851,9 @@ public void perimeter(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getPerimeter(); String hql = format( "SELECT id, perimeter(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where geometrytype(geom) in ('ST_Polygon', 'ST_MultiPolygon') and srid(geom) = %d", - pckg, expectationsFactory.getTestSrid() ); + pckg, + expectationsFactory.getTestSrid() + ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -782,7 +871,9 @@ public void pointonsurface(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getPointOnSurface(); String hql = format( "SELECT id, pointonsurface(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where geometrytype(geom) in ('ST_Polygon', 'ST_MultiPolygon') and srid(geom) = %d", - pckg, expectationsFactory.getTestSrid() ); + pckg, + expectationsFactory.getTestSrid() + ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -800,17 +891,21 @@ public void pointn(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getPointN( 1 ); String hql = format( "SELECT id, pointn(geom, :n) FROM org.hibernate.spatial.integration.%s.GeomEntity where geometrytype(geom) in ('ST_LineString') and srid(geom) = %d", - pckg, expectationsFactory.getTestSrid() ); + pckg, + expectationsFactory.getTestSrid() + ); Map params = createQueryParams( "n", 1 ); retrieveHQLResultsAndCompare( dbexpected, hql, params, pckg ); } - @Test(expected = SQLException.class) // ST_GEOMETRY columns are not supported + // ST_GEOMETRY columns are not supported + @Test(expected = SQLException.class) public void test_snaptogrid_on_jts() throws SQLException { snaptogrid( JTS ); } - @Test(expected = SQLException.class) // ST_GEOMETRY columns are not supported + // ST_GEOMETRY columns are not supported + @Test(expected = SQLException.class) public void test_snaptogrid_on_geolatte() throws SQLException { snaptogrid( GEOLATTE ); } @@ -819,7 +914,8 @@ public void snaptogrid(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getSnapToGrid(); String hql = format( "SELECT id, snaptogrid(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where srid(geom) = %d", - pckg, expectationsFactory.getTestSrid() ); + pckg, expectationsFactory.getTestSrid() + ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -835,8 +931,10 @@ public void test_startpoint_on_geolatte() throws SQLException { public void startpoint(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getStartPoint(); - String hql = format( "SELECT id, startpoint(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity g where geometrytype(geom) = 'ST_LineString'", - pckg ); + String hql = format( + "SELECT id, startpoint(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity g where geometrytype(geom) = 'ST_LineString'", + pckg + ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -852,7 +950,10 @@ public void test_unionaggr_on_geolatte() throws SQLException { public void unionaggr(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getUnionAggr(); - String hql = format( "SELECT cast(count(g) as int), unionaggr(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity g", pckg ); + String hql = format( + "SELECT cast(count(g) as int), unionaggr(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity g", + pckg + ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -870,7 +971,9 @@ public void x(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getX(); String hql = format( "SELECT id, x(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where geometrytype(geom) in ('ST_Point') and srid(geom) = %d", - pckg, expectationsFactory.getTestSrid() ); + pckg, + expectationsFactory.getTestSrid() + ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -888,7 +991,8 @@ public void xmax(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getXMax(); String hql = format( "SELECT id, xmax(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where srid(geom) = %d", - pckg, expectationsFactory.getTestSrid() ); + pckg, expectationsFactory.getTestSrid() + ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -906,7 +1010,8 @@ public void xmin(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getXMin(); String hql = format( "SELECT id, xmin(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where srid(geom) = %d", - pckg, expectationsFactory.getTestSrid() ); + pckg, expectationsFactory.getTestSrid() + ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -924,7 +1029,9 @@ public void y(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getY(); String hql = format( "SELECT id, y(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where geometrytype(geom) in ('ST_Point') and srid(geom) = %d", - pckg, expectationsFactory.getTestSrid() ); + pckg, + expectationsFactory.getTestSrid() + ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -942,7 +1049,8 @@ public void ymax(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getYMax(); String hql = format( "SELECT id, ymax(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where srid(geom) = %d", - pckg, expectationsFactory.getTestSrid() ); + pckg, expectationsFactory.getTestSrid() + ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -960,7 +1068,8 @@ public void ymin(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getYMin(); String hql = format( "SELECT id, ymin(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where srid(geom) = %d", - pckg, expectationsFactory.getTestSrid() ); + pckg, expectationsFactory.getTestSrid() + ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -978,7 +1087,9 @@ public void z(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getZ(); String hql = format( "SELECT id, z(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where geometrytype(geom) in ('ST_Point') and srid(geom) = %d", - pckg, expectationsFactory.getTestSrid() ); + pckg, + expectationsFactory.getTestSrid() + ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -996,7 +1107,8 @@ public void zmax(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getZMax(); String hql = format( "SELECT id, zmax(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where srid(geom) = %d", - pckg, expectationsFactory.getTestSrid() ); + pckg, expectationsFactory.getTestSrid() + ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -1014,7 +1126,8 @@ public void zmin(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getZMin(); String hql = format( "SELECT id, zmin(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where srid(geom) = %d", - pckg, expectationsFactory.getTestSrid() ); + pckg, expectationsFactory.getTestSrid() + ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -1032,14 +1145,16 @@ public void nestedfunction(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getNestedFunctionInner( expectationsFactory.getTestPolygon() ); String hql = format( "SELECT id, geom FROM org.hibernate.spatial.integration.%s.GeomEntity g where dwithin(geom, srid(:filter, 0), 1) = true", - pckg ); + pckg + ); Map params = createQueryParams( "filter", expectationsFactory.getTestPolygon() ); retrieveHQLResultsAndCompare( dbexpected, hql, params, pckg ); - + dbexpected = hanaExpectationsFactory.getNestedFunctionOuter( expectationsFactory.getTestPolygon() ); hql = format( "SELECT id, geom FROM org.hibernate.spatial.integration.%s.GeomEntity g where dwithin(:filter, srid(geom, 0), 1) = true", - pckg ); + pckg + ); retrieveHQLResultsAndCompare( dbexpected, hql, params, pckg ); } diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/postgis/PostgisUnmarshalTest.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/postgis/PostgisUnmarshalTest.java index 2cabdd06c975..811ef756d912 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/postgis/PostgisUnmarshalTest.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/postgis/PostgisUnmarshalTest.java @@ -32,9 +32,9 @@ */ public class PostgisUnmarshalTest { - private CoordinateReferenceSystem crs = CoordinateReferenceSystems.WGS84; - private Geometry geom = linestring( crs, g( 6.123, 53.234 ), g( 6.133, 53.244 ) ); - private Geometry geomNoSrid = linestring( + private final CoordinateReferenceSystem crs = CoordinateReferenceSystems.WGS84; + private final Geometry geom = linestring( crs, g( 6.123, 53.234 ), g( 6.133, 53.244 ) ); + private final Geometry geomNoSrid = linestring( CoordinateReferenceSystems.PROJECTED_2D_METER, c( 6.123, 53.234 ), c( 6.133, 53.244 ) diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/AbstractTestStoreRetrieve.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/AbstractTestStoreRetrieve.java index 5037e4f7b03c..165446473717 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/AbstractTestStoreRetrieve.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/AbstractTestStoreRetrieve.java @@ -1,3 +1,10 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ + package org.hibernate.spatial.integration; import java.util.HashMap; @@ -66,7 +73,7 @@ private void retrieveAndCompare(Map stored) { tx = session.beginTransaction(); for ( E storedEntity : stored.values() ) { id = storedEntity.getId(); - E retrievedEntity = (E) session.get( getGeomEntityClass(), id ); + E retrievedEntity = session.get( getGeomEntityClass(), id ); G retrievedGeometry = retrievedEntity.getGeom(); G storedGeometry = storedEntity.getGeom(); String msg = createFailureMessage( storedEntity.getId(), storedGeometry, retrievedGeometry ); @@ -110,7 +117,6 @@ private void storeTestObjects(Map stored) { for ( TestDataElement element : testData ) { id = element.id; tx = session.beginTransaction(); - ; E entity = createFrom( element, dialect ); stored.put( entity.getId(), entity ); session.save( entity ); diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/DecodeUtil.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/DecodeUtil.java index 2b13afa14227..c72b7c8e5126 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/DecodeUtil.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/DecodeUtil.java @@ -1,3 +1,10 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ + package org.hibernate.spatial.integration; import org.hibernate.dialect.AbstractHANADialect; diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/GeomEntityLike.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/GeomEntityLike.java index ead7b4e12666..53b907ac2aba 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/GeomEntityLike.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/GeomEntityLike.java @@ -1,3 +1,10 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ + package org.hibernate.spatial.integration; /** diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/TestGeolatteSpatialPredicates.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/TestGeolatteSpatialPredicates.java index 6163de1b5bcd..777d7c299538 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/TestGeolatteSpatialPredicates.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/TestGeolatteSpatialPredicates.java @@ -41,7 +41,7 @@ @SkipForDialect(value = HANASpatialDialect.class, comment = "The HANA dialect is tested via org.hibernate.spatial.dialect.hana.TestHANASpatialFunctions", jiraKey = "HHH-12426") public class TestGeolatteSpatialPredicates extends SpatialFunctionalTestCase { - private static HSMessageLogger LOG = Logger.getMessageLogger( + private static final HSMessageLogger LOG = Logger.getMessageLogger( HSMessageLogger.class, TestGeolatteSpatialPredicates.class.getName() ); diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/TestJTSSpatialPredicates.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/TestJTSSpatialPredicates.java index 50d8f8c0ff5a..480b20e72dd5 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/TestJTSSpatialPredicates.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/TestJTSSpatialPredicates.java @@ -41,7 +41,7 @@ @SkipForDialect(value = HANASpatialDialect.class, comment = "The HANA dialect is tested via org.hibernate.spatial.dialect.hana.TestHANASpatialFunctions", jiraKey = "HHH-12426") public class TestJTSSpatialPredicates extends SpatialFunctionalTestCase { - private static HSMessageLogger LOG = Logger.getMessageLogger( + private static final HSMessageLogger LOG = Logger.getMessageLogger( HSMessageLogger.class, TestJTSSpatialPredicates.class.getName() ); diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/TestSpatialFunctions.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/TestSpatialFunctions.java index e51df68ee88c..cccabd0419bc 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/TestSpatialFunctions.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/TestSpatialFunctions.java @@ -473,7 +473,9 @@ public void distance(String pckg) throws SQLException { } Map dbexpected = expectationsFactory.getDistance( expectationsFactory.getTestPolygon() ); String hql = format( - "SELECT id, distance(geom, :filter) from %s where srid(geom) = %d", entityName( pckg ), expectationsFactory.getTestSrid() + "SELECT id, distance(geom, :filter) from %s where srid(geom) = %d", + entityName( pckg ), + expectationsFactory.getTestSrid() ); Map params = createQueryParams( "filter", expectationsFactory.getTestPolygon() ); retrieveHQLResultsAndCompare( dbexpected, hql, params, pckg ); diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/TestSpatialRestrictions.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/TestSpatialRestrictions.java index c82c16a650ff..dc3c2b567a1e 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/TestSpatialRestrictions.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/TestSpatialRestrictions.java @@ -9,6 +9,7 @@ import java.sql.SQLException; import java.util.List; +import java.util.Locale; import java.util.Map; import org.hibernate.Criteria; @@ -36,7 +37,7 @@ @SkipForDialect(value = HANASpatialDialect.class, comment = "The HANA dialect is tested via org.hibernate.spatial.dialect.hana.TestHANASpatialFunctions", jiraKey = "HHH-12426") public class TestSpatialRestrictions extends SpatialFunctionalTestCase { - private static HSMessageLogger LOG = Logger.getMessageLogger( + private static final HSMessageLogger LOG = Logger.getMessageLogger( HSMessageLogger.class, TestSpatialRestrictions.class.getName() ); @@ -208,7 +209,11 @@ private void compare(Map dbexpected, List list) { if ( entry.getValue() ) { cnt++; if ( !findInList( entry.getKey(), (List) list ) ) { - fail( String.format( "Expected object with id= %d, but not found in result", entry.getKey() ) ); + fail( String.format( + Locale.ENGLISH, + "Expected object with id= %d, but not found in result", + entry.getKey() + ) ); } } } diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/geolatte/GeomEntity.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/geolatte/GeomEntity.java index 6e10b6d2c2aa..cfb09b46a6a0 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/geolatte/GeomEntity.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/geolatte/GeomEntity.java @@ -88,11 +88,7 @@ public boolean equals(Object o) { GeomEntity geomEntity = (GeomEntity) o; - if ( !id.equals( geomEntity.id ) ) { - return false; - } - - return true; + return id.equals( geomEntity.id ); } @Override diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/geolatte/TestStoreRetrieveUsingGeolatte.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/geolatte/TestStoreRetrieveUsingGeolatte.java index f2f14f5c878f..c9deb170cf36 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/geolatte/TestStoreRetrieveUsingGeolatte.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/geolatte/TestStoreRetrieveUsingGeolatte.java @@ -28,7 +28,7 @@ @Skip(condition = SpatialDialectMatcher.class, message = "No Spatial Dialect") public class TestStoreRetrieveUsingGeolatte extends AbstractTestStoreRetrieve { - private static HSMessageLogger LOG = Logger.getMessageLogger( + private static final HSMessageLogger LOG = Logger.getMessageLogger( HSMessageLogger.class, TestStoreRetrieveUsingGeolatte.class.getName() ); diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/jts/JtsGeomEntity.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/jts/JtsGeomEntity.java index 5e25e1a459d3..13abdc3338c3 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/jts/JtsGeomEntity.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/jts/JtsGeomEntity.java @@ -82,11 +82,7 @@ public boolean equals(Object o) { JtsGeomEntity geomEntity = (JtsGeomEntity) o; - if ( !id.equals( geomEntity.id ) ) { - return false; - } - - return true; + return id.equals( geomEntity.id ); } @Override diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/AbstractExpectationsFactory.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/AbstractExpectationsFactory.java index 7753de9167bb..fbaca2308f1f 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/AbstractExpectationsFactory.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/AbstractExpectationsFactory.java @@ -793,24 +793,22 @@ protected Map retrieveExpected(NativeSQLStatement nativeSQLState case STRING: expected.put( id, (T) results.getString( 2 ) ); break; - case INTEGER: - { - Long value = Long.valueOf( results.getLong( 2 ) ); - if ( results.wasNull() ) { - value = null; // This is required because the Hibernate BasicExtractor also checks ResultSet#wasNull which can lead to a mismatch between the expected and the actual results - } - expected.put( id, (T) value ); + case INTEGER: { + Long value = Long.valueOf( results.getLong( 2 ) ); + if ( results.wasNull() ) { + value = null; // This is required because the Hibernate BasicExtractor also checks ResultSet#wasNull which can lead to a mismatch between the expected and the actual results } + expected.put( id, (T) value ); + } break; - case DOUBLE: - { - Double value = Double.valueOf( results.getDouble( 2 ) ); - if ( results.wasNull() ) { - value = null; //this is required because SQL Server converts automatically null to 0.0 - } - expected.put( id, (T) value ); + case DOUBLE: { + Double value = Double.valueOf( results.getDouble( 2 ) ); + if ( results.wasNull() ) { + value = null; //this is required because SQL Server converts automatically null to 0.0 } - break; + expected.put( id, (T) value ); + } + break; case BOOLEAN: expected.put( id, (T) Boolean.valueOf( results.getBoolean( 2 ) ) ); break; diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/DataSourceUtils.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/DataSourceUtils.java index f6ead580e222..fb3d6f8e49cf 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/DataSourceUtils.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/DataSourceUtils.java @@ -14,6 +14,7 @@ import java.io.InputStreamReader; import java.io.StringWriter; import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -42,7 +43,7 @@ public class DataSourceUtils { - private static HSMessageLogger LOG = Logger.getMessageLogger( + private static final HSMessageLogger LOG = Logger.getMessageLogger( HSMessageLogger.class, DataSourceUtils.class.getName() ); @@ -257,7 +258,7 @@ public String parseSqlIn(String fileName) throws IOException { BufferedReader reader = null; try { reader = new BufferedReader( - new InputStreamReader( is, Charset.forName( "UTF-8" ) ) + new InputStreamReader( is, StandardCharsets.UTF_8 ) ); StringWriter sw = new StringWriter(); diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/GeolatteGeometryEquality.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/GeolatteGeometryEquality.java index 3b58d2aea1b6..4060b20d3ede 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/GeolatteGeometryEquality.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/GeolatteGeometryEquality.java @@ -1,3 +1,10 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ + package org.hibernate.spatial.testing; import org.geolatte.geom.Geometry; diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/GeometryEquality.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/GeometryEquality.java index 92003fad5205..e32cbf19c167 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/GeometryEquality.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/GeometryEquality.java @@ -1,3 +1,10 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ + package org.hibernate.spatial.testing; /** diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/NativeSQLStatement.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/NativeSQLStatement.java index ab8e0aa886c9..d33b122a6e75 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/NativeSQLStatement.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/NativeSQLStatement.java @@ -29,7 +29,7 @@ public interface NativeSQLStatement { * * @throws SQLException */ - public PreparedStatement prepare(Connection connection) throws SQLException; + PreparedStatement prepare(Connection connection) throws SQLException; - public String toString(); + String toString(); } diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/SQLExpressionTemplate.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/SQLExpressionTemplate.java index d15d2dd5584e..4bfd3a180056 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/SQLExpressionTemplate.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/SQLExpressionTemplate.java @@ -22,6 +22,6 @@ public interface SQLExpressionTemplate { * * @return an insert SQL for testDataElement */ - public String toInsertSql(TestDataElement testDataElement); + String toInsertSql(TestDataElement testDataElement); } diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/SpatialFunctionalTestCase.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/SpatialFunctionalTestCase.java index 48a4a9751c6c..7c15817e9636 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/SpatialFunctionalTestCase.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/SpatialFunctionalTestCase.java @@ -75,7 +75,7 @@ private void cleanUpTest(String pckg) { try { session = openSession(); tx = session.beginTransaction(); - String hql = String.format( "delete from %s", entityName(pckg) ); + String hql = String.format( "delete from %s", entityName( pckg ) ); Query q = session.createQuery( hql ); q.executeUpdate(); tx.commit(); @@ -238,7 +238,7 @@ else if ( expected instanceof Geometry ) { "Failure on testsuite-suite for case " + id, geometryEquality.test( (Geometry) expected, - (Geometry) org.geolatte.geom.jts.JTS.to( (org.geolatte.geom.Geometry) received ) + org.geolatte.geom.jts.JTS.to( (org.geolatte.geom.Geometry) received ) ) ); } @@ -255,9 +255,10 @@ else if ( expected instanceof Geometry ) { } protected String entityName(String pckg) { - if (JTS.equalsIgnoreCase( pckg )) { + if ( JTS.equalsIgnoreCase( pckg ) ) { return "org.hibernate.spatial.integration.jts.JtsGeomEntity"; - } else { + } + else { return "org.hibernate.spatial.integration.geolatte.GeomEntity"; } } diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/TestData.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/TestData.java index 6590ebf5d8ee..bf9fb65c280d 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/TestData.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/TestData.java @@ -26,8 +26,6 @@ public class TestData implements List { protected TestData() { } - ; - public static TestData fromFile(String fileName) { TestDataReader reader = new TestDataReader(); return fromFile( fileName, reader ); diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/TestSupportFactories.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/TestSupportFactories.java index d8fab275b25b..7ed693440b47 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/TestSupportFactories.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/TestSupportFactories.java @@ -27,7 +27,7 @@ */ public class TestSupportFactories { - private static TestSupportFactories instance = new TestSupportFactories(); + private static final TestSupportFactories instance = new TestSupportFactories(); private TestSupportFactories() { } diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/converter/GeometryConverter.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/converter/GeometryConverter.java index b1f566b6ed25..8383c2459c82 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/converter/GeometryConverter.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/converter/GeometryConverter.java @@ -16,8 +16,8 @@ /** * @author Steve Ebersole */ -@Converter( autoApply = true ) -public class GeometryConverter implements AttributeConverter { +@Converter(autoApply = true) +public class GeometryConverter implements AttributeConverter { @Override public byte[] convertToDatabaseColumn(Geometry attribute) { if ( attribute == null ) { diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/converter/GeometryConverterTest.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/converter/GeometryConverterTest.java index 875171126983..549d23c7fa9c 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/converter/GeometryConverterTest.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/converter/GeometryConverterTest.java @@ -36,17 +36,17 @@ public class GeometryConverterTest extends BaseUnitTestCase { @Test public void testConverterUsage() { - try ( final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder() + try (final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder() .applySetting( AvailableSettings.DIALECT, GeoDBDialect.class ) .applySetting( AvailableSettings.HBM2DDL_AUTO, Action.CREATE_DROP ) - .build() ) { + .build()) { final MetadataSources metadataSources = new MetadataSources( ssr ) .addAnnotatedClass( GeometryConverter.class ) .addAnnotatedClass( MyEntity.class ); final MetadataBuilderImplementor metadataBuilder = (MetadataBuilderImplementor) metadataSources.getMetadataBuilder(); - try ( final SessionFactoryImplementor sessionFactory = - (SessionFactoryImplementor) metadataBuilder.build().buildSessionFactory() ) { + try (final SessionFactoryImplementor sessionFactory = (SessionFactoryImplementor) metadataBuilder.build() + .buildSessionFactory()) { final TypeConfiguration typeConfiguration = sessionFactory.getMetamodel().getTypeConfiguration(); diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/converter/MyEntity.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/converter/MyEntity.java index 2fbb21389094..61d9e14ebb4e 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/converter/MyEntity.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/converter/MyEntity.java @@ -17,7 +17,7 @@ * @author Steve Ebersole */ @Entity -@Table( name = "SP_CUST_TYPE_CONV_ENTITY") +@Table(name = "SP_CUST_TYPE_CONV_ENTITY") public class MyEntity { private Integer id; private Geometry geometry; diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/db2/DB2DataSourceUtils.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/db2/DB2DataSourceUtils.java index 2984cabe14b4..482c1a72c030 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/db2/DB2DataSourceUtils.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/db2/DB2DataSourceUtils.java @@ -1,24 +1,9 @@ /* - * This file is part of Hibernate Spatial, an extension to the - * hibernate ORM solution for spatial (geographic) data. + * Hibernate, Relational Persistence for Idiomatic Java * - * Copyright © 2014 Adtech Geospatial - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . */ - package org.hibernate.spatial.testing.dialects.db2; import java.sql.SQLException; diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/db2/DB2ExpectationsFactory.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/db2/DB2ExpectationsFactory.java index 99185d223c5d..dc2ad910b685 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/db2/DB2ExpectationsFactory.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/db2/DB2ExpectationsFactory.java @@ -1,24 +1,9 @@ /* - * This file is part of Hibernate Spatial, an extension to the - * hibernate ORM solution for spatial (geographic) data. + * Hibernate, Relational Persistence for Idiomatic Java * - * Copyright © 2014 Adtech Geospatial - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . */ - package org.hibernate.spatial.testing.dialects.db2; import java.sql.SQLException; diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/db2/DB2ExpressionTemplate.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/db2/DB2ExpressionTemplate.java index 7fd484e8c863..b9a5b1d92762 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/db2/DB2ExpressionTemplate.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/db2/DB2ExpressionTemplate.java @@ -1,24 +1,9 @@ /* - * This file is part of Hibernate Spatial, an extension to the - * hibernate ORM solution for spatial (geographic) data. + * Hibernate, Relational Persistence for Idiomatic Java * - * Copyright © 2014 Adtech Geospatial - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . */ - package org.hibernate.spatial.testing.dialects.db2; import org.hibernate.spatial.testing.SQLExpressionTemplate; diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/db2/DB2TestSupport.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/db2/DB2TestSupport.java index b8221fdd43dd..d3a40692c220 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/db2/DB2TestSupport.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/db2/DB2TestSupport.java @@ -1,22 +1,8 @@ /* - * This file is part of Hibernate Spatial, an extension to the - * hibernate ORM solution for spatial (geographic) data. + * Hibernate, Relational Persistence for Idiomatic Java * - * Copyright © 2014 Adtech Geospatial - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library 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 library; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . */ package org.hibernate.spatial.testing.dialects.db2; @@ -35,8 +21,8 @@ public class DB2TestSupport extends TestSupport { public TestData createTestData(BaseCoreFunctionalTestCase testcase) { - if ( "org.hibernate.spatial.integration.TestSpatialFunctions".equals( testcase.getClass() - .getCanonicalName() ) ) { + if ( "org.hibernate.spatial.integration.TestSpatialFunctions".equals( + testcase.getClass().getCanonicalName() ) ) { return TestData.fromFile( "db2/test-db2nozm-only-polygon.xml" ); } return TestData.fromFile( "db2/test-db2nozm-data-set.xml" ); diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/h2geodb/GeoDBDataSourceUtils.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/h2geodb/GeoDBDataSourceUtils.java index f114bcd598b5..e00e7449885b 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/h2geodb/GeoDBDataSourceUtils.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/h2geodb/GeoDBDataSourceUtils.java @@ -44,7 +44,7 @@ private void initGeoDB(Connection conn) { String errorMsg = "Problem initializing GeoDB."; try { Class geoDB = Thread.currentThread().getContextClassLoader().loadClass( "geodb.GeoDB" ); - Method m = geoDB.getDeclaredMethod( "InitGeoDB", new Class[] { Connection.class } ); + Method m = geoDB.getDeclaredMethod( "InitGeoDB", Connection.class ); m.invoke( null, conn ); } catch (ClassNotFoundException e) { diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/hana/HANAExpectationsFactory.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/hana/HANAExpectationsFactory.java index f305127bca4f..9e87081545c6 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/hana/HANAExpectationsFactory.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/hana/HANAExpectationsFactory.java @@ -38,7 +38,8 @@ protected NativeSQLStatement createNativeDimensionSQL() { protected NativeSQLStatement createNativeBufferStatement(Double distance) { return createNativeSQLStatement( "select t.id, t.geom.ST_Buffer(?) from GeomTest t where t.geom.ST_SRID() = " + getTestSrid(), - new Object[]{ distance } ); + new Object[] { distance } + ); } @Override @@ -46,7 +47,8 @@ protected NativeSQLStatement createNativeConvexHullStatement(Geometry geom) { return createNativeSQLStatementAllWKTParams( "select t.id, t.geom.ST_Union(ST_GeomFromText(?, " + getTestSrid() + ")).ST_ConvexHull().ST_AsEWKB() from GeomTest t where t.geom.ST_SRID() = " + getTestSrid(), - geom.toText() ); + geom.toText() + ); } @Override @@ -54,7 +56,8 @@ protected NativeSQLStatement createNativeIntersectionStatement(Geometry geom) { return createNativeSQLStatementAllWKTParams( "select t.id, t.geom.ST_Intersection(ST_GeomFromText(?, " + getTestSrid() + ")).ST_AsEWKB() from GeomTest t where t.geom.ST_SRID() = " + getTestSrid(), - geom.toText() ); + geom.toText() + ); } @Override @@ -62,7 +65,8 @@ protected NativeSQLStatement createNativeDifferenceStatement(Geometry geom) { return createNativeSQLStatementAllWKTParams( "select t.id, t.geom.ST_Difference(ST_GeomFromText(?, " + getTestSrid() + ")).ST_AsEWKB() from GeomTest t where t.geom.ST_SRID() = " + getTestSrid(), - geom.toText() ); + geom.toText() + ); } @Override @@ -70,14 +74,16 @@ protected NativeSQLStatement createNativeSymDifferenceStatement(Geometry geom) { return createNativeSQLStatementAllWKTParams( "select t.id, t.geom.ST_SymDifference(ST_GeomFromText(?, " + getTestSrid() + ")).ST_AsEWKB() from GeomTest t where t.geom.ST_SRID() = " + getTestSrid(), - geom.toText() ); + geom.toText() + ); } @Override protected NativeSQLStatement createNativeGeomUnionStatement(Geometry geom) { return createNativeSQLStatementAllWKTParams( "select t.id, t.geom.ST_Union(ST_GeomFromText(?, " + getTestSrid() + ")).ST_AsEWKB() from GeomTest t where t.geom.ST_SRID() = " + getTestSrid(), - geom.toText() ); + geom.toText() + ); } @Override @@ -138,7 +144,8 @@ protected NativeSQLStatement createNativeWithinStatement(Geometry geom) { return createNativeSQLStatementAllWKTParams( "select t.id, t.geom.ST_Within(ST_GeomFromText(?, " + getTestSrid() + ")) from GeomTest t where t.geom.ST_Within(ST_GeomFromText(?, " + getTestSrid() + ")) = 1 and t.geom.ST_SRID() = " + getTestSrid(), - geom.toText() ); + geom.toText() + ); } @Override @@ -146,7 +153,8 @@ protected NativeSQLStatement createNativeEqualsStatement(Geometry geom) { return createNativeSQLStatementAllWKTParams( "select t.id, t.geom.ST_Equals(ST_GeomFromText(?, " + getTestSrid() + ")) from GeomTest t where t.geom.ST_Equals(ST_GeomFromText(?, " + getTestSrid() + ")) = 1 and t.geom.ST_SRID() = " + getTestSrid(), - geom.toText() ); + geom.toText() + ); } @Override @@ -154,7 +162,8 @@ protected NativeSQLStatement createNativeCrossesStatement(Geometry geom) { return createNativeSQLStatementAllWKTParams( "select t.id, t.geom.ST_Crosses(ST_GeomFromText(?, " + getTestSrid() + ")) from GeomTest t where t.geom.ST_Crosses(ST_GeomFromText(?, " + getTestSrid() + ")) = 1 and t.geom.ST_SRID() = " + getTestSrid(), - geom.toText() ); + geom.toText() + ); } @Override @@ -162,7 +171,8 @@ protected NativeSQLStatement createNativeContainsStatement(Geometry geom) { return createNativeSQLStatementAllWKTParams( "select t.id, t.geom.ST_Contains(ST_GeomFromText(?, " + getTestSrid() + ")) from GeomTest t where t.geom.ST_Contains(ST_GeomFromText(?, " + getTestSrid() + ")) = 1 and t.geom.ST_SRID() = " + getTestSrid(), - geom.toText() ); + geom.toText() + ); } @Override @@ -170,7 +180,8 @@ protected NativeSQLStatement createNativeDisjointStatement(Geometry geom) { return createNativeSQLStatementAllWKTParams( "select t.id, t.geom.ST_Disjoint(ST_GeomFromText(?, " + getTestSrid() + ")) from GeomTest t where t.geom.ST_Disjoint(ST_GeomFromText(?, " + getTestSrid() + ")) = 1 and t.geom.ST_SRID() = " + getTestSrid(), - geom.toText() ); + geom.toText() + ); } @Override @@ -189,7 +200,8 @@ protected NativeSQLStatement createNativeIntersectsStatement(Geometry geom) { return createNativeSQLStatementAllWKTParams( "select t.id, t.geom.ST_Intersects(ST_GeomFromText(?, " + getTestSrid() + ")) from GeomTest t where t.geom.ST_Intersects(ST_GeomFromText(?, " + getTestSrid() + ")) = 1 and t.geom.ST_SRID() = " + getTestSrid(), - geom.toText() ); + geom.toText() + ); } @Override @@ -198,7 +210,8 @@ protected NativeSQLStatement createNativeFilterStatement(Geometry geom) { "select t.id, t.geom.ST_IntersectsFilter(ST_GeomFromText(?, " + getTestSrid() + ")) from GeomTest t where t.geom.ST_IntersectsFilter(ST_GeomFromText(?, " + getTestSrid() + ")) = 1 and t.geom.ST_SRID() = " + getTestSrid(), - geom.toText() ); + geom.toText() + ); } @Override @@ -206,7 +219,8 @@ protected NativeSQLStatement createNativeTouchesStatement(Geometry geom) { return createNativeSQLStatementAllWKTParams( "select t.id, t.geom.ST_Touches(ST_GeomFromText(?, " + getTestSrid() + ")) from GeomTest t where t.geom.ST_Touches(ST_GeomFromText(?, " + getTestSrid() + ")) = 1 and t.geom.ST_SRID() = " + getTestSrid(), - geom.toText() ); + geom.toText() + ); } @Override @@ -214,7 +228,8 @@ protected NativeSQLStatement createNativeOverlapsStatement(Geometry geom) { return createNativeSQLStatementAllWKTParams( "select t.id, t.geom.ST_Overlaps(ST_GeomFromText(?, " + getTestSrid() + ")) from GeomTest t where t.geom.ST_Overlaps(ST_GeomFromText(?, " + getTestSrid() + ")) = 1 and t.geom.ST_SRID() = " + getTestSrid(), - geom.toText() ); + geom.toText() + ); } @Override @@ -231,14 +246,16 @@ protected NativeSQLStatement createNativeDwithinStatement(Point geom, double dis "select t.id, t.geom.ST_WithinDistance(ST_GeomFromText(?, " + getTestSrid() + "), " + distance + ") from GeomTest t where t.geom.ST_WithinDistance(ST_GeomFromText(?, " + getTestSrid() + "), " + distance + ") = 1 and t.geom.ST_SRID() = " + getTestSrid(), - geom.toText() ); + geom.toText() + ); } @Override protected NativeSQLStatement createNativeDistanceStatement(Geometry geom) { return createNativeSQLStatementAllWKTParams( "select t.id, t.geom.ST_Distance(ST_GeomFromText(?, " + getTestSrid() + ")) from GeomTest t where t.geom.ST_SRID() = " + getTestSrid(), - geom.toText() ); + geom.toText() + ); } @Override @@ -263,6 +280,7 @@ public int getTestSrid() { * Returns the expected alpha shapes of all testsuite-suite geometries. * * @return map of identifier, alpha shape + * * @throws SQLException */ public Map getAlphaShape(double radius) throws SQLException { @@ -272,13 +290,15 @@ public Map getAlphaShape(double radius) throws SQLException { private NativeSQLStatement createNativeAlphaShapeStatement(double radius) { return createNativeSQLStatement( "select t.id, t.geom.ST_AlphaShape(?).ST_AsEWKB() from GeomTest t where t.geom.ST_GeometryType() in ('ST_Point', 'ST_MultiPoint')", - new Object[]{ radius } ); + new Object[] { radius } + ); } /** * Returns the expected area of all testsuite-suite geometries. * * @return map of identifier, area + * * @throws SQLException */ public Map getArea() throws SQLException { @@ -286,13 +306,15 @@ public Map getArea() throws SQLException { } private NativeSQLStatement createNativeAreaStatement() { - return createNativeSQLStatement( "select t.id, t.geom.ST_Area() from GeomTest t where t.geom.ST_GeometryType() in ('ST_Polygon', 'ST_MultiPolygon')" ); + return createNativeSQLStatement( + "select t.id, t.geom.ST_Area() from GeomTest t where t.geom.ST_GeometryType() in ('ST_Polygon', 'ST_MultiPolygon')" ); } /** * Returns the expected EWKB representation of all testsuite-suite geometries. * * @return map of identifier, EWKB + * * @throws SQLException */ public Map getAsEWKB() throws SQLException { @@ -307,6 +329,7 @@ private NativeSQLStatement createNativeAsEWKBStatement() { * Returns the expected EWKT representation of all testsuite-suite geometries. * * @return map of identifier, EWKT + * * @throws SQLException */ public Map getAsEWKT() throws SQLException { @@ -321,6 +344,7 @@ private NativeSQLStatement createNativeAsEWKTStatement() { * Returns the expected GeoJSON representation of all testsuite-suite geometries. * * @return map of identifier, GeoJSON + * * @throws SQLException */ public Map getAsGeoJSON() throws SQLException { @@ -335,6 +359,7 @@ private NativeSQLStatement createNativeAsGeoJSONStatement() { * Returns the expected SVG representation of all testsuite-suite geometries. * * @return map of identifier, SVG + * * @throws SQLException */ public Map getAsSVG() throws SQLException { @@ -349,6 +374,7 @@ private NativeSQLStatement createNativeAsSVGStatement() { * Returns the expected aggregated SVG representation of all testsuite-suite geometries. * * @return map of count, SVG + * * @throws SQLException */ public Map getAsSVGAggr() throws SQLException { @@ -363,6 +389,7 @@ private NativeSQLStatement createNativeAsSVGAggrStatement() { * Returns the expected WKB representation of all testsuite-suite geometries. * * @return map of identifier, WKB + * * @throws SQLException */ public Map getAsWKB() throws SQLException { @@ -377,6 +404,7 @@ private NativeSQLStatement createNativeAsWKBStatement() { * Returns the expected WKT representation of all testsuite-suite geometries. * * @return map of identifier, WKT + * * @throws SQLException */ public Map getAsWKT() throws SQLException { @@ -391,6 +419,7 @@ private NativeSQLStatement createNativeAsWKTStatement() { * Returns the expected centroid of all testsuite-suite geometries. * * @return map of id, centroid + * * @throws SQLException */ public Map getCentroid() throws SQLException { @@ -398,13 +427,15 @@ public Map getCentroid() throws SQLException { } private NativeSQLStatement createNativeCentroidStatement() { - return createNativeSQLStatement( "select id, t.geom.ST_Centroid() from GeomTest t where t.geom.ST_GeometryType() = 'ST_Polygon'" ); + return createNativeSQLStatement( + "select id, t.geom.ST_Centroid() from GeomTest t where t.geom.ST_GeometryType() = 'ST_Polygon'" ); } /** * Returns the expected aggregated convex hull representation of all testsuite-suite geometries. * * @return map of count, convex hull + * * @throws SQLException */ public Map getConvexHullAggr() throws SQLException { @@ -419,6 +450,7 @@ private NativeSQLStatement createNativeConvexHullAggrStatement() { * Returns the expected number of coordinate dimensions of all testsuite-suite geometries. * * @return map of identifier, coordinate dimension + * * @throws SQLException */ public Map getCoordDim() throws SQLException { @@ -433,6 +465,7 @@ private NativeSQLStatement createNativeCoordDimStatement() { * Returns the testsuite-suite geometries that are covered by the given geometry. * * @return map of identifier, whether the geometry is covered + * * @throws SQLException */ public Map getCoveredBy(Geometry geom) throws SQLException { @@ -443,13 +476,15 @@ private NativeSQLStatement createNativeCoveredByStatement(Geometry geom) { return createNativeSQLStatementAllWKTParams( "select t.id, t.geom.ST_CoveredBy(ST_GeomFromText(?, " + getTestSrid() + ")) from GeomTest t where t.geom.ST_CoveredBy(ST_GeomFromText(?, " + getTestSrid() + ")) = 1 and t.geom.ST_SRID() = " + getTestSrid(), - geom.toText() ); + geom.toText() + ); } /** * Returns the testsuite-suite geometries that are cover the given geometry. * * @return map of identifier, whether the geometry covers the given geometry + * * @throws SQLException */ public Map getCovers(Geometry geom) throws SQLException { @@ -460,13 +495,15 @@ private NativeSQLStatement createNativeCoversStatement(Geometry geom) { return createNativeSQLStatementAllWKTParams( "select t.id, t.geom.ST_Covers(ST_GeomFromText(?, " + getTestSrid() + ")) from GeomTest t where t.geom.ST_Covers(ST_GeomFromText(?, " + getTestSrid() + ")) = 1 and t.geom.ST_SRID() = " + getTestSrid(), - geom.toText() ); + geom.toText() + ); } /** * Returns the expected endpoint of all testsuite-suite geometries. * * @return map of id, endpoint + * * @throws SQLException */ public Map getEndPoint() throws SQLException { @@ -474,13 +511,15 @@ public Map getEndPoint() throws SQLException { } private NativeSQLStatement createNativeEndPointStatement() { - return createNativeSQLStatement( "select id, t.geom.ST_EndPoint() from GeomTest t where t.geom.ST_GeometryType() = 'ST_LineString'" ); + return createNativeSQLStatement( + "select id, t.geom.ST_EndPoint() from GeomTest t where t.geom.ST_GeometryType() = 'ST_LineString'" ); } /** * Returns the expected aggregated bounding rectangle of all testsuite-suite geometries. * * @return map of count, bounding rectangle + * * @throws SQLException */ public Map getEnvelopeAggr() throws SQLException { @@ -495,6 +534,7 @@ private NativeSQLStatement createNativeEnvelopeAggrStatement() { * Returns the expected exterior ring of all testsuite-suite geometries. * * @return map of id, exterior ring + * * @throws SQLException */ public Map getExteriorRing() throws SQLException { @@ -502,13 +542,15 @@ public Map getExteriorRing() throws SQLException { } private NativeSQLStatement createNativeExteriorRingStatement() { - return createNativeSQLStatement( "select id, t.geom.ST_ExteriorRing() from GeomTest t where t.geom.ST_GeometryType() = 'ST_Polygon'" ); + return createNativeSQLStatement( + "select id, t.geom.ST_ExteriorRing() from GeomTest t where t.geom.ST_GeometryType() = 'ST_Polygon'" ); } /** * Returns the geometry from an EWKB representation. * * @return map of id, geometry + * * @throws SQLException */ public Map getGeomFromEWKB(byte[] ewkb) throws SQLException { @@ -516,13 +558,14 @@ public Map getGeomFromEWKB(byte[] ewkb) throws SQLException { } private NativeSQLStatement createNativeGeomFromEWKBStatement(byte[] ewkb) { - return createNativeSQLStatement( "select 1, ST_GeomFromEWKB(?) from GeomTest t", new Object[]{ ewkb } ); + return createNativeSQLStatement( "select 1, ST_GeomFromEWKB(?) from GeomTest t", new Object[] { ewkb } ); } /** * Returns the geometry from an EWKT representation. * * @return map of id, geometry + * * @throws SQLException */ public Map getGeomFromEWKT(String ewkt) throws SQLException { @@ -530,13 +573,14 @@ public Map getGeomFromEWKT(String ewkt) throws SQLException { } private NativeSQLStatement createNativeGeomFromEWKTStatement(String ewkt) { - return createNativeSQLStatement( "select 1, ST_GeomFromEWKT(?) from GeomTest t", new Object[]{ ewkt } ); + return createNativeSQLStatement( "select 1, ST_GeomFromEWKT(?) from GeomTest t", new Object[] { ewkt } ); } /** * Returns the geometry from a text representation. * * @return map of id, geometry + * * @throws SQLException */ public Map getGeomFromText(String text) throws SQLException { @@ -544,13 +588,14 @@ public Map getGeomFromText(String text) throws SQLException { } private NativeSQLStatement createNativeGeomFromTextStatement(String text) { - return createNativeSQLStatement( "select 1, ST_GeomFromText(?) from GeomTest t", new Object[]{ text } ); + return createNativeSQLStatement( "select 1, ST_GeomFromText(?) from GeomTest t", new Object[] { text } ); } /** * Returns the geometry from a WKB representation. * * @return map of id, geometry + * * @throws SQLException */ public Map getGeomFromWKB(byte[] wkb) throws SQLException { @@ -558,13 +603,14 @@ public Map getGeomFromWKB(byte[] wkb) throws SQLException { } private NativeSQLStatement createNativeGeomFromWKBStatement(byte[] wkb) { - return createNativeSQLStatement( "select 1, ST_GeomFromWKB(?) from GeomTest t", new Object[]{ wkb } ); + return createNativeSQLStatement( "select 1, ST_GeomFromWKB(?) from GeomTest t", new Object[] { wkb } ); } /** * Returns the geometry from a WKT representation. * * @return map of id, geometry + * * @throws SQLException */ public Map getGeomFromWKT(String wkt) throws SQLException { @@ -572,13 +618,14 @@ public Map getGeomFromWKT(String wkt) throws SQLException { } private NativeSQLStatement createNativeGeomFromWKTStatement(String wkt) { - return createNativeSQLStatement( "select 1, ST_GeomFromWKT(?) from GeomTest t", new Object[]{ wkt } ); + return createNativeSQLStatement( "select 1, ST_GeomFromWKT(?) from GeomTest t", new Object[] { wkt } ); } /** * Returns the expected nth geometry of all testsuite-suite geometries. * * @return map of id, geometry + * * @throws SQLException */ public Map getGeometryN(int n) throws SQLException { @@ -586,14 +633,17 @@ public Map getGeometryN(int n) throws SQLException { } private NativeSQLStatement createNativeGeometryNStatement(int n) { - return createNativeSQLStatement( "select id, t.geom.ST_GeometryN(?) from GeomTest t where t.geom.ST_GeometryType() = 'ST_GeometryCollection'", - new Object[]{ n } ); + return createNativeSQLStatement( + "select id, t.geom.ST_GeometryN(?) from GeomTest t where t.geom.ST_GeometryType() = 'ST_GeometryCollection'", + new Object[] { n } + ); } /** * Returns the expected nth interior ring of all testsuite-suite geometries. * * @return map of id, interior ring + * * @throws SQLException */ public Map getInteriorRingN(int n) throws SQLException { @@ -601,14 +651,17 @@ public Map getInteriorRingN(int n) throws SQLException { } private NativeSQLStatement createNativeInteriorRingNStatement(int n) { - return createNativeSQLStatement( "select id, t.geom.ST_InteriorRingN(?) from GeomTest t where t.geom.ST_GeometryType() = 'ST_Polygon'", - new Object[]{ n } ); + return createNativeSQLStatement( + "select id, t.geom.ST_InteriorRingN(?) from GeomTest t where t.geom.ST_GeometryType() = 'ST_Polygon'", + new Object[] { n } + ); } /** * Returns the expected aggregated intersection of all testsuite-suite geometries. * * @return map of count, intersection + * * @throws SQLException */ public Map getIntersectionAggr() throws SQLException { @@ -623,6 +676,7 @@ private NativeSQLStatement createNativeIntersectionAggrStatement() { * Returns the testsuite-suite geometries that intersect the given rectangle. * * @return map of identifier, whether the geometry intersects the given rectangle + * * @throws SQLException */ public Map getIntersectsRect(Point pmin, Point pmax) throws SQLException { @@ -634,13 +688,15 @@ private NativeSQLStatement createNativeIntersectsRectStatement(Point pmin, Point "select t.id, t.geom.ST_IntersectsRect(ST_GeomFromText(?, " + getTestSrid() + "), ST_GeomFromText(?, " + getTestSrid() + ")) from GeomTest t where t.geom.ST_IntersectsRect(ST_GeomFromText(?, " + getTestSrid() + "), ST_GeomFromText(?, " + getTestSrid() + ")) = 1 and t.geom.ST_SRID() = " + getTestSrid(), - new Object[]{ pmin.toText(), pmax.toText(), pmin.toText(), pmax.toText() } ); + new Object[] { pmin.toText(), pmax.toText(), pmin.toText(), pmax.toText() } + ); } /** * Returns the testsuite-suite geometries that are 3D geometries. * * @return map of identifier, whether the geometry is 3D + * * @throws SQLException */ public Map getIs3D() throws SQLException { @@ -656,6 +712,7 @@ private NativeSQLStatement createNativeIs3DStatement() { * Returns the testsuite-suite geometries that are closed. * * @return map of identifier, whether the geometry is closed + * * @throws SQLException */ public Map getIsClosed() throws SQLException { @@ -672,6 +729,7 @@ private NativeSQLStatement createNativeIsClosedStatement() { * Returns the testsuite-suite geometries that are measured. * * @return map of identifier, whether the geometry is measured + * * @throws SQLException */ public Map getIsMeasured() throws SQLException { @@ -688,6 +746,7 @@ private NativeSQLStatement createNativeIsMeasuredStatement() { * Returns the testsuite-suite geometries that are rings. * * @return map of identifier, whether the geometry is a ring + * * @throws SQLException */ public Map getIsRing() throws SQLException { @@ -704,6 +763,7 @@ private NativeSQLStatement createNativeIsRingStatement() { * Returns the testsuite-suite geometries that are valid. * * @return map of identifier, whether the geometry is valid + * * @throws SQLException */ public Map getIsValid() throws SQLException { @@ -720,6 +780,7 @@ private NativeSQLStatement createNativeIsValidStatement() { * Returns the length of all testsuite-suite geometries. * * @return map of identifier, length + * * @throws SQLException */ public Map getLength() throws SQLException { @@ -736,6 +797,7 @@ private NativeSQLStatement createNativeLengthStatement() { * Returns the measure value of all testsuite-suite geometries. * * @return map of identifier, measure value + * * @throws SQLException */ public Map getM() throws SQLException { @@ -752,6 +814,7 @@ private NativeSQLStatement createNativeMStatement() { * Returns the maximum measure value of all testsuite-suite geometries. * * @return map of identifier, maximum measure value + * * @throws SQLException */ public Map getMMax() throws SQLException { @@ -768,6 +831,7 @@ private NativeSQLStatement createNativeMMaxStatement() { * Returns the minimum measure value of all testsuite-suite geometries. * * @return map of identifier, minimum measure value + * * @throws SQLException */ public Map getMMin() throws SQLException { @@ -784,6 +848,7 @@ private NativeSQLStatement createNativeMMinStatement() { * Returns the number of geometries of all testsuite-suite geometries. * * @return map of identifier, number of geometries + * * @throws SQLException */ public Map getNumGeometries() throws SQLException { @@ -800,6 +865,7 @@ private NativeSQLStatement createNativeNumGeometriesStatement() { * Returns the number of interior rings of all testsuite-suite geometries. * * @return map of identifier, number of interior rings + * * @throws SQLException */ public Map getNumInteriorRing() throws SQLException { @@ -816,6 +882,7 @@ private NativeSQLStatement createNativeNumInteriorRingStatement() { * Returns the number of interior rings of all testsuite-suite geometries. * * @return map of identifier, number of interior rings + * * @throws SQLException */ public Map getNumInteriorRings() throws SQLException { @@ -832,6 +899,7 @@ private NativeSQLStatement createNativeNumInteriorRingsStatement() { * Returns the number of points of all testsuite-suite geometries. * * @return map of identifier, number of points + * * @throws SQLException */ public Map getNumPoints() throws SQLException { @@ -848,6 +916,7 @@ private NativeSQLStatement createNativeNumPointsStatement() { * Returns the testsuite-suite geometries that are equal. * * @return map of identifier, whether the geometry is equal + * * @throws SQLException */ public Map getOrderingEquals(Geometry geom) throws SQLException { @@ -858,13 +927,15 @@ private NativeSQLStatement createNativeOrderingEqualsStatement(Geometry geom) { return createNativeSQLStatementAllWKTParams( "select t.id, t.geom.ST_OrderingEquals(ST_GeomFromText(?)) from GeomTest t where t.geom.ST_OrderingEquals(ST_GeomFromText(?)) = 1 and t.geom.ST_SRID() = " + getTestSrid(), - geom.toText() ); + geom.toText() + ); } /** * Returns the perimeter of all testsuite-suite geometries. * * @return map of identifier, perimeter + * * @throws SQLException */ public Map getPerimeter() throws SQLException { @@ -881,6 +952,7 @@ private NativeSQLStatement createNativePerimeterStatement() { * Returns a point on the surface of all testsuite-suite geometries. * * @return map of identifier, point on surface + * * @throws SQLException */ public Map getPointOnSurface() throws SQLException { @@ -897,6 +969,7 @@ private NativeSQLStatement createNativePointOnSurfaceStatement() { * Returns the nth point of all testsuite-suite geometries. * * @return map of identifier, point + * * @throws SQLException */ public Map getPointN(int n) throws SQLException { @@ -907,13 +980,15 @@ private NativeSQLStatement createNativePointNStatement(int n) { return createNativeSQLStatement( "select t.id, t.geom.ST_PointN(?) from GeomTest t where t.geom.ST_GeometryType() in ('ST_LineString') and t.geom.ST_SRID() = " + getTestSrid(), - new Object[]{ n } ); + new Object[] { n } + ); } /** * Returns a copy of all testsuite-suite geometries with all points snapped to the grid. * * @return map of identifier, geometry + * * @throws SQLException */ public Map getSnapToGrid() throws SQLException { @@ -930,6 +1005,7 @@ private NativeSQLStatement createNativeSnapToGridStatement() { * Returns the expected startpoint of all testsuite-suite geometries. * * @return map of id, startpoint + * * @throws SQLException */ public Map getStartPoint() throws SQLException { @@ -937,13 +1013,15 @@ public Map getStartPoint() throws SQLException { } private NativeSQLStatement createNativeStartPointStatement() { - return createNativeSQLStatement( "select id, t.geom.ST_StartPoint() from GeomTest t where t.geom.ST_GeometryType() = 'ST_LineString'" ); + return createNativeSQLStatement( + "select id, t.geom.ST_StartPoint() from GeomTest t where t.geom.ST_GeometryType() = 'ST_LineString'" ); } /** * Returns the expected aggregated union of all testsuite-suite geometries. * * @return map of count, union + * * @throws SQLException */ public Map getUnionAggr() throws SQLException { @@ -958,6 +1036,7 @@ private NativeSQLStatement createNativeUnionAggrStatement() { * Returns the x coordinate of all testsuite-suite geometries. * * @return map of identifier, x coordinate + * * @throws SQLException */ public Map getX() throws SQLException { @@ -974,6 +1053,7 @@ private NativeSQLStatement createNativeXStatement() { * Returns the maximum x coordinate of all testsuite-suite geometries. * * @return map of identifier, maximum x coordinate + * * @throws SQLException */ public Map getXMax() throws SQLException { @@ -990,6 +1070,7 @@ private NativeSQLStatement createNativeXMaxStatement() { * Returns the minimum x coordinate of all testsuite-suite geometries. * * @return map of identifier, minumum x coordinate + * * @throws SQLException */ public Map getXMin() throws SQLException { @@ -1006,6 +1087,7 @@ private NativeSQLStatement createNativeXMinStatement() { * Returns the y coordinate of all testsuite-suite geometries. * * @return map of identifier, y coordinate + * * @throws SQLException */ public Map getY() throws SQLException { @@ -1022,6 +1104,7 @@ private NativeSQLStatement createNativeYStatement() { * Returns the maximum y coordinate of all testsuite-suite geometries. * * @return map of identifier, maximum y coordinate + * * @throws SQLException */ public Map getYMax() throws SQLException { @@ -1038,6 +1121,7 @@ private NativeSQLStatement createNativeYMaxStatement() { * Returns the minimum y coordinate of all testsuite-suite geometries. * * @return map of identifier, minumum y coordinate + * * @throws SQLException */ public Map getYMin() throws SQLException { @@ -1054,6 +1138,7 @@ private NativeSQLStatement createNativeYMinStatement() { * Returns the z coordinate of all testsuite-suite geometries. * * @return map of identifier, z coordinate + * * @throws SQLException */ public Map getZ() throws SQLException { @@ -1070,6 +1155,7 @@ private NativeSQLStatement createNativeZStatement() { * Returns the maximum z coordinate of all testsuite-suite geometries. * * @return map of identifier, maximum z coordinate + * * @throws SQLException */ public Map getZMax() throws SQLException { @@ -1086,6 +1172,7 @@ private NativeSQLStatement createNativeZMaxStatement() { * Returns the minimum z coordinate of all testsuite-suite geometries. * * @return map of identifier, minumum z coordinate + * * @throws SQLException */ public Map getZMin() throws SQLException { @@ -1102,6 +1189,7 @@ private NativeSQLStatement createNativeZMinStatement() { * Returns the result of a nested function call with a parameter inside the inner function * * @return map of identifier, geometry + * * @throws SQLException */ public Map getNestedFunctionInner(Geometry geom) throws SQLException { @@ -1112,13 +1200,15 @@ private NativeSQLStatement createNativeNestedFunctionInnerStatement(Geometry geo return createNativeSQLStatementAllWKTParams( "select t.id, t.geom from GeomTest t where t.geom.ST_WithinDistance(ST_GeomFromText(?, " + getTestSrid() + ").ST_SRID(0), 1) = 1", - geom.toText() ); + geom.toText() + ); } /** * Returns the result of a nested function call with a parameter inside the outer function * * @return map of identifier, geometry + * * @throws SQLException */ public Map getNestedFunctionOuter(Geometry geom) throws SQLException { @@ -1128,6 +1218,7 @@ public Map getNestedFunctionOuter(Geometry geom) throws SQLEx private NativeSQLStatement createNativeNestedFunctionOuterStatement(Geometry geom) { return createNativeSQLStatementAllWKTParams( "select t.id, t.geom from GeomTest t where ST_GeomFromText(?, " + getTestSrid() + ").ST_WithinDistance(geom.ST_SRID(0), 1) = 1", - geom.toText() ); + geom.toText() + ); } } diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/mysql/MySQL8ExpectationsFactory.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/mysql/MySQL8ExpectationsFactory.java index 4b05cee14f08..def100dcdac3 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/mysql/MySQL8ExpectationsFactory.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/mysql/MySQL8ExpectationsFactory.java @@ -93,7 +93,6 @@ protected NativeSQLStatement createNativeDisjointStatement(Geometry geom) { } - @Override protected NativeSQLStatement createNativeRelateStatement(Geometry geom, String matrix) { throw new UnsupportedOperationException(); diff --git a/hibernate-spatial/src/test/resources/db2/setup_db.sql b/hibernate-spatial/src/test/resources/db2/setup_db.sql index c2e3fb8be3f0..cb156f7f064e 100644 --- a/hibernate-spatial/src/test/resources/db2/setup_db.sql +++ b/hibernate-spatial/src/test/resources/db2/setup_db.sql @@ -26,42 +26,42 @@ connect to sample; -- Create SQL function to return EWKT format from a geometry create or replace function db2gse.asewkt(geometry db2gse.st_geometry) -returns clob(2G) -specific db2gse.asewkt1 -language sql -deterministice -no external action -reads sql data -return 'srid=' || varchar(db2gse.st_srsid(geometry)) || ';' || db2gse.st_astext(geometry) + returns clob(2G) + specific db2gse.asewkt1 + language sql + deterministice + no external action + reads sql data + return 'srid=' || varchar (db2gse.st_srsid(geometry)) || ';' || db2gse.st_astext(geometry) ; -- Create SQL function to create a geometry from EWKT format create or replace function db2gse.geomfromewkt(instring varchar(32000)) -returns db2gse.st_geometry -specific db2gse.fromewkt1 -language sql -deterministic -no external action -reads sql data -return db2gse.st_geometry( -substr(instring,posstr(instring,';')+1, length(instring) - posstr(instring,';')), -integer(substr(instring,posstr(instring,'=')+1,posstr(instring,';')-(posstr(instring,'=')+1))) -) + returns db2gse.st_geometry + specific db2gse.fromewkt1 + language sql + deterministic + no external action + reads sql data + return db2gse.st_geometry( + substr(instring,posstr(instring,';')+1, length (instring) - posstr(instring,';')), + integer (substr(instring,posstr(instring,'=')+1,posstr(instring,';')-(posstr(instring,'=')+1))) + ) ; -- Create a DB2 transform group to return and accept EWKT CREATE TRANSFORM FOR db2gse.ST_Geometry EWKT ( - FROM SQL WITH FUNCTION db2gse.asewkt(db2gse.ST_Geometry), - TO SQL WITH FUNCTION db2gse.geomfromewkt(varchar(32000)) ) + FROM SQL WITH FUNCTION db2gse.asewkt(db2gse.ST_Geometry), + TO SQL WITH FUNCTION db2gse.geomfromewkt(varchar(32000)) ) ; -- Redefine the default DB2_PROGRAM to return and accept EWKT instead of WKT DROP TRANSFORM DB2_PROGRAM FOR db2gse.ST_Geometry; CREATE TRANSFORM FOR db2gse.ST_Geometry DB2_PROGRAM ( - FROM SQL WITH FUNCTION db2gse.asewkt(db2gse.ST_Geometry), - TO SQL WITH FUNCTION db2gse.geomfromewkt(varchar(32000)) ) + FROM SQL WITH FUNCTION db2gse.asewkt(db2gse.ST_Geometry), + TO SQL WITH FUNCTION db2gse.geomfromewkt(varchar(32000)) ) ; - + -- Give the test userid authority to create and access tables grant dataaccess on database to hstest; diff --git a/hibernate-spatial/src/test/resources/db2/test-db2nozm-data-set.xml b/hibernate-spatial/src/test/resources/db2/test-db2nozm-data-set.xml index aa9ace21e32d..c327748cb791 100644 --- a/hibernate-spatial/src/test/resources/db2/test-db2nozm-data-set.xml +++ b/hibernate-spatial/src/test/resources/db2/test-db2nozm-data-set.xml @@ -23,7 +23,7 @@ SRID=4326;LINESTRING(10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0) - + 11 MULTILINESTRING SRID=4326;MULTILINESTRING((10.0 5.0, 20.0 15.0),( 25.0 30.0, 30.0 20.0)) @@ -32,7 +32,8 @@ 12 MULTILINESTRING - SRID=4326;MULTILINESTRING((10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0), (40.0 20.0, 42.0 18.0, 43.0 16.0, 40 14.0)) + SRID=4326;MULTILINESTRING((10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0), (40.0 20.0, 42.0 18.0, 43.0 16.0, 40 + 14.0)) @@ -42,7 +43,7 @@ SRID=4326;POLYGON( (0 0, 10 0, 10 10, 0 10, 0 0) ) - + 18 POLYGON SRID=4326;POLYGON((0 0, 10 0, 10 10, 0 10, 0 0), (2 2, 2 5, 5 5, 5 2, 2 2)) @@ -60,10 +61,11 @@ SRID=4326;MULTIPOLYGON(((105 100, 130 134, 120 140, 105 100)), ((10 20, 44 50, 30 40, 10 20))) - + 22 MULTIPOLYGON - SRID=4326;MULTIPOLYGON(((0 0, 50 0, 50 50, 0 50, 0 0), (10 10, 10 20, 20 20, 20 10, 10 10)), ((105 100, 130 134, 120 140, 105 100))) + SRID=4326;MULTIPOLYGON(((0 0, 50 0, 50 50, 0 50, 0 0), (10 10, 10 20, 20 20, 20 10, 10 10)), ((105 100, 130 + 134, 120 140, 105 100))) diff --git a/hibernate-spatial/src/test/resources/db2/test-db2nozm-only-polygon.xml b/hibernate-spatial/src/test/resources/db2/test-db2nozm-only-polygon.xml index b181ddb7b712..d02fe2f560b1 100644 --- a/hibernate-spatial/src/test/resources/db2/test-db2nozm-only-polygon.xml +++ b/hibernate-spatial/src/test/resources/db2/test-db2nozm-only-polygon.xml @@ -6,7 +6,7 @@ SRID=4326;POLYGON( (0 0, 10 0, 10 10, 0 10, 0 0) ) - + 18 POLYGON SRID=4326;POLYGON((0 0, 10 0, 10 10, 0 10, 0 0), (2 2, 2 5, 5 5, 5 2, 2 2)) @@ -24,10 +24,11 @@ SRID=4326;MULTIPOLYGON(((105 100, 130 134, 120 140, 105 100)), ((10 20, 44 50, 30 40, 10 20))) - + 22 MULTIPOLYGON - SRID=4326;MULTIPOLYGON(((0 0, 50 0, 50 50, 0 50, 0 0), (10 10, 10 20, 20 20, 20 10, 10 10)), ((105 100, 130 134, 120 140, 105 100))) + SRID=4326;MULTIPOLYGON(((0 0, 50 0, 50 50, 0 50, 0 0), (10 10, 10 20, 20 20, 20 10, 10 10)), ((105 100, 130 + 134, 120 140, 105 100))) diff --git a/hibernate-spatial/src/test/resources/hana/test-hana-data-set.xml b/hibernate-spatial/src/test/resources/hana/test-hana-data-set.xml index 6912c6784944..6ab61d960965 100644 --- a/hibernate-spatial/src/test/resources/hana/test-hana-data-set.xml +++ b/hibernate-spatial/src/test/resources/hana/test-hana-data-set.xml @@ -45,7 +45,7 @@ LINESTRING(10.0 5.0, 20.0 15.0, 30.25 22.375, 10 30.0) - + 7 LINESTRING @@ -86,7 +86,8 @@ 13 MULTILINESTRING - MULTILINESTRING M((10.0 5.0 1.0, 20.0 15.0 2.0, 30.25 22.375 1.0, 10 30.0 1.0),(40.0 20.0 0.0, 42.0 18.0 1.0, + MULTILINESTRING M((10.0 5.0 1.0, 20.0 15.0 2.0, 30.25 22.375 1.0, 10 30.0 1.0),(40.0 20.0 0.0, 42.0 18.0 + 1.0, 43.0 16.0 2.0, 40 14.0 3.0)) @@ -94,7 +95,8 @@ 14 MULTILINESTRING - MULTILINESTRING ZM((10.0 5.0 1.0 0.0, 20.0 15.0 2.0 0.0, 30.25 22.375 1.0 1.0, 10 30.0 1.0 2.0),(40.0 20.0 0.0 + MULTILINESTRING ZM((10.0 5.0 1.0 0.0, 20.0 15.0 2.0 0.0, 30.25 22.375 1.0 1.0, 10 30.0 1.0 2.0),(40.0 20.0 + 0.0 3.0, 42.0 18.0 1.0 4.0, 43.0 16.0 2.0 5.0, 40 14.0 3.0 6.0)) diff --git a/hibernate-spatial/src/test/resources/hibernate.properties b/hibernate-spatial/src/test/resources/hibernate.properties index 12af9edae928..70d610afc06b 100644 --- a/hibernate-spatial/src/test/resources/hibernate.properties +++ b/hibernate-spatial/src/test/resources/hibernate.properties @@ -4,26 +4,19 @@ # License: GNU Lesser General Public License (LGPL), version 2.1 or later. # See the lgpl.txt file in the root directory or . # - # Default unit/integration test config. - -hibernate.show_sql true - -hibernate.max_fetch_depth 5 - -hibernate.dialect @db.dialect@ -hibernate.connection.driver_class @jdbc.driver@ -hibernate.connection.url @jdbc.url@ -hibernate.connection.username @jdbc.user@ -hibernate.connection.password @jdbc.pass@ - +hibernate.show_sql=true +hibernate.max_fetch_depth=5 +hibernate.dialect=@db.dialect@ +hibernate.connection.driver_class=@jdbc.driver@ +hibernate.connection.url=@jdbc.url@ +hibernate.connection.username=@jdbc.user@ +hibernate.connection.password=@jdbc.pass@ #hibernate.cache.region_prefix hibernate.test #hibernate.cache.region.factory_class org.hibernate.testing.cache.CachingRegionFactory # ## NOTE: hibernate.jdbc.batch_versioned_data should be set to false when testing with Oracle #hibernate.jdbc.batch_versioned_data true - - ## Configs for spatial databases (used during testing on local dev environment). # #hibernate.dialect org.hibernate.spatial.dialect.postgis.PostgisPG95Dialect @@ -31,7 +24,6 @@ hibernate.connection.password @jdbc.pass@ #hibernate.connection.url jdbc:postgresql://localhost:9432/ #hibernate.connection.username hibern8 #hibernate.connection.password hibern8 - ## ## GeoDb (H2 spatial extension) ## @@ -40,8 +32,6 @@ hibernate.connection.password @jdbc.pass@ #hibernate.connection.url jdbc:h2:mem:testhbs;DB_CLOSE_DELAY=-1;MVCC=true #hibernate.connection.username sa #hibernate.connection.password sa - - ## ## Oracle 11g ## @@ -51,15 +41,12 @@ hibernate.connection.password @jdbc.pass@ #hibernate.connection.url jdbc:oracle:thin:@localhost:1521/orcl12c #hibernate.connection.username C##hibernate #hibernate.connection.password hibernate - #hibernate.dialect org.hibernate.spatial.dialect.oracle.OracleSpatialSDO10gDialect #hibernate.connection.driver_class oracle.jdbc.OracleDriver #hibernate.connection.url jdbc:oracle:thin:@localhost:1521/orcl12c #hibernate.connection.username C##hibernate #hibernate.connection.password hibernate # - - ## ## MS SQL Server dialect ## @@ -68,9 +55,6 @@ hibernate.connection.password @jdbc.pass@ #hibernate.connection.url jdbc:sqlserver://localhost:1433;databaseName=TestDb #hibernate.connection.username hibern8 #hibernate.connection.password hibern8Pass - - - ## ## MySQL 5 dialects ## @@ -79,7 +63,6 @@ hibernate.connection.password @jdbc.pass@ #hibernate.connection.url jdbc:mysql://hibernate-spatial-integration.cctaez8ywvn2.eu-west-1.rds.amazonaws.com/test #hibernate.connection.username hbs #hibernate.connection.password - ## ## MySQL 5 InnoDDB dialect ## @@ -88,7 +71,6 @@ hibernate.connection.password @jdbc.pass@ #hibernate.connection.url jdbc:mysql://localhost/testhbs #hibernate.connection.username hibernate #hibernate.connection.password hibernate - ## ## MySQL 5.6.1 dialect ## @@ -97,7 +79,6 @@ hibernate.connection.password @jdbc.pass@ #hibernate.connection.url jdbc:mysql://hibernate-spatial-integration.cctaez8ywvn2.eu-west-1.rds.amazonaws.com:3306/test #hibernate.connection.username hbs #hibernate.connection.password - ## ## HANA dialect ## @@ -106,7 +87,6 @@ hibernate.connection.password @jdbc.pass@ #hibernate.connection.url jdbc:sap://localhost:30015 #hibernate.connection.username HIBERNATE_TEST #hibernate.connection.password H1bernate_test - ## ## DB2 dialect ## diff --git a/hibernate-spatial/src/test/resources/log4j.properties b/hibernate-spatial/src/test/resources/log4j.properties index 8127f9c512f3..5156e0d55e13 100644 --- a/hibernate-spatial/src/test/resources/log4j.properties +++ b/hibernate-spatial/src/test/resources/log4j.properties @@ -8,9 +8,6 @@ log4j.appender.stdout=org.apache.log4j.ConsoleAppender log4j.appender.stdout.Target=System.out log4j.appender.stdout.layout=org.apache.log4j.PatternLayout log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n - - log4j.rootLogger=info, stdout log4j.logger.org.hibernate.SQL=DEBUG - log4j.logger.org.hibernate.spatial=debug diff --git a/hibernate-spatial/src/test/resources/mysql/test-mysql-functions-data-set.xml b/hibernate-spatial/src/test/resources/mysql/test-mysql-functions-data-set.xml index 3bccf4643a28..253a6c64d668 100644 --- a/hibernate-spatial/src/test/resources/mysql/test-mysql-functions-data-set.xml +++ b/hibernate-spatial/src/test/resources/mysql/test-mysql-functions-data-set.xml @@ -57,7 +57,8 @@ In MySQL these are stored as null objects. 12 MULTILINESTRING - SRID=4326;MULTILINESTRING((10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0), (40.0 20.0, 42.0 18.0, 43.0 16.0, 40 14.0)) + SRID=4326;MULTILINESTRING((10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0), (40.0 20.0, 42.0 18.0, 43.0 16.0, 40 + 14.0)) @@ -86,7 +87,8 @@ In MySQL these are stored as null objects. 22 MULTIPOLYGON - SRID=4326;MULTIPOLYGON(( (0 0, 0 50, 50 50, 50 0, 0 0), (10 10, 10 20, 20 20, 20 10, 10 10) ),((105 100, 120 140, 130 + SRID=4326;MULTIPOLYGON(( (0 0, 0 50, 50 50, 50 0, 0 0), (10 10, 10 20, 20 20, 20 10, 10 10) ),((105 100, + 120 140, 130 134, 105 100)) ) @@ -116,14 +118,16 @@ In MySQL these are stored as null objects. 32 GEOMETRYCOLLECTION - SRID=4326;GEOMETRYCOLLECTION(POINT(4 0), LINESTRING(4 2, 5 3), POLYGON((0 0, 3 0, 3 3,0 3, 0 0),(1 1, 2 1, 2 2, 1 2, + SRID=4326;GEOMETRYCOLLECTION(POINT(4 0), LINESTRING(4 2, 5 3), POLYGON((0 0, 3 0, 3 3,0 3, 0 0),(1 1, 2 1, + 2 2, 1 2, 1 1))) 33 GEOMETRYCOLLECTION - SRID=4326;GEOMETRYCOLLECTION( MULTIPOINT(21 2, 25 5, 30 3), MULTIPOLYGON( ((10 20, 30 40, 44 50, 10 20)), ((105 100, + SRID=4326;GEOMETRYCOLLECTION( MULTIPOINT(21 2, 25 5, 30 3), MULTIPOLYGON( ((10 20, 30 40, 44 50, 10 20)), + ((105 100, 120 140, 130 134, 105 100)) ), MULTILINESTRING((10.0 5.0, 20.0 15.0),( 25.0 30.0, 30.0 20.0))) diff --git a/hibernate-spatial/src/test/resources/mysql/test-mysql8-functions-data-set.xml b/hibernate-spatial/src/test/resources/mysql/test-mysql8-functions-data-set.xml index 1ea78924cf9a..7a14edc5ef2b 100644 --- a/hibernate-spatial/src/test/resources/mysql/test-mysql8-functions-data-set.xml +++ b/hibernate-spatial/src/test/resources/mysql/test-mysql8-functions-data-set.xml @@ -57,7 +57,8 @@ In MySQL these are stored as null objects. 12 MULTILINESTRING - SRID=31370;MULTILINESTRING((10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0), (40.0 20.0, 42.0 18.0, 43.0 16.0, 40 14.0)) + SRID=31370;MULTILINESTRING((10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0), (40.0 20.0, 42.0 18.0, 43.0 16.0, 40 + 14.0)) @@ -86,7 +87,8 @@ In MySQL these are stored as null objects. 22 MULTIPOLYGON - SRID=31370;MULTIPOLYGON(( (0 0, 0 50, 50 50, 50 0, 0 0), (10 10, 10 20, 20 20, 20 10, 10 10) ),((15 10, 12 14, 13 + SRID=31370;MULTIPOLYGON(( (0 0, 0 50, 50 50, 50 0, 0 0), (10 10, 10 20, 20 20, 20 10, 10 10) ),((15 10, 12 + 14, 13 14, 15 10)) ) @@ -116,14 +118,16 @@ In MySQL these are stored as null objects. 32 GEOMETRYCOLLECTION - SRID=31370;GEOMETRYCOLLECTION(POINT(4 0), LINESTRING(4 2, 5 3), POLYGON((0 0, 3 0, 3 3,0 3, 0 0),(1 1, 2 1, 2 2, 1 2, + SRID=31370;GEOMETRYCOLLECTION(POINT(4 0), LINESTRING(4 2, 5 3), POLYGON((0 0, 3 0, 3 3,0 3, 0 0),(1 1, 2 1, + 2 2, 1 2, 1 1))) 33 GEOMETRYCOLLECTION - SRID=31370;GEOMETRYCOLLECTION( MULTIPOINT(21 2, 25 5, 30 3), MULTIPOLYGON( ((10 20, 30 40, 44 50, 10 20)), ((15 10, + SRID=31370;GEOMETRYCOLLECTION( MULTIPOINT(21 2, 25 5, 30 3), MULTIPOLYGON( ((10 20, 30 40, 44 50, 10 20)), + ((15 10, 12 14, 13 14, 15 10)) ), MULTILINESTRING((10.0 5.0, 20.0 15.0),( 25.0 30.0, 30.0 20.0))) diff --git a/hibernate-spatial/src/test/resources/oracle10g/org.hibernate.spatial.dialect.oracle.OracleSpatial10gDialect.properties b/hibernate-spatial/src/test/resources/oracle10g/org.hibernate.spatial.dialect.oracle.OracleSpatial10gDialect.properties index dfd92385fced..dd32af94b841 100644 --- a/hibernate-spatial/src/test/resources/oracle10g/org.hibernate.spatial.dialect.oracle.OracleSpatial10gDialect.properties +++ b/hibernate-spatial/src/test/resources/oracle10g/org.hibernate.spatial.dialect.oracle.OracleSpatial10gDialect.properties @@ -4,6 +4,5 @@ # License: GNU Lesser General Public License (LGPL), version 2.1 or later. # See the lgpl.txt file in the root directory or . # - OGC_STRICT=true CONNECTION-FINDER=org.hibernate.spatial.dialect.oracle.DefaultConnectionFinder \ No newline at end of file diff --git a/hibernate-spatial/src/test/resources/oracle10g/test-sdo-geometry-data-set-2D.xml b/hibernate-spatial/src/test/resources/oracle10g/test-sdo-geometry-data-set-2D.xml index 34c2b3cb583c..32822819ca5f 100644 --- a/hibernate-spatial/src/test/resources/oracle10g/test-sdo-geometry-data-set-2D.xml +++ b/hibernate-spatial/src/test/resources/oracle10g/test-sdo-geometry-data-set-2D.xml @@ -57,7 +57,8 @@ 12 MULTILINESTRING - SRID=4326;MULTILINESTRING((10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0), (40.0 20.0, 42.0 18.0, 43.0 16.0, 40 14.0)) + SRID=4326;MULTILINESTRING((10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0), (40.0 20.0, 42.0 18.0, 43.0 16.0, 40 + 14.0)) SDO_GEOMETRY(2006, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,2,1,9,2,1), SDO_ORDINATE_ARRAY(10.0,5.0,20.0,15.0,30.3,22.4,10,30.0,40.0,20.0,42.0,18.0,43.0,16.0,40,14.0)) diff --git a/hibernate-spatial/src/test/resources/oracle10g/test-sdo-geometry-data-set.xml b/hibernate-spatial/src/test/resources/oracle10g/test-sdo-geometry-data-set.xml index 46fae25086ea..aeda0a393289 100644 --- a/hibernate-spatial/src/test/resources/oracle10g/test-sdo-geometry-data-set.xml +++ b/hibernate-spatial/src/test/resources/oracle10g/test-sdo-geometry-data-set.xml @@ -100,7 +100,8 @@ 12 MULTILINESTRING - SRID=4326;MULTILINESTRING((10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0), (40.0 20.0, 42.0 18.0, 43.0 16.0, 40 14.0)) + SRID=4326;MULTILINESTRING((10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0), (40.0 20.0, 42.0 18.0, 43.0 16.0, 40 + 14.0)) SDO_GEOMETRY(2006, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,2,1,9,2,1), SDO_ORDINATE_ARRAY(10.0,5.0,20.0,15.0,30.3,22.4,10,30.0,40.0,20.0,42.0,18.0,43.0,16.0,40,14.0)) @@ -121,7 +122,8 @@ 14 MULTILINESTRING - SRID=4326;MULTILINESTRING((10.0 5.0 1.0 0.0, 20.0 15.0 2.0 0.0, 30.3 22.4 1.0 1.0, 10 30.0 1.0 2.0),(40.0 20.0 0.0 + SRID=4326;MULTILINESTRING((10.0 5.0 1.0 0.0, 20.0 15.0 2.0 0.0, 30.3 22.4 1.0 1.0, 10 30.0 1.0 2.0),(40.0 + 20.0 0.0 3.0, 42.0 18.0 1.0 4.0, 43.0 16.0 2.0 5.0, 40 14.0 3.0 6.0)) SDO_GEOMETRY(4406, 4326, NULL, SDO_ELEM_INFO_ARRAY(1,2,1,17,2,1), @@ -185,7 +187,8 @@ 21 MULTIPOLYGON - SRID=4326;MULTIPOLYGON( ((10 20 1, 30 40 2, 44 50 2, 10 20 1)), ((105 100 0, 120 140 10, 130 134 20, 105 100 0)) ) + SRID=4326;MULTIPOLYGON( ((10 20 1, 30 40 2, 44 50 2, 10 20 1)), ((105 100 0, 120 140 10, 130 134 20, 105 + 100 0)) ) SDO_GEOMETRY(3007, 4326, NULL, SDO_ELEM_INFO_ARRAY(1, 1003, 1, 13, 1003, 1), SDO_ORDINATE_ARRAY(10,20,1,30,40,2,44,50,2,10,20,1,105,100,0,120,140,10,130,134,20,105,100,0)) @@ -194,7 +197,8 @@ 22 MULTIPOLYGON - SRID=4326;MULTIPOLYGON(( (0 0, 0 50, 50 50, 50 0, 0 0), (10 10, 10 20, 20 20, 20 10, 10 10) ),((105 100, 120 140, 130 + SRID=4326;MULTIPOLYGON(( (0 0, 0 50, 50 50, 50 0, 0 0), (10 10, 10 20, 20 20, 20 10, 10 10) ),((105 100, + 120 140, 130 134, 105 100))) SDO_GEOMETRY(2007, 4326, NULL, SDO_ELEM_INFO_ARRAY(1, 1003, 1, 11, 2003, 1, 21, 1003, 1), diff --git a/hibernate-spatial/src/test/resources/postgis-functions-test.xml b/hibernate-spatial/src/test/resources/postgis-functions-test.xml index aca8756bfed2..d3af9d7f7951 100644 --- a/hibernate-spatial/src/test/resources/postgis-functions-test.xml +++ b/hibernate-spatial/src/test/resources/postgis-functions-test.xml @@ -53,7 +53,8 @@ 9 MULTILINESTRING - SRID=4326;MULTILINESTRING((10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0), (40.0 20.0, 42.0 18.0, 43.0 16.0, 40 14.0)) + SRID=4326;MULTILINESTRING((10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0), (40.0 20.0, 42.0 18.0, 43.0 16.0, 40 + 14.0)) diff --git a/hibernate-spatial/src/test/resources/sqlserver/create-sqlserver-test-schema.sql b/hibernate-spatial/src/test/resources/sqlserver/create-sqlserver-test-schema.sql index 7f3217b2a2b7..a557267699b0 100644 --- a/hibernate-spatial/src/test/resources/sqlserver/create-sqlserver-test-schema.sql +++ b/hibernate-spatial/src/test/resources/sqlserver/create-sqlserver-test-schema.sql @@ -1,9 +1,8 @@ - CREATE TABLE "HBS"."dbo"."geomtest" ( -id int PRIMARY KEY NOT NULL, -type varchar(50), -geom geometry + id int PRIMARY KEY NOT NULL, + type varchar(50), + geom geometry ) diff --git a/hibernate-spatial/src/test/resources/sqlserver/hibernate-spatial-sqlserver-test.properties b/hibernate-spatial/src/test/resources/sqlserver/hibernate-spatial-sqlserver-test.properties index ee539962e7c8..eded179a19cb 100644 --- a/hibernate-spatial/src/test/resources/sqlserver/hibernate-spatial-sqlserver-test.properties +++ b/hibernate-spatial/src/test/resources/sqlserver/hibernate-spatial-sqlserver-test.properties @@ -4,14 +4,12 @@ # License: GNU Lesser General Public License (LGPL), version 2.1 or later. # See the lgpl.txt file in the root directory or . # - # # $Id: hibernate-spatial-sqlserver-test.properties 182 2010-03-20 17:30:12Z maesenka $ # - -jdbcUrl = jdbc:sqlserver://sqlserver.geovise.com:1433;databaseName=HBS -jdbcDriver = com.microsoft.sqlserver.jdbc.SQLServerDriver -jdbcUser = hbs -jdbcPass = hbs -dataset = test-data-set.xml +jdbcUrl=jdbc:sqlserver://sqlserver.geovise.com:1433;databaseName=HBS +jdbcDriver=com.microsoft.sqlserver.jdbc.SQLServerDriver +jdbcUser=hbs +jdbcPass=hbs +dataset=test-data-set.xml diff --git a/hibernate-spatial/src/test/resources/test-data-set.xml b/hibernate-spatial/src/test/resources/test-data-set.xml index 3713db6804c4..7029a31fd85c 100644 --- a/hibernate-spatial/src/test/resources/test-data-set.xml +++ b/hibernate-spatial/src/test/resources/test-data-set.xml @@ -72,14 +72,16 @@ 12 MULTILINESTRING - SRID=4326;MULTILINESTRING((10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0), (40.0 20.0, 42.0 18.0, 43.0 16.0, 40 14.0)) + SRID=4326;MULTILINESTRING((10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0), (40.0 20.0, 42.0 18.0, 43.0 16.0, 40 + 14.0)) 13 MULTILINESTRING - SRID=4326;MULTILINESTRING((10.0 5.0 1.0, 20.0 15.0 2.0, 30.3 22.4 1.0, 10 30.0 1.0),(40.0 20.0 0.0, 42.0 18.0 1.0, + SRID=4326;MULTILINESTRING((10.0 5.0 1.0, 20.0 15.0 2.0, 30.3 22.4 1.0, 10 30.0 1.0),(40.0 20.0 0.0, 42.0 + 18.0 1.0, 43.0 16.0 2.0, 40 14.0 3.0)) @@ -87,7 +89,8 @@ 14 MULTILINESTRING - SRID=4326;MULTILINESTRING((10.0 5.0 1.0 0.0, 20.0 15.0 2.0 0.0, 30.3 22.4 1.0 1.0, 10 30.0 1.0 2.0),(40.0 20.0 0.0 + SRID=4326;MULTILINESTRING((10.0 5.0 1.0 0.0, 20.0 15.0 2.0 0.0, 30.3 22.4 1.0 1.0, 10 30.0 1.0 2.0),(40.0 + 20.0 0.0 3.0, 42.0 18.0 1.0 4.0, 43.0 16.0 2.0 5.0, 40 14.0 3.0 6.0)) @@ -127,13 +130,15 @@ 21 MULTIPOLYGON - SRID=4326;MULTIPOLYGON( ((10 20 1, 30 40 2, 44 50 2, 10 20 1)), ((105 100 0, 120 140 10, 130 134 20, 105 100 0)) ) + SRID=4326;MULTIPOLYGON( ((10 20 1, 30 40 2, 44 50 2, 10 20 1)), ((105 100 0, 120 140 10, 130 134 20, 105 + 100 0)) ) 22 MULTIPOLYGON - SRID=4326;MULTIPOLYGON(( (0 0, 0 50, 50 50, 50 0, 0 0), (10 10, 10 20, 20 20, 20 10, 10 10) ),((105 100, 120 140, 130 + SRID=4326;MULTIPOLYGON(( (0 0, 0 50, 50 50, 50 0, 0 0), (10 10, 10 20, 20 20, 20 10, 10 10) ),((105 100, + 120 140, 130 134, 105 100)) ) @@ -173,14 +178,16 @@ 32 GEOMETRYCOLLECTION - SRID=4326;GEOMETRYCOLLECTION(POINT(4 0), LINESTRING(4 2, 5 3), POLYGON((0 0, 3 0, 3 3,0 3, 0 0),(1 1, 2 1, 2 2, 1 2, + SRID=4326;GEOMETRYCOLLECTION(POINT(4 0), LINESTRING(4 2, 5 3), POLYGON((0 0, 3 0, 3 3,0 3, 0 0),(1 1, 2 1, + 2 2, 1 2, 1 1))) 33 GEOMETRYCOLLECTION - SRID=4326;GEOMETRYCOLLECTION( MULTIPOINT(21 2, 25 5, 30 3), MULTIPOLYGON( ((10 20, 30 40, 44 50, 10 20)), ((105 100, + SRID=4326;GEOMETRYCOLLECTION( MULTIPOINT(21 2, 25 5, 30 3), MULTIPOLYGON( ((10 20, 30 40, 44 50, 10 20)), + ((105 100, 120 140, 130 134, 105 100)) ), MULTILINESTRING((10.0 5.0, 20.0 15.0),( 25.0 30.0, 30.0 20.0))) From a094e17d2a0a06c4f08f56fa2a5c0bf6c91f66ce Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Mon, 8 Feb 2021 16:26:09 +0100 Subject: [PATCH 003/644] HHH-14445 Javassist skip EntityWithMutableAttributesTest, LoadAndUpdateEntitiesWithCollectionsTest, SimpleDynamicUpdateTest, SimpleDynamicUpdateTest --- .../EntityWithMutableAttributesTest.java | 12 ++++++++++ ...dAndUpdateEntitiesWithCollectionsTest.java | 20 +++++++++++++++- .../SimpleDynamicUpdateTest.java | 6 +++++ .../DynamicUpdateAndCollectionsTest.java | 23 ++++++++++++++++++- 4 files changed, 59 insertions(+), 2 deletions(-) diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/EntityWithMutableAttributesTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/EntityWithMutableAttributesTest.java index 138d9cd3796d..4eed240516a0 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/EntityWithMutableAttributesTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/EntityWithMutableAttributesTest.java @@ -64,6 +64,9 @@ protected void applyMetadataSources(MetadataSources sources) { @Before public void setUp() { + if ( skipTest ) { + return; + } inTransaction( session -> { User user = new User(); @@ -87,6 +90,9 @@ public void setUp() { @After public void tearDown() { + if ( skipTest ) { + return; + } inTransaction( session -> { session.createQuery( "delete from User" ).executeUpdate(); @@ -97,6 +103,9 @@ public void tearDown() { @Test public void testLoad() { + if ( skipTest ) { + return; + } inTransaction( session -> { User user = session.load( User.class, 1 ); @@ -114,6 +123,9 @@ user, instanceOf( PersistentAttributeInterceptable.class ) @Test public void testMutableAttributeIsUpdated() { + if ( skipTest ) { + return; + } inTransaction( session -> { User user = session.load( User.class, 1 ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/LoadAndUpdateEntitiesWithCollectionsTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/LoadAndUpdateEntitiesWithCollectionsTest.java index 2d28ef1c2974..668da7bb9775 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/LoadAndUpdateEntitiesWithCollectionsTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/LoadAndUpdateEntitiesWithCollectionsTest.java @@ -63,6 +63,9 @@ protected void applyMetadataSources(MetadataSources sources) { @Before public void setUp() { + if ( skipTest ) { + return; + } inTransaction( session -> { User user = new User(); @@ -90,7 +93,10 @@ public void setUp() { } @After - public void tearDwon() { + public void tearDown() { + if ( skipTest ) { + return; + } inTransaction( session -> { session.createQuery( "delete from SamplingOrder" ).executeUpdate(); @@ -103,6 +109,9 @@ public void tearDwon() { @Test public void testLoad() { + if ( skipTest ) { + return; + } inTransaction( session -> { CriteriaBuilder cb = session.getCriteriaBuilder(); @@ -126,6 +135,9 @@ public void testLoad() { @Test public void testAddUserRoles() { + if ( skipTest ) { + return; + } inTransaction( session -> { SamplingOrder samplingOrder = getSamplingOrder( session ); @@ -200,6 +212,9 @@ public void testAddUserRoles() { @Test public void testDeleteUserRoles() { + if ( skipTest ) { + return; + } inTransaction( session -> { SamplingOrder samplingOrder = getSamplingOrder( session ); @@ -220,6 +235,9 @@ public void testDeleteUserRoles() { @Test public void testModifyUserMail() { + if ( skipTest ) { + return; + } inTransaction( session -> { SamplingOrder samplingOrder = getSamplingOrder( session ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/SimpleDynamicUpdateTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/SimpleDynamicUpdateTest.java index bdf0eab5fa0a..491eae665f2c 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/SimpleDynamicUpdateTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/SimpleDynamicUpdateTest.java @@ -63,6 +63,9 @@ protected void applyMetadataSources(MetadataSources sources) { @Before public void setUp() { + if ( skipTest ) { + return; + } inTransaction( session -> { User user = new User(); @@ -88,6 +91,9 @@ public void setUp() { @Test public void testIt() { + if ( skipTest ) { + return; + } inTransaction( session -> { User user = session.getReference( User.class, 1 ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/dynamicupdate/DynamicUpdateAndCollectionsTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/dynamicupdate/DynamicUpdateAndCollectionsTest.java index 24616b88340d..a258efd8d8a9 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/dynamicupdate/DynamicUpdateAndCollectionsTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/dynamicupdate/DynamicUpdateAndCollectionsTest.java @@ -66,6 +66,9 @@ protected void applyMetadataSources(MetadataSources sources) { @Before public void setUp() { + if ( skipTest ) { + return; + } inTransaction( session -> { User user = new User(); @@ -92,7 +95,10 @@ public void setUp() { } @After - public void tearDwon() { + public void tearDown() { + if ( skipTest ) { + return; + } inTransaction( session -> { session.createQuery( "delete from SamplingOrder" ).executeUpdate(); @@ -105,6 +111,9 @@ public void tearDwon() { @Test public void testLoad() { + if ( skipTest ) { + return; + } inTransaction( session -> { CriteriaBuilder cb = session.getCriteriaBuilder(); @@ -128,6 +137,9 @@ public void testLoad() { @Test public void testRemoveCustomers() { + if ( skipTest ) { + return; + } Long samplingOrderId = fromTransaction( session -> { SamplingOrder samplingOrder = getSamplingOrderFetchCustomer( session ); @@ -146,6 +158,9 @@ public void testRemoveCustomers() { @Test public void testAddUserRoles() { + if ( skipTest ) { + return; + } inTransaction( session -> { SamplingOrder samplingOrder = getSamplingOrderFetchCustomer( session ); @@ -207,6 +222,9 @@ public void testAddUserRoles() { @Test public void testDeleteUserRoles() { + if ( skipTest ) { + return; + } inTransaction( session -> { SamplingOrder samplingOrder = getSamplingOrderFetchCustomer( session ); @@ -226,6 +244,9 @@ public void testDeleteUserRoles() { @Test public void testModifyUserMail() { + if ( skipTest ) { + return; + } inTransaction( session -> { SamplingOrder samplingOrder = getSamplingOrderFetchCustomer( session ); From 04a40f839798886351ce7212c741c9832abd4738 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Fri, 5 Feb 2021 17:23:48 +0100 Subject: [PATCH 004/644] HHH-14444 Test concurrent usage of ID generator optimizers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Yoann Rodière --- .../OptimizerConcurrencyUnitTest.java | 188 ++++++++++++++++++ .../id/enhanced/OptimizerUnitTest.java | 66 +----- .../org/hibernate/id/enhanced/SourceMock.java | 79 ++++++++ 3 files changed, 268 insertions(+), 65 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/id/enhanced/OptimizerConcurrencyUnitTest.java create mode 100644 hibernate-core/src/test/java/org/hibernate/id/enhanced/SourceMock.java diff --git a/hibernate-core/src/test/java/org/hibernate/id/enhanced/OptimizerConcurrencyUnitTest.java b/hibernate-core/src/test/java/org/hibernate/id/enhanced/OptimizerConcurrencyUnitTest.java new file mode 100644 index 000000000000..9757e9504893 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/id/enhanced/OptimizerConcurrencyUnitTest.java @@ -0,0 +1,188 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.id.enhanced; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import java.util.concurrent.TimeUnit; +import java.util.concurrent.TimeoutException; +import java.util.stream.Collectors; + +import org.hibernate.AssertionFailure; + +import org.hibernate.testing.junit4.BaseUnitTestCase; +import org.hibernate.testing.junit4.CustomParameterized; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.assertj.core.api.Assertions.assertThatCode; +import static org.junit.Assert.assertEquals; + +@RunWith(CustomParameterized.class) +public class OptimizerConcurrencyUnitTest extends BaseUnitTestCase { + + @Parameterized.Parameters(name = "{0}") + public static List params() { + List params = new ArrayList<>(); + for ( StandardOptimizerDescriptor value : StandardOptimizerDescriptor.values() ) { + params.add( new Object[] { value } ); + } + return params; + } + + private final StandardOptimizerDescriptor optimizerDescriptor; + + public OptimizerConcurrencyUnitTest(StandardOptimizerDescriptor optimizerDescriptor) { + this.optimizerDescriptor = optimizerDescriptor; + } + + @Test + public void testConcurrentUsage_singleTenancy() throws InterruptedException { + final int increment = 50; + final int taskCount = 100 * increment; + + Optimizer optimizer = buildOptimizer( 1, increment ); + + List> tasks = new ArrayList<>(); + + SourceMock sequence = new SourceMock( 1, increment ); + assertEquals( 0, sequence.getTimesCalled() ); + assertEquals( -1, sequence.getCurrentValue() ); + + for ( int i = 0; i < taskCount; i++ ) { + tasks.add( new Callable() { + @Override + public Long call() throws Exception { + return ( Long ) optimizer.generate( sequence ); + } + } ); + } + + ExecutorService executor = Executors.newFixedThreadPool( 10 ); + List> futures; + try { + futures = executor.invokeAll( tasks ); + executor.shutdown(); + executor.awaitTermination( 10, TimeUnit.SECONDS ); + } + finally { + executor.shutdownNow(); + } + + assertThat( futures ) + .allSatisfy( future -> { + assertThat( future ).isDone(); + assertThatCode( future::get ).doesNotThrowAnyException(); + } ); + List generated = futures.stream().map( this::getDoneFutureValue ).collect( Collectors.toList()); + assertThat( generated ) + .hasSize( taskCount ) + // Check for uniqueness + .containsExactlyInAnyOrderElementsOf( new HashSet<>( generated ) ); + System.out.println( "Generated IDs: " + generated ); + } + + @Test + public void testConcurrentUsage_multiTenancy() throws InterruptedException { + final int increment = 50; + + final int tenantCount = 5; + final int taskCountPerTenant = 20 * increment; + + Optimizer optimizer = buildOptimizer( 1, increment ); + + Map>> tasksByTenantId = new LinkedHashMap<>(); + + for ( int i = 0; i < tenantCount; i++ ) { + String tenantId = "tenant#" + i; + + SourceMock sequenceForTenant = new SourceMock( tenantId, 1, increment ); + assertEquals( 0, sequenceForTenant.getTimesCalled() ); + assertEquals( -1, sequenceForTenant.getCurrentValue() ); + + List> tasksForTenant = new ArrayList<>(); + tasksByTenantId.put( tenantId, tasksForTenant ); + for ( int j = 0; j < taskCountPerTenant; j++ ) { + tasksForTenant.add( new Callable() { + @Override + public Long call() throws Exception { + return ( Long ) optimizer.generate( sequenceForTenant ); + } + } ); + } + } + + List> tasks = new ArrayList<>(); + // Make sure to interleave tenants + for ( int i = 0; i < taskCountPerTenant; i++ ) { + for ( List> tasksForTenant : tasksByTenantId.values() ) { + tasks.add( tasksForTenant.get( i ) ); + } + } + + ExecutorService executor = Executors.newFixedThreadPool( 10 ); + List> futures; + try { + futures = executor.invokeAll( tasks ); + executor.shutdown(); + executor.awaitTermination( 10, TimeUnit.SECONDS ); + } + finally { + executor.shutdownNow(); + } + + assertThat( futures ) + .allSatisfy( future -> { + assertThat( future ).isDone(); + assertThatCode( future::get ).doesNotThrowAnyException(); + } ); + + Map>> futuresByTenantId = new LinkedHashMap<>(); + for ( int i = 0; i < tenantCount; i++ ) { + List> futuresForTenant = new ArrayList<>(); + for ( int j = 0; j < taskCountPerTenant; j++ ) { + futuresForTenant.add( futures.get( i + j * tenantCount ) ); + } + String tenantId = "tenant#" + i; + futuresByTenantId.put( tenantId, futuresForTenant ); + } + + for ( Map.Entry>> entry : futuresByTenantId.entrySet() ) { + List generated = entry.getValue().stream().map( this::getDoneFutureValue ) + .collect( Collectors.toList()); + assertThat( generated ) + .hasSize( taskCountPerTenant ) + // Check for uniqueness + .containsExactlyInAnyOrderElementsOf( new HashSet<>( generated ) ); + System.out.println( "Generated IDs for '" + entry.getKey() + "': " + generated ); + } + } + + private Optimizer buildOptimizer(long initial, int increment) { + return OptimizerFactory.buildOptimizer( optimizerDescriptor.getExternalName(), Long.class, increment, initial ); + } + + private R getDoneFutureValue(Future future) { + try { + return future.get(0, TimeUnit.SECONDS); + } + catch (InterruptedException | ExecutionException | TimeoutException e) { + throw new AssertionFailure( "Unexpected Future state", e ); + } + } + +} diff --git a/hibernate-core/src/test/java/org/hibernate/id/enhanced/OptimizerUnitTest.java b/hibernate-core/src/test/java/org/hibernate/id/enhanced/OptimizerUnitTest.java index 808b3ed1c7fe..05579cbd995e 100644 --- a/hibernate-core/src/test/java/org/hibernate/id/enhanced/OptimizerUnitTest.java +++ b/hibernate-core/src/test/java/org/hibernate/id/enhanced/OptimizerUnitTest.java @@ -6,12 +6,8 @@ */ package org.hibernate.id.enhanced; -import org.junit.Ignore; -import org.junit.Test; - -import org.hibernate.id.IdentifierGeneratorHelper; -import org.hibernate.id.IntegralDataTypeHolder; import org.hibernate.testing.junit4.BaseUnitTestCase; +import org.junit.Test; import static org.junit.Assert.assertEquals; @@ -321,64 +317,4 @@ private static Optimizer buildOptimizer( return OptimizerFactory.buildOptimizer( descriptor.getExternalName(), Long.class, increment, initial ); } - private static class SourceMock implements AccessCallback { - private IdentifierGeneratorHelper.BasicHolder value = new IdentifierGeneratorHelper.BasicHolder( Long.class ); - private long initialValue; - private int increment; - private int timesCalled = 0; - - public SourceMock(long initialValue) { - this( initialValue, 1 ); - } - - public SourceMock(long initialValue, int increment) { - this( initialValue, increment, 0 ); - } - - public SourceMock(long initialValue, int increment, int timesCalled) { - this.increment = increment; - this.timesCalled = timesCalled; - if ( timesCalled != 0 ) { - this.value.initialize( initialValue ); - this.initialValue = 1; - } - else { - this.value.initialize( -1 ); - this.initialValue = initialValue; - } - } - - public IntegralDataTypeHolder getNextValue() { - try { - if ( timesCalled == 0 ) { - initValue(); - return value.copy(); - } - else { - return value.add( increment ).copy(); - } - } - finally { - timesCalled++; - } - } - - @Override - public String getTenantIdentifier() { - return null; - } - - private void initValue() { - this.value.initialize( initialValue ); - } - - public int getTimesCalled() { - return timesCalled; - } - - public long getCurrentValue() { - return value == null ? -1 : value.getActualLongValue(); - } - } - } diff --git a/hibernate-core/src/test/java/org/hibernate/id/enhanced/SourceMock.java b/hibernate-core/src/test/java/org/hibernate/id/enhanced/SourceMock.java new file mode 100644 index 000000000000..3015cfb6c777 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/id/enhanced/SourceMock.java @@ -0,0 +1,79 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.id.enhanced; + +import org.hibernate.id.IdentifierGeneratorHelper; +import org.hibernate.id.IntegralDataTypeHolder; + +class SourceMock implements AccessCallback { + private final String tenantId; + private final long initialValue; + private final int increment; + private volatile long currentValue; + private volatile int timesCalled; + + public SourceMock(long initialValue) { + this( initialValue, 1 ); + } + + public SourceMock(long initialValue, int increment) { + this( null, initialValue, increment ); + } + + public SourceMock(String tenantId, long initialValue, int increment) { + this( tenantId, initialValue, increment, 0 ); + } + + public SourceMock(long initialValue, int increment, int timesCalled) { + this( null, initialValue, increment, timesCalled ); + } + + public SourceMock(String tenantId, long initialValue, int increment, int timesCalled) { + this.tenantId = tenantId; + this.increment = increment; + this.timesCalled = timesCalled; + if ( timesCalled != 0 ) { + this.currentValue = initialValue; + this.initialValue = 1; + } + else { + this.currentValue = -1; + this.initialValue = initialValue; + } + } + + @Override + public synchronized IntegralDataTypeHolder getNextValue() { + try { + if ( timesCalled == 0 ) { + currentValue = initialValue; + } + else { + currentValue += increment; + } + IdentifierGeneratorHelper.BasicHolder result = new IdentifierGeneratorHelper.BasicHolder( Long.class ); + result.initialize( currentValue ); + return result; + } + finally { + ++timesCalled; + } + } + + @Override + public String getTenantIdentifier() { + return tenantId; + } + + public int getTimesCalled() { + return timesCalled; + } + + public long getCurrentValue() { + return currentValue; + } +} From 5c155f3f8db035c626bae877a045712caad2d28c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Mon, 8 Feb 2021 13:23:58 +0100 Subject: [PATCH 005/644] HHH-14444 Avoid synchronization for single-tenant generation in PooledLoThreadLocalOptimizer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Yoann Rodière --- .../PooledLoThreadLocalOptimizer.java | 28 ++++++++++--------- 1 file changed, 15 insertions(+), 13 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/id/enhanced/PooledLoThreadLocalOptimizer.java b/hibernate-core/src/main/java/org/hibernate/id/enhanced/PooledLoThreadLocalOptimizer.java index e54af6d14812..7d1a58d4532b 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/enhanced/PooledLoThreadLocalOptimizer.java +++ b/hibernate-core/src/main/java/org/hibernate/id/enhanced/PooledLoThreadLocalOptimizer.java @@ -58,26 +58,28 @@ public PooledLoThreadLocalOptimizer(Class returnClass, int incrementSize) { public Serializable generate(AccessCallback callback) { if ( callback.getTenantIdentifier() == null ) { final GenerationState local = localAssignedIds.get(); - if ( local.value != null && local.value.lt( local.upperLimitValue ) ) { - return local.value.makeValueThenIncrement(); - } + return generate( local, callback ); } synchronized (this) { final GenerationState generationState = locateGenerationState( callback.getTenantIdentifier() ); - if ( generationState.lastSourceValue == null - || !generationState.value.lt( generationState.upperLimitValue )) { - generationState.lastSourceValue = callback.getNextValue(); - generationState.upperLimitValue = generationState.lastSourceValue.copy().add( incrementSize ); - generationState.value = generationState.lastSourceValue.copy(); - // handle cases where initial-value is less that one (hsqldb for instance). - while (generationState.value.lt( 1 )) { - generationState.value.increment(); - } + return generate(generationState, callback); + } + } + + private Serializable generate(GenerationState generationState, AccessCallback callback) { + if ( generationState.value == null + || !generationState.value.lt( generationState.upperLimitValue ) ) { + generationState.lastSourceValue = callback.getNextValue(); + generationState.upperLimitValue = generationState.lastSourceValue.copy().add( incrementSize ); + generationState.value = generationState.lastSourceValue.copy(); + // handle cases where initial-value is less that one (hsqldb for instance). + while ( generationState.value.lt( 1 ) ) { + generationState.value.increment(); } - return generationState.value.makeValueThenIncrement(); } + return generationState.value.makeValueThenIncrement(); } private Map tenantSpecificState; From 511dda7deed08a2eb304674dd524485c6e14cbbd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Mon, 8 Feb 2021 13:27:54 +0100 Subject: [PATCH 006/644] HHH-14444 Avoid synchronization for multi-tenant generation in PooledLoThreadLocalOptimizer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Yoann Rodière --- .../PooledLoThreadLocalOptimizer.java | 35 ++++++------------- 1 file changed, 10 insertions(+), 25 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/id/enhanced/PooledLoThreadLocalOptimizer.java b/hibernate-core/src/main/java/org/hibernate/id/enhanced/PooledLoThreadLocalOptimizer.java index 7d1a58d4532b..307629c22797 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/enhanced/PooledLoThreadLocalOptimizer.java +++ b/hibernate-core/src/main/java/org/hibernate/id/enhanced/PooledLoThreadLocalOptimizer.java @@ -40,6 +40,9 @@ private static class GenerationState { private IntegralDataTypeHolder upperLimitValue; } + private final ThreadLocal singleTenantState = ThreadLocal.withInitial( GenerationState::new ); + private final ThreadLocal> multiTenantStates = ThreadLocal.withInitial( HashMap::new ); + /** * Constructs a PooledLoThreadLocalOptimizer. * @@ -56,16 +59,8 @@ public PooledLoThreadLocalOptimizer(Class returnClass, int incrementSize) { @Override public Serializable generate(AccessCallback callback) { - if ( callback.getTenantIdentifier() == null ) { - final GenerationState local = localAssignedIds.get(); - return generate( local, callback ); - } - - synchronized (this) { - final GenerationState generationState = locateGenerationState( callback.getTenantIdentifier() ); - - return generate(generationState, callback); - } + final GenerationState generationState = locateGenerationState( callback.getTenantIdentifier() ); + return generate( generationState, callback ); } private Serializable generate(GenerationState generationState, AccessCallback callback) { @@ -82,26 +77,16 @@ private Serializable generate(GenerationState generationState, AccessCallback ca return generationState.value.makeValueThenIncrement(); } - private Map tenantSpecificState; - private final ThreadLocal localAssignedIds = ThreadLocal.withInitial( GenerationState::new ); - private GenerationState locateGenerationState(String tenantIdentifier) { if ( tenantIdentifier == null ) { - return localAssignedIds.get(); + return singleTenantState.get(); } else { - GenerationState state; - if ( tenantSpecificState == null ) { - tenantSpecificState = new HashMap(); + Map states = multiTenantStates.get(); + GenerationState state = states.get( tenantIdentifier ); + if ( state == null ) { state = new GenerationState(); - tenantSpecificState.put( tenantIdentifier, state ); - } - else { - state = tenantSpecificState.get( tenantIdentifier ); - if ( state == null ) { - state = new GenerationState(); - tenantSpecificState.put( tenantIdentifier, state ); - } + states.put( tenantIdentifier, state ); } return state; } From 14e181806fd4e4b30704256490fc25f13d0d0637 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Mon, 8 Feb 2021 13:31:02 +0100 Subject: [PATCH 007/644] HHH-14444 Encapsulate ID generation in GenerationState for PooledLoThreadLocalOptimizer MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is just a cosmetic change, it doesn't change the behavior at all. Signed-off-by: Yoann Rodière --- .../PooledLoThreadLocalOptimizer.java | 49 +++++++++---------- 1 file changed, 24 insertions(+), 25 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/id/enhanced/PooledLoThreadLocalOptimizer.java b/hibernate-core/src/main/java/org/hibernate/id/enhanced/PooledLoThreadLocalOptimizer.java index 307629c22797..ead2222275db 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/enhanced/PooledLoThreadLocalOptimizer.java +++ b/hibernate-core/src/main/java/org/hibernate/id/enhanced/PooledLoThreadLocalOptimizer.java @@ -31,15 +31,6 @@ public class PooledLoThreadLocalOptimizer extends AbstractOptimizer { PooledLoOptimizer.class.getName() ); - private static class GenerationState { - // last value read from db source - private IntegralDataTypeHolder lastSourceValue; - // the current generator value - private IntegralDataTypeHolder value; - // the value at which we'll hit the db again - private IntegralDataTypeHolder upperLimitValue; - } - private final ThreadLocal singleTenantState = ThreadLocal.withInitial( GenerationState::new ); private final ThreadLocal> multiTenantStates = ThreadLocal.withInitial( HashMap::new ); @@ -59,22 +50,8 @@ public PooledLoThreadLocalOptimizer(Class returnClass, int incrementSize) { @Override public Serializable generate(AccessCallback callback) { - final GenerationState generationState = locateGenerationState( callback.getTenantIdentifier() ); - return generate( generationState, callback ); - } - - private Serializable generate(GenerationState generationState, AccessCallback callback) { - if ( generationState.value == null - || !generationState.value.lt( generationState.upperLimitValue ) ) { - generationState.lastSourceValue = callback.getNextValue(); - generationState.upperLimitValue = generationState.lastSourceValue.copy().add( incrementSize ); - generationState.value = generationState.lastSourceValue.copy(); - // handle cases where initial-value is less that one (hsqldb for instance). - while ( generationState.value.lt( 1 ) ) { - generationState.value.increment(); - } - } - return generationState.value.makeValueThenIncrement(); + return locateGenerationState( callback.getTenantIdentifier() ) + .generate( callback, incrementSize ); } private GenerationState locateGenerationState(String tenantIdentifier) { @@ -112,4 +89,26 @@ public IntegralDataTypeHolder getLastSourceValue() { public boolean applyIncrementSizeToSourceValues() { return true; } + + private static class GenerationState { + // last value read from db source + private IntegralDataTypeHolder lastSourceValue; + // the current generator value + private IntegralDataTypeHolder value; + // the value at which we'll hit the db again + private IntegralDataTypeHolder upperLimitValue; + + private Serializable generate(AccessCallback callback, int incrementSize) { + if ( value == null || !value.lt( upperLimitValue ) ) { + lastSourceValue = callback.getNextValue(); + upperLimitValue = lastSourceValue.copy().add( incrementSize ); + value = lastSourceValue.copy(); + // handle cases where initial-value is less that one (hsqldb for instance). + while ( value.lt( 1 ) ) { + value.increment(); + } + } + return value.makeValueThenIncrement(); + } + } } From 81a9b87ec19112c89970a85382ba93de4968ac66 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Mon, 25 Jan 2021 21:25:39 +0000 Subject: [PATCH 008/644] HHH-14447 Add missing EventGroupListeners into FastSessionService and take advantage of them --- .../action/internal/CollectionAction.java | 15 +++ .../internal/CollectionRecreateAction.java | 32 +++---- .../internal/CollectionRemoveAction.java | 31 +++--- .../internal/CollectionUpdateAction.java | 31 +++--- .../action/internal/EntityAction.java | 18 +++- .../action/internal/EntityDeleteAction.java | 67 ++++++------- .../internal/EntityIdentityInsertAction.java | 57 +++++------ .../action/internal/EntityInsertAction.java | 54 ++++------- .../action/internal/EntityUpdateAction.java | 55 ++++------- .../AbstractFlushingEventListener.java | 11 +-- .../event/service/spi/EventListenerGroup.java | 18 +++- .../internal/FastSessionServices.java | 94 ++++++++++++++----- .../java/org/hibernate/loader/Loader.java | 5 +- .../process/internal/AbstractRowReader.java | 5 +- 14 files changed, 262 insertions(+), 231 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/CollectionAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/CollectionAction.java index aeea0b96d650..0338b451f35e 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/CollectionAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/CollectionAction.java @@ -20,6 +20,7 @@ import org.hibernate.event.service.spi.EventListenerRegistry; import org.hibernate.event.spi.EventSource; import org.hibernate.event.spi.EventType; +import org.hibernate.internal.FastSessionServices; import org.hibernate.internal.util.StringHelper; import org.hibernate.persister.collection.CollectionPersister; import org.hibernate.pretty.MessageHelper; @@ -184,6 +185,11 @@ public void doAfterTransactionCompletion(boolean success, SharedSessionContractI } } + /** + * @deprecated This will be removed as it's not very efficient. If you need access to EventListenerGroup(s), + * use the direct references from {@link #getFastSessionServices()}. + */ + @Deprecated protected EventListenerGroup listenerGroup(EventType eventType) { return getSession() .getFactory() @@ -195,4 +201,13 @@ protected EventListenerGroup listenerGroup(EventType eventType) { protected EventSource eventSource() { return (EventSource) getSession(); } + + /** + * Convenience method for all subclasses. + * @return the {@link FastSessionServices} instance from the SessionFactory. + */ + protected FastSessionServices getFastSessionServices() { + return session.getFactory().getFastSessionServices(); + } + } diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/CollectionRecreateAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/CollectionRecreateAction.java index b1823b8683a0..b97d87ad5d6d 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/CollectionRecreateAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/CollectionRecreateAction.java @@ -11,8 +11,6 @@ import org.hibernate.HibernateException; import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.event.service.spi.EventListenerGroup; -import org.hibernate.event.spi.EventType; import org.hibernate.event.spi.PostCollectionRecreateEvent; import org.hibernate.event.spi.PostCollectionRecreateEventListener; import org.hibernate.event.spi.PreCollectionRecreateEvent; @@ -61,24 +59,22 @@ public void execute() throws HibernateException { } private void preRecreate() { - final EventListenerGroup listenerGroup = listenerGroup( EventType.PRE_COLLECTION_RECREATE ); - if ( listenerGroup.isEmpty() ) { - return; - } - final PreCollectionRecreateEvent event = new PreCollectionRecreateEvent( getPersister(), getCollection(), eventSource() ); - for ( PreCollectionRecreateEventListener listener : listenerGroup.listeners() ) { - listener.onPreRecreateCollection( event ); - } + getFastSessionServices() + .eventListenerGroup_PRE_COLLECTION_RECREATE + .fireLazyEventOnEachListener( this::newPreCollectionRecreateEvent, PreCollectionRecreateEventListener::onPreRecreateCollection ); + } + + private PreCollectionRecreateEvent newPreCollectionRecreateEvent() { + return new PreCollectionRecreateEvent( getPersister(), getCollection(), eventSource() ); } private void postRecreate() { - final EventListenerGroup listenerGroup = listenerGroup( EventType.POST_COLLECTION_RECREATE ); - if ( listenerGroup.isEmpty() ) { - return; - } - final PostCollectionRecreateEvent event = new PostCollectionRecreateEvent( getPersister(), getCollection(), eventSource() ); - for ( PostCollectionRecreateEventListener listener : listenerGroup.listeners() ) { - listener.onPostRecreateCollection( event ); - } + getFastSessionServices() + .eventListenerGroup_POST_COLLECTION_RECREATE + .fireLazyEventOnEachListener( this::newPostCollectionRecreateEvent, PostCollectionRecreateEventListener::onPostRecreateCollection ); + } + + private PostCollectionRecreateEvent newPostCollectionRecreateEvent() { + return new PostCollectionRecreateEvent( getPersister(), getCollection(), eventSource() ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/CollectionRemoveAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/CollectionRemoveAction.java index 5bcc5b51713c..a81fdce7f949 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/CollectionRemoveAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/CollectionRemoveAction.java @@ -114,34 +114,33 @@ public void execute() throws HibernateException { } private void preRemove() { - final EventListenerGroup listenerGroup = listenerGroup( EventType.PRE_COLLECTION_REMOVE ); - if ( listenerGroup.isEmpty() ) { - return; - } - final PreCollectionRemoveEvent event = new PreCollectionRemoveEvent( + getFastSessionServices() + .eventListenerGroup_PRE_COLLECTION_REMOVE + .fireLazyEventOnEachListener( this::newPreCollectionRemoveEvent, PreCollectionRemoveEventListener::onPreRemoveCollection ); + } + + private PreCollectionRemoveEvent newPreCollectionRemoveEvent() { + return new PreCollectionRemoveEvent( getPersister(), getCollection(), eventSource(), affectedOwner ); - for ( PreCollectionRemoveEventListener listener : listenerGroup.listeners() ) { - listener.onPreRemoveCollection( event ); - } } private void postRemove() { - final EventListenerGroup listenerGroup = listenerGroup( EventType.POST_COLLECTION_REMOVE ); - if ( listenerGroup.isEmpty() ) { - return; - } - final PostCollectionRemoveEvent event = new PostCollectionRemoveEvent( + getFastSessionServices() + .eventListenerGroup_POST_COLLECTION_REMOVE + .fireLazyEventOnEachListener( this::newPostCollectionRemoveEvent, PostCollectionRemoveEventListener::onPostRemoveCollection ); + } + + private PostCollectionRemoveEvent newPostCollectionRemoveEvent() { + return new PostCollectionRemoveEvent( getPersister(), getCollection(), eventSource(), affectedOwner ); - for ( PostCollectionRemoveEventListener listener : listenerGroup.listeners() ) { - listener.onPostRemoveCollection( event ); - } } + } diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/CollectionUpdateAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/CollectionUpdateAction.java index e44805c281a0..e8aba7ff2ddd 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/CollectionUpdateAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/CollectionUpdateAction.java @@ -100,32 +100,31 @@ else if ( collection.needsRecreate( persister ) ) { } private void preUpdate() { - final EventListenerGroup listenerGroup = listenerGroup( EventType.PRE_COLLECTION_UPDATE ); - if ( listenerGroup.isEmpty() ) { - return; - } - final PreCollectionUpdateEvent event = new PreCollectionUpdateEvent( + getFastSessionServices() + .eventListenerGroup_PRE_COLLECTION_UPDATE + .fireLazyEventOnEachListener( this::newPreCollectionUpdateEvent, PreCollectionUpdateEventListener::onPreUpdateCollection ); + } + + private PreCollectionUpdateEvent newPreCollectionUpdateEvent() { + return new PreCollectionUpdateEvent( getPersister(), getCollection(), eventSource() ); - for ( PreCollectionUpdateEventListener listener : listenerGroup.listeners() ) { - listener.onPreUpdateCollection( event ); - } } private void postUpdate() { - final EventListenerGroup listenerGroup = listenerGroup( EventType.POST_COLLECTION_UPDATE ); - if ( listenerGroup.isEmpty() ) { - return; - } - final PostCollectionUpdateEvent event = new PostCollectionUpdateEvent( + getFastSessionServices() + .eventListenerGroup_POST_COLLECTION_UPDATE + .fireLazyEventOnEachListener( this::newPostCollectionUpdateEvent, PostCollectionUpdateEventListener::onPostUpdateCollection ); + } + + private PostCollectionUpdateEvent newPostCollectionUpdateEvent() { + return new PostCollectionUpdateEvent( getPersister(), getCollection(), eventSource() ); - for ( PostCollectionUpdateEventListener listener : listenerGroup.listeners() ) { - listener.onPostUpdateCollection( event ); - } } + } diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityAction.java index b69f3deec2b7..a154f8dd7d9f 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityAction.java @@ -18,12 +18,11 @@ import org.hibernate.event.service.spi.EventListenerRegistry; import org.hibernate.event.spi.EventSource; import org.hibernate.event.spi.EventType; +import org.hibernate.internal.FastSessionServices; import org.hibernate.internal.util.StringHelper; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.pretty.MessageHelper; -import org.jboss.logging.Logger; - /** * Base class for actions relating to insert/update/delete of an entity * instance. @@ -32,7 +31,6 @@ */ public abstract class EntityAction implements Executable, Serializable, Comparable, AfterTransactionCompletionProcess { - private static final Logger LOG = Logger.getLogger(EntityAction.class); private final String entityName; private final Serializable id; @@ -189,6 +187,11 @@ public void afterDeserialize(SharedSessionContractImplementor session) { } } + /** + * @deprecated This will be removed as it's not very efficient. If you need access to EventListenerGroup(s), + * use the direct references from {@link #getFastSessionServices()}. + */ + @Deprecated protected EventListenerGroup listenerGroup(EventType eventType) { return getSession() .getFactory() @@ -200,4 +203,13 @@ protected EventListenerGroup listenerGroup(EventType eventType) { protected EventSource eventSource() { return (EventSource) getSession(); } + + /** + * Convenience method for all subclasses. + * @return the {@link FastSessionServices} instance from the SessionFactory. + */ + protected FastSessionServices getFastSessionServices() { + return session.getFactory().getFastSessionServices(); + } + } diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityDeleteAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityDeleteAction.java index 9054f3be2e54..8eb41190f324 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityDeleteAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityDeleteAction.java @@ -17,7 +17,6 @@ import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.event.service.spi.EventListenerGroup; -import org.hibernate.event.spi.EventType; import org.hibernate.event.spi.PostCommitDeleteEventListener; import org.hibernate.event.spi.PostDeleteEvent; import org.hibernate.event.spi.PostDeleteEventListener; @@ -154,7 +153,7 @@ public void execute() throws HibernateException { protected boolean preDelete() { boolean veto = false; - final EventListenerGroup listenerGroup = listenerGroup( EventType.PRE_DELETE ); + final EventListenerGroup listenerGroup = getFastSessionServices().eventListenerGroup_PRE_DELETE; if ( listenerGroup.isEmpty() ) { return veto; } @@ -166,47 +165,49 @@ protected boolean preDelete() { } protected void postDelete() { - final EventListenerGroup listenerGroup = listenerGroup( EventType.POST_DELETE ); - if ( listenerGroup.isEmpty() ) { - return; - } - final PostDeleteEvent event = new PostDeleteEvent( + getFastSessionServices() + .eventListenerGroup_POST_DELETE + .fireLazyEventOnEachListener( this::newPostDeleteEvent, PostDeleteEventListener::onPostDelete ); + } + + PostDeleteEvent newPostDeleteEvent() { + return new PostDeleteEvent( getInstance(), getId(), state, getPersister(), eventSource() ); - for ( PostDeleteEventListener listener : listenerGroup.listeners() ) { + } + + protected void postCommitDelete(boolean success) { + final EventListenerGroup eventListeners = getFastSessionServices() + .eventListenerGroup_POST_COMMIT_DELETE; + if (success) { + eventListeners.fireLazyEventOnEachListener( this::newPostDeleteEvent, EntityDeleteAction::postCommitDeleteOnSuccess ); + } + else { + eventListeners.fireLazyEventOnEachListener( this::newPostDeleteEvent, EntityDeleteAction::postCommitDeleteOnUnsuccessful ); + } + } + + private static void postCommitDeleteOnSuccess(PostDeleteEventListener listener, PostDeleteEvent event) { + if ( listener instanceof PostCommitDeleteEventListener ) { + listener.onPostDelete( event ); + } + else { + //default to the legacy implementation that always fires the event listener.onPostDelete( event ); } } - protected void postCommitDelete(boolean success) { - final EventListenerGroup listenerGroup = listenerGroup( EventType.POST_COMMIT_DELETE ); - if ( listenerGroup.isEmpty() ) { - return; + private static void postCommitDeleteOnUnsuccessful(PostDeleteEventListener listener, PostDeleteEvent event) { + if ( listener instanceof PostCommitDeleteEventListener ) { + ( (PostCommitDeleteEventListener) listener ).onPostDeleteCommitFailed( event ); } - final PostDeleteEvent event = new PostDeleteEvent( - getInstance(), - getId(), - state, - getPersister(), - eventSource() - ); - for ( PostDeleteEventListener listener : listenerGroup.listeners() ) { - if ( PostCommitDeleteEventListener.class.isInstance( listener ) ) { - if ( success ) { - listener.onPostDelete( event ); - } - else { - ((PostCommitDeleteEventListener) listener).onPostDeleteCommitFailed( event ); - } - } - else { - //default to the legacy implementation that always fires the event - listener.onPostDelete( event ); - } + else { + //default to the legacy implementation that always fires the event + listener.onPostDelete( event ); } } @@ -228,7 +229,7 @@ public void doAfterTransactionCompletion(boolean success, SharedSessionContractI @Override protected boolean hasPostCommitEventListeners() { - final EventListenerGroup group = listenerGroup( EventType.POST_COMMIT_DELETE ); + final EventListenerGroup group = getFastSessionServices().eventListenerGroup_POST_COMMIT_DELETE; for ( PostDeleteEventListener listener : group.listeners() ) { if ( listener.requiresPostCommitHandling( getPersister() ) ) { return true; diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityIdentityInsertAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityIdentityInsertAction.java index c962c2c1d80a..422e3918c492 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityIdentityInsertAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityIdentityInsertAction.java @@ -121,7 +121,7 @@ public boolean needsAfterTransactionCompletion() { @Override protected boolean hasPostCommitEventListeners() { - final EventListenerGroup group = listenerGroup( EventType.POST_COMMIT_INSERT ); + final EventListenerGroup group = getFastSessionServices().eventListenerGroup_POST_COMMIT_INSERT; for ( PostInsertEventListener listener : group.listeners() ) { if ( listener.requiresPostCommitHandling( getPersister() ) ) { return true; @@ -142,57 +142,42 @@ public void doAfterTransactionCompletion(boolean success, SharedSessionContractI } protected void postInsert() { - final EventSource eventSource = eventSource(); if ( isDelayed ) { - eventSource.getPersistenceContextInternal().replaceDelayedEntityIdentityInsertKeys( delayedEntityKey, generatedId ); + eventSource().getPersistenceContextInternal().replaceDelayedEntityIdentityInsertKeys( delayedEntityKey, generatedId ); } + getFastSessionServices() + .eventListenerGroup_POST_INSERT + .fireLazyEventOnEachListener( this::newPostInsertEvent, PostInsertEventListener::onPostInsert ); + } - final EventListenerGroup listenerGroup = listenerGroup( EventType.POST_INSERT ); - if ( listenerGroup.isEmpty() ) { - return; - } - final PostInsertEvent event = new PostInsertEvent( + PostInsertEvent newPostInsertEvent() { + return new PostInsertEvent( getInstance(), generatedId, getState(), getPersister(), - eventSource + eventSource() ); - for ( PostInsertEventListener listener : listenerGroup.listeners() ) { - listener.onPostInsert( event ); - } } protected void postCommitInsert(boolean success) { - final EventListenerGroup listenerGroup = listenerGroup( EventType.POST_COMMIT_INSERT ); - if ( listenerGroup.isEmpty() ) { - return; + getFastSessionServices() + .eventListenerGroup_POST_COMMIT_INSERT + .fireLazyEventOnEachListener( this::newPostInsertEvent, success ? PostInsertEventListener::onPostInsert : this::postCommitInsertOnFailure ); + } + + private void postCommitInsertOnFailure(PostInsertEventListener listener, PostInsertEvent event) { + if ( listener instanceof PostCommitInsertEventListener ) { + ((PostCommitInsertEventListener) listener).onPostInsertCommitFailed( event ); } - final PostInsertEvent event = new PostInsertEvent( - getInstance(), - generatedId, - getState(), - getPersister(), - eventSource() - ); - for ( PostInsertEventListener listener : listenerGroup.listeners() ) { - if ( PostCommitInsertEventListener.class.isInstance( listener ) ) { - if ( success ) { - listener.onPostInsert( event ); - } - else { - ((PostCommitInsertEventListener) listener).onPostInsertCommitFailed( event ); - } - } - else { - //default to the legacy implementation that always fires the event - listener.onPostInsert( event ); - } + else { + //default to the legacy implementation that always fires the event + listener.onPostInsert( event ); } } protected boolean preInsert() { - final EventListenerGroup listenerGroup = listenerGroup( EventType.PRE_INSERT ); + final EventListenerGroup listenerGroup = getFastSessionServices().eventListenerGroup_PRE_INSERT; if ( listenerGroup.isEmpty() ) { // NO_VETO return false; diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityInsertAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityInsertAction.java index fcbadde8e0ea..cf32a4962626 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityInsertAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityInsertAction.java @@ -171,54 +171,41 @@ protected boolean cacheInsert(EntityPersister persister, Object ck) { } protected void postInsert() { - final EventListenerGroup listenerGroup = listenerGroup( EventType.POST_INSERT ); - if ( listenerGroup.isEmpty() ) { - return; - } - final PostInsertEvent event = new PostInsertEvent( + getFastSessionServices() + .eventListenerGroup_POST_INSERT + .fireLazyEventOnEachListener( this::newPostInsertEvent, PostInsertEventListener::onPostInsert ); + } + + private PostInsertEvent newPostInsertEvent() { + return new PostInsertEvent( getInstance(), getId(), getState(), getPersister(), eventSource() ); - for ( PostInsertEventListener listener : listenerGroup.listeners() ) { - listener.onPostInsert( event ); - } } protected void postCommitInsert(boolean success) { - final EventListenerGroup listenerGroup = listenerGroup( EventType.POST_COMMIT_INSERT ); - if ( listenerGroup.isEmpty() ) { - return; + getFastSessionServices() + .eventListenerGroup_POST_COMMIT_INSERT + .fireLazyEventOnEachListener( this::newPostInsertEvent, success ? PostInsertEventListener::onPostInsert : this::postCommitOnFailure ); + } + + private void postCommitOnFailure(PostInsertEventListener listener, PostInsertEvent event) { + if ( listener instanceof PostCommitInsertEventListener ) { + ((PostCommitInsertEventListener) listener).onPostInsertCommitFailed( event ); } - final PostInsertEvent event = new PostInsertEvent( - getInstance(), - getId(), - getState(), - getPersister(), - eventSource() - ); - for ( PostInsertEventListener listener : listenerGroup.listeners() ) { - if ( PostCommitInsertEventListener.class.isInstance( listener ) ) { - if ( success ) { - listener.onPostInsert( event ); - } - else { - ((PostCommitInsertEventListener) listener).onPostInsertCommitFailed( event ); - } - } - else { - //default to the legacy implementation that always fires the event - listener.onPostInsert( event ); - } + else { + //default to the legacy implementation that always fires the event + listener.onPostInsert( event ); } } protected boolean preInsert() { boolean veto = false; - final EventListenerGroup listenerGroup = listenerGroup( EventType.PRE_INSERT ); + final EventListenerGroup listenerGroup = getFastSessionServices().eventListenerGroup_PRE_INSERT; if ( listenerGroup.isEmpty() ) { return veto; } @@ -263,13 +250,12 @@ protected boolean cacheAfterInsert(EntityDataAccess cache, Object ck) { @Override protected boolean hasPostCommitEventListeners() { - final EventListenerGroup group = listenerGroup( EventType.POST_COMMIT_INSERT ); + final EventListenerGroup group = getFastSessionServices().eventListenerGroup_POST_COMMIT_INSERT; for ( PostInsertEventListener listener : group.listeners() ) { if ( listener.requiresPostCommitHandling( getPersister() ) ) { return true; } } - return false; } diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityUpdateAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityUpdateAction.java index 2560cdb9665f..f2cd99fee0e2 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityUpdateAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityUpdateAction.java @@ -288,7 +288,7 @@ protected boolean cacheUpdate(EntityPersister persister, Object previousVersion, protected boolean preUpdate() { boolean veto = false; - final EventListenerGroup listenerGroup = listenerGroup( EventType.PRE_UPDATE ); + final EventListenerGroup listenerGroup = getFastSessionServices().eventListenerGroup_PRE_UPDATE; if ( listenerGroup.isEmpty() ) { return veto; } @@ -307,11 +307,13 @@ protected boolean preUpdate() { } protected void postUpdate() { - final EventListenerGroup listenerGroup = listenerGroup( EventType.POST_UPDATE ); - if ( listenerGroup.isEmpty() ) { - return; - } - final PostUpdateEvent event = new PostUpdateEvent( + getFastSessionServices() + .eventListenerGroup_POST_UPDATE + .fireLazyEventOnEachListener( this::newPostUpdateEvent, PostUpdateEventListener::onPostUpdate ); + } + + private PostUpdateEvent newPostUpdateEvent() { + return new PostUpdateEvent( getInstance(), getId(), state, @@ -320,44 +322,27 @@ protected void postUpdate() { getPersister(), eventSource() ); - for ( PostUpdateEventListener listener : listenerGroup.listeners() ) { - listener.onPostUpdate( event ); - } } protected void postCommitUpdate(boolean success) { - final EventListenerGroup listenerGroup = listenerGroup( EventType.POST_COMMIT_UPDATE ); - if ( listenerGroup.isEmpty() ) { - return; + getFastSessionServices() + .eventListenerGroup_POST_COMMIT_UPDATE + .fireLazyEventOnEachListener( this::newPostUpdateEvent, success ? PostUpdateEventListener::onPostUpdate : this::onPostCommitFailure ); + } + + private void onPostCommitFailure(PostUpdateEventListener listener, PostUpdateEvent event) { + if ( listener instanceof PostCommitUpdateEventListener ) { + ((PostCommitUpdateEventListener) listener).onPostUpdateCommitFailed( event ); } - final PostUpdateEvent event = new PostUpdateEvent( - getInstance(), - getId(), - state, - previousState, - dirtyFields, - getPersister(), - eventSource() - ); - for ( PostUpdateEventListener listener : listenerGroup.listeners() ) { - if ( PostCommitUpdateEventListener.class.isInstance( listener ) ) { - if ( success ) { - listener.onPostUpdate( event ); - } - else { - ((PostCommitUpdateEventListener) listener).onPostUpdateCommitFailed( event ); - } - } - else { - //default to the legacy implementation that always fires the event - listener.onPostUpdate( event ); - } + else { + //default to the legacy implementation that always fires the event + listener.onPostUpdate( event ); } } @Override protected boolean hasPostCommitEventListeners() { - final EventListenerGroup group = listenerGroup( EventType.POST_COMMIT_UPDATE ); + final EventListenerGroup group = getFastSessionServices().eventListenerGroup_POST_COMMIT_UPDATE; for ( PostUpdateEventListener listener : group.listeners() ) { if ( listener.requiresPostCommitHandling( getPersister() ) ) { return true; diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractFlushingEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractFlushingEventListener.java index 162af5e1a39f..d596c6e8e613 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractFlushingEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractFlushingEventListener.java @@ -28,6 +28,7 @@ import org.hibernate.engine.spi.PersistenceContext; import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.engine.spi.Status; +import org.hibernate.event.service.spi.EventListenerGroup; import org.hibernate.event.service.spi.EventListenerRegistry; import org.hibernate.event.service.spi.JpaBootstrapSensitive; import org.hibernate.event.spi.EventSource; @@ -205,10 +206,8 @@ private int flushEntities(final FlushEvent event, final PersistenceContext persi LOG.trace( "Flushing entities and processing referenced collections" ); final EventSource source = event.getSession(); - final Iterable flushListeners = source.getFactory().getServiceRegistry() - .getService( EventListenerRegistry.class ) - .getEventListenerGroup( EventType.FLUSH_ENTITY ) - .listeners(); + final EventListenerGroup flushListeners = source.getFactory() + .getFastSessionServices().eventListenerGroup_FLUSH_ENTITY; // Among other things, updateReachables() will recursively load all // collections that are moving roles. This might cause entities to @@ -228,9 +227,7 @@ private int flushEntities(final FlushEvent event, final PersistenceContext persi if ( status != Status.LOADING && status != Status.GONE ) { final FlushEntityEvent entityEvent = new FlushEntityEvent( source, me.getKey(), entry ); - for ( FlushEntityEventListener listener : flushListeners ) { - listener.onFlushEntity( entityEvent ); - } + flushListeners.fireEventOnEachListener( entityEvent, FlushEntityEventListener::onFlushEntity ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/event/service/spi/EventListenerGroup.java b/hibernate-core/src/main/java/org/hibernate/event/service/spi/EventListenerGroup.java index 21c47abb95e0..df62868c4894 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/service/spi/EventListenerGroup.java +++ b/hibernate-core/src/main/java/org/hibernate/event/service/spi/EventListenerGroup.java @@ -80,7 +80,7 @@ public interface EventListenerGroup extends Serializable { * Fires an event on each registered event listener of this group. * * Implementation note (performance): - * the first argument is a supplier so that events can avoid allocation when no listener is registered. + * the first argument is a supplier so that events can avoid being created when no listener is registered. * the second argument is specifically designed to avoid needing a capturing lambda. * * @param eventSupplier @@ -88,7 +88,7 @@ public interface EventListenerGroup extends Serializable { * @param the kind of event */ @Incubating - void fireLazyEventOnEachListener(final Supplier eventSupplier, final BiConsumer actionOnEvent); + void fireLazyEventOnEachListener(final Supplier eventSupplier, final BiConsumer actionOnEvent); /** * Similar as {@link #fireLazyEventOnEachListener(Supplier, BiConsumer)} except it doesn't use a {{@link Supplier}}: @@ -98,9 +98,19 @@ public interface EventListenerGroup extends Serializable { * @param the kind of event */ @Incubating - void fireEventOnEachListener(final U event, final BiConsumer actionOnEvent); + void fireEventOnEachListener(final U event, final BiConsumer actionOnEvent); + /** + * Similar to {@link #fireEventOnEachListener(Object, BiConsumer)}, but allows passing a third parameter + * to the consumer; our code based occasionally needs a third parameter: having this additional variant + * allows using the optimal iteration more extensively and reduce allocations. + * @param event + * @param param + * @param actionOnEvent + * @param + * @param + */ @Incubating - void fireEventOnEachListener(final U event, X param, final EventActionWithParameter actionOnEvent); + void fireEventOnEachListener(final U event, X param, final EventActionWithParameter actionOnEvent); } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/FastSessionServices.java b/hibernate-core/src/main/java/org/hibernate/internal/FastSessionServices.java index 7539eb6e460d..8f04bcb53e6a 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/FastSessionServices.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/FastSessionServices.java @@ -26,14 +26,28 @@ import org.hibernate.event.spi.DirtyCheckEventListener; import org.hibernate.event.spi.EventType; import org.hibernate.event.spi.EvictEventListener; +import org.hibernate.event.spi.FlushEntityEventListener; import org.hibernate.event.spi.FlushEventListener; import org.hibernate.event.spi.InitializeCollectionEventListener; import org.hibernate.event.spi.LoadEventListener; import org.hibernate.event.spi.LockEventListener; import org.hibernate.event.spi.MergeEventListener; import org.hibernate.event.spi.PersistEventListener; +import org.hibernate.event.spi.PostCollectionRecreateEventListener; +import org.hibernate.event.spi.PostCollectionRemoveEventListener; +import org.hibernate.event.spi.PostCollectionUpdateEventListener; +import org.hibernate.event.spi.PostDeleteEventListener; +import org.hibernate.event.spi.PostInsertEventListener; import org.hibernate.event.spi.PostLoadEvent; import org.hibernate.event.spi.PostLoadEventListener; +import org.hibernate.event.spi.PostUpdateEventListener; +import org.hibernate.event.spi.PreCollectionRecreateEventListener; +import org.hibernate.event.spi.PreCollectionRemoveEventListener; +import org.hibernate.event.spi.PreCollectionUpdateEventListener; +import org.hibernate.event.spi.PreDeleteEventListener; +import org.hibernate.event.spi.PreInsertEventListener; +import org.hibernate.event.spi.PreLoadEventListener; +import org.hibernate.event.spi.PreUpdateEventListener; import org.hibernate.event.spi.RefreshEventListener; import org.hibernate.event.spi.ReplicateEventListener; import org.hibernate.event.spi.ResolveNaturalIdEventListener; @@ -89,28 +103,44 @@ public final class FastSessionServices { */ final Map defaultSessionProperties; - // All session events need to be iterated frequently: - final EventListenerGroup eventListenerGroup_AUTO_FLUSH; - final EventListenerGroup eventListenerGroup_CLEAR; - final EventListenerGroup eventListenerGroup_DELETE; - final EventListenerGroup eventListenerGroup_DIRTY_CHECK; - final EventListenerGroup eventListenerGroup_EVICT; - final EventListenerGroup eventListenerGroup_FLUSH; - final EventListenerGroup eventListenerGroup_INIT_COLLECTION; - final EventListenerGroup eventListenerGroup_LOAD; - final EventListenerGroup eventListenerGroup_LOCK; - final EventListenerGroup eventListenerGroup_MERGE; - final EventListenerGroup eventListenerGroup_PERSIST; - final EventListenerGroup eventListenerGroup_PERSIST_ONFLUSH; - final EventListenerGroup eventListenerGroup_REFRESH; - final EventListenerGroup eventListenerGroup_REPLICATE; - final EventListenerGroup eventListenerGroup_RESOLVE_NATURAL_ID; - final EventListenerGroup eventListenerGroup_SAVE; - final EventListenerGroup eventListenerGroup_SAVE_UPDATE; - final EventListenerGroup eventListenerGroup_UPDATE; - - //Frequently used by 2LC initialization: - final EventListenerGroup eventListenerGroup_POST_LOAD; + // All session events need to be iterated frequently; CollectionAction and EventAction also need + // most of these very frequently: + public final EventListenerGroup eventListenerGroup_AUTO_FLUSH; + public final EventListenerGroup eventListenerGroup_CLEAR; + public final EventListenerGroup eventListenerGroup_DELETE; + public final EventListenerGroup eventListenerGroup_DIRTY_CHECK; + public final EventListenerGroup eventListenerGroup_EVICT; + public final EventListenerGroup eventListenerGroup_FLUSH_ENTITY; + public final EventListenerGroup eventListenerGroup_FLUSH; + public final EventListenerGroup eventListenerGroup_INIT_COLLECTION; + public final EventListenerGroup eventListenerGroup_LOAD; + public final EventListenerGroup eventListenerGroup_LOCK; + public final EventListenerGroup eventListenerGroup_MERGE; + public final EventListenerGroup eventListenerGroup_PERSIST; + public final EventListenerGroup eventListenerGroup_PERSIST_ONFLUSH; + public final EventListenerGroup eventListenerGroup_POST_COLLECTION_RECREATE; + public final EventListenerGroup eventListenerGroup_POST_COLLECTION_REMOVE; + public final EventListenerGroup eventListenerGroup_POST_COLLECTION_UPDATE; + public final EventListenerGroup eventListenerGroup_POST_COMMIT_DELETE; + public final EventListenerGroup eventListenerGroup_POST_DELETE; + public final EventListenerGroup eventListenerGroup_POST_COMMIT_INSERT; + public final EventListenerGroup eventListenerGroup_POST_INSERT; + public final EventListenerGroup eventListenerGroup_POST_LOAD; //Frequently used by 2LC initialization: + public final EventListenerGroup eventListenerGroup_POST_COMMIT_UPDATE; + public final EventListenerGroup eventListenerGroup_POST_UPDATE; + public final EventListenerGroup eventListenerGroup_PRE_COLLECTION_RECREATE; + public final EventListenerGroup eventListenerGroup_PRE_COLLECTION_REMOVE; + public final EventListenerGroup eventListenerGroup_PRE_COLLECTION_UPDATE; + public final EventListenerGroup eventListenerGroup_PRE_DELETE; + public final EventListenerGroup eventListenerGroup_PRE_INSERT; + public final EventListenerGroup eventListenerGroup_PRE_LOAD; + public final EventListenerGroup eventListenerGroup_PRE_UPDATE; + public final EventListenerGroup eventListenerGroup_REFRESH; + public final EventListenerGroup eventListenerGroup_REPLICATE; + public final EventListenerGroup eventListenerGroup_RESOLVE_NATURAL_ID; + public final EventListenerGroup eventListenerGroup_SAVE; + public final EventListenerGroup eventListenerGroup_SAVE_UPDATE; + public final EventListenerGroup eventListenerGroup_UPDATE; //Intentionally Package private: final boolean disallowOutOfTransactionUpdateOperations; @@ -148,19 +178,36 @@ public final class FastSessionServices { this.eventListenerGroup_DIRTY_CHECK = listeners( eventListenerRegistry, EventType.DIRTY_CHECK ); this.eventListenerGroup_EVICT = listeners( eventListenerRegistry, EventType.EVICT ); this.eventListenerGroup_FLUSH = listeners( eventListenerRegistry, EventType.FLUSH ); + this.eventListenerGroup_FLUSH_ENTITY = listeners( eventListenerRegistry, EventType.FLUSH_ENTITY ); this.eventListenerGroup_INIT_COLLECTION = listeners( eventListenerRegistry, EventType.INIT_COLLECTION ); this.eventListenerGroup_LOAD = listeners( eventListenerRegistry, EventType.LOAD ); this.eventListenerGroup_LOCK = listeners( eventListenerRegistry, EventType.LOCK ); this.eventListenerGroup_MERGE = listeners( eventListenerRegistry, EventType.MERGE ); this.eventListenerGroup_PERSIST = listeners( eventListenerRegistry, EventType.PERSIST ); this.eventListenerGroup_PERSIST_ONFLUSH = listeners( eventListenerRegistry, EventType.PERSIST_ONFLUSH ); + this.eventListenerGroup_POST_COLLECTION_RECREATE = listeners( eventListenerRegistry, EventType.POST_COLLECTION_RECREATE ); + this.eventListenerGroup_POST_COLLECTION_REMOVE = listeners( eventListenerRegistry, EventType.POST_COLLECTION_REMOVE ); + this.eventListenerGroup_POST_COLLECTION_UPDATE = listeners( eventListenerRegistry, EventType.POST_COLLECTION_UPDATE ); + this.eventListenerGroup_POST_COMMIT_DELETE = listeners( eventListenerRegistry, EventType.POST_COMMIT_DELETE ); + this.eventListenerGroup_POST_COMMIT_INSERT = listeners( eventListenerRegistry, EventType.POST_COMMIT_INSERT ); + this.eventListenerGroup_POST_COMMIT_UPDATE = listeners( eventListenerRegistry, EventType.POST_COMMIT_UPDATE ); + this.eventListenerGroup_POST_DELETE = listeners( eventListenerRegistry, EventType.POST_DELETE ); + this.eventListenerGroup_POST_INSERT = listeners( eventListenerRegistry, EventType.POST_INSERT ); + this.eventListenerGroup_POST_LOAD = listeners( eventListenerRegistry, EventType.POST_LOAD ); + this.eventListenerGroup_POST_UPDATE = listeners( eventListenerRegistry, EventType.POST_UPDATE ); + this.eventListenerGroup_PRE_COLLECTION_RECREATE = listeners( eventListenerRegistry, EventType.PRE_COLLECTION_RECREATE ); + this.eventListenerGroup_PRE_COLLECTION_REMOVE = listeners( eventListenerRegistry, EventType.PRE_COLLECTION_REMOVE ); + this.eventListenerGroup_PRE_COLLECTION_UPDATE = listeners( eventListenerRegistry, EventType.PRE_COLLECTION_UPDATE ); + this.eventListenerGroup_PRE_DELETE = listeners( eventListenerRegistry, EventType.PRE_DELETE ); + this.eventListenerGroup_PRE_INSERT = listeners( eventListenerRegistry, EventType.PRE_INSERT ); + this.eventListenerGroup_PRE_LOAD = listeners( eventListenerRegistry, EventType.PRE_LOAD ); + this.eventListenerGroup_PRE_UPDATE = listeners( eventListenerRegistry, EventType.PRE_UPDATE ); this.eventListenerGroup_REFRESH = listeners( eventListenerRegistry, EventType.REFRESH ); this.eventListenerGroup_REPLICATE = listeners( eventListenerRegistry, EventType.REPLICATE ); this.eventListenerGroup_RESOLVE_NATURAL_ID = listeners( eventListenerRegistry, EventType.RESOLVE_NATURAL_ID ); this.eventListenerGroup_SAVE = listeners( eventListenerRegistry, EventType.SAVE ); this.eventListenerGroup_SAVE_UPDATE = listeners( eventListenerRegistry, EventType.SAVE_UPDATE ); this.eventListenerGroup_UPDATE = listeners( eventListenerRegistry, EventType.UPDATE ); - this.eventListenerGroup_POST_LOAD = listeners( eventListenerRegistry, EventType.POST_LOAD ); //Other highly useful constants: this.dialect = jdbcServices.getJdbcEnvironment().getDialect(); @@ -186,6 +233,7 @@ public final class FastSessionServices { this.defaultSessionEventListeners = sessionFactoryOptions.getBaselineSessionEventsListenerBuilder(); this.defaultLockOptions = initializeDefaultLockOptions( defaultSessionProperties ); this.initialSessionFlushMode = initializeDefaultFlushMode( defaultSessionProperties ); + } private static FlushMode initializeDefaultFlushMode(Map defaultSessionProperties) { diff --git a/hibernate-core/src/main/java/org/hibernate/loader/Loader.java b/hibernate-core/src/main/java/org/hibernate/loader/Loader.java index 43239a3b7d9f..589432bd949a 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/Loader.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/Loader.java @@ -1191,9 +1191,8 @@ private void initializeEntitiesAndCollections( if ( hydratedObjectsSize != 0 ) { final Iterable listeners = session .getFactory() - .getServiceRegistry() - .getService( EventListenerRegistry.class ) - .getEventListenerGroup( EventType.PRE_LOAD ) + .getFastSessionServices() + .eventListenerGroup_PRE_LOAD .listeners(); for ( Object hydratedObject : hydratedObjects ) { diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/process/internal/AbstractRowReader.java b/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/process/internal/AbstractRowReader.java index 121e38af3e5e..4e640e41e11f 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/process/internal/AbstractRowReader.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/process/internal/AbstractRowReader.java @@ -239,9 +239,8 @@ private void performTwoPhaseLoad( final SharedSessionContractImplementor session = context.getSession(); final Iterable listeners = session .getFactory() - .getServiceRegistry() - .getService( EventListenerRegistry.class ) - .getEventListenerGroup( EventType.PRE_LOAD ) + .getFastSessionServices() + .eventListenerGroup_PRE_LOAD .listeners(); for ( HydratedEntityRegistration registration : hydratedEntityRegistrations ) { From 2eaa0f8c67871802bd83d361ed26bc00c2f893c1 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Tue, 9 Feb 2021 12:26:08 +0000 Subject: [PATCH 009/644] HHH-14447 Remove unneccessary type check --- .../action/internal/EntityDeleteAction.java | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityDeleteAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityDeleteAction.java index 8eb41190f324..fbe0a12a4cd9 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityDeleteAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityDeleteAction.java @@ -184,23 +184,13 @@ protected void postCommitDelete(boolean success) { final EventListenerGroup eventListeners = getFastSessionServices() .eventListenerGroup_POST_COMMIT_DELETE; if (success) { - eventListeners.fireLazyEventOnEachListener( this::newPostDeleteEvent, EntityDeleteAction::postCommitDeleteOnSuccess ); + eventListeners.fireLazyEventOnEachListener( this::newPostDeleteEvent, PostDeleteEventListener::onPostDelete ); } else { eventListeners.fireLazyEventOnEachListener( this::newPostDeleteEvent, EntityDeleteAction::postCommitDeleteOnUnsuccessful ); } } - private static void postCommitDeleteOnSuccess(PostDeleteEventListener listener, PostDeleteEvent event) { - if ( listener instanceof PostCommitDeleteEventListener ) { - listener.onPostDelete( event ); - } - else { - //default to the legacy implementation that always fires the event - listener.onPostDelete( event ); - } - } - private static void postCommitDeleteOnUnsuccessful(PostDeleteEventListener listener, PostDeleteEvent event) { if ( listener instanceof PostCommitDeleteEventListener ) { ( (PostCommitDeleteEventListener) listener ).onPostDeleteCommitFailed( event ); From 15caff9cbccc1397e5f7da83abb08c03d0e439db Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Tue, 9 Feb 2021 13:03:18 +0100 Subject: [PATCH 010/644] Fix PostgreSQL cleanup wrt extensions, fix Oracle cleanup wrt sys objects, always drop id tables in tests, fix global temp table tests, add on commit delete rows for hana dialects --- .github/ci-prerequisites.sh | 7 ++ .github/workflows/contributor-build.yml | 2 + docker_db.sh | 64 +++++++++++++++++++ gradle/databases.gradle | 33 ++++++---- gradle/java-module.gradle | 2 + .../dialect/HANACloudColumnStoreDialect.java | 5 ++ .../dialect/HANAColumnStoreDialect.java | 5 ++ .../dialect/HANARowStoreDialect.java | 5 ++ .../hibernate/hql/spi/id/IdTableHelper.java | 4 +- .../BaseEntityManagerFunctionalTestCase.java | 4 +- .../org/hibernate/jpa/test/lock/LockTest.java | 3 +- ...tementIsClosedAfterALockExceptionTest.java | 2 +- .../bulkid/AbstractBulkCompositeIdTest.java | 5 +- ...obalTemporaryTableBulkCompositeIdTest.java | 4 +- .../hibernate/test/locking/LockModeTest.java | 8 +++ .../sql/hand/custom/oracle/Mappings.hbm.xml | 1 + .../test/BaseEnversJPAFunctionalTestCase.java | 4 +- .../cleaner/OracleDatabaseCleaner.java | 6 +- .../cleaner/PostgreSQLDatabaseCleaner.java | 14 ++++ .../junit4/BaseCoreFunctionalTestCase.java | 4 +- .../BaseNonConfigCoreFunctionalTestCase.java | 4 +- 21 files changed, 157 insertions(+), 29 deletions(-) create mode 100755 .github/ci-prerequisites.sh diff --git a/.github/ci-prerequisites.sh b/.github/ci-prerequisites.sh new file mode 100755 index 000000000000..91a65fad52f9 --- /dev/null +++ b/.github/ci-prerequisites.sh @@ -0,0 +1,7 @@ +# Reclaim disk space, otherwise we only have 13 GB free at the start of a job + +docker rmi node:10 node:12 mcr.microsoft.com/azure-pipelines/node8-typescript:latest +# That is 18 GB +sudo rm -rf /usr/share/dotnet +# That is 1.2 GB +sudo rm -rf /usr/share/swift \ No newline at end of file diff --git a/.github/workflows/contributor-build.yml b/.github/workflows/contributor-build.yml index 966e5a30110c..3414218fd8a7 100644 --- a/.github/workflows/contributor-build.yml +++ b/.github/workflows/contributor-build.yml @@ -43,6 +43,8 @@ jobs: experimental: true steps: - uses: actions/checkout@v2 + - name: Reclaim Disk Space + run: .github/ci-prerequisites.sh - name: Set up Java 8 uses: actions/setup-java@v1 with: diff --git a/docker_db.sh b/docker_db.sh index 772baee82d45..a7368776d2e5 100755 --- a/docker_db.sh +++ b/docker_db.sh @@ -87,6 +87,70 @@ alter database drop logfile group 3; EOF\"" } +oracle_ee() { + docker rm -f oracle || true + # We need to use the defaults + # sys as sysdba/Oradoc_db1 + docker run --name oracle -d -p 1521:1521 store/oracle/database-enterprise:12.2.0.1-slim + # Give the container some time to start + OUTPUT= + while [[ $OUTPUT != *"NLS_CALENDAR"* ]]; do + echo "Waiting for Oracle to start..." + sleep 10 + OUTPUT=$(docker logs oracle) + done + echo "Oracle successfully started" + # We increase file sizes to avoid online resizes as that requires lots of CPU which is restricted in XE + docker exec oracle bash -c "source /home/oracle/.bashrc; \$ORACLE_HOME/bin/sqlplus sys/Oradoc_db1@ORCLCDB as sysdba <$temp_dir/password.json + chmod 777 -R $temp_dir + docker rm -f hana || true + docker run -d --name hana -p 39013:39013 -p 39017:39017 -p 39041-39045:39041-39045 -p 1128-1129:1128-1129 -p 59013-59014:59013-59014 \ + --ulimit nofile=1048576:1048576 \ + --sysctl kernel.shmmax=1073741824 \ + --sysctl net.ipv4.ip_local_port_range='40000 60999' \ + --sysctl kernel.shmmni=524288 \ + --sysctl kernel.shmall=8388608 \ + -v $temp_dir:/config \ + store/saplabs/hanaexpress:2.00.045.00.20200121.1 \ + --passwords-url file:///config/password.json \ + --agree-to-sap-license + # Give the container some time to start + OUTPUT= + while [[ $OUTPUT != *"Startup finished"* ]]; do + echo "Waiting for HANA to start..." + sleep 10 + OUTPUT=$(docker logs hana) + done + echo "HANA successfully started" +} + if [ -z ${1} ]; then echo "No db name provided" echo "Provide one of:" diff --git a/gradle/databases.gradle b/gradle/databases.gradle index d7fdcedfac3b..b4dcb1d775dd 100644 --- a/gradle/databases.gradle +++ b/gradle/databases.gradle @@ -36,7 +36,8 @@ ext { 'jdbc.driver': 'org.postgresql.Driver', 'jdbc.user' : 'hibernate_orm_test', 'jdbc.pass' : 'hibernate_orm_test', - 'jdbc.url' : 'jdbc:postgresql:hibernate_orm_test' + // Disable prepared statement caching due to https://www.postgresql.org/message-id/CAEcMXhmmRd4-%2BNQbnjDT26XNdUoXdmntV9zdr8%3DTu8PL9aVCYg%40mail.gmail.com + 'jdbc.url' : 'jdbc:postgresql://' + dbHost + '/hibernate_orm_test?preparedStatementCacheQueries=0' ], pgsql_docker : [ 'db.dialect' : 'org.hibernate.dialect.PostgreSQL10Dialect', @@ -87,7 +88,8 @@ ext { 'jdbc.driver': 'org.postgresql.Driver', 'jdbc.user' : 'hibernate_orm_test', 'jdbc.pass' : 'hibernate_orm_test', - 'jdbc.url' : 'jdbc:postgresql:hibernate_orm_test' + // Disable prepared statement caching due to https://www.postgresql.org/message-id/CAEcMXhmmRd4-%2BNQbnjDT26XNdUoXdmntV9zdr8%3DTu8PL9aVCYg%40mail.gmail.com + 'jdbc.url' : 'jdbc:postgresql://' + dbHost + '/hibernate_orm_test?preparedStatementCacheQueries=0' ], oracle : [ 'db.dialect' : 'org.hibernate.dialect.Oracle10gDialect', @@ -96,15 +98,13 @@ ext { 'jdbc.pass' : 'hibernate_orm_test', 'jdbc.url' : 'jdbc:oracle:thin:@localhost:1521/xe' ], - // Uses the default settings for using https://hub.docker.com/_/oracle-database-enterprise-edition - // After registering to get access (see instructions at above link), start it for testing with: - // docker run --ulimit memlock=-1:-1 -it --rm=true --memory-swappiness=0 --name ORCLCDB -p 1521:1521 store/oracle/database-enterprise:12.2.0.1-slim + // Use ./docker_db.sh oracle_ee to start the database oracle_docker : [ 'db.dialect' : 'org.hibernate.dialect.Oracle12cDialect', 'jdbc.driver': 'oracle.jdbc.OracleDriver', - 'jdbc.user' : 'sys as sysdba', - 'jdbc.pass' : 'Oradoc_db1', - 'jdbc.url' : 'jdbc:oracle:thin:@localhost:1521:ORCLCDB' + 'jdbc.user' : 'c##hibernate_orm_test', + 'jdbc.pass' : 'hibernate_orm_test', + 'jdbc.url' : 'jdbc:oracle:thin:@' + dbHost + ':1521/ORCLPDB1.localdomain' ], oracle_ci : [ 'db.dialect' : 'org.hibernate.dialect.Oracle12cDialect', @@ -153,21 +153,32 @@ ext { 'jdbc.driver': 'com.sap.db.jdbc.Driver', 'jdbc.user' : 'HIBERNATE_TEST', 'jdbc.pass' : 'H1bernate_test', - 'jdbc.url' : 'jdbc:sap://localhost:30015/' + // Disable prepared statement caching due to https://help.sap.com/viewer/0eec0d68141541d1b07893a39944924e/2.0.04/en-US/78f2163887814223858e4369d18e2847.html + 'jdbc.url' : 'jdbc:sap://localhost:30015/?statementCacheSize=0' ], hana_cloud : [ 'db.dialect' : 'org.hibernate.dialect.HANACloudColumnStoreDialect', 'jdbc.driver': 'com.sap.db.jdbc.Driver', 'jdbc.user' : 'HIBERNATE_TEST', 'jdbc.pass' : 'H1bernate_test', - 'jdbc.url' : 'jdbc:sap://localhost:443/?encrypt=true&validateCertificate=false' + // Disable prepared statement caching due to https://help.sap.com/viewer/0eec0d68141541d1b07893a39944924e/2.0.04/en-US/78f2163887814223858e4369d18e2847.html + 'jdbc.url' : 'jdbc:sap://localhost:443/?encrypt=true&validateCertificate=false&statementCacheSize=0' ], hana_vlad : [ 'db.dialect' : 'org.hibernate.dialect.HANAColumnStoreDialect', 'jdbc.driver': 'com.sap.db.jdbc.Driver', 'jdbc.user' : 'VLAD', 'jdbc.pass' : 'V1ad_test', - 'jdbc.url' : 'jdbc:sap://localhost:39015/' + // Disable prepared statement caching due to https://help.sap.com/viewer/0eec0d68141541d1b07893a39944924e/2.0.04/en-US/78f2163887814223858e4369d18e2847.html + 'jdbc.url' : 'jdbc:sap://localhost:39015/?statementCacheSize=0' + ], + hana_docker : [ + 'db.dialect' : 'org.hibernate.dialect.HANAColumnStoreDialect', + 'jdbc.driver': 'com.sap.db.jdbc.Driver', + 'jdbc.user' : 'SYSTEM', + 'jdbc.pass' : 'H1bernate_test', + // Disable prepared statement caching due to https://help.sap.com/viewer/0eec0d68141541d1b07893a39944924e/2.0.04/en-US/78f2163887814223858e4369d18e2847.html + 'jdbc.url' : 'jdbc:sap://' + dbHost + ':39017/?statementCacheSize=0' ], cockroachdb : [ 'db.dialect' : 'org.hibernate.dialect.CockroachDB192Dialect', diff --git a/gradle/java-module.gradle b/gradle/java-module.gradle index 4a3066d7908e..8e286469af59 100644 --- a/gradle/java-module.gradle +++ b/gradle/java-module.gradle @@ -287,6 +287,8 @@ test { systemProperty 'user.country', 'US' systemProperty 'user.timezone', 'UTC' systemProperty 'file.encoding', 'UTF-8' + // Needed for AdoptOpenJDK on alpine? The problem is similar to this: https://github.com/mockito/mockito/issues/978 + jvmArgs '-XX:+StartAttachListener' } // Enable the experimental features of ByteBuddy with JDK 15+ diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/HANACloudColumnStoreDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/HANACloudColumnStoreDialect.java index 9948f065228e..58f2342afb8f 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/HANACloudColumnStoreDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/HANACloudColumnStoreDialect.java @@ -103,6 +103,11 @@ public String getTruncateIdTableCommand() { return "truncate table"; } + @Override + public String getCreateIdTableStatementOptions() { + return "on commit delete rows"; + } + }, AfterUseAction.CLEAN ); } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/HANAColumnStoreDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/HANAColumnStoreDialect.java index 4015adeb7294..b14939035b3c 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/HANAColumnStoreDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/HANAColumnStoreDialect.java @@ -62,6 +62,11 @@ public String getTruncateIdTableCommand() { return "truncate table"; } + @Override + public String getCreateIdTableStatementOptions() { + return "on commit delete rows"; + } + }, AfterUseAction.CLEAN ); } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/HANARowStoreDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/HANARowStoreDialect.java index f83d7857dc2f..0587662a25df 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/HANARowStoreDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/HANARowStoreDialect.java @@ -44,6 +44,11 @@ public MultiTableBulkIdStrategy getDefaultMultiTableBulkIdStrategy() { public String getCreateIdTableCommand() { return "create global temporary row table"; } + + @Override + public String getCreateIdTableStatementOptions() { + return "on commit delete rows"; + } }, AfterUseAction.CLEAN ); } diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/IdTableHelper.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/IdTableHelper.java index 85cb7318e60f..551bf3a9e467 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/IdTableHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/IdTableHelper.java @@ -184,7 +184,7 @@ public void executeIdTableCreationStatements( target.accept( createStatement ); } catch ( CommandAcceptanceException e) { - // The exception will be logged, so ignore this + log.debugf( "Error attempting to export id-table [%s] : %s", createStatement, e.getMessage() ); } } } @@ -215,7 +215,7 @@ public void executeIdTableDropStatements( target.accept( dropStatement ); } catch ( CommandAcceptanceException e) { - // The exception will be logged, so ignore this + log.debugf( "Error attempting to drop id-table : [%s]", e.getMessage() ); } } } diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/BaseEntityManagerFunctionalTestCase.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/BaseEntityManagerFunctionalTestCase.java index 70de84fca09d..68d5d7542c21 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/BaseEntityManagerFunctionalTestCase.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/BaseEntityManagerFunctionalTestCase.java @@ -228,9 +228,9 @@ protected Map getConfig() { config.put( AvailableSettings.XML_FILE_NAMES, dds ); } + config.put( GlobalTemporaryTableBulkIdStrategy.DROP_ID_TABLES, "true" ); + config.put( LocalTemporaryTableBulkIdStrategy.DROP_ID_TABLES, "true" ); if ( !config.containsKey( Environment.CONNECTION_PROVIDER ) ) { - config.put( GlobalTemporaryTableBulkIdStrategy.DROP_ID_TABLES, "true" ); - config.put( LocalTemporaryTableBulkIdStrategy.DROP_ID_TABLES, "true" ); config.put( AvailableSettings.CONNECTION_PROVIDER, SharedDriverManagerConnectionProviderImpl.getInstance() diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/lock/LockTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/lock/LockTest.java index 2db85ccd69ff..b4661b3ccf0d 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/lock/LockTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/lock/LockTest.java @@ -61,8 +61,7 @@ public class LockTest extends BaseEntityManagerFunctionalTestCase { @Override protected void addConfigOptions(Map options) { super.addConfigOptions( options ); - // Looks like Oracle Connections that experience a timeout produce different errors when they timeout again?! - SharedDriverManagerConnectionProviderImpl.getInstance().reset(); + // We can't use a shared connection provider if we use TransactionUtil.setJdbcTimeout because that is set on the connection level options.remove( org.hibernate.cfg.AvailableSettings.CONNECTION_PROVIDER ); } diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/lock/StatementIsClosedAfterALockExceptionTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/lock/StatementIsClosedAfterALockExceptionTest.java index de6fbd5c01f2..bd94f204dff3 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/lock/StatementIsClosedAfterALockExceptionTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/lock/StatementIsClosedAfterALockExceptionTest.java @@ -44,7 +44,7 @@ public class StatementIsClosedAfterALockExceptionTest extends BaseEntityManagerF @Override protected Map getConfig() { Map config = super.getConfig(); - CONNECTION_PROVIDER.setConnectionProvider( (ConnectionProvider) config.get( AvailableSettings.CONNECTION_PROVIDER ) ); + // We can't use a shared connection provider if we use TransactionUtil.setJdbcTimeout because that is set on the connection level config.put( org.hibernate.cfg.AvailableSettings.CONNECTION_PROVIDER, CONNECTION_PROVIDER diff --git a/hibernate-core/src/test/java/org/hibernate/test/bulkid/AbstractBulkCompositeIdTest.java b/hibernate-core/src/test/java/org/hibernate/test/bulkid/AbstractBulkCompositeIdTest.java index a21b27896239..4b468ccd1365 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bulkid/AbstractBulkCompositeIdTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bulkid/AbstractBulkCompositeIdTest.java @@ -35,7 +35,10 @@ protected Class[] getAnnotatedClasses() { @Override protected Configuration constructConfiguration() { Configuration configuration = super.constructConfiguration(); - configuration.setProperty( AvailableSettings.HQL_BULK_ID_STRATEGY, getMultiTableBulkIdStrategyClass().getName() ); + Class strategyClass = getMultiTableBulkIdStrategyClass(); + if ( strategyClass != null ) { + configuration.setProperty( AvailableSettings.HQL_BULK_ID_STRATEGY, strategyClass.getName() ); + } return configuration; } diff --git a/hibernate-core/src/test/java/org/hibernate/test/bulkid/GlobalTemporaryTableBulkCompositeIdTest.java b/hibernate-core/src/test/java/org/hibernate/test/bulkid/GlobalTemporaryTableBulkCompositeIdTest.java index 97a348617957..d6b8dd104edc 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bulkid/GlobalTemporaryTableBulkCompositeIdTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bulkid/GlobalTemporaryTableBulkCompositeIdTest.java @@ -14,6 +14,8 @@ public class GlobalTemporaryTableBulkCompositeIdTest extends AbstractBulkComposi @Override protected Class getMultiTableBulkIdStrategyClass() { - return GlobalTemporaryTableBulkIdStrategy.class; + // Since we only allow dialects that support global temporary tables, we avoid overriding the strategy + // This is important because otherwise we would loose id table configurations that are made in the dialects + return null; } } \ No newline at end of file diff --git a/hibernate-core/src/test/java/org/hibernate/test/locking/LockModeTest.java b/hibernate-core/src/test/java/org/hibernate/test/locking/LockModeTest.java index 35c99bc8020a..ed5f620615eb 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/locking/LockModeTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/locking/LockModeTest.java @@ -14,6 +14,8 @@ import org.hibernate.LockMode; import org.hibernate.LockOptions; import org.hibernate.Session; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.cfg.Configuration; import org.hibernate.dialect.CockroachDB192Dialect; import org.hibernate.dialect.SQLServerDialect; import org.hibernate.dialect.SybaseASE15Dialect; @@ -53,6 +55,12 @@ protected Class[] getAnnotatedClasses() { return new Class[] { A.class }; } + @Override + protected void configure(Configuration configuration) { + // We can't use a shared connection provider if we use TransactionUtil.setJdbcTimeout because that is set on the connection level + configuration.getProperties().remove( AvailableSettings.CONNECTION_PROVIDER ); + } + @Override public void prepareTest() throws Exception { doInHibernate( this::sessionFactory, session -> { diff --git a/hibernate-core/src/test/java/org/hibernate/test/sql/hand/custom/oracle/Mappings.hbm.xml b/hibernate-core/src/test/java/org/hibernate/test/sql/hand/custom/oracle/Mappings.hbm.xml index 3ff55901b6a0..dfea94f55f83 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/sql/hand/custom/oracle/Mappings.hbm.xml +++ b/hibernate-core/src/test/java/org/hibernate/test/sql/hand/custom/oracle/Mappings.hbm.xml @@ -125,6 +125,7 @@ FROM ORGANIZATION org LEFT OUTER JOIN EMPLOYMENT emp ON org.ORGID = emp.EMPLOYER WHERE org.ORGID=? + ORDER BY emp.EMPID diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/BaseEnversJPAFunctionalTestCase.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/BaseEnversJPAFunctionalTestCase.java index 7bdca897dfeb..4525a1423b05 100644 --- a/hibernate-envers/src/test/java/org/hibernate/envers/test/BaseEnversJPAFunctionalTestCase.java +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/BaseEnversJPAFunctionalTestCase.java @@ -143,9 +143,9 @@ protected Map getConfig() { config.put( AvailableSettings.XML_FILE_NAMES, dds ); } + config.put( GlobalTemporaryTableBulkIdStrategy.DROP_ID_TABLES, "true" ); + config.put( LocalTemporaryTableBulkIdStrategy.DROP_ID_TABLES, "true" ); if ( !Environment.getProperties().containsKey( Environment.CONNECTION_PROVIDER ) ) { - config.put( GlobalTemporaryTableBulkIdStrategy.DROP_ID_TABLES, "true" ); - config.put( LocalTemporaryTableBulkIdStrategy.DROP_ID_TABLES, "true" ); config.put( org.hibernate.cfg.AvailableSettings.CONNECTION_PROVIDER, SharedDriverManagerConnectionProviderImpl.getInstance() diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cleaner/OracleDatabaseCleaner.java b/hibernate-testing/src/main/java/org/hibernate/testing/cleaner/OracleDatabaseCleaner.java index bf0717d3e23f..ce1ca54bf4e1 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/cleaner/OracleDatabaseCleaner.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/cleaner/OracleDatabaseCleaner.java @@ -67,8 +67,8 @@ public void clearAllSchemas(Connection connection) { return statement.executeQuery( "SELECT 'DROP TABLE ' || owner || '.\"' || table_name || '\" CASCADE CONSTRAINTS' " + "FROM all_tables " + - // Exclude the tables owner by sys - "WHERE owner NOT IN ('SYS')" + + // Only look at tables owned by the current user + "WHERE owner = sys_context('USERENV', 'SESSION_USER')" + // Normally, user tables aren't in sysaux " AND tablespace_name NOT IN ('SYSAUX')" + // Apparently, user tables have global stats off @@ -76,7 +76,7 @@ public void clearAllSchemas(Connection connection) { // Exclude the tables with names starting like 'DEF$_' " AND table_name NOT LIKE 'DEF$\\_%' ESCAPE '\\'" + " UNION ALL " + - "SELECT 'DROP SEQUENCE ' || sequence_owner || '.' || sequence_name FROM all_sequences WHERE sequence_owner NOT IN (" + SYSTEM_SEQUENCE_OWNERS + ")" + "SELECT 'DROP SEQUENCE ' || sequence_owner || '.' || sequence_name FROM all_sequences WHERE sequence_owner = sys_context('USERENV', 'SESSION_USER') and sequence_name not like 'ISEQ$$%'" ); } catch (SQLException sqlException) { diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cleaner/PostgreSQLDatabaseCleaner.java b/hibernate-testing/src/main/java/org/hibernate/testing/cleaner/PostgreSQLDatabaseCleaner.java index 3d75067737c3..0f6f6d8f6e34 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/cleaner/PostgreSQLDatabaseCleaner.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/cleaner/PostgreSQLDatabaseCleaner.java @@ -85,12 +85,26 @@ private void clearSchema0(Connection c, Function schemasPr // Collect schema objects String user = c.getMetaData().getUserName(); LOG.log( Level.FINEST, "Collect schema objects: START" ); + Map> schemaExtensions = new HashMap<>(); + try (Statement s2 = c.createStatement()) { + rs = s2.executeQuery( + "SELECT ns.nspname, 'CREATE EXTENSION ' || e.extname || ' SCHEMA \"' || ns.nspname || '\" VERSION ' || e.extversion FROM pg_extension e JOIN pg_catalog.pg_namespace ns ON e.extnamespace = ns.oid WHERE e.extname <> 'plpgsql'" + ); + while ( rs.next() ) { + schemaExtensions.computeIfAbsent( rs.getString( 1 ), k -> new ArrayList<>() ) + .add( rs.getString( 2 ) ); + } + } rs = schemasProvider.apply( s ); while ( rs.next() ) { String schema = rs.getString( 1 ); sqls.add( "DROP SCHEMA \"" + schema + "\" CASCADE" ); sqls.add( "CREATE SCHEMA \"" + schema + "\"" ); sqls.add( "GRANT ALL ON SCHEMA \"" + schema + "\" TO \"" + user + "\"" ); + List extensions = schemaExtensions.get( schema ); + if ( extensions != null ) { + sqls.addAll( extensions ); + } } LOG.log( Level.FINEST, "Collect schema objects: END" ); diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseCoreFunctionalTestCase.java b/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseCoreFunctionalTestCase.java index 56a5a6902296..ebd52c8ee21f 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseCoreFunctionalTestCase.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseCoreFunctionalTestCase.java @@ -179,9 +179,9 @@ protected Configuration constructConfiguration() { } configuration.setImplicitNamingStrategy( ImplicitNamingStrategyLegacyJpaImpl.INSTANCE ); configuration.setProperty( Environment.DIALECT, getDialect().getClass().getName() ); + configuration.getProperties().put( GlobalTemporaryTableBulkIdStrategy.DROP_ID_TABLES, "true" ); + configuration.getProperties().put( LocalTemporaryTableBulkIdStrategy.DROP_ID_TABLES, "true" ); if ( !Environment.getProperties().containsKey( Environment.CONNECTION_PROVIDER ) ) { - configuration.getProperties().put( GlobalTemporaryTableBulkIdStrategy.DROP_ID_TABLES, "true" ); - configuration.getProperties().put( LocalTemporaryTableBulkIdStrategy.DROP_ID_TABLES, "true" ); configuration.getProperties().put( AvailableSettings.CONNECTION_PROVIDER, SharedDriverManagerConnectionProviderImpl.getInstance() diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseNonConfigCoreFunctionalTestCase.java b/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseNonConfigCoreFunctionalTestCase.java index 179ecbe71a56..8c23dceece90 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseNonConfigCoreFunctionalTestCase.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseNonConfigCoreFunctionalTestCase.java @@ -179,9 +179,9 @@ protected final StandardServiceRegistryBuilder constructStandardServiceRegistryB afterBootstrapServiceRegistryBuilt( bsr ); final Map settings = new HashMap(); + settings.put( GlobalTemporaryTableBulkIdStrategy.DROP_ID_TABLES, "true" ); + settings.put( LocalTemporaryTableBulkIdStrategy.DROP_ID_TABLES, "true" ); if ( !Environment.getProperties().containsKey( Environment.CONNECTION_PROVIDER ) ) { - settings.put( GlobalTemporaryTableBulkIdStrategy.DROP_ID_TABLES, "true" ); - settings.put( LocalTemporaryTableBulkIdStrategy.DROP_ID_TABLES, "true" ); settings.put( AvailableSettings.CONNECTION_PROVIDER, SharedDriverManagerConnectionProviderImpl.getInstance() From 611796c0fc413b27f240d83c49925414b1b71fc5 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Wed, 10 Feb 2021 13:11:35 -0600 Subject: [PATCH 011/644] HHH-14450 - Drop ability to disable "enhanced proxies" --- .../SessionFactoryOptionsBuilder.java | 8 - .../boot/spi/SessionFactoryOptions.java | 5 +- .../spi/interceptor/EnhancementHelper.java | 12 +- .../interceptor/LazyAttributesMetadata.java | 2 - .../org/hibernate/cfg/AvailableSettings.java | 4 + .../internal/DefaultLoadEventListener.java | 5 - .../internal/DefaultMergeEventListener.java | 3 +- .../internal/StatelessSessionImpl.java | 4 +- .../java/org/hibernate/loader/Loader.java | 7 +- .../java/org/hibernate/mapping/Property.java | 2 +- .../entity/AbstractEntityPersister.java | 2 - .../org/hibernate/tuple/PropertyFactory.java | 1 - .../BytecodeEnhancementMetadataPojoImpl.java | 3 +- .../tuple/entity/EntityMetamodel.java | 2 - .../InstrumentedProxyLazyToOneTest.java | 1 - .../cascade/CascadeDeleteManyToOneTest.java | 13 + .../cascade/CascadeOnUninitializedTest.java | 9 + .../lazy/BidirectionalLazyTest.java | 5 + .../enhancement/lazy/LazyLoadingTest.java | 71 ++-- ...turalIdInUninitializedAssociationTest.java | 9 + ...lingWithInheritanceEagerManyToOneTest.java | 323 ------------------ .../QueryScrollingWithInheritanceTest.java | 306 ----------------- .../lazy/StatelessQueryScrollingTest.java | 6 - .../UninitializedAssociationsInCacheTest.java | 5 + .../group/BidirectionalLazyGroupsTest.java | 5 + .../enhancement/lazy/group/LazyGroupTest.java | 6 + ...anyToOneNonUpdatableNonInsertableTest.java | 5 + .../notfound/LazyNotFoundOneToOneTest.java | 16 +- .../lazy/proxy/BatchFetchProxyTest.java | 1 - .../lazy/proxy/BidirectionalProxyTest.java | 1 - .../lazy/proxy/DeepInheritanceProxyTest.java | 1 - ...epInheritanceWithNonEntitiesProxyTest.java | 1 - .../EntitySharedInCollectionAndToOneTest.java | 1 - .../lazy/proxy/FetchGraphTest.java | 1 - .../LazyCollectionDeletedAllowProxyTest.java | 1 - ...azyGroupWithInheritanceAllowProxyTest.java | 3 - .../proxy/LazyGroupWithInheritanceTest.java | 5 + ...roxyFactoryWithSubclassesStatefulTest.java | 6 - ...oxyFactoryWithSubclassesStatelessTest.java | 5 - ...azyToOnesProxyMergeWithSubclassesTest.java | 6 - ...oOnesProxyWithSubclassesStatelessTest.java | 5 - .../LazyToOnesProxyWithSubclassesTest.java | 5 - .../proxy/LoadANonExistingEntityTest.java | 1 - ...adANonExistingNotFoundBatchEntityTest.java | 1 - .../LoadANonExistingNotFoundEntityTest.java | 1 - .../MappedSuperclassWithEmbeddableTest.java | 1 - .../proxy/MapsIdProxyBidirectionalTest.java | 1 - .../proxy/MapsIdProxyUnidirectionalTest.java | 1 - .../lazy/proxy/MergeDetachedToProxyTest.java | 1 - .../lazy/proxy/MergeProxyTest.java | 1 - .../NaturalIdInUninitializedProxyTest.java | 1 - .../lazy/proxy/ProxyDeletionTest.java | 1 - ...eInlineDirtyTrackingDynamicUpdateTest.java | 1 - ...alizeAndUpdateInlineDirtyTrackingTest.java | 5 - .../proxy/ProxyInitializeAndUpdateTest.java | 5 - ...ithInheritanceProxyEagerManyToOneTest.java | 5 - .../SetIdentifierOnAEnhancedProxyTest.java | 1 - .../lazy/proxy/SharingReferenceTest.java | 1 - .../SimpleUpdateTestWithLazyLoading.java | 1 - ...WithLazyLoadingAndInlineDirtyTracking.java | 1 - .../proxy/batch/AbstractBatchingTest.java | 1 - ...rtyCheckPrivateUnMappedCollectionTest.java | 1 - .../EntityWithMutableAttributesTest.java | 1 - ...dAndUpdateEntitiesWithCollectionsTest.java | 1 - .../ManyToOnePropertyAccessByFieldTest.java | 1 - ...neWithEmbeddedAndNotOptionalFieldTest.java | 1 - .../SimpleDynamicUpdateTest.java | 1 - .../DynamicUpdateAndCollectionsTest.java | 1 - .../test/cache/EnhancedProxyCacheTest.java | 1 - 69 files changed, 134 insertions(+), 787 deletions(-) delete mode 100644 hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/QueryScrollingWithInheritanceEagerManyToOneTest.java delete mode 100644 hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/QueryScrollingWithInheritanceTest.java diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java index e07e0e53f405..364ccd6fc3f0 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java @@ -65,7 +65,6 @@ import org.hibernate.tuple.entity.EntityTuplizerFactory; import static org.hibernate.cfg.AvailableSettings.ACQUIRE_CONNECTIONS; -import static org.hibernate.cfg.AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY; import static org.hibernate.cfg.AvailableSettings.ALLOW_JTA_TRANSACTION_ACCESS; import static org.hibernate.cfg.AvailableSettings.ALLOW_REFRESH_DETACHED_ENTITY; import static org.hibernate.cfg.AvailableSettings.ALLOW_UPDATE_OUTSIDE_TRANSACTION; @@ -197,7 +196,6 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions { private boolean orderUpdatesEnabled; private boolean orderInsertsEnabled; private boolean postInsertIdentifierDelayed; - private boolean enhancementAsProxyEnabled; private boolean collectionsInDefaultFetchGroupEnabled; // JPA callbacks @@ -351,7 +349,6 @@ public SessionFactoryOptionsBuilder(StandardServiceRegistry serviceRegistry, Boo this.defaultNullPrecedence = NullPrecedence.parse( defaultNullPrecedence ); this.orderUpdatesEnabled = ConfigurationHelper.getBoolean( ORDER_UPDATES, configurationSettings ); this.orderInsertsEnabled = ConfigurationHelper.getBoolean( ORDER_INSERTS, configurationSettings ); - this.enhancementAsProxyEnabled = ConfigurationHelper.getBoolean( ALLOW_ENHANCEMENT_AS_PROXY, configurationSettings ); this.callbacksEnabled = ConfigurationHelper.getBoolean( JPA_CALLBACKS_ENABLED, configurationSettings, true ); @@ -1063,11 +1060,6 @@ public boolean areJPACallbacksEnabled() { return callbacksEnabled; } - @Override - public boolean isEnhancementAsProxyEnabled() { - return enhancementAsProxyEnabled; - } - @Override public boolean isCollectionsInDefaultFetchGroupEnabled() { return collectionsInDefaultFetchGroupEnabled; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java index 36ddfbc4e340..df6e62f99c09 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java @@ -310,9 +310,12 @@ default boolean areJPACallbacksEnabled() { /** * Can bytecode-enhanced entity classes be used as a "proxy"? + * + * @deprecated (since 5.5) use of enhanced proxies is always enabled */ + @Deprecated default boolean isEnhancementAsProxyEnabled() { - return false; + return true; } default boolean isCollectionsInDefaultFetchGroupEnabled() { diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/EnhancementHelper.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/EnhancementHelper.java index 261412fe7f12..d7ebc605e872 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/EnhancementHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/EnhancementHelper.java @@ -31,7 +31,6 @@ public class EnhancementHelper { public static boolean includeInBaseFetchGroup( Property bootMapping, boolean isEnhanced, - boolean allowEnhancementAsProxy, boolean collectionsInDefaultFetchGroupEnabled) { final Value value = bootMapping.getValue(); @@ -57,7 +56,16 @@ public static boolean includeInBaseFetchGroup( } // include it in the base fetch group so long as the config allows // using the FK to create an "enhancement proxy" - return allowEnhancementAsProxy; + //return allowEnhancementAsProxy; + // ^^ previously we had to explicitly enable use of enhanced proxies. + // for the moment just return `true` assuming we can. + // + // there are cases where this block overall misses quite a few cases + // where it returns the least optimal value. This is true even outside + // this enhanced-proxy point + // + // those will all be addressed in the commits for HHH-13658 + return true; } } diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/LazyAttributesMetadata.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/LazyAttributesMetadata.java index f06b78f0003e..a7edad7aea7f 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/LazyAttributesMetadata.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/LazyAttributesMetadata.java @@ -34,7 +34,6 @@ public class LazyAttributesMetadata implements Serializable { public static LazyAttributesMetadata from( PersistentClass mappedEntity, boolean isEnhanced, - boolean allowEnhancementAsProxy, boolean collectionsInDefaultFetchGroupEnabled) { final Map lazyAttributeDescriptorMap = new LinkedHashMap<>(); final Map> fetchGroupToAttributesMap = new HashMap<>(); @@ -48,7 +47,6 @@ public static LazyAttributesMetadata from( final boolean lazy = ! EnhancementHelper.includeInBaseFetchGroup( property, isEnhanced, - allowEnhancementAsProxy, collectionsInDefaultFetchGroupEnabled ); if ( lazy ) { diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java index 91e1f663ff62..cc547527859e 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java @@ -890,7 +890,11 @@ public interface AvailableSettings extends org.hibernate.jpa.AvailableSettings { * the results of those methods * * @implSpec See {@link org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor} + * + * @deprecated (as of 5.5) with no replacement. When using enhancement based lazy loading + * using the enhanced class as proxy is always used when appropriate. */ + @Deprecated String ALLOW_ENHANCEMENT_AS_PROXY = "hibernate.bytecode.allow_enhancement_as_proxy"; /** diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultLoadEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultLoadEventListener.java index 48af0592cf3f..5888f4acf9ad 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultLoadEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultLoadEventListener.java @@ -252,10 +252,6 @@ private Object proxyOrLoad( final PersistenceContext persistenceContext = session.getPersistenceContextInternal(); - final boolean allowBytecodeProxy = factory - .getSessionFactoryOptions() - .isEnhancementAsProxyEnabled(); - final EntityMetamodel entityMetamodel = persister.getEntityMetamodel(); final boolean entityHasHibernateProxyFactory = entityMetamodel .getTuplizer() @@ -263,7 +259,6 @@ private Object proxyOrLoad( // Check for the case where we can use the entity itself as a proxy if ( options.isAllowProxyCreation() - && allowBytecodeProxy && entityMetamodel.getBytecodeEnhancementMetadata().isEnhancedForLazyLoading() ) { // if there is already a managed entity instance associated with the PC, return it final Object managed = persistenceContext.getEntity( keyToLoad ); diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultMergeEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultMergeEventListener.java index 11a78e2cb2bf..66902cad0c74 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultMergeEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultMergeEventListener.java @@ -364,8 +364,7 @@ private Object unproxyManagedForDetachedMerging( } if ( incoming instanceof PersistentAttributeInterceptable - && persister.getBytecodeEnhancementMetadata().isEnhancedForLazyLoading() - && source.getSessionFactory().getSessionFactoryOptions().isEnhancementAsProxyEnabled() ) { + && persister.getBytecodeEnhancementMetadata().isEnhancedForLazyLoading() ) { final PersistentAttributeInterceptor incomingInterceptor = ( (PersistentAttributeInterceptable) incoming ).$$_hibernate_getInterceptor(); final PersistentAttributeInterceptor managedInterceptor = ( (PersistentAttributeInterceptable) managed ).$$_hibernate_getInterceptor(); diff --git a/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java index 1327cd29869c..14cc081a13a6 100755 --- a/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java @@ -70,12 +70,10 @@ public void setInternalFetchProfile(String internalFetchProfile) { private final PersistenceContext temporaryPersistenceContext = new StatefulPersistenceContext( this ); private final boolean connectionProvided; - private final boolean allowBytecodeProxy; public StatelessSessionImpl(SessionFactoryImpl factory, SessionCreationOptions options) { super( factory, options ); connectionProvided = options.getConnection() != null; - allowBytecodeProxy = getFactory().getSessionFactoryOptions().isEnhancementAsProxyEnabled(); } @Override @@ -306,7 +304,7 @@ public Object internalLoad( final EntityMetamodel entityMetamodel = persister.getEntityMetamodel(); final BytecodeEnhancementMetadata bytecodeEnhancementMetadata = entityMetamodel.getBytecodeEnhancementMetadata(); - if ( allowBytecodeProxy && bytecodeEnhancementMetadata.isEnhancedForLazyLoading() ) { + if ( bytecodeEnhancementMetadata.isEnhancedForLazyLoading() ) { // if the entity defines a HibernateProxy factory, see if there is an // existing proxy associated with the PC - and if so, use it diff --git a/hibernate-core/src/main/java/org/hibernate/loader/Loader.java b/hibernate-core/src/main/java/org/hibernate/loader/Loader.java index 589432bd949a..2095ecc0f6a9 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/Loader.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/Loader.java @@ -62,9 +62,7 @@ import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.spi.SubselectFetch; import org.hibernate.engine.spi.TypedValue; -import org.hibernate.event.service.spi.EventListenerRegistry; import org.hibernate.event.spi.EventSource; -import org.hibernate.event.spi.EventType; import org.hibernate.event.spi.PostLoadEvent; import org.hibernate.event.spi.PreLoadEvent; import org.hibernate.event.spi.PreLoadEventListener; @@ -115,13 +113,10 @@ public abstract class Loader { private final SessionFactoryImplementor factory; private volatile ColumnNameCache columnNameCache; - private final boolean enhancementAsProxyEnabled; - private boolean isJdbc4 = true; public Loader(SessionFactoryImplementor factory) { this.factory = factory; - this.enhancementAsProxyEnabled = factory.getSessionFactoryOptions().isEnhancementAsProxyEnabled(); } /** @@ -1662,7 +1657,7 @@ protected void instanceAlreadyLoaded( ); } - if ( enhancementAsProxyEnabled && persister.getBytecodeEnhancementMetadata().isEnhancedForLazyLoading() ) { + if ( persister.getBytecodeEnhancementMetadata().isEnhancedForLazyLoading() ) { // we have found an existing "managed copy" in the session // we need to check if this copy is an enhanced-proxy and, if so, // perform the hydration just as if it were "not yet loaded" diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Property.java b/hibernate-core/src/main/java/org/hibernate/mapping/Property.java index 0c14c9bc615f..697abe7a5be9 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Property.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Property.java @@ -249,7 +249,7 @@ public void setLazy(boolean lazy) { * @apiNote This form reports whether the property is considered part of the * base fetch group based solely on the mapping information. However, * {@link EnhancementHelper#includeInBaseFetchGroup} is used internally to make that - * decision to account for {@link org.hibernate.cfg.AvailableSettings#ALLOW_ENHANCEMENT_AS_PROXY} + * decision to account for other details */ public boolean isLazy() { if ( value instanceof ToOne ) { diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index c222292001cd..635bfe096e5d 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -743,7 +743,6 @@ public AbstractEntityPersister( final boolean lazy = ! EnhancementHelper.includeInBaseFetchGroup( prop, entityMetamodel.isInstrumented(), - sessionFactoryOptions.isEnhancementAsProxyEnabled(), sessionFactoryOptions.isCollectionsInDefaultFetchGroupEnabled() ); @@ -821,7 +820,6 @@ public AbstractEntityPersister( final boolean lazy = ! EnhancementHelper.includeInBaseFetchGroup( prop, entityMetamodel.isInstrumented(), - sessionFactoryOptions.isEnhancementAsProxyEnabled(), sessionFactoryOptions.isCollectionsInDefaultFetchGroupEnabled() ); while ( colIter.hasNext() ) { diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/PropertyFactory.java b/hibernate-core/src/main/java/org/hibernate/tuple/PropertyFactory.java index 97949ebf2e67..0d7b3a166846 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/PropertyFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/PropertyFactory.java @@ -174,7 +174,6 @@ public static NonIdentifierAttribute buildEntityBasedAttribute( final boolean lazy = ! EnhancementHelper.includeInBaseFetchGroup( property, lazyAvailable, - sessionFactoryOptions.isEnhancementAsProxyEnabled(), sessionFactoryOptions.isCollectionsInDefaultFetchGroupEnabled() ); diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/BytecodeEnhancementMetadataPojoImpl.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/BytecodeEnhancementMetadataPojoImpl.java index 0e8ceeee6503..19720a10a3de 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/entity/BytecodeEnhancementMetadataPojoImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/entity/BytecodeEnhancementMetadataPojoImpl.java @@ -38,12 +38,11 @@ public static BytecodeEnhancementMetadata from( PersistentClass persistentClass, Set identifierAttributeNames, CompositeType nonAggregatedCidMapper, - boolean allowEnhancementAsProxy, boolean collectionsInDefaultFetchGroupEnabled) { final Class mappedClass = persistentClass.getMappedClass(); final boolean enhancedForLazyLoading = PersistentAttributeInterceptable.class.isAssignableFrom( mappedClass ); final LazyAttributesMetadata lazyAttributesMetadata = enhancedForLazyLoading - ? LazyAttributesMetadata.from( persistentClass, true, allowEnhancementAsProxy, collectionsInDefaultFetchGroupEnabled ) + ? LazyAttributesMetadata.from( persistentClass, true, collectionsInDefaultFetchGroupEnabled ) : LazyAttributesMetadata.nonEnhanced( persistentClass.getEntityName() ); return new BytecodeEnhancementMetadataPojoImpl( diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java index 61564422c0f4..62afe53c8ff3 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java @@ -169,7 +169,6 @@ public EntityMetamodel( persistentClass, idAttributeNames, nonAggregatedCidMapper, - sessionFactoryOptions.isEnhancementAsProxyEnabled(), sessionFactoryOptions.isCollectionsInDefaultFetchGroupEnabled() ); } @@ -252,7 +251,6 @@ public EntityMetamodel( boolean lazy = ! EnhancementHelper.includeInBaseFetchGroup( prop, bytecodeEnhancementMetadata.isEnhancedForLazyLoading(), - sessionFactoryOptions.isEnhancementAsProxyEnabled(), sessionFactoryOptions.isCollectionsInDefaultFetchGroupEnabled() ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/InstrumentedProxyLazyToOneTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/InstrumentedProxyLazyToOneTest.java index 22629e899200..ff9c9bb20a7d 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/InstrumentedProxyLazyToOneTest.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/InstrumentedProxyLazyToOneTest.java @@ -37,7 +37,6 @@ protected Class[] getAnnotatedClasses() { @Override protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { ssrb.applySetting( AvailableSettings.GENERATE_STATISTICS, "true" ); - ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); } @Override diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/cascade/CascadeDeleteManyToOneTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/cascade/CascadeDeleteManyToOneTest.java index 5ba8d3a6016f..13179fd805c1 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/cascade/CascadeDeleteManyToOneTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/cascade/CascadeDeleteManyToOneTest.java @@ -22,6 +22,7 @@ import org.hibernate.annotations.LazyToOneOption; import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata; +import org.hibernate.testing.FailureExpected; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; @@ -64,6 +65,10 @@ public void prepare() { } @Test + @FailureExpected( + jiraKey = "HHH-13658", + message = "Assertions specific to enhanced lazy loading but disallowing enhanced proxies, which is no longer valid" + ) public void testManagedWithUninitializedAssociation() { // Delete the Child doInHibernate( @@ -109,6 +114,10 @@ public void testManagedWithInitializedAssociation() { } @Test + @FailureExpected( + jiraKey = "HHH-13658", + message = "Assertions specific to enhanced lazy loading but disallowing enhanced proxies, which is no longer valid" + ) public void testDetachedWithUninitializedAssociation() { final Child detachedChild = doInHibernate( this::sessionFactory, s -> { @@ -136,6 +145,10 @@ public void testDetachedWithUninitializedAssociation() { } @Test + @FailureExpected( + jiraKey = "HHH-13658", + message = "Assertions specific to enhanced lazy loading but disallowing enhanced proxies, which is no longer valid" + ) public void testDetachedWithInitializedAssociation() { final Child detachedChild = doInHibernate( this::sessionFactory, s -> { diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/cascade/CascadeOnUninitializedTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/cascade/CascadeOnUninitializedTest.java index 39a2637f5096..adbf88cf8d33 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/cascade/CascadeOnUninitializedTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/cascade/CascadeOnUninitializedTest.java @@ -19,6 +19,7 @@ import org.hibernate.annotations.LazyToOneOption; import org.hibernate.cfg.AvailableSettings; +import org.hibernate.testing.FailureExpected; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; @@ -54,6 +55,10 @@ protected void addSettings(Map settings) { } @Test + @FailureExpected( + jiraKey = "HHH-13658", + message = "Assertions specific to enhanced lazy loading but disallowing enhanced proxies, which is no longer valid" + ) public void testMergeDetachedEnhancedEntityWithUninitializedManyToOne() { Person person = persistPersonWithManyToOne(); @@ -81,6 +86,10 @@ public void testMergeDetachedEnhancedEntityWithUninitializedManyToOne() { } @Test + @FailureExpected( + jiraKey = "HHH-13658", + message = "Assertions specific to enhanced lazy loading but disallowing enhanced proxies, which is no longer valid" + ) public void testDeleteEnhancedEntityWithUninitializedManyToOne() { Person person = persistPersonWithManyToOne(); diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/BidirectionalLazyTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/BidirectionalLazyTest.java index 5a636b08aeb7..5b11dd827ccf 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/BidirectionalLazyTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/BidirectionalLazyTest.java @@ -26,6 +26,7 @@ import org.hibernate.engine.spi.EntityEntry; import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.testing.FailureExpected; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; import org.hibernate.testing.bytecode.enhancement.CustomEnhancementContext; @@ -53,6 +54,10 @@ EnhancerTestContext.class, // supports laziness and dirty-checking BidirectionalLazyTest.NoDirtyCheckEnhancementContext.class // supports laziness; does not support dirty-checking }) +@FailureExpected( + jiraKey = "HHH-13658", + message = "Assertions specific to enhanced lazy loading but disallowing enhanced proxies, which is no longer valid" +) public class BidirectionalLazyTest extends BaseCoreFunctionalTestCase { public Class[] getAnnotatedClasses() { diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/LazyLoadingTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/LazyLoadingTest.java index be6b56594275..ccdd9d3ee036 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/LazyLoadingTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/LazyLoadingTest.java @@ -6,40 +6,42 @@ */ package org.hibernate.test.bytecode.enhancement.lazy; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import javax.persistence.Table; + +import org.hibernate.Hibernate; import org.hibernate.annotations.LazyToOne; import org.hibernate.annotations.LazyToOneOption; +import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor; import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.Configuration; +import org.hibernate.engine.spi.PersistentAttributeInterceptable; +import org.hibernate.engine.spi.PersistentAttributeInterceptor; import org.hibernate.proxy.HibernateProxy; + import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import javax.persistence.CascadeType; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.ManyToOne; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.CoreMatchers.notNullValue; import static org.hibernate.testing.bytecode.enhancement.EnhancerTestUtils.checkDirtyTracking; -import static org.hibernate.testing.bytecode.enhancement.EnhancerTestUtils.getFieldByReflection; import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; /** * @author Luis Barreiro @@ -82,13 +84,15 @@ public void prepare() { public void test() { doInHibernate( this::sessionFactory, s -> { Child loadedChild = s.load( Child.class, lastChildID ); + assertThat( loadedChild, not( instanceOf( HibernateProxy.class ) ) ); + assertThat( loadedChild, instanceOf( PersistentAttributeInterceptable.class ) ); + final PersistentAttributeInterceptable interceptable = (PersistentAttributeInterceptable) loadedChild; + final PersistentAttributeInterceptor interceptor = interceptable.$$_hibernate_getInterceptor(); + assertThat( interceptor, instanceOf( EnhancementAsProxyLazinessInterceptor.class ) ); - Object nameByReflection = getFieldByReflection( loadedChild, "name" ); - assertNotNull( "Non-lazy field 'name' was not loaded", nameByReflection ); - - Object parentByReflection = getFieldByReflection( loadedChild, "parent" ); - assertNull( "Lazy field 'parent' is initialized", parentByReflection ); - assertFalse( loadedChild instanceof HibernateProxy ); + assertThat( Hibernate.isPropertyInitialized( loadedChild, "name" ), is( false ) ); + assertThat( Hibernate.isPropertyInitialized( loadedChild, "parent" ), is( false ) ); + assertThat( Hibernate.isPropertyInitialized( loadedChild, "children" ), is( false ) ); Parent loadedParent = loadedChild.parent; assertThat( loadedChild.name, notNullValue() ); @@ -97,23 +101,18 @@ public void test() { checkDirtyTracking( loadedChild ); - parentByReflection = getFieldByReflection( loadedChild, "parent" ); - Object childrenByReflection = getFieldByReflection( loadedParent, "children" ); - assertNotNull( "Lazy field 'parent' is not loaded", parentByReflection ); - assertNull( "Lazy field 'children' is initialized", childrenByReflection ); - assertFalse( loadedParent instanceof HibernateProxy ); - assertEquals( parentID, loadedParent.id ); + assertThat( Hibernate.isPropertyInitialized( loadedChild, "name" ), is( true ) ); + assertThat( Hibernate.isPropertyInitialized( loadedChild, "parent" ), is( true ) ); + assertThat( Hibernate.isPropertyInitialized( loadedChild, "children" ), is( true ) ); Collection loadedChildren = loadedParent.children; + assertThat( Hibernate.isInitialized( loadedChildren ), is( false ) ); checkDirtyTracking( loadedChild ); checkDirtyTracking( loadedParent ); - childrenByReflection = getFieldByReflection( loadedParent, "children" ); - assertNotNull( "Lazy field 'children' is not loaded", childrenByReflection ); - assertFalse( loadedChildren instanceof HibernateProxy ); - assertEquals( CHILDREN_SIZE, loadedChildren.size() ); - assertTrue( loadedChildren.contains( loadedChild ) ); + loadedChildren.size(); + assertThat( Hibernate.isInitialized( loadedChildren ), is( true ) ); } ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/NaturalIdInUninitializedAssociationTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/NaturalIdInUninitializedAssociationTest.java index 3e9ede028f0a..dec35dcb8297 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/NaturalIdInUninitializedAssociationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/NaturalIdInUninitializedAssociationTest.java @@ -21,6 +21,7 @@ import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cfg.AvailableSettings; +import org.hibernate.testing.FailureExpected; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; import org.hibernate.testing.bytecode.enhancement.EnhancementOptions; @@ -43,6 +44,10 @@ public class NaturalIdInUninitializedAssociationTest extends BaseNonConfigCoreFunctionalTestCase { @Test + @FailureExpected( + jiraKey = "HHH-13658", + message = "Assertions specific to enhanced lazy loading but disallowing enhanced proxies, which is no longer valid" + ) public void testImmutableNaturalId() { inTransaction( session -> { @@ -60,6 +65,10 @@ public void testImmutableNaturalId() { } @Test + @FailureExpected( + jiraKey = "HHH-13658", + message = "Assertions specific to enhanced lazy loading but disallowing enhanced proxies, which is no longer valid" + ) public void testMutableNaturalId() { inTransaction( session -> { diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/QueryScrollingWithInheritanceEagerManyToOneTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/QueryScrollingWithInheritanceEagerManyToOneTest.java deleted file mode 100644 index 7fc33ef7ade1..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/QueryScrollingWithInheritanceEagerManyToOneTest.java +++ /dev/null @@ -1,323 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later - * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html - */ -package org.hibernate.test.bytecode.enhancement.lazy; - -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.Set; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.Id; -import javax.persistence.Inheritance; -import javax.persistence.InheritanceType; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.OneToMany; -import javax.persistence.Table; - -import org.hibernate.Hibernate; -import org.hibernate.ScrollMode; -import org.hibernate.ScrollableResults; -import org.hibernate.Session; -import org.hibernate.StatelessSession; -import org.hibernate.annotations.LazyToOne; -import org.hibernate.annotations.LazyToOneOption; -import org.hibernate.boot.MetadataSources; -import org.hibernate.boot.SessionFactoryBuilder; -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import org.hibernate.cfg.AvailableSettings; -import org.hibernate.dialect.DB2Dialect; -import org.hibernate.query.Query; -import org.hibernate.stat.spi.StatisticsImplementor; - -import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; -import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -/** - * @author Andrea Boriero - */ -@RunWith(BytecodeEnhancerRunner.class) -public class QueryScrollingWithInheritanceEagerManyToOneTest extends BaseNonConfigCoreFunctionalTestCase { - @Override - protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { - super.configureStandardServiceRegistryBuilder( ssrb ); - ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "false" ); - } - - @Override - protected void configureSessionFactoryBuilder(SessionFactoryBuilder sfb) { - super.configureSessionFactoryBuilder( sfb ); - sfb.applyStatisticsSupport( true ); - sfb.applySecondLevelCacheSupport( false ); - sfb.applyQueryCacheSupport( false ); - } - - @Override - protected void applyMetadataSources(MetadataSources sources) { - super.applyMetadataSources( sources ); - sources.addAnnotatedClass( EmployeeParent.class ); - sources.addAnnotatedClass( Employee.class ); - sources.addAnnotatedClass( OtherEntity.class ); - } - - @Test - public void testScrollableWithStatelessSession() { - final StatisticsImplementor stats = sessionFactory().getStatistics(); - stats.clear(); - ScrollableResults scrollableResults = null; - final StatelessSession statelessSession = sessionFactory().openStatelessSession(); - - try { - statelessSession.beginTransaction(); - Query query = statelessSession.createQuery( - "select distinct e from Employee e left join fetch e.otherEntities order by e.dept", - Employee.class - ); - if ( getDialect() instanceof DB2Dialect ) { - /* - FetchingScrollableResultsImp#next() in order to check if the ResultSet is empty calls ResultSet#isBeforeFirst() - but the support for ResultSet#isBeforeFirst() is optional for ResultSets with a result - set type of TYPE_FORWARD_ONLY and db2 does not support it. - */ - scrollableResults = query.scroll( ScrollMode.SCROLL_INSENSITIVE ); - } - else { - scrollableResults = query.scroll( ScrollMode.FORWARD_ONLY ); - } - - while ( scrollableResults.next() ) { - final Employee employee = (Employee) scrollableResults.get( 0 ); - assertThat( Hibernate.isPropertyInitialized( employee, "otherEntities" ), is( true ) ); - assertThat( Hibernate.isInitialized( employee.getOtherEntities() ), is( true ) ); - if ( "ENG1".equals( employee.getDept() ) ) { - assertThat( employee.getOtherEntities().size(), is( 2 ) ); - for ( OtherEntity otherEntity : employee.getOtherEntities() ) { - if ( "test1".equals( otherEntity.id ) ) { - assertThat( Hibernate.isPropertyInitialized( otherEntity, "employee" ), is( false ) ); - assertThat( Hibernate.isPropertyInitialized( otherEntity, "employeeParent" ), is( true ) ); - assertThat( otherEntity.employeeParent, is( employee ) ); - } - else { - assertThat( Hibernate.isPropertyInitialized( otherEntity, "employee" ), is( false ) ); - assertThat( Hibernate.isPropertyInitialized( otherEntity, "employeeParent" ), is( true ) ); - assertThat( Hibernate.isInitialized( otherEntity.employeeParent ), is( true ) ); - } - } - } - else { - assertThat( employee.getOtherEntities().size(), is( 0 ) ); - } - } - statelessSession.getTransaction().commit(); - assertThat( stats.getPrepareStatementCount(), is( 2L ) ); - } - finally { - if ( scrollableResults != null ) { - scrollableResults.close(); - } - if ( statelessSession.getTransaction().isActive() ) { - statelessSession.getTransaction().rollback(); - } - statelessSession.close(); - } - } - - @Test - public void testScrollableWithSession() { - final StatisticsImplementor stats = sessionFactory().getStatistics(); - stats.clear(); - ScrollableResults scrollableResults = null; - final Session session = sessionFactory().openSession(); - - try { - session.beginTransaction(); - Query query = session.createQuery( - "select distinct e from Employee e left join fetch e.otherEntities order by e.dept", - Employee.class - ); - if ( getDialect() instanceof DB2Dialect ) { - /* - FetchingScrollableResultsImp#next() in order to check if the ResultSet is empty calls ResultSet#isBeforeFirst() - but the support for ResultSet#isBeforeFirst() is optional for ResultSets with a result - set type of TYPE_FORWARD_ONLY and db2 does not support it. - */ - scrollableResults = query.scroll( ScrollMode.SCROLL_INSENSITIVE ); - } - else { - scrollableResults = query.scroll( ScrollMode.FORWARD_ONLY ); - } - - while ( scrollableResults.next() ) { - final Employee employee = (Employee) scrollableResults.get( 0 ); - assertThat( Hibernate.isPropertyInitialized( employee, "otherEntities" ), is( true ) ); - assertThat( Hibernate.isInitialized( employee.getOtherEntities() ), is( true ) ); - if ( "ENG1".equals( employee.getDept() ) ) { - assertThat( employee.getOtherEntities().size(), is( 2 ) ); - for ( OtherEntity otherEntity : employee.getOtherEntities() ) { - if ( "test1".equals( otherEntity.id ) ) { - assertThat( Hibernate.isPropertyInitialized( otherEntity, "employee" ), is( false ) ); - assertThat( Hibernate.isPropertyInitialized( otherEntity, "employeeParent" ), is( true ) ); - assertThat( otherEntity.employeeParent, is( employee ) ); - } - else { - assertThat( Hibernate.isPropertyInitialized( otherEntity, "employee" ), is( false ) ); - assertThat( Hibernate.isPropertyInitialized( otherEntity, "employeeParent" ), is( true ) ); - assertThat( Hibernate.isInitialized( otherEntity.employeeParent ), is( true ) ); - } - } - } - else { - assertThat( employee.getOtherEntities().size(), is( 0 ) ); - } - } - session.getTransaction().commit(); - assertThat( stats.getPrepareStatementCount(), is( 2L ) ); - } - finally { - if ( scrollableResults != null ) { - scrollableResults.close(); - } - if ( session.getTransaction().isActive() ) { - session.getTransaction().rollback(); - } - session.close(); - } - } - - @Before - public void prepareTestData() { - inTransaction( - session -> { - Employee e1 = new Employee( "ENG1" ); - Employee e2 = new Employee( "ENG2" ); - OtherEntity other1 = new OtherEntity( "test1" ); - OtherEntity other2 = new OtherEntity( "test2" ); - e1.getOtherEntities().add( other1 ); - e1.getOtherEntities().add( other2 ); - e1.getParentOtherEntities().add( other1 ); - e1.getParentOtherEntities().add( other2 ); - other1.employee = e1; - other2.employee = e1; - other1.employeeParent = e1; - other2.employeeParent = e2; - session.persist( other1 ); - session.persist( other2 ); - session.persist( e1 ); - session.persist( e2 ); - } - ); - } - - @After - public void cleanUpTestData() { - inTransaction( - session -> { - session.createQuery( "delete from OtherEntity" ).executeUpdate(); - session.createQuery( "delete from Employee" ).executeUpdate(); - session.createQuery( "delete from EmployeeParent" ).executeUpdate(); - } - ); - } - - @Entity(name = "EmployeeParent") - @Table(name = "EmployeeParent") - @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) - public static abstract class EmployeeParent { - - @Id - private String dept; - - @OneToMany(targetEntity = OtherEntity.class, mappedBy = "employeeParent", fetch = FetchType.LAZY) - protected Set parentOtherEntities = new HashSet<>(); - - public Set getParentOtherEntities() { - if ( parentOtherEntities == null ) { - parentOtherEntities = new LinkedHashSet(); - } - return parentOtherEntities; - } - - public void setOtherEntities(Set pParentOtherEntites) { - parentOtherEntities = pParentOtherEntites; - } - - public String getDept() { - return dept; - } - - protected void setDept(String dept) { - this.dept = dept; - } - - } - - @Entity(name = "Employee") - @Table(name = "Employee") - public static class Employee extends EmployeeParent { - - @OneToMany(targetEntity = OtherEntity.class, mappedBy = "employee", fetch = FetchType.LAZY) - protected Set otherEntities = new HashSet<>(); - - public Employee(String dept) { - this(); - setDept( dept ); - } - - protected Employee() { - // this form used by Hibernate - } - - public Set getOtherEntities() { - if ( otherEntities == null ) { - otherEntities = new LinkedHashSet(); - } - return otherEntities; - } - - public void setOtherEntities(Set pOtherEntites) { - otherEntities = pOtherEntites; - } - } - - @Entity(name = "OtherEntity") - @Table(name = "OtherEntity") - public static class OtherEntity { - - @Id - private String id; - - @ManyToOne(fetch = FetchType.LAZY) - @LazyToOne(LazyToOneOption.NO_PROXY) - @JoinColumn(name = "Employee_Id") - protected Employee employee = null; - - @ManyToOne(fetch = FetchType.EAGER) - //@LazyToOne(LazyToOneOption.NO_PROXY) - @JoinColumn(name = "EmployeeParent_Id") - protected EmployeeParent employeeParent = null; - - protected OtherEntity() { - // this form used by Hibernate - } - - public OtherEntity(String id) { - this.id = id; - } - - public String getId() { - return id; - } - } - -} diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/QueryScrollingWithInheritanceTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/QueryScrollingWithInheritanceTest.java deleted file mode 100644 index e9be4a677e48..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/QueryScrollingWithInheritanceTest.java +++ /dev/null @@ -1,306 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later - * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html - */ -package org.hibernate.test.bytecode.enhancement.lazy; - -import java.util.HashSet; -import java.util.LinkedHashSet; -import java.util.Set; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.Id; -import javax.persistence.Inheritance; -import javax.persistence.InheritanceType; -import javax.persistence.JoinColumn; -import javax.persistence.ManyToOne; -import javax.persistence.OneToMany; -import javax.persistence.Table; - -import org.hibernate.Hibernate; -import org.hibernate.ScrollMode; -import org.hibernate.ScrollableResults; -import org.hibernate.Session; -import org.hibernate.StatelessSession; -import org.hibernate.annotations.LazyToOne; -import org.hibernate.annotations.LazyToOneOption; -import org.hibernate.boot.MetadataSources; -import org.hibernate.boot.SessionFactoryBuilder; -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import org.hibernate.cfg.AvailableSettings; -import org.hibernate.dialect.DB2Dialect; -import org.hibernate.query.Query; -import org.hibernate.stat.spi.StatisticsImplementor; - -import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; -import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; -import org.junit.After; -import org.junit.Before; -import org.junit.Test; -import org.junit.runner.RunWith; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -/** - * @author Andrea Boriero - */ -@RunWith(BytecodeEnhancerRunner.class) -public class QueryScrollingWithInheritanceTest extends BaseNonConfigCoreFunctionalTestCase { - @Override - protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { - super.configureStandardServiceRegistryBuilder( ssrb ); - } - - @Override - protected void configureSessionFactoryBuilder(SessionFactoryBuilder sfb) { - super.configureSessionFactoryBuilder( sfb ); - sfb.applyStatisticsSupport( true ); - sfb.applySecondLevelCacheSupport( false ); - sfb.applyQueryCacheSupport( false ); - } - - @Override - protected void applyMetadataSources(MetadataSources sources) { - super.applyMetadataSources( sources ); - sources.addAnnotatedClass( EmployeeParent.class ); - sources.addAnnotatedClass( Employee.class ); - sources.addAnnotatedClass( OtherEntity.class ); - } - - @Test - public void testScrollableWithStatelessSession() { - final StatisticsImplementor stats = sessionFactory().getStatistics(); - stats.clear(); - ScrollableResults scrollableResults = null; - final StatelessSession statelessSession = sessionFactory().openStatelessSession(); - - try { - statelessSession.beginTransaction(); - Query query = statelessSession.createQuery( - "select distinct e from Employee e left join fetch e.otherEntities order by e.dept", - Employee.class - ); - if ( getDialect() instanceof DB2Dialect ) { - /* - FetchingScrollableResultsImp#next() in order to check if the ResultSet is empty calls ResultSet#isBeforeFirst() - but the support for ResultSet#isBeforeFirst() is optional for ResultSets with a result - set type of TYPE_FORWARD_ONLY and db2 does not support it. - */ - scrollableResults = query.scroll( ScrollMode.SCROLL_INSENSITIVE ); - } - else { - scrollableResults = query.scroll( ScrollMode.FORWARD_ONLY ); - } - - while ( scrollableResults.next() ) { - final Employee employee = (Employee) scrollableResults.get( 0 ); - assertThat( Hibernate.isPropertyInitialized( employee, "otherEntities" ), is( true ) ); - assertThat( Hibernate.isInitialized( employee.getOtherEntities() ), is( true ) ); - if ( "ENG1".equals( employee.getDept() ) ) { - assertThat( employee.getOtherEntities().size(), is( 2 ) ); - for ( OtherEntity otherEntity : employee.getOtherEntities() ) { - assertThat( Hibernate.isPropertyInitialized( otherEntity, "employee" ), is( false ) ); - assertThat( Hibernate.isPropertyInitialized( otherEntity, "employeeParent" ), is( false ) ); - } - } - else { - assertThat( employee.getOtherEntities().size(), is( 0 ) ); - } - } - statelessSession.getTransaction().commit(); - assertThat( stats.getPrepareStatementCount(), is( 1L ) ); - } - finally { - if ( scrollableResults != null ) { - scrollableResults.close(); - } - if ( statelessSession.getTransaction().isActive() ) { - statelessSession.getTransaction().rollback(); - } - statelessSession.close(); - } - } - - @Test - public void testScrollableWithSession() { - final StatisticsImplementor stats = sessionFactory().getStatistics(); - stats.clear(); - ScrollableResults scrollableResults = null; - final Session session = sessionFactory().openSession(); - - try { - session.beginTransaction(); - Query query = session.createQuery( - "select distinct e from Employee e left join fetch e.otherEntities order by e.dept", - Employee.class - ); - if ( getDialect() instanceof DB2Dialect ) { - /* - FetchingScrollableResultsImp#next() in order to check if the ResultSet is empty calls ResultSet#isBeforeFirst() - but the support for ResultSet#isBeforeFirst() is optional for ResultSets with a result - set type of TYPE_FORWARD_ONLY and db2 does not support it. - */ - scrollableResults = query.scroll( ScrollMode.SCROLL_INSENSITIVE ); - } - else { - scrollableResults = query.scroll( ScrollMode.FORWARD_ONLY ); - } - - while ( scrollableResults.next() ) { - final Employee employee = (Employee) scrollableResults.get( 0 ); - assertThat( Hibernate.isPropertyInitialized( employee, "otherEntities" ), is( true ) ); - assertThat( Hibernate.isInitialized( employee.getOtherEntities() ), is( true ) ); - if ( "ENG1".equals( employee.getDept() ) ) { - assertThat( employee.getOtherEntities().size(), is( 2 ) ); - for ( OtherEntity otherEntity : employee.getOtherEntities() ) { - assertThat( Hibernate.isPropertyInitialized( otherEntity, "employee" ), is( false ) ); - assertThat( Hibernate.isPropertyInitialized( otherEntity, "employeeParent" ), is( false ) ); - } - } - else { - assertThat( employee.getOtherEntities().size(), is( 0 ) ); - } - } - session.getTransaction().commit(); - assertThat( stats.getPrepareStatementCount(), is( 1L ) ); - } - finally { - if ( scrollableResults != null ) { - scrollableResults.close(); - } - if ( session.getTransaction().isActive() ) { - session.getTransaction().rollback(); - } - session.close(); - } - } - - @Before - public void prepareTestData() { - inTransaction( - session -> { - Employee e1 = new Employee( "ENG1" ); - Employee e2 = new Employee( "ENG2" ); - OtherEntity other1 = new OtherEntity( "test1" ); - OtherEntity other2 = new OtherEntity( "test2" ); - e1.getOtherEntities().add( other1 ); - e1.getOtherEntities().add( other2 ); - e1.getParentOtherEntities().add( other1 ); - e1.getParentOtherEntities().add( other2 ); - other1.employee = e1; - other2.employee = e1; - other1.employeeParent = e1; - other2.employeeParent = e2; - session.persist( other1 ); - session.persist( other2 ); - session.persist( e1 ); - session.persist( e2 ); - } - ); - } - - @After - public void cleanUpTestData() { - inTransaction( - session -> { - session.createQuery( "delete from OtherEntity" ).executeUpdate(); - session.createQuery( "delete from Employee" ).executeUpdate(); - session.createQuery( "delete from EmployeeParent" ).executeUpdate(); - } - ); - } - - @Entity(name = "EmployeeParent") - @Table(name = "EmployeeParent") - @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) - public static abstract class EmployeeParent { - - @Id - private String dept; - - @OneToMany(targetEntity = OtherEntity.class, mappedBy = "employeeParent", fetch = FetchType.LAZY) - protected Set parentOtherEntities = new HashSet<>(); - - public Set getParentOtherEntities() { - if ( parentOtherEntities == null ) { - parentOtherEntities = new LinkedHashSet(); - } - return parentOtherEntities; - } - - public void setOtherEntities(Set pParentOtherEntites) { - parentOtherEntities = pParentOtherEntites; - } - - public String getDept() { - return dept; - } - - protected void setDept(String dept) { - this.dept = dept; - } - - } - - @Entity(name = "Employee") - @Table(name = "Employee") - public static class Employee extends EmployeeParent { - - @OneToMany(targetEntity = OtherEntity.class, mappedBy = "employee", fetch = FetchType.LAZY) - protected Set otherEntities = new HashSet<>(); - - public Employee(String dept) { - this(); - setDept( dept ); - } - - protected Employee() { - // this form used by Hibernate - } - - public Set getOtherEntities() { - if ( otherEntities == null ) { - otherEntities = new LinkedHashSet(); - } - return otherEntities; - } - - public void setOtherEntities(Set pOtherEntites) { - otherEntities = pOtherEntites; - } - } - - @Entity(name = "OtherEntity") - @Table(name = "OtherEntity") - public static class OtherEntity { - - @Id - private String id; - - @ManyToOne(fetch = FetchType.LAZY) - @LazyToOne(LazyToOneOption.NO_PROXY) - @JoinColumn(name = "Employee_Id") - protected Employee employee = null; - - @ManyToOne(fetch = FetchType.LAZY) - @LazyToOne(LazyToOneOption.NO_PROXY) - @JoinColumn(name = "EmployeeParent_Id") - protected EmployeeParent employeeParent = null; - - protected OtherEntity() { - // this form used by Hibernate - } - - public OtherEntity(String id) { - this.id = id; - } - - public String getId() { - return id; - } - } - -} diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/StatelessQueryScrollingTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/StatelessQueryScrollingTest.java index 2aa0d1cdf448..0a8836efc63a 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/StatelessQueryScrollingTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/StatelessQueryScrollingTest.java @@ -174,12 +174,6 @@ public void deleteTestData() { ); } - @Override - protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { - super.configureStandardServiceRegistryBuilder( ssrb ); - ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); - } - @Override protected void applyMetadataSources(MetadataSources sources) { super.applyMetadataSources( sources ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/cache/UninitializedAssociationsInCacheTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/cache/UninitializedAssociationsInCacheTest.java index 7878831fd822..7659cca0baf1 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/cache/UninitializedAssociationsInCacheTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/cache/UninitializedAssociationsInCacheTest.java @@ -25,6 +25,7 @@ import org.hibernate.cfg.Configuration; import org.hibernate.stat.CacheRegionStatistics; +import org.hibernate.testing.FailureExpected; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; @@ -52,6 +53,10 @@ protected void configure(Configuration configuration) { @Test @TestForIssue( jiraKey = "HHH-11766") + @FailureExpected( + jiraKey = "HHH-13658", + message = "Assertions specific to enhanced lazy loading but disallowing enhanced proxies, which is no longer valid" + ) public void attributeLoadingFromCache() { final AtomicLong bossId = new AtomicLong(); final AtomicLong teamleaderId = new AtomicLong(); diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/group/BidirectionalLazyGroupsTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/group/BidirectionalLazyGroupsTest.java index 8898e38d3008..9fa36a539ea6 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/group/BidirectionalLazyGroupsTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/group/BidirectionalLazyGroupsTest.java @@ -23,6 +23,7 @@ import org.hibernate.bytecode.enhance.spi.DefaultEnhancementContext; import org.hibernate.bytecode.enhance.spi.UnloadedClass; +import org.hibernate.testing.FailureExpected; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; import org.hibernate.testing.bytecode.enhancement.CustomEnhancementContext; @@ -48,6 +49,10 @@ EnhancerTestContext.class, BidirectionalLazyGroupsTest.NoDirtyCheckEnhancementContext.class }) +@FailureExpected( + jiraKey = "HHH-13658", + message = "Assertions specific to enhanced lazy loading but disallowing enhanced proxies, which is no longer valid" +) public class BidirectionalLazyGroupsTest extends BaseCoreFunctionalTestCase { public Class[] getAnnotatedClasses() { diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/group/LazyGroupTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/group/LazyGroupTest.java index 275c16b5b3fa..3501d1e2dbb5 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/group/LazyGroupTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/group/LazyGroupTest.java @@ -12,6 +12,8 @@ import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.Configuration; import org.hibernate.proxy.HibernateProxy; + +import org.hibernate.testing.FailureExpected; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; @@ -45,6 +47,10 @@ */ @TestForIssue( jiraKey = "HHH-11155" ) @RunWith( BytecodeEnhancerRunner.class ) +@FailureExpected( + jiraKey = "HHH-13658", + message = "Assertions specific to enhanced lazy loading but disallowing enhanced proxies, which is no longer valid" +) public class LazyGroupTest extends BaseCoreFunctionalTestCase { @Override diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/notfound/LazyNotFoundManyToOneNonUpdatableNonInsertableTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/notfound/LazyNotFoundManyToOneNonUpdatableNonInsertableTest.java index 2db7e7102438..05ace8cdfce6 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/notfound/LazyNotFoundManyToOneNonUpdatableNonInsertableTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/notfound/LazyNotFoundManyToOneNonUpdatableNonInsertableTest.java @@ -26,6 +26,7 @@ import org.hibernate.annotations.NotFound; import org.hibernate.annotations.NotFoundAction; +import org.hibernate.testing.FailureExpected; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; @@ -50,6 +51,10 @@ protected Class[] getAnnotatedClasses() { } @Test + @FailureExpected( + jiraKey = "HHH-13658", + message = "Assertions specific to enhanced lazy loading but disallowing enhanced proxies, which is no longer valid" + ) public void test() { doInHibernate( this::sessionFactory, session -> { diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/notfound/LazyNotFoundOneToOneTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/notfound/LazyNotFoundOneToOneTest.java index 8908f2caf423..5b00fb227f5b 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/notfound/LazyNotFoundOneToOneTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/notfound/LazyNotFoundOneToOneTest.java @@ -15,8 +15,6 @@ import javax.persistence.Entity; import javax.persistence.FetchType; import javax.persistence.ForeignKey; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.OneToOne; @@ -27,7 +25,10 @@ import org.hibernate.annotations.LazyToOneOption; import org.hibernate.annotations.NotFound; import org.hibernate.annotations.NotFoundAction; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.cfg.Configuration; +import org.hibernate.testing.FailureExpected; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; @@ -37,6 +38,7 @@ import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; @TestForIssue( jiraKey = "HHH-12226") @RunWith( BytecodeEnhancerRunner.class ) @@ -51,7 +53,17 @@ protected Class[] getAnnotatedClasses() { }; } + @Override + protected void configure(Configuration configuration) { + super.configure(configuration); + configuration.setProperty( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); + } + @Test + @FailureExpected( + jiraKey = "HHH-13658", + message = "Assertions specific to enhanced lazy loading but disallowing enhanced proxies, which is no longer valid" + ) public void test() { doInHibernate( this::sessionFactory, session -> { diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/BatchFetchProxyTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/BatchFetchProxyTest.java index 70522bccd7e1..a0ac0445b12e 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/BatchFetchProxyTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/BatchFetchProxyTest.java @@ -224,7 +224,6 @@ public void cleanupDate() { @Override protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { super.configureStandardServiceRegistryBuilder( ssrb ); - ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); ssrb.applySetting( AvailableSettings.FORMAT_SQL, "false" ); ssrb.applySetting( AvailableSettings.GENERATE_STATISTICS, "true" ); ssrb.applySetting( AvailableSettings.SHOW_SQL, true ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/BidirectionalProxyTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/BidirectionalProxyTest.java index 2ffdf94dbbc4..79185b7ef41d 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/BidirectionalProxyTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/BidirectionalProxyTest.java @@ -126,7 +126,6 @@ public void testIt() { @Override protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { super.configureStandardServiceRegistryBuilder( ssrb ); - ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); ssrb.applySetting( AvailableSettings.FORMAT_SQL, "false" ); ssrb.applySetting( AvailableSettings.GENERATE_STATISTICS, "true" ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/DeepInheritanceProxyTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/DeepInheritanceProxyTest.java index 6b522ce761cc..b2b490a2ea69 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/DeepInheritanceProxyTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/DeepInheritanceProxyTest.java @@ -484,7 +484,6 @@ public void testLeafSetValueToInitialize() { @Override protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { super.configureStandardServiceRegistryBuilder( ssrb ); - ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); ssrb.applySetting( AvailableSettings.FORMAT_SQL, "false" ); ssrb.applySetting( AvailableSettings.GENERATE_STATISTICS, "true" ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/DeepInheritanceWithNonEntitiesProxyTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/DeepInheritanceWithNonEntitiesProxyTest.java index 5b1e466e3b10..28c40332cb67 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/DeepInheritanceWithNonEntitiesProxyTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/DeepInheritanceWithNonEntitiesProxyTest.java @@ -1288,7 +1288,6 @@ public void testLeafSetValueInNonEntity() { @Override protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { super.configureStandardServiceRegistryBuilder( ssrb ); - ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); ssrb.applySetting( AvailableSettings.FORMAT_SQL, "false" ); ssrb.applySetting( AvailableSettings.GENERATE_STATISTICS, "true" ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/EntitySharedInCollectionAndToOneTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/EntitySharedInCollectionAndToOneTest.java index 0735e8e9988d..3fa5e8d574ab 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/EntitySharedInCollectionAndToOneTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/EntitySharedInCollectionAndToOneTest.java @@ -116,7 +116,6 @@ public void createTestData() { @Override protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { super.configureStandardServiceRegistryBuilder( ssrb ); - ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); ssrb.applySetting( AvailableSettings.FORMAT_SQL, "false" ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/FetchGraphTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/FetchGraphTest.java index a29d28c42424..5913890382e1 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/FetchGraphTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/FetchGraphTest.java @@ -509,7 +509,6 @@ public void testQueryAndDeleteEEntity() { @Override protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { super.configureStandardServiceRegistryBuilder( ssrb ); - ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); ssrb.applySetting( AvailableSettings.FORMAT_SQL, "false" ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LazyCollectionDeletedAllowProxyTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LazyCollectionDeletedAllowProxyTest.java index e3cbe4779e0a..73d0ec1d58b0 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LazyCollectionDeletedAllowProxyTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LazyCollectionDeletedAllowProxyTest.java @@ -58,7 +58,6 @@ public Class[] getAnnotatedClasses() { protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { super.configureStandardServiceRegistryBuilder( ssrb ); - ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); ssrb.applySetting( AvailableSettings.USE_SECOND_LEVEL_CACHE, "false" ); ssrb.applySetting( AvailableSettings.ENABLE_LAZY_LOAD_NO_TRANS, "true" ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LazyGroupWithInheritanceAllowProxyTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LazyGroupWithInheritanceAllowProxyTest.java index 535a3b529663..3e874140381b 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LazyGroupWithInheritanceAllowProxyTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LazyGroupWithInheritanceAllowProxyTest.java @@ -191,9 +191,6 @@ public void queryEntityWithAssociationToAbstractRuntimeFetch() { protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { super.configureStandardServiceRegistryBuilder( ssrb ); - // todo : this is the only difference between this test and LazyGroupWithInheritanceTest - ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); - ssrb.applySetting( AvailableSettings.GENERATE_STATISTICS, "true" ); ssrb.applySetting( AvailableSettings.USE_SECOND_LEVEL_CACHE, "false" ); ssrb.applySetting( AvailableSettings.USE_QUERY_CACHE, "false" ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LazyGroupWithInheritanceTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LazyGroupWithInheritanceTest.java index fbb13398edfd..bfb41f7a60cb 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LazyGroupWithInheritanceTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LazyGroupWithInheritanceTest.java @@ -15,6 +15,7 @@ import org.hibernate.cfg.AvailableSettings; import org.hibernate.stat.Statistics; +import org.hibernate.testing.FailureExpected; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; import org.hibernate.testing.bytecode.enhancement.CustomEnhancementContext; @@ -38,6 +39,10 @@ @EnhancementOptions( lazyLoading = true ) public class LazyGroupWithInheritanceTest extends BaseNonConfigCoreFunctionalTestCase { @Test + @FailureExpected( + jiraKey = "HHH-13658", + message = "Assertions specific to enhanced lazy loading but disallowing enhanced proxies, which is no longer valid" + ) public void queryEntityWithAssociationToAbstract() { final Statistics stats = sessionFactory().getStatistics(); stats.clear(); diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LazyToOnesNoProxyFactoryWithSubclassesStatefulTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LazyToOnesNoProxyFactoryWithSubclassesStatefulTest.java index a522e5319534..eae1e0f841a9 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LazyToOnesNoProxyFactoryWithSubclassesStatefulTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LazyToOnesNoProxyFactoryWithSubclassesStatefulTest.java @@ -57,12 +57,6 @@ @TestForIssue( jiraKey = "HHH-13640" ) @RunWith(BytecodeEnhancerRunner.class) public class LazyToOnesNoProxyFactoryWithSubclassesStatefulTest extends BaseNonConfigCoreFunctionalTestCase { - @Override - protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { - super.configureStandardServiceRegistryBuilder( ssrb ); - ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); - } - @Override protected void configureSessionFactoryBuilder(SessionFactoryBuilder sfb) { super.configureSessionFactoryBuilder( sfb ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LazyToOnesNoProxyFactoryWithSubclassesStatelessTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LazyToOnesNoProxyFactoryWithSubclassesStatelessTest.java index e29f7935d496..3ddfff01bde5 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LazyToOnesNoProxyFactoryWithSubclassesStatelessTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LazyToOnesNoProxyFactoryWithSubclassesStatelessTest.java @@ -57,11 +57,6 @@ @TestForIssue( jiraKey = "HHH-13640" ) @RunWith(BytecodeEnhancerRunner.class) public class LazyToOnesNoProxyFactoryWithSubclassesStatelessTest extends BaseNonConfigCoreFunctionalTestCase { - @Override - protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { - super.configureStandardServiceRegistryBuilder( ssrb ); - ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); - } @Override protected void configureSessionFactoryBuilder(SessionFactoryBuilder sfb) { diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LazyToOnesProxyMergeWithSubclassesTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LazyToOnesProxyMergeWithSubclassesTest.java index 3ee27bbf8f85..e1dff8976422 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LazyToOnesProxyMergeWithSubclassesTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LazyToOnesProxyMergeWithSubclassesTest.java @@ -47,12 +47,6 @@ @RunWith(BytecodeEnhancerRunner.class ) @EnhancementOptions(lazyLoading = true) public class LazyToOnesProxyMergeWithSubclassesTest extends BaseNonConfigCoreFunctionalTestCase { - @Override - protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { - super.configureStandardServiceRegistryBuilder( ssrb ); - ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); - } - @Override protected void configureSessionFactoryBuilder(SessionFactoryBuilder sfb) { super.configureSessionFactoryBuilder( sfb ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LazyToOnesProxyWithSubclassesStatelessTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LazyToOnesProxyWithSubclassesStatelessTest.java index 5eb5a38aac12..00b205a14a3d 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LazyToOnesProxyWithSubclassesStatelessTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LazyToOnesProxyWithSubclassesStatelessTest.java @@ -43,11 +43,6 @@ @TestForIssue( jiraKey = "HHH-13640" ) @RunWith(BytecodeEnhancerRunner.class) public class LazyToOnesProxyWithSubclassesStatelessTest extends BaseNonConfigCoreFunctionalTestCase { - @Override - protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { - super.configureStandardServiceRegistryBuilder( ssrb ); - ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); - } @Override protected void configureSessionFactoryBuilder(SessionFactoryBuilder sfb) { diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LazyToOnesProxyWithSubclassesTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LazyToOnesProxyWithSubclassesTest.java index 47a8925fce6e..ba16490b25b5 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LazyToOnesProxyWithSubclassesTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LazyToOnesProxyWithSubclassesTest.java @@ -43,11 +43,6 @@ @TestForIssue( jiraKey = "HHH-13640" ) @RunWith(BytecodeEnhancerRunner.class) public class LazyToOnesProxyWithSubclassesTest extends BaseNonConfigCoreFunctionalTestCase { - @Override - protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { - super.configureStandardServiceRegistryBuilder( ssrb ); - ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); - } @Override protected void configureSessionFactoryBuilder(SessionFactoryBuilder sfb) { diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LoadANonExistingEntityTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LoadANonExistingEntityTest.java index c7816936e4cd..39c062be811c 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LoadANonExistingEntityTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LoadANonExistingEntityTest.java @@ -159,7 +159,6 @@ public void cleanupDate() { @Override protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { super.configureStandardServiceRegistryBuilder( ssrb ); - ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); ssrb.applySetting( AvailableSettings.FORMAT_SQL, "false" ); ssrb.applySetting( AvailableSettings.GENERATE_STATISTICS, "true" ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LoadANonExistingNotFoundBatchEntityTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LoadANonExistingNotFoundBatchEntityTest.java index 32561ea38327..4937169f45e9 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LoadANonExistingNotFoundBatchEntityTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LoadANonExistingNotFoundBatchEntityTest.java @@ -181,7 +181,6 @@ public void cleanupDate() { @Override protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { super.configureStandardServiceRegistryBuilder( ssrb ); - ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); ssrb.applySetting( AvailableSettings.FORMAT_SQL, "false" ); ssrb.applySetting( AvailableSettings.GENERATE_STATISTICS, "true" ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LoadANonExistingNotFoundEntityTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LoadANonExistingNotFoundEntityTest.java index f193ffe4eb86..92959d7116f8 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LoadANonExistingNotFoundEntityTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LoadANonExistingNotFoundEntityTest.java @@ -161,7 +161,6 @@ public void cleanupDate() { @Override protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { super.configureStandardServiceRegistryBuilder( ssrb ); - ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); ssrb.applySetting( AvailableSettings.FORMAT_SQL, "false" ); ssrb.applySetting( AvailableSettings.GENERATE_STATISTICS, "true" ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/MappedSuperclassWithEmbeddableTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/MappedSuperclassWithEmbeddableTest.java index 4871d8581951..5fb7877e7ccd 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/MappedSuperclassWithEmbeddableTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/MappedSuperclassWithEmbeddableTest.java @@ -41,7 +41,6 @@ public class MappedSuperclassWithEmbeddableTest extends BaseNonConfigCoreFunctio @Override protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { super.configureStandardServiceRegistryBuilder( ssrb ); - ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); ssrb.applySetting( AvailableSettings.FORMAT_SQL, "false" ); ssrb.applySetting( AvailableSettings.USE_SECOND_LEVEL_CACHE, "false" ); ssrb.applySetting( AvailableSettings.GENERATE_STATISTICS, "true" ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/MapsIdProxyBidirectionalTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/MapsIdProxyBidirectionalTest.java index 9488550aefa1..1ae43e2d070d 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/MapsIdProxyBidirectionalTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/MapsIdProxyBidirectionalTest.java @@ -132,7 +132,6 @@ public void cleanupDate() { @Override protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { super.configureStandardServiceRegistryBuilder( ssrb ); - ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); ssrb.applySetting( AvailableSettings.FORMAT_SQL, "false" ); ssrb.applySetting( AvailableSettings.GENERATE_STATISTICS, "true" ); ssrb.applySetting( AvailableSettings.SHOW_SQL, true ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/MapsIdProxyUnidirectionalTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/MapsIdProxyUnidirectionalTest.java index 0d763ac02be6..bb3963844635 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/MapsIdProxyUnidirectionalTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/MapsIdProxyUnidirectionalTest.java @@ -101,7 +101,6 @@ public void cleanupDate() { @Override protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { super.configureStandardServiceRegistryBuilder( ssrb ); - ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); ssrb.applySetting( AvailableSettings.FORMAT_SQL, "false" ); ssrb.applySetting( AvailableSettings.GENERATE_STATISTICS, "true" ); ssrb.applySetting( AvailableSettings.SHOW_SQL, true ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/MergeDetachedToProxyTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/MergeDetachedToProxyTest.java index c05c93eeec98..957b98393fc8 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/MergeDetachedToProxyTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/MergeDetachedToProxyTest.java @@ -118,7 +118,6 @@ public void testMergeUpdatedDetachedOntoProxy() { @Override protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { super.configureStandardServiceRegistryBuilder( ssrb ); - ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); ssrb.applySetting( AvailableSettings.FORMAT_SQL, "false" ); ssrb.applySetting( AvailableSettings.GENERATE_STATISTICS, "true" ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/MergeProxyTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/MergeProxyTest.java index 7fa72565baf4..2f9d4b4fe386 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/MergeProxyTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/MergeProxyTest.java @@ -170,7 +170,6 @@ public void testMergeDetachInitializedByAccessProxy() { @Override protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { super.configureStandardServiceRegistryBuilder( ssrb ); - ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); ssrb.applySetting( AvailableSettings.FORMAT_SQL, "false" ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/NaturalIdInUninitializedProxyTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/NaturalIdInUninitializedProxyTest.java index 37f677804e94..1f0bede4959e 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/NaturalIdInUninitializedProxyTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/NaturalIdInUninitializedProxyTest.java @@ -74,7 +74,6 @@ public void testMutableNaturalId() { @Override protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { super.configureStandardServiceRegistryBuilder( ssrb ); - ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); ssrb.applySetting( AvailableSettings.FORMAT_SQL, "false" ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/ProxyDeletionTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/ProxyDeletionTest.java index 634027793be6..2372a4a6a6aa 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/ProxyDeletionTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/ProxyDeletionTest.java @@ -54,7 +54,6 @@ public void testGetAndDeleteEEntity() { @Override protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { super.configureStandardServiceRegistryBuilder( ssrb ); - ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); ssrb.applySetting( AvailableSettings.FORMAT_SQL, "false" ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/ProxyInitializeAndUpdateInlineDirtyTrackingDynamicUpdateTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/ProxyInitializeAndUpdateInlineDirtyTrackingDynamicUpdateTest.java index 54cadd683113..b9dc51bfacc3 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/ProxyInitializeAndUpdateInlineDirtyTrackingDynamicUpdateTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/ProxyInitializeAndUpdateInlineDirtyTrackingDynamicUpdateTest.java @@ -46,7 +46,6 @@ public class ProxyInitializeAndUpdateInlineDirtyTrackingDynamicUpdateTest extend @Override protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { super.configureStandardServiceRegistryBuilder( ssrb ); - ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); } @Override diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/ProxyInitializeAndUpdateInlineDirtyTrackingTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/ProxyInitializeAndUpdateInlineDirtyTrackingTest.java index 67f458b06527..9a076abc644b 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/ProxyInitializeAndUpdateInlineDirtyTrackingTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/ProxyInitializeAndUpdateInlineDirtyTrackingTest.java @@ -36,11 +36,6 @@ @RunWith(BytecodeEnhancerRunner.class) @EnhancementOptions(lazyLoading = true,inlineDirtyChecking = true) public class ProxyInitializeAndUpdateInlineDirtyTrackingTest extends BaseNonConfigCoreFunctionalTestCase { - @Override - protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { - super.configureStandardServiceRegistryBuilder( ssrb ); - ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); - } @Override protected void configureSessionFactoryBuilder(SessionFactoryBuilder sfb) { diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/ProxyInitializeAndUpdateTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/ProxyInitializeAndUpdateTest.java index f5a4ba2dc97b..92de81d0c0c3 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/ProxyInitializeAndUpdateTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/ProxyInitializeAndUpdateTest.java @@ -37,11 +37,6 @@ @RunWith(BytecodeEnhancerRunner.class) @EnhancementOptions(lazyLoading = true) public class ProxyInitializeAndUpdateTest extends BaseNonConfigCoreFunctionalTestCase { - @Override - protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { - super.configureStandardServiceRegistryBuilder( ssrb ); - ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); - } @Override protected void configureSessionFactoryBuilder(SessionFactoryBuilder sfb) { diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/QueryScrollingWithInheritanceProxyEagerManyToOneTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/QueryScrollingWithInheritanceProxyEagerManyToOneTest.java index 17ba37ec472f..a84d1e09ac6b 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/QueryScrollingWithInheritanceProxyEagerManyToOneTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/QueryScrollingWithInheritanceProxyEagerManyToOneTest.java @@ -49,11 +49,6 @@ */ @RunWith(BytecodeEnhancerRunner.class) public class QueryScrollingWithInheritanceProxyEagerManyToOneTest extends BaseNonConfigCoreFunctionalTestCase { - @Override - protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { - super.configureStandardServiceRegistryBuilder( ssrb ); - ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); - } @Override protected void configureSessionFactoryBuilder(SessionFactoryBuilder sfb) { diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/SetIdentifierOnAEnhancedProxyTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/SetIdentifierOnAEnhancedProxyTest.java index 875fd3d9dc89..33954bb22dad 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/SetIdentifierOnAEnhancedProxyTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/SetIdentifierOnAEnhancedProxyTest.java @@ -66,7 +66,6 @@ public class SetIdentifierOnAEnhancedProxyTest extends BaseNonConfigCoreFunction @Override protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { super.configureStandardServiceRegistryBuilder( ssrb ); - ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); ssrb.applySetting( AvailableSettings.FORMAT_SQL, "false" ); ssrb.applySetting( AvailableSettings.USE_SECOND_LEVEL_CACHE, "false" ); ssrb.applySetting( AvailableSettings.ENABLE_LAZY_LOAD_NO_TRANS, "true" ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/SharingReferenceTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/SharingReferenceTest.java index 26bdac94eedd..44adcf1bcc9b 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/SharingReferenceTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/SharingReferenceTest.java @@ -43,7 +43,6 @@ public class SharingReferenceTest extends BaseNonConfigCoreFunctionalTestCase { @Override protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { super.configureStandardServiceRegistryBuilder( ssrb ); - ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); ssrb.applySetting( AvailableSettings.FORMAT_SQL, "false" ); ssrb.applySetting( AvailableSettings.GENERATE_STATISTICS, "true" ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/SimpleUpdateTestWithLazyLoading.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/SimpleUpdateTestWithLazyLoading.java index b8faa119d938..a75ffc471560 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/SimpleUpdateTestWithLazyLoading.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/SimpleUpdateTestWithLazyLoading.java @@ -61,7 +61,6 @@ public class SimpleUpdateTestWithLazyLoading extends BaseNonConfigCoreFunctional @Override protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { super.configureStandardServiceRegistryBuilder( ssrb ); - ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); ssrb.applySetting( AvailableSettings.FORMAT_SQL, "false" ); ssrb.applySetting( AvailableSettings.USE_SECOND_LEVEL_CACHE, "false" ); ssrb.applySetting( AvailableSettings.ENABLE_LAZY_LOAD_NO_TRANS, "true" ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/SimpleUpdateTestWithLazyLoadingAndInlineDirtyTracking.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/SimpleUpdateTestWithLazyLoadingAndInlineDirtyTracking.java index c2f0ad46cf20..70a9d0a36961 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/SimpleUpdateTestWithLazyLoadingAndInlineDirtyTracking.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/SimpleUpdateTestWithLazyLoadingAndInlineDirtyTracking.java @@ -55,7 +55,6 @@ public class SimpleUpdateTestWithLazyLoadingAndInlineDirtyTracking extends BaseN @Override protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { super.configureStandardServiceRegistryBuilder( ssrb ); - ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); ssrb.applySetting( AvailableSettings.FORMAT_SQL, "false" ); ssrb.applySetting( AvailableSettings.USE_SECOND_LEVEL_CACHE, "false" ); ssrb.applySetting( AvailableSettings.ENABLE_LAZY_LOAD_NO_TRANS, "true" ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/batch/AbstractBatchingTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/batch/AbstractBatchingTest.java index b07aeda24c15..00a293ac00ac 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/batch/AbstractBatchingTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/batch/AbstractBatchingTest.java @@ -46,7 +46,6 @@ public abstract class AbstractBatchingTest extends BaseNonConfigCoreFunctionalTe @Override protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { super.configureStandardServiceRegistryBuilder( ssrb ); - ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); ssrb.applySetting( AvailableSettings.DEFAULT_BATCH_FETCH_SIZE, "100" ); ssrb.applySetting( AvailableSettings.GENERATE_STATISTICS, "true" ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/DirtyCheckPrivateUnMappedCollectionTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/DirtyCheckPrivateUnMappedCollectionTest.java index bc9ee1489db0..2e0ebab3bf2a 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/DirtyCheckPrivateUnMappedCollectionTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/DirtyCheckPrivateUnMappedCollectionTest.java @@ -41,7 +41,6 @@ public class DirtyCheckPrivateUnMappedCollectionTest extends BaseNonConfigCoreFu @Override protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { super.configureStandardServiceRegistryBuilder( ssrb ); - ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); ssrb.applySetting( AvailableSettings.DEFAULT_BATCH_FETCH_SIZE, "100" ); ssrb.applySetting( AvailableSettings.GENERATE_STATISTICS, "true" ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/EntityWithMutableAttributesTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/EntityWithMutableAttributesTest.java index 4eed240516a0..25487266aa5e 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/EntityWithMutableAttributesTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/EntityWithMutableAttributesTest.java @@ -44,7 +44,6 @@ public class EntityWithMutableAttributesTest extends BaseNonConfigCoreFunctional @Override protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { super.configureStandardServiceRegistryBuilder( ssrb ); - ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); ssrb.applySetting( AvailableSettings.DEFAULT_BATCH_FETCH_SIZE, "100" ); ssrb.applySetting( AvailableSettings.GENERATE_STATISTICS, "true" ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/LoadAndUpdateEntitiesWithCollectionsTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/LoadAndUpdateEntitiesWithCollectionsTest.java index 668da7bb9775..47056359eea8 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/LoadAndUpdateEntitiesWithCollectionsTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/LoadAndUpdateEntitiesWithCollectionsTest.java @@ -41,7 +41,6 @@ public class LoadAndUpdateEntitiesWithCollectionsTest extends BaseNonConfigCoreF @Override protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { super.configureStandardServiceRegistryBuilder( ssrb ); - ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); ssrb.applySetting( AvailableSettings.DEFAULT_BATCH_FETCH_SIZE, "100" ); ssrb.applySetting( AvailableSettings.GENERATE_STATISTICS, "true" ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/ManyToOnePropertyAccessByFieldTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/ManyToOnePropertyAccessByFieldTest.java index 25b90e82c003..11d96769c7eb 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/ManyToOnePropertyAccessByFieldTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/ManyToOnePropertyAccessByFieldTest.java @@ -63,7 +63,6 @@ public class ManyToOnePropertyAccessByFieldTest extends BaseNonConfigCoreFunctio @Override protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { super.configureStandardServiceRegistryBuilder( ssrb ); - ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); ssrb.applySetting( AvailableSettings.FORMAT_SQL, "false" ); ssrb.applySetting( AvailableSettings.GENERATE_STATISTICS, "true" ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/ManyToOneWithEmbeddedAndNotOptionalFieldTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/ManyToOneWithEmbeddedAndNotOptionalFieldTest.java index b502391e8f41..0917b14da440 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/ManyToOneWithEmbeddedAndNotOptionalFieldTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/ManyToOneWithEmbeddedAndNotOptionalFieldTest.java @@ -46,7 +46,6 @@ public class ManyToOneWithEmbeddedAndNotOptionalFieldTest extends BaseNonConfigC @Override protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { super.configureStandardServiceRegistryBuilder( ssrb ); - ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); ssrb.applySetting( AvailableSettings.FORMAT_SQL, "false" ); ssrb.applySetting( AvailableSettings.GENERATE_STATISTICS, "true" ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/SimpleDynamicUpdateTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/SimpleDynamicUpdateTest.java index 491eae665f2c..22bb1f5df04d 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/SimpleDynamicUpdateTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/SimpleDynamicUpdateTest.java @@ -43,7 +43,6 @@ public class SimpleDynamicUpdateTest extends BaseNonConfigCoreFunctionalTestCase @Override protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { super.configureStandardServiceRegistryBuilder( ssrb ); - ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); ssrb.applySetting( AvailableSettings.DEFAULT_BATCH_FETCH_SIZE, "100" ); ssrb.applySetting( AvailableSettings.GENERATE_STATISTICS, "true" ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/dynamicupdate/DynamicUpdateAndCollectionsTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/dynamicupdate/DynamicUpdateAndCollectionsTest.java index a258efd8d8a9..4933bd6ee6dd 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/dynamicupdate/DynamicUpdateAndCollectionsTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/dynamicupdate/DynamicUpdateAndCollectionsTest.java @@ -44,7 +44,6 @@ public class DynamicUpdateAndCollectionsTest extends BaseNonConfigCoreFunctional @Override protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { super.configureStandardServiceRegistryBuilder( ssrb ); - ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); ssrb.applySetting( AvailableSettings.DEFAULT_BATCH_FETCH_SIZE, "100" ); ssrb.applySetting( AvailableSettings.GENERATE_STATISTICS, "true" ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/cache/EnhancedProxyCacheTest.java b/hibernate-core/src/test/java/org/hibernate/test/cache/EnhancedProxyCacheTest.java index 7b75dc3ed5f2..ac7b976c0f9a 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/cache/EnhancedProxyCacheTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/cache/EnhancedProxyCacheTest.java @@ -43,7 +43,6 @@ public class EnhancedProxyCacheTest extends BaseCoreFunctionalTestCase { @Override protected void configure(Configuration cfg) { super.configure( cfg ); - cfg.setProperty( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); cfg.setProperty( Environment.GENERATE_STATISTICS, "true" ); cfg.setProperty( Environment.USE_SECOND_LEVEL_CACHE, "true" ); } From 8a01b4dab447ce788ba203b6a75f9a0908d3f9f3 Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Wed, 10 Feb 2021 15:41:54 -0800 Subject: [PATCH 012/644] HHH-14390 : StackOverflowError with @Fetch(FetchMode.SELECT) mapped for entity with an ID that is a bidirectional one-to-one eager association --- .../java/org/hibernate/cfg/OneToOneSecondPass.java | 11 ++++++----- .../OneToOneEagerDerivedIdFetchModeSelectTest.java | 3 --- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/OneToOneSecondPass.java b/hibernate-core/src/main/java/org/hibernate/cfg/OneToOneSecondPass.java index 3c7883424d11..a8778fb224aa 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/OneToOneSecondPass.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/OneToOneSecondPass.java @@ -237,14 +237,15 @@ else if ( otherSideProperty.getValue() instanceof ManyToOne ) { boolean referenceToPrimaryKey = referencesDerivedId || mappedBy == null; value.setReferenceToPrimaryKey( referenceToPrimaryKey ); - // If the other side is a derived ID, and both sides are eager using FetchMode.JOIN, - // prevent an infinite loop of attempts to resolve identifiers by making - // this side use FetchMode.SELECT. + // If the other side is an entity with an ID that is derived from + // this side's owner entity, and both sides of the association are eager, + // then this side must be set to FetchMode.SELECT; otherwise, + // there will be an infinite loop attempting to load the derived ID on + // the opposite side. if ( referencesDerivedId && !value.isLazy() && value.getFetchMode() == FetchMode.JOIN && - !otherSideProperty.isLazy() && - otherSideProperty.getValue().getFetchMode() == FetchMode.JOIN ) { + !otherSideProperty.isLazy() ) { value.setFetchMode( FetchMode.SELECT ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/bidirectional/OneToOneEagerDerivedIdFetchModeSelectTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/bidirectional/OneToOneEagerDerivedIdFetchModeSelectTest.java index 7c2ef517c0bd..57efe4a732f3 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/bidirectional/OneToOneEagerDerivedIdFetchModeSelectTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/bidirectional/OneToOneEagerDerivedIdFetchModeSelectTest.java @@ -36,7 +36,6 @@ public class OneToOneEagerDerivedIdFetchModeSelectTest extends BaseCoreFunctiona @Test @TestForIssue(jiraKey = "HHH-14390") - @FailureExpected(jiraKey = "HHH-14390") public void testQuery() { doInHibernate( this::sessionFactory, session -> { @@ -52,7 +51,6 @@ public void testQuery() { @Test @TestForIssue(jiraKey = "HHH-14390") - @FailureExpected(jiraKey = "HHH-14390") public void testQueryById() { doInHibernate( this::sessionFactory, session -> { @@ -82,7 +80,6 @@ public void testFindById() { @Test @TestForIssue(jiraKey = "HHH-14390") - @FailureExpected(jiraKey = "HHH-14390") public void testFindByPrimaryKey() { doInHibernate( this::sessionFactory, session -> { From 27fbacf7d2849ee0707cc04b3ed7a6327fa046eb Mon Sep 17 00:00:00 2001 From: Karel Maesen Date: Thu, 11 Feb 2021 21:33:55 +0100 Subject: [PATCH 013/644] HHH-14453 Fix Hana integration test --- .../hana/TestHANASpatialFunctions.java | 214 +++++++++--------- 1 file changed, 107 insertions(+), 107 deletions(-) diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/hana/TestHANASpatialFunctions.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/hana/TestHANASpatialFunctions.java index 068c4033b058..81ca06f9c785 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/hana/TestHANASpatialFunctions.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/hana/TestHANASpatialFunctions.java @@ -65,8 +65,8 @@ public void alphashape(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getAlphaShape( 1 ); String hql = format( Locale.ENGLISH, - "SELECT id, alphashape(geom, 1) FROM org.hibernate.spatial.integration.%s.GeomEntity where geometrytype(geom) in ('ST_Point', 'ST_MultiPoint')", - pckg + "SELECT id, alphashape(geom, 1) FROM %s where geometrytype(geom) in ('ST_Point', 'ST_MultiPoint')", + entityName( pckg ) ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -84,8 +84,8 @@ public void test_area_on_geolatte() throws SQLException { public void area(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getArea(); String hql = format( - "SELECT id, area(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where geometrytype(geom) in ('ST_Polygon', 'ST_MultiPolygon')", - pckg + "SELECT id, area(geom) FROM %s where geometrytype(geom) in ('ST_Polygon', 'ST_MultiPolygon')", + entityName( pckg ) ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -102,7 +102,7 @@ public void test_asewkb_on_geolatte() throws SQLException { public void asewkb(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getAsEWKB(); - String hql = format( "SELECT id, asewkb(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity", pckg ); + String hql = format( "SELECT id, asewkb(geom) FROM %s", entityName( pckg ) ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -118,7 +118,7 @@ public void test_asewkt_on_geolatte() throws SQLException { public void asewkt(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getAsEWKT(); - String hql = format( "SELECT id, asewkt(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity", pckg ); + String hql = format( "SELECT id, asewkt(geom) FROM %s", entityName( pckg ) ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -134,7 +134,7 @@ public void test_asgeojson_on_geolatte() throws SQLException { public void asgeojson(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getAsGeoJSON(); - String hql = format( "SELECT id, asgeojson(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity", pckg ); + String hql = format( "SELECT id, asgeojson(geom) FROM %s", entityName( pckg ) ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -150,7 +150,7 @@ public void test_assvg_on_geolatte() throws SQLException { public void assvg(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getAsSVG(); - String hql = format( "SELECT id, assvg(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity", pckg ); + String hql = format( "SELECT id, assvg(geom) FROM %s", entityName( pckg ) ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -167,8 +167,8 @@ public void test_assvgaggr_on_geolatte() throws SQLException { public void assvgaggr(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getAsSVGAggr(); String hql = format( - "SELECT cast(count(g) as int), assvgaggr(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity g", - pckg + "SELECT cast(count(g) as int), assvgaggr(geom) FROM %s g", + entityName( pckg ) ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -185,7 +185,7 @@ public void test_aswkb_on_geolatte() throws SQLException { public void aswkb(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getAsWKB(); - String hql = format( "SELECT id, aswkb(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity", pckg ); + String hql = format( "SELECT id, aswkb(geom) FROM %s", entityName( pckg ) ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -201,7 +201,7 @@ public void test_aswkt_on_geolatte() throws SQLException { public void aswkt(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getAsWKT(); - String hql = format( "SELECT id, aswkt(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity", pckg ); + String hql = format( "SELECT id, aswkt(geom) FROM %s", entityName( pckg ) ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -218,8 +218,8 @@ public void test_convexhullaggr_on_geolatte() throws SQLException { public void convexhullaggr(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getConvexHullAggr(); String hql = format( - "SELECT cast(count(g) as int), convexhullaggr(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity g", - pckg + "SELECT cast(count(g) as int), convexhullaggr(geom) FROM %s g", + entityName( pckg ) ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -237,8 +237,8 @@ public void test_centroid_on_geolatte() throws SQLException { public void centroid(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getCentroid(); String hql = format( - "SELECT id, centroid(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity g where geometrytype(geom) = 'ST_Polygon'", - pckg + "SELECT id, centroid(geom) FROM %s g where geometrytype(geom) = 'ST_Polygon'", + entityName( pckg ) ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -255,7 +255,7 @@ public void test_coorddim_on_geolatte() throws SQLException { public void coorddim(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getCoordDim(); - String hql = format( "SELECT id, coorddim(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity", pckg ); + String hql = format( "SELECT id, coorddim(geom) FROM %s", entityName( pckg ) ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -272,8 +272,8 @@ public void test_coveredby_on_geolatte() throws SQLException { public void coveredby(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getCoveredBy( expectationsFactory.getTestPolygon() ); String hql = format( - "SELECT id, coveredby(geom, :filter) FROM org.hibernate.spatial.integration.%s.GeomEntity where coveredby(geom, :filter) = true and srid(geom) = %d", - pckg, + "SELECT id, coveredby(geom, :filter) FROM %s where coveredby(geom, :filter) = true and srid(geom) = %d", + entityName( pckg ), expectationsFactory.getTestSrid() ); Map params = createQueryParams( "filter", expectationsFactory.getTestPolygon() ); @@ -293,8 +293,8 @@ public void test_covers_on_geolatte() throws SQLException { public void covers(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getCovers( expectationsFactory.getTestPolygon() ); String hql = format( - "SELECT id, covers(geom, :filter) FROM org.hibernate.spatial.integration.%s.GeomEntity where covers(geom, :filter) = true and srid(geom) = %d", - pckg, + "SELECT id, covers(geom, :filter) FROM %s where covers(geom, :filter) = true and srid(geom) = %d", + entityName( pckg ), expectationsFactory.getTestSrid() ); Map params = createQueryParams( "filter", expectationsFactory.getTestPolygon() ); @@ -314,8 +314,8 @@ public void test_endpoint_on_geolatte() throws SQLException { public void endpoint(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getEndPoint(); String hql = format( - "SELECT id, endpoint(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity g where geometrytype(geom) = 'ST_LineString'", - pckg + "SELECT id, endpoint(geom) FROM %s g where geometrytype(geom) = 'ST_LineString'", + entityName( pckg ) ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -333,8 +333,8 @@ public void test_envelopeaggr_on_geolatte() throws SQLException { public void envelopeaggr(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getEnvelopeAggr(); String hql = format( - "SELECT cast(count(g) as int), envelopeaggr(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity g", - pckg + "SELECT cast(count(g) as int), envelopeaggr(geom) FROM %s g", + entityName( pckg ) ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -352,8 +352,8 @@ public void test_exteriorring_on_geolatte() throws SQLException { public void exteriorring(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getExteriorRing(); String hql = format( - "SELECT id, exteriorring(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity g where geometrytype(geom) = 'ST_Polygon'", - pckg + "SELECT id, exteriorring(geom) FROM %s g where geometrytype(geom) = 'ST_Polygon'", + entityName( pckg ) ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -373,9 +373,9 @@ public void geomfromewkb(String pckg) throws SQLException { byte[] ewkb = writer.write( expectationsFactory.getTestPolygon() ); Map dbexpected = hanaExpectationsFactory.getGeomFromEWKB( ewkb ); String hql = format( - "SELECT 1, cast(geomfromewkb(:param) as %s) FROM org.hibernate.spatial.integration.%s.GeomEntity g", + "SELECT 1, cast(geomfromewkb(:param) as %s) FROM %s g", getGeometryTypeFromPackage( pckg ), - pckg + entityName( pckg ) ); Map params = createQueryParams( "param", ewkb ); retrieveHQLResultsAndCompare( dbexpected, hql, params, pckg ); @@ -396,9 +396,9 @@ public void geomfromewkt(String pckg) throws SQLException { String ewkt = "SRID=" + expectationsFactory.getTestSrid() + ";" + writer.write( expectationsFactory.getTestPolygon() ); Map dbexpected = hanaExpectationsFactory.getGeomFromEWKT( ewkt ); String hql = format( - "SELECT 1, cast(geomfromewkt(:param) as %s) FROM org.hibernate.spatial.integration.%s.GeomEntity g", + "SELECT 1, cast(geomfromewkt(:param) as %s) FROM %s g", getGeometryTypeFromPackage( pckg ), - pckg + entityName( pckg ) ); Map params = createQueryParams( "param", ewkt ); retrieveHQLResultsAndCompare( dbexpected, hql, params, pckg ); @@ -418,9 +418,9 @@ public void geomfromtext(String pckg) throws SQLException { String text = expectationsFactory.getTestPolygon().toText(); Map dbexpected = hanaExpectationsFactory.getGeomFromText( text ); String hql = format( - "SELECT 1, cast(geomfromtext(:param) as %s) FROM org.hibernate.spatial.integration.%s.GeomEntity g", + "SELECT 1, cast(geomfromtext(:param) as %s) FROM %s g", getGeometryTypeFromPackage( pckg ), - pckg + entityName( pckg ) ); Map params = createQueryParams( "param", text ); retrieveHQLResultsAndCompare( dbexpected, hql, params, pckg ); @@ -441,9 +441,9 @@ public void geomfromwkb(String pckg) throws SQLException { byte[] wkb = writer.write( expectationsFactory.getTestPolygon() ); Map dbexpected = hanaExpectationsFactory.getGeomFromWKB( wkb ); String hql = format( - "SELECT 1, cast(geomfromwkb(:param) as %s) FROM org.hibernate.spatial.integration.%s.GeomEntity g", + "SELECT 1, cast(geomfromwkb(:param) as %s) FROM %s g", getGeometryTypeFromPackage( pckg ), - pckg + entityName( pckg ) ); Map params = createQueryParams( "param", wkb ); retrieveHQLResultsAndCompare( dbexpected, hql, params, pckg ); @@ -464,9 +464,9 @@ public void geomfromwkt(String pckg) throws SQLException { String wkt = writer.write( expectationsFactory.getTestPolygon() ); Map dbexpected = hanaExpectationsFactory.getGeomFromWKT( wkt ); String hql = format( - "SELECT 1, cast(geomfromwkt(:param) as %s) FROM org.hibernate.spatial.integration.%s.GeomEntity g", + "SELECT 1, cast(geomfromwkt(:param) as %s) FROM %s g", getGeometryTypeFromPackage( pckg ), - pckg + entityName( pckg ) ); Map params = createQueryParams( "param", wkt ); retrieveHQLResultsAndCompare( dbexpected, hql, params, pckg ); @@ -485,9 +485,9 @@ public void test_geometryn_on_geolatte() throws SQLException { public void geometryn(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getGeometryN( 1 ); String hql = format( - "SELECT id, cast(geometryn(geom, :n) as %s) FROM org.hibernate.spatial.integration.%s.GeomEntity g where geometrytype(geom) = 'ST_GeometryCollection'", + "SELECT id, cast(geometryn(geom, :n) as %s) FROM %s g where geometrytype(geom) = 'ST_GeometryCollection'", getGeometryTypeFromPackage( pckg ), - pckg + entityName( pckg ) ); Map params = createQueryParams( "n", 1 ); retrieveHQLResultsAndCompare( dbexpected, hql, params, pckg ); @@ -506,9 +506,9 @@ public void test_interiorringn_on_geolatte() throws SQLException { public void interiorringn(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getInteriorRingN( 1 ); String hql = format( - "SELECT id, cast(interiorringn(geom, :n) as %s) FROM org.hibernate.spatial.integration.%s.GeomEntity g where geometrytype(geom) = 'ST_Polygon'", + "SELECT id, cast(interiorringn(geom, :n) as %s) FROM %s g where geometrytype(geom) = 'ST_Polygon'", getGeometryTypeFromPackage( pckg ), - pckg + entityName( pckg ) ); Map params = createQueryParams( "n", 1 ); retrieveHQLResultsAndCompare( dbexpected, hql, params, pckg ); @@ -527,8 +527,8 @@ public void test_intersectionaggr_on_geolatte() throws SQLException { public void intersectionaggr(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getIntersectionAggr(); String hql = format( - "SELECT cast(count(g) as int), intersectionaggr(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity g", - pckg + "SELECT cast(count(g) as int), intersectionaggr(geom) FROM %s g", + entityName( pckg ) ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -549,8 +549,8 @@ public void intersectsrect(String pckg) throws SQLException { expectationsFactory.getTestPoint() ); String hql = format( - "SELECT id, intersectsrect(geom, :pmin, :pmax) FROM org.hibernate.spatial.integration.%s.GeomEntity where intersectsrect(geom, :pmin, :pmax) = true and srid(geom) = %d", - pckg, + "SELECT id, intersectsrect(geom, :pmin, :pmax) FROM %s where intersectsrect(geom, :pmin, :pmax) = true and srid(geom) = %d", + entityName( pckg ), expectationsFactory.getTestSrid() ); Map params = createQueryParams( "pmin", expectationsFactory.getTestPoint().reverse() ); @@ -571,8 +571,8 @@ public void test_is3d_on_geolatte() throws SQLException { public void is3d(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getIs3D(); String hql = format( - "SELECT id, is3d(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where is3d(geom) = true and srid(geom) = %d", - pckg, + "SELECT id, is3d(geom) FROM %s where is3d(geom) = true and srid(geom) = %d", + entityName( pckg ), expectationsFactory.getTestSrid() ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); @@ -591,8 +591,8 @@ public void test_isclosed_on_geolatte() throws SQLException { public void isclosed(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getIsClosed(); String hql = format( - "SELECT id, isclosed(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where geometrytype(geom) in ('ST_LineString', 'ST_MultiLineString') and isclosed(geom) = true and srid(geom) = %d", - pckg, + "SELECT id, isclosed(geom) FROM %s where geometrytype(geom) in ('ST_LineString', 'ST_MultiLineString') and isclosed(geom) = true and srid(geom) = %d", + entityName( pckg ), expectationsFactory.getTestSrid() ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); @@ -611,8 +611,8 @@ public void test_ismeasured_on_geolatte() throws SQLException { public void ismeasured(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getIsMeasured(); String hql = format( - "SELECT id, ismeasured(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where ismeasured(geom) = true and srid(geom) = %d", - pckg, + "SELECT id, ismeasured(geom) FROM %s where ismeasured(geom) = true and srid(geom) = %d", + entityName( pckg ), expectationsFactory.getTestSrid() ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); @@ -631,8 +631,8 @@ public void test_isring_on_geolatte() throws SQLException { public void isring(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getIsRing(); String hql = format( - "SELECT id, isring(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where geometrytype(geom) in ('ST_LineString') and srid(geom) = %d", - pckg, + "SELECT id, isring(geom) FROM %s where geometrytype(geom) in ('ST_LineString') and srid(geom) = %d", + entityName( pckg ), expectationsFactory.getTestSrid() ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); @@ -651,8 +651,8 @@ public void test_isvalid_on_geolatte() throws SQLException { public void isvalid(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getIsValid(); String hql = format( - "SELECT id, isvalid(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where isvalid(geom) = true and srid(geom) = %d", - pckg, + "SELECT id, isvalid(geom) FROM %s where isvalid(geom) = true and srid(geom) = %d", + entityName( pckg ), expectationsFactory.getTestSrid() ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); @@ -671,8 +671,8 @@ public void test_length_on_geolatte() throws SQLException { public void length(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getLength(); String hql = format( - "SELECT id, length(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where geometrytype(geom) in ('ST_LineString', 'ST_MultiLineString') and srid(geom) = %d", - pckg, + "SELECT id, length(geom) FROM %s where geometrytype(geom) in ('ST_LineString', 'ST_MultiLineString') and srid(geom) = %d", + entityName( pckg ), expectationsFactory.getTestSrid() ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); @@ -691,8 +691,8 @@ public void test_m_on_geolatte() throws SQLException { public void m(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getM(); String hql = format( - "SELECT id, m(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where geometrytype(geom) in ('ST_Point') and srid(geom) = %d", - pckg, + "SELECT id, m(geom) FROM %s where geometrytype(geom) in ('ST_Point') and srid(geom) = %d", + entityName( pckg ), expectationsFactory.getTestSrid() ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); @@ -711,8 +711,8 @@ public void test_mmax_on_geolatte() throws SQLException { public void mmax(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getMMax(); String hql = format( - "SELECT id, mmax(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where srid(geom) = %d", - pckg, expectationsFactory.getTestSrid() + "SELECT id, mmax(geom) FROM %s where srid(geom) = %d", + entityName( pckg ), expectationsFactory.getTestSrid() ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -730,8 +730,8 @@ public void test_mmin_on_geolatte() throws SQLException { public void mmin(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getMMin(); String hql = format( - "SELECT id, mmin(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where srid(geom) = %d", - pckg, expectationsFactory.getTestSrid() + "SELECT id, mmin(geom) FROM %s where srid(geom) = %d", + entityName( pckg ), expectationsFactory.getTestSrid() ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -749,8 +749,8 @@ public void test_numgeometries_on_geolatte() throws SQLException { public void numgeometries(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getNumGeometries(); String hql = format( - "SELECT id, numgeometries(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where geometrytype(geom) in ('ST_GeometryCollection') and srid(geom) = %d", - pckg, + "SELECT id, numgeometries(geom) FROM %s where geometrytype(geom) in ('ST_GeometryCollection') and srid(geom) = %d", + entityName( pckg ), expectationsFactory.getTestSrid() ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); @@ -769,8 +769,8 @@ public void test_numnuminteriorring_on_geolatte() throws SQLException { public void numinteriorring(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getNumInteriorRing(); String hql = format( - "SELECT id, numinteriorring(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where geometrytype(geom) in ('ST_Polygon') and srid(geom) = %d", - pckg, + "SELECT id, numinteriorring(geom) FROM %s where geometrytype(geom) in ('ST_Polygon') and srid(geom) = %d", + entityName( pckg ), expectationsFactory.getTestSrid() ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); @@ -789,8 +789,8 @@ public void test_numnuminteriorrings_on_geolatte() throws SQLException { public void numinteriorrings(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getNumInteriorRings(); String hql = format( - "SELECT id, numinteriorrings(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where geometrytype(geom) in ('ST_Polygon') and srid(geom) = %d", - pckg, + "SELECT id, numinteriorrings(geom) FROM %s where geometrytype(geom) in ('ST_Polygon') and srid(geom) = %d", + entityName( pckg ), expectationsFactory.getTestSrid() ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); @@ -809,8 +809,8 @@ public void test_numpoints_on_geolatte() throws SQLException { public void numpoints(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getNumPoints(); String hql = format( - "SELECT id, numpoints(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where geometrytype(geom) in ('ST_LineString') and srid(geom) = %d", - pckg, + "SELECT id, numpoints(geom) FROM %s where geometrytype(geom) in ('ST_LineString') and srid(geom) = %d", + entityName( pckg ), expectationsFactory.getTestSrid() ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); @@ -829,8 +829,8 @@ public void test_orderingequals_on_geolatte() throws SQLException { public void orderingequals(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getOrderingEquals( expectationsFactory.getTestPolygon() ); String hql = format( - "SELECT id, orderingequals(geom, :filter) FROM org.hibernate.spatial.integration.%s.GeomEntity where orderingequals(geom, :filter) = true and srid(geom) = %d", - pckg, + "SELECT id, orderingequals(geom, :filter) FROM %s where orderingequals(geom, :filter) = true and srid(geom) = %d", + entityName( pckg ), expectationsFactory.getTestSrid() ); Map params = createQueryParams( "filter", expectationsFactory.getTestPolygon() ); @@ -850,8 +850,8 @@ public void test_perimeter_on_geolatte() throws SQLException { public void perimeter(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getPerimeter(); String hql = format( - "SELECT id, perimeter(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where geometrytype(geom) in ('ST_Polygon', 'ST_MultiPolygon') and srid(geom) = %d", - pckg, + "SELECT id, perimeter(geom) FROM %s where geometrytype(geom) in ('ST_Polygon', 'ST_MultiPolygon') and srid(geom) = %d", + entityName( pckg ), expectationsFactory.getTestSrid() ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); @@ -870,8 +870,8 @@ public void test_pointonsurface_on_geolatte() throws SQLException { public void pointonsurface(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getPointOnSurface(); String hql = format( - "SELECT id, pointonsurface(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where geometrytype(geom) in ('ST_Polygon', 'ST_MultiPolygon') and srid(geom) = %d", - pckg, + "SELECT id, pointonsurface(geom) FROM %s where geometrytype(geom) in ('ST_Polygon', 'ST_MultiPolygon') and srid(geom) = %d", + entityName( pckg ), expectationsFactory.getTestSrid() ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); @@ -890,8 +890,8 @@ public void test_pointn_on_geolatte() throws SQLException { public void pointn(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getPointN( 1 ); String hql = format( - "SELECT id, pointn(geom, :n) FROM org.hibernate.spatial.integration.%s.GeomEntity where geometrytype(geom) in ('ST_LineString') and srid(geom) = %d", - pckg, + "SELECT id, pointn(geom, :n) FROM %s where geometrytype(geom) in ('ST_LineString') and srid(geom) = %d", + entityName( pckg ), expectationsFactory.getTestSrid() ); Map params = createQueryParams( "n", 1 ); @@ -913,8 +913,8 @@ public void test_snaptogrid_on_geolatte() throws SQLException { public void snaptogrid(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getSnapToGrid(); String hql = format( - "SELECT id, snaptogrid(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where srid(geom) = %d", - pckg, expectationsFactory.getTestSrid() + "SELECT id, snaptogrid(geom) FROM %s where srid(geom) = %d", + entityName( pckg ), expectationsFactory.getTestSrid() ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -932,8 +932,8 @@ public void test_startpoint_on_geolatte() throws SQLException { public void startpoint(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getStartPoint(); String hql = format( - "SELECT id, startpoint(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity g where geometrytype(geom) = 'ST_LineString'", - pckg + "SELECT id, startpoint(geom) FROM %s g where geometrytype(geom) = 'ST_LineString'", + entityName( pckg ) ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -951,8 +951,8 @@ public void test_unionaggr_on_geolatte() throws SQLException { public void unionaggr(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getUnionAggr(); String hql = format( - "SELECT cast(count(g) as int), unionaggr(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity g", - pckg + "SELECT cast(count(g) as int), unionaggr(geom) FROM %s g", + entityName( pckg ) ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -970,8 +970,8 @@ public void test_x_on_geolatte() throws SQLException { public void x(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getX(); String hql = format( - "SELECT id, x(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where geometrytype(geom) in ('ST_Point') and srid(geom) = %d", - pckg, + "SELECT id, x(geom) FROM %s where geometrytype(geom) in ('ST_Point') and srid(geom) = %d", + entityName( pckg ), expectationsFactory.getTestSrid() ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); @@ -990,8 +990,8 @@ public void test_xmax_on_geolatte() throws SQLException { public void xmax(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getXMax(); String hql = format( - "SELECT id, xmax(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where srid(geom) = %d", - pckg, expectationsFactory.getTestSrid() + "SELECT id, xmax(geom) FROM %s where srid(geom) = %d", + entityName( pckg ), expectationsFactory.getTestSrid() ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -1009,8 +1009,8 @@ public void test_xmin_on_geolatte() throws SQLException { public void xmin(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getXMin(); String hql = format( - "SELECT id, xmin(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where srid(geom) = %d", - pckg, expectationsFactory.getTestSrid() + "SELECT id, xmin(geom) FROM %s where srid(geom) = %d", + entityName( pckg ), expectationsFactory.getTestSrid() ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -1028,8 +1028,8 @@ public void test_y_on_geolatte() throws SQLException { public void y(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getY(); String hql = format( - "SELECT id, y(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where geometrytype(geom) in ('ST_Point') and srid(geom) = %d", - pckg, + "SELECT id, y(geom) FROM %s where geometrytype(geom) in ('ST_Point') and srid(geom) = %d", + entityName( pckg ), expectationsFactory.getTestSrid() ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); @@ -1048,8 +1048,8 @@ public void test_ymax_on_geolatte() throws SQLException { public void ymax(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getYMax(); String hql = format( - "SELECT id, ymax(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where srid(geom) = %d", - pckg, expectationsFactory.getTestSrid() + "SELECT id, ymax(geom) FROM %s where srid(geom) = %d", + entityName( pckg ), expectationsFactory.getTestSrid() ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -1067,8 +1067,8 @@ public void test_ymin_on_geolatte() throws SQLException { public void ymin(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getYMin(); String hql = format( - "SELECT id, ymin(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where srid(geom) = %d", - pckg, expectationsFactory.getTestSrid() + "SELECT id, ymin(geom) FROM %s where srid(geom) = %d", + entityName( pckg ), expectationsFactory.getTestSrid() ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -1086,8 +1086,8 @@ public void test_z_on_geolatte() throws SQLException { public void z(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getZ(); String hql = format( - "SELECT id, z(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where geometrytype(geom) in ('ST_Point') and srid(geom) = %d", - pckg, + "SELECT id, z(geom) FROM %s where geometrytype(geom) in ('ST_Point') and srid(geom) = %d", + entityName( pckg ), expectationsFactory.getTestSrid() ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); @@ -1106,8 +1106,8 @@ public void test_zmax_on_geolatte() throws SQLException { public void zmax(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getZMax(); String hql = format( - "SELECT id, zmax(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where srid(geom) = %d", - pckg, expectationsFactory.getTestSrid() + "SELECT id, zmax(geom) FROM %s where srid(geom) = %d", + entityName( pckg ), expectationsFactory.getTestSrid() ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -1125,8 +1125,8 @@ public void test_zmin_on_geolatte() throws SQLException { public void zmin(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getZMin(); String hql = format( - "SELECT id, zmin(geom) FROM org.hibernate.spatial.integration.%s.GeomEntity where srid(geom) = %d", - pckg, expectationsFactory.getTestSrid() + "SELECT id, zmin(geom) FROM %s where srid(geom) = %d", + entityName( pckg ), expectationsFactory.getTestSrid() ); retrieveHQLResultsAndCompare( dbexpected, hql, pckg ); } @@ -1144,16 +1144,16 @@ public void test_nestedfunction_on_geolatte() throws SQLException { public void nestedfunction(String pckg) throws SQLException { Map dbexpected = hanaExpectationsFactory.getNestedFunctionInner( expectationsFactory.getTestPolygon() ); String hql = format( - "SELECT id, geom FROM org.hibernate.spatial.integration.%s.GeomEntity g where dwithin(geom, srid(:filter, 0), 1) = true", - pckg + "SELECT id, geom FROM %s g where dwithin(geom, srid(:filter, 0), 1) = true", + entityName( pckg ) ); Map params = createQueryParams( "filter", expectationsFactory.getTestPolygon() ); retrieveHQLResultsAndCompare( dbexpected, hql, params, pckg ); dbexpected = hanaExpectationsFactory.getNestedFunctionOuter( expectationsFactory.getTestPolygon() ); hql = format( - "SELECT id, geom FROM org.hibernate.spatial.integration.%s.GeomEntity g where dwithin(:filter, srid(geom, 0), 1) = true", - pckg + "SELECT id, geom FROM %s g where dwithin(:filter, srid(geom, 0), 1) = true", + entityName( pckg ) ); retrieveHQLResultsAndCompare( dbexpected, hql, params, pckg ); } From 7e2747516ab98a268626009b70c66262e8a284fa Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Thu, 11 Feb 2021 16:04:41 -0800 Subject: [PATCH 014/644] HHH-14389 : Add test case that throw IllegalArgumentException using EntityManager#find by ID when ID is a one-to-one association --- ...oOneEagerDerivedIdFetchModeSelectTest.java | 16 ---------------- ...ToOneLazyDerivedIdFetchModeSelectTest.java | 16 ---------------- .../OneToOneWithDerivedIdentityTest.java | 19 ++++++++++--------- ...oOneEagerDerivedIdFetchModeSelectTest.java | 16 ---------------- ...ToOneLazyDerivedIdFetchModeSelectTest.java | 16 ---------------- 5 files changed, 10 insertions(+), 73 deletions(-) diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/bidirectional/OneToOneEagerDerivedIdFetchModeSelectTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/bidirectional/OneToOneEagerDerivedIdFetchModeSelectTest.java index 57efe4a732f3..334bc867b6cf 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/bidirectional/OneToOneEagerDerivedIdFetchModeSelectTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/bidirectional/OneToOneEagerDerivedIdFetchModeSelectTest.java @@ -19,7 +19,6 @@ import org.hibernate.annotations.Fetch; import org.hibernate.annotations.FetchMode; -import org.hibernate.testing.FailureExpected; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; import org.junit.After; @@ -29,7 +28,6 @@ import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertSame; public class OneToOneEagerDerivedIdFetchModeSelectTest extends BaseCoreFunctionalTestCase { private Foo foo; @@ -64,20 +62,6 @@ public void testQueryById() { }); } - @Test - @FailureExpected( jiraKey = "HHH-14389") - public void testFindById() { - - doInHibernate( this::sessionFactory, session -> { - Bar newBar = session.find( Bar.class, foo ); - assertNotNull( newBar ); - assertNotNull( newBar.getFoo() ); - assertSame( foo, newBar.getFoo() ); - assertEquals( foo.getId(), newBar.getFoo().getId() ); - assertEquals( "Some details", newBar.getDetails() ); - }); - } - @Test @TestForIssue(jiraKey = "HHH-14390") public void testFindByPrimaryKey() { diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/bidirectional/OneToOneLazyDerivedIdFetchModeSelectTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/bidirectional/OneToOneLazyDerivedIdFetchModeSelectTest.java index aec7d4a826d3..3c78716fd8bc 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/bidirectional/OneToOneLazyDerivedIdFetchModeSelectTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/bidirectional/OneToOneLazyDerivedIdFetchModeSelectTest.java @@ -18,7 +18,6 @@ import org.hibernate.annotations.Fetch; import org.hibernate.annotations.FetchMode; -import org.hibernate.testing.FailureExpected; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; import org.junit.After; @@ -28,7 +27,6 @@ import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertSame; public class OneToOneLazyDerivedIdFetchModeSelectTest extends BaseCoreFunctionalTestCase { private Foo foo; @@ -63,20 +61,6 @@ public void testQueryById() { }); } - @Test - @FailureExpected( jiraKey = "HHH-14389") - public void testFindById() { - - doInHibernate( this::sessionFactory, session -> { - Bar newBar = session.find( Bar.class, foo ); - assertNotNull( newBar ); - assertNotNull( newBar.getFoo() ); - assertSame( foo, newBar.getFoo() ); - assertEquals( foo.getId(), newBar.getFoo().getId() ); - assertEquals( "Some details", newBar.getDetails() ); - }); - } - @Test @TestForIssue(jiraKey = "HHH-14390") public void testFindByPrimaryKey() { diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/bidirectional/OneToOneWithDerivedIdentityTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/bidirectional/OneToOneWithDerivedIdentityTest.java index b55cc6fbf1b8..5bdc276055e9 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/bidirectional/OneToOneWithDerivedIdentityTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/bidirectional/OneToOneWithDerivedIdentityTest.java @@ -11,6 +11,7 @@ import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.util.List; @@ -18,7 +19,6 @@ import org.hibernate.Session; import org.hibernate.engine.spi.SessionImplementor; -import org.hibernate.testing.FailureExpected; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; import org.junit.Test; @@ -80,7 +80,6 @@ public void testQueryById() { @Test @TestForIssue(jiraKey = "HHH-14389") - @FailureExpected( jiraKey = "HHH-14389") public void testFindById() { Session s = openSession(); s.beginTransaction(); @@ -95,13 +94,15 @@ public void testFindById() { assertEquals( foo.getId(), bar.getFoo().getId() ); s.clear(); - Bar newBar = s.find( Bar.class, foo ); - assertNotNull( newBar ); - assertNotNull( newBar.getFoo() ); - assertSame( foo, newBar.getFoo() ); - assertEquals( foo.getId(), newBar.getFoo().getId() ); - assertEquals( "Some details", newBar.getDetails() ); - s.getTransaction().rollback(); + try { + s.find( Bar.class, foo ); + fail( "Should have thrown IllegalArgumentException" ); + } + catch(IllegalArgumentException expected) { + } + finally { + s.getTransaction().rollback(); + } s.close(); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/unidirectional/OneToOneEagerDerivedIdFetchModeSelectTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/unidirectional/OneToOneEagerDerivedIdFetchModeSelectTest.java index 95b02f4d8406..8a7872defd94 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/unidirectional/OneToOneEagerDerivedIdFetchModeSelectTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/unidirectional/OneToOneEagerDerivedIdFetchModeSelectTest.java @@ -17,7 +17,6 @@ import org.hibernate.annotations.Fetch; import org.hibernate.annotations.FetchMode; -import org.hibernate.testing.FailureExpected; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; import org.junit.After; @@ -27,7 +26,6 @@ import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertSame; public class OneToOneEagerDerivedIdFetchModeSelectTest extends BaseCoreFunctionalTestCase { private Foo foo; @@ -61,20 +59,6 @@ public void testQueryById() { }); } - @Test - @FailureExpected( jiraKey = "HHH-14389") - public void testFindById() { - - doInHibernate( this::sessionFactory, session -> { - Bar newBar = session.find( Bar.class, foo ); - assertNotNull( newBar ); - assertNotNull( newBar.getFoo() ); - assertSame( foo, newBar.getFoo() ); - assertEquals( foo.getId(), newBar.getFoo().getId() ); - assertEquals( "Some details", newBar.getDetails() ); - }); - } - @Test @TestForIssue(jiraKey = "HHH-14390") public void testFindByPrimaryKey() { diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/unidirectional/OneToOneLazyDerivedIdFetchModeSelectTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/unidirectional/OneToOneLazyDerivedIdFetchModeSelectTest.java index 8afe8d29b3ad..34708dbf701e 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/unidirectional/OneToOneLazyDerivedIdFetchModeSelectTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/unidirectional/OneToOneLazyDerivedIdFetchModeSelectTest.java @@ -17,7 +17,6 @@ import org.hibernate.annotations.Fetch; import org.hibernate.annotations.FetchMode; -import org.hibernate.testing.FailureExpected; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; import org.junit.After; @@ -27,7 +26,6 @@ import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertSame; public class OneToOneLazyDerivedIdFetchModeSelectTest extends BaseCoreFunctionalTestCase { private Foo foo; @@ -62,20 +60,6 @@ public void testQueryById() { }); } - @Test - @FailureExpected( jiraKey = "HHH-14389") - public void testFindById() { - - doInHibernate( this::sessionFactory, session -> { - Bar newBar = session.find( Bar.class, foo ); - assertNotNull( newBar ); - assertNotNull( newBar.getFoo() ); - assertSame( foo, newBar.getFoo() ); - assertEquals( foo.getId(), newBar.getFoo().getId() ); - assertEquals( "Some details", newBar.getDetails() ); - }); - } - @Test @TestForIssue(jiraKey = "HHH-14390") public void testFindByPrimaryKey() { From 031f12a1ec96ffaa46c9358c720a8dd7e3aa5bc7 Mon Sep 17 00:00:00 2001 From: Karel Maesen Date: Mon, 8 Feb 2021 23:33:03 +0100 Subject: [PATCH 015/644] HHH-14446 Add integration test profiles for mysql and postgis --- docker_db.sh | 7 ++++++- gradle/databases.gradle | 8 ++++++++ hibernate-spatial/databases/postgispg96/matrix.gradle | 2 +- .../databases/postgispg96/resources/hibernate.properties | 7 +++---- hibernate-spatial/hibernate-spatial.gradle | 2 +- .../org/hibernate/spatial/testing/DataSourceUtils.java | 3 ++- 6 files changed, 21 insertions(+), 8 deletions(-) diff --git a/docker_db.sh b/docker_db.sh index a7368776d2e5..4b6052951d8c 100755 --- a/docker_db.sh +++ b/docker_db.sh @@ -7,7 +7,7 @@ mysql_5_7() { mysql_8_0() { docker rm -f mysql || true - docker run --name mysql -e MYSQL_USER=hibernate_orm_test -e MYSQL_PASSWORD=hibernate_orm_test -e MYSQL_DATABASE=hibernate_orm_test -p3306:3306 -d mysql:8.0.21 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci + docker run --name mysql -e MYSQL_USER=hibernate_orm_test -e MYSQL_PASSWORD=hibernate_orm_test -e MYSQL_ROOT_PASSWORD=hibernate_orm_test -e MYSQL_DATABASE=hibernate_orm_test -p3306:3306 -d mysql:8.0.21 --character-set-server=utf8mb4 --collation-server=utf8mb4_unicode_ci } mariadb() { @@ -20,6 +20,11 @@ postgresql_9_5() { docker run --name postgres -e POSTGRES_USER=hibernate_orm_test -e POSTGRES_PASSWORD=hibernate_orm_test -e POSTGRES_DB=hibernate_orm_test -p5432:5432 -d postgres:9.5 } +postgis_9_6(){ + docker rm -f postgis || true + docker run --name postgis -e POSTGRES_USER=hibernate_orm_test -e POSTGRES_PASSWORD=hibernate_orm_test -e POSTGRES_DB=hibernate_orm_test -p5432:5432 -d mdillon/postgis:9.6 +} + db2() { docker rm -f db2 || true docker run --name db2 --privileged -e DB2INSTANCE=orm_test -e DB2INST1_PASSWORD=orm_test -e DBNAME=orm_test -e LICENSE=accept -e AUTOCONFIG=false -e ARCHIVE_LOGS=false -e TO_CREATE_SAMPLEDB=false -e REPODB=false -p 50000:50000 -d ibmcom/db2:11.5.5.0 diff --git a/gradle/databases.gradle b/gradle/databases.gradle index b4dcb1d775dd..4c04e887c54a 100644 --- a/gradle/databases.gradle +++ b/gradle/databases.gradle @@ -69,6 +69,14 @@ ext { 'jdbc.pass' : 'hibernate_orm_test', 'jdbc.url' : 'jdbc:mysql://127.0.0.1/hibernate_orm_test?useSSL=false' ], + // uses docker mysql_8_0 + mysql8_spatial_ci: [ + 'db.dialect' : 'org.hibernate.spatial.dialect.mysql.MySQL8SpatialDialect', + 'jdbc.driver': 'com.mysql.cj.jdbc.Driver', + 'jdbc.user' : 'hibernate_orm_test', + 'jdbc.pass' : 'hibernate_orm_test', + 'jdbc.url' : 'jdbc:mysql://' + dbHost + '/hibernate_orm_test?allowPublicKeyRetrieval=true&useSSL=false' + ], mariadb : [ 'db.dialect' : 'org.hibernate.dialect.MariaDB103Dialect', 'jdbc.driver': 'org.mariadb.jdbc.Driver', diff --git a/hibernate-spatial/databases/postgispg96/matrix.gradle b/hibernate-spatial/databases/postgispg96/matrix.gradle index 5059cb9072d0..f59a2fafc469 100644 --- a/hibernate-spatial/databases/postgispg96/matrix.gradle +++ b/hibernate-spatial/databases/postgispg96/matrix.gradle @@ -4,4 +4,4 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -jdbcDependency 'org.postgresql:postgresql:42.2.2' \ No newline at end of file +jdbcDependency 'org.postgresql:postgresql:42.2.16' \ No newline at end of file diff --git a/hibernate-spatial/databases/postgispg96/resources/hibernate.properties b/hibernate-spatial/databases/postgispg96/resources/hibernate.properties index 4d1aa4760601..15d5b8ffac9c 100644 --- a/hibernate-spatial/databases/postgispg96/resources/hibernate.properties +++ b/hibernate-spatial/databases/postgispg96/resources/hibernate.properties @@ -8,10 +8,9 @@ hibernate.dialect org.hibernate.spatial.dialect.postgis.PostgisPG95Dialect hibernate.connection.driver_class org.postgresql.Driver -hibernate.connection.url jdbc:postgresql://localhost:9432/ -hibernate.connection.username hibern8 -hibernate.connection.password hibern8 - +hibernate.connection.url jdbc:postgresql://localhost/hibernate_orm_test +hibernate.connection.username hibernate_orm_test +hibernate.connection.password hibernate_orm_test hibernate.show_sql true hibernate.format_sql true diff --git a/hibernate-spatial/hibernate-spatial.gradle b/hibernate-spatial/hibernate-spatial.gradle index 573d7f68391b..4915d432968a 100644 --- a/hibernate-spatial/hibernate-spatial.gradle +++ b/hibernate-spatial/hibernate-spatial.gradle @@ -25,7 +25,7 @@ dependencies { testCompile(libraries.junit) testCompile(project(':hibernate-testing')) - testCompile([group: 'commons-dbcp', name: 'commons-dbcp', version: '1.4']) + testCompile([group: 'org.apache.commons', name: 'commons-dbcp2', version: '2.8.0']) testCompile(libraries.validation) testCompile(libraries.jandex) testCompile(libraries.classmate) diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/DataSourceUtils.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/DataSourceUtils.java index fb3d6f8e49cf..3bad90978301 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/DataSourceUtils.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/DataSourceUtils.java @@ -29,7 +29,8 @@ import org.jboss.logging.Logger; -import org.apache.commons.dbcp.BasicDataSource; + +import org.apache.commons.dbcp2.BasicDataSource; import org.geolatte.geom.Geometry; import org.geolatte.geom.codec.Wkt; import org.geolatte.geom.codec.WktDecodeException; From a4676415848abce27ba4524e40a0058e718b5bbc Mon Sep 17 00:00:00 2001 From: Karel Maesen Date: Thu, 11 Feb 2021 17:40:16 +0100 Subject: [PATCH 016/644] HHH-14446 Fix PostgreSQL create extension syntax --- .../hibernate/testing/cleaner/PostgreSQLDatabaseCleaner.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cleaner/PostgreSQLDatabaseCleaner.java b/hibernate-testing/src/main/java/org/hibernate/testing/cleaner/PostgreSQLDatabaseCleaner.java index 0f6f6d8f6e34..567b05f45601 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/cleaner/PostgreSQLDatabaseCleaner.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/cleaner/PostgreSQLDatabaseCleaner.java @@ -88,7 +88,7 @@ private void clearSchema0(Connection c, Function schemasPr Map> schemaExtensions = new HashMap<>(); try (Statement s2 = c.createStatement()) { rs = s2.executeQuery( - "SELECT ns.nspname, 'CREATE EXTENSION ' || e.extname || ' SCHEMA \"' || ns.nspname || '\" VERSION ' || e.extversion FROM pg_extension e JOIN pg_catalog.pg_namespace ns ON e.extnamespace = ns.oid WHERE e.extname <> 'plpgsql'" + "SELECT ns.nspname, 'CREATE EXTENSION ' || e.extname || ' SCHEMA \"' || ns.nspname || '\"' FROM pg_extension e JOIN pg_catalog.pg_namespace ns ON e.extnamespace = ns.oid WHERE e.extname <> 'plpgsql'" ); while ( rs.next() ) { schemaExtensions.computeIfAbsent( rs.getString( 1 ), k -> new ArrayList<>() ) From da8cd19968a7f09e823d6f9d1698e834f6e3b3c2 Mon Sep 17 00:00:00 2001 From: Karel Maesen Date: Thu, 11 Feb 2021 17:49:28 +0100 Subject: [PATCH 017/644] HHH-14446 Add spatial integration test profiles for oracle and ms sqlserver --- gradle/databases.gradle | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/gradle/databases.gradle b/gradle/databases.gradle index 4c04e887c54a..e5bd1721f8bb 100644 --- a/gradle/databases.gradle +++ b/gradle/databases.gradle @@ -121,6 +121,13 @@ ext { 'jdbc.pass' : 'Oracle18', 'jdbc.url' : 'jdbc:oracle:thin:@' + dbHost + ':1521:XE' ], + oracle_spatial_ci : [ + 'db.dialect' : 'org.hibernate.spatial.dialect.oracle.OracleSpatial10gDialect', + 'jdbc.driver': 'oracle.jdbc.OracleDriver', + 'jdbc.user' : 'SYSTEM', + 'jdbc.pass' : 'Oracle18', + 'jdbc.url' : 'jdbc:oracle:thin:@' + dbHost + ':1521:XE' + ], mssql : [ 'db.dialect' : 'org.hibernate.dialect.SQLServer2012Dialect', 'jdbc.driver': 'com.microsoft.sqlserver.jdbc.SQLServerDriver', @@ -135,6 +142,13 @@ ext { 'jdbc.pass' : 'Hibernate_orm_test', 'jdbc.url' : 'jdbc:sqlserver://' + dbHost + ';databaseName=hibernate_orm_test' ], + mssql_spatial_ci : [ + 'db.dialect' : 'org.hibernate.spatial.dialect.sqlserver.SqlServer2012SpatialDialect', + 'jdbc.driver': 'com.microsoft.sqlserver.jdbc.SQLServerDriver', + 'jdbc.user' : 'sa', + 'jdbc.pass' : 'Hibernate_orm_test', + 'jdbc.url' : 'jdbc:sqlserver://' + dbHost + ';databaseName=hibernate_orm_test' + ], informix : [ 'db.dialect' : 'org.hibernate.dialect.InformixDialect', 'jdbc.driver': 'com.informix.jdbc.IfxDriver', From 6d97df670771a98e42988788a5d964695ac28948 Mon Sep 17 00:00:00 2001 From: Karel Maesen Date: Thu, 11 Feb 2021 20:13:09 +0100 Subject: [PATCH 018/644] HHH-14446 Add spatial integration test profiles for DB2 and HANA --- docker_db.sh | 61 +++++++++++++++++++ gradle/databases.gradle | 15 +++++ .../testing/cleaner/DB2DatabaseCleaner.java | 1 + 3 files changed, 77 insertions(+) diff --git a/docker_db.sh b/docker_db.sh index 4b6052951d8c..f58053db8369 100755 --- a/docker_db.sh +++ b/docker_db.sh @@ -38,6 +38,65 @@ db2() { docker exec -t db2 su - orm_test bash -c ". /database/config/orm_test/sqllib/db2profile && /database/config/orm_test/sqllib/bin/db2 'connect to orm_test' && /database/config/orm_test/sqllib/bin/db2 'CREATE USER TEMPORARY TABLESPACE usr_tbsp MANAGED BY AUTOMATIC STORAGE'" } +db2_spatial() { + docker rm -f db2spatial || true + temp_dir=$(mktemp -d) + cat <${temp_dir}/ewkt.sql +create or replace function db2gse.asewkt(geometry db2gse.st_geometry) +returns clob(2G) +specific db2gse.asewkt1 +language sql +deterministic +no external action +reads sql data +return 'srid=' || varchar(db2gse.st_srsid(geometry)) || ';' || db2gse.st_astext(geometry) +; + +-- Create SQL function to create a geometry from EWKT format +create or replace function db2gse.geomfromewkt(instring varchar(32000)) +returns db2gse.st_geometry +specific db2gse.fromewkt1 +language sql +deterministic +no external action +reads sql data +return db2gse.st_geometry( +substr(instring,posstr(instring,';')+1, length(instring) - posstr(instring,';')), +integer(substr(instring,posstr(instring,'=')+1,posstr(instring,';')-(posstr(instring,'=')+1))) +) +; +-- Create a DB2 transform group to return and accept EWKT +CREATE TRANSFORM FOR db2gse.ST_Geometry EWKT ( + FROM SQL WITH FUNCTION db2gse.asewkt(db2gse.ST_Geometry), + TO SQL WITH FUNCTION db2gse.geomfromewkt(varchar(32000)) ) + ; + +-- Redefine the default DB2_PROGRAM to return and accept EWKT instead of WKT +DROP TRANSFORM DB2_PROGRAM FOR db2gse.ST_Geometry; +CREATE TRANSFORM FOR db2gse.ST_Geometry DB2_PROGRAM ( + FROM SQL WITH FUNCTION db2gse.asewkt(db2gse.ST_Geometry), + TO SQL WITH FUNCTION db2gse.geomfromewkt(varchar(32000)) ) +; +EOF + docker run --name db2spatial --privileged -e DB2INSTANCE=orm_test -e DB2INST1_PASSWORD=orm_test -e DBNAME=orm_test -e LICENSE=accept -e AUTOCONFIG=false -e ARCHIVE_LOGS=false -e TO_CREATE_SAMPLEDB=false -e REPODB=false \ + -v ${temp_dir}:/conf \ + -p 50000:50000 -d ibmcom/db2:11.5.5.0 + + # Give the container some time to start + OUTPUT= + while [[ $OUTPUT != *"Setup has completed."* ]]; do + echo "Waiting for DB2 to start..." + sleep 10 + OUTPUT=$(docker logs db2spatial) + done + sleep 10 + echo "Enabling spatial extender" + docker exec -t db2spatial su - orm_test bash -c "/database/config/orm_test/sqllib/db2profile && /database/config/orm_test/sqllib/bin/db2se enable_db orm_test" + echo "Installing required transform group" + docker exec -t db2spatial su - orm_test bash -c "/database/config/orm_test/sqllib/db2profile && /database/config/orm_test/sqllib/bin/db2 'connect to orm_test' && /database/config/orm_test/sqllib/bin/db2 -tvf /conf/ewkt.sql" + +} + mssql() { docker rm -f mssql || true docker run --name mssql -d -p 1433:1433 -e "SA_PASSWORD=Hibernate_orm_test" -e ACCEPT_EULA=Y microsoft/mssql-server-linux:2017-CU13 @@ -166,6 +225,8 @@ if [ -z ${1} ]; then echo -e "\tdb2" echo -e "\tmssql" echo -e "\toracle" + echo -e "\tpostgis_9_6" + echo -e "\tdb2_spatial" else ${1} fi \ No newline at end of file diff --git a/gradle/databases.gradle b/gradle/databases.gradle index e5bd1721f8bb..f570b1e8f06a 100644 --- a/gradle/databases.gradle +++ b/gradle/databases.gradle @@ -170,6 +170,13 @@ ext { 'jdbc.pass' : 'orm_test', 'jdbc.url' : 'jdbc:db2://' + dbHost + ':50000/orm_test' ], + db2_spatial_ci : [ + 'db.dialect' : 'org.hibernate.spatial.dialect.db2.DB2SpatialDialect', + 'jdbc.driver': 'com.ibm.db2.jcc.DB2Driver', + 'jdbc.user' : 'orm_test', + 'jdbc.pass' : 'orm_test', + 'jdbc.url' : 'jdbc:db2://' + dbHost + ':50000/orm_test' + ], hana : [ 'db.dialect' : 'org.hibernate.dialect.HANAColumnStoreDialect', 'jdbc.driver': 'com.sap.db.jdbc.Driver', @@ -202,6 +209,14 @@ ext { // Disable prepared statement caching due to https://help.sap.com/viewer/0eec0d68141541d1b07893a39944924e/2.0.04/en-US/78f2163887814223858e4369d18e2847.html 'jdbc.url' : 'jdbc:sap://' + dbHost + ':39017/?statementCacheSize=0' ], + hana_spatial_ci : [ + 'db.dialect' : 'org.hibernate.spatial.dialect.hana.HANASpatialDialect', + 'jdbc.driver': 'com.sap.db.jdbc.Driver', + 'jdbc.user' : 'SYSTEM', + 'jdbc.pass' : 'H1bernate_test', + // Disable prepared statement caching due to https://help.sap.com/viewer/0eec0d68141541d1b07893a39944924e/2.0.04/en-US/78f2163887814223858e4369d18e2847.html + 'jdbc.url' : 'jdbc:sap://' + dbHost + ':39017/?statementCacheSize=0' + ], cockroachdb : [ 'db.dialect' : 'org.hibernate.dialect.CockroachDB192Dialect', // CockroachDB uses the same pgwire protocol as PostgreSQL, so the driver is the same. diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cleaner/DB2DatabaseCleaner.java b/hibernate-testing/src/main/java/org/hibernate/testing/cleaner/DB2DatabaseCleaner.java index b359cbada173..e33f1169a5fb 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/cleaner/DB2DatabaseCleaner.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/cleaner/DB2DatabaseCleaner.java @@ -28,6 +28,7 @@ public class DB2DatabaseCleaner implements DatabaseCleaner { + "'SYSIBMADM'," + "'SYSPUBLIC'," + "'SYSSTAT'," + + "'DB2GSE'," + "'SYSTOOLS'"; private final List ignoredTables = new ArrayList<>(); From 0d140cc30c15c2e044b96597f816fa5138520102 Mon Sep 17 00:00:00 2001 From: Karel Maesen Date: Fri, 12 Feb 2021 15:11:44 +0100 Subject: [PATCH 019/644] HHH-14446 Add CockroachDB docker setup --- docker_db.sh | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/docker_db.sh b/docker_db.sh index f58053db8369..878e366f6c26 100755 --- a/docker_db.sh +++ b/docker_db.sh @@ -215,6 +215,19 @@ hana() { echo "HANA successfully started" } +cockroachdb() { + docker rm -f cockroach || true + docker run -d --name=cockroach -p 26257:26257 -p 8080:8080 cockroachdb/cockroach:v20.2.4 start-single-node --insecure + OUTPUT= + while [[ $OUTPUT != *"CockroachDB node starting"* ]]; do + echo "Waiting for CockroachDB to start..." + sleep 10 + OUTPUT=$(docker logs cockroach) + done + echo "Cockroachdb successfully started" + +} + if [ -z ${1} ]; then echo "No db name provided" echo "Provide one of:" @@ -227,6 +240,8 @@ if [ -z ${1} ]; then echo -e "\toracle" echo -e "\tpostgis_9_6" echo -e "\tdb2_spatial" + echo -e "\thana" + echo -e "\tcockroachdb" else ${1} fi \ No newline at end of file From 6cead49fec02761cb616fe8ea20134b90115f8b5 Mon Sep 17 00:00:00 2001 From: Karel Maesen Date: Fri, 12 Feb 2021 15:14:16 +0100 Subject: [PATCH 020/644] HHH-14446 Add PostgresqlDatabaseCleaner checks Since the PostgreSQL JDBC driver is also used for CockroachDB, we need to test explicitly if the database is indeed PostgreSQL. --- .../cleaner/PostgreSQLDatabaseCleaner.java | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cleaner/PostgreSQLDatabaseCleaner.java b/hibernate-testing/src/main/java/org/hibernate/testing/cleaner/PostgreSQLDatabaseCleaner.java index 567b05f45601..d7d758527a31 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/cleaner/PostgreSQLDatabaseCleaner.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/cleaner/PostgreSQLDatabaseCleaner.java @@ -31,7 +31,8 @@ public class PostgreSQLDatabaseCleaner implements DatabaseCleaner { @Override public boolean isApplicable(Connection connection) { try { - return connection.getMetaData().getDatabaseProductName().startsWith( "PostgreSQL" ); + return connection.getMetaData().getDatabaseProductName().startsWith( "PostgreSQL" ) + && isPostgresql( connection ); } catch (SQLException e) { throw new RuntimeException( "Could not resolve the database metadata!", e ); @@ -211,4 +212,19 @@ private void clearData0(Connection connection, String schemaName, Function Date: Fri, 12 Feb 2021 15:24:47 +0100 Subject: [PATCH 021/644] HHH-14446 Switching to the postgis provided docker --- docker_db.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docker_db.sh b/docker_db.sh index 878e366f6c26..d853d283b54f 100755 --- a/docker_db.sh +++ b/docker_db.sh @@ -20,9 +20,9 @@ postgresql_9_5() { docker run --name postgres -e POSTGRES_USER=hibernate_orm_test -e POSTGRES_PASSWORD=hibernate_orm_test -e POSTGRES_DB=hibernate_orm_test -p5432:5432 -d postgres:9.5 } -postgis_9_6(){ +postgis(){ docker rm -f postgis || true - docker run --name postgis -e POSTGRES_USER=hibernate_orm_test -e POSTGRES_PASSWORD=hibernate_orm_test -e POSTGRES_DB=hibernate_orm_test -p5432:5432 -d mdillon/postgis:9.6 + docker run --name postgis -e POSTGRES_USER=hibernate_orm_test -e POSTGRES_PASSWORD=hibernate_orm_test -e POSTGRES_DB=hibernate_orm_test -p5432:5432 -d postgis/postgis } db2() { @@ -238,7 +238,7 @@ if [ -z ${1} ]; then echo -e "\tdb2" echo -e "\tmssql" echo -e "\toracle" - echo -e "\tpostgis_9_6" + echo -e "\tpostgis" echo -e "\tdb2_spatial" echo -e "\thana" echo -e "\tcockroachdb" From 42ca47dc4e24ca7e417526a66f25fd88cc4627e9 Mon Sep 17 00:00:00 2001 From: Karel Maesen Date: Fri, 12 Feb 2021 15:37:15 +0100 Subject: [PATCH 022/644] HHH-14446 Fix a tag for Postgis docker image --- docker_db.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker_db.sh b/docker_db.sh index d853d283b54f..770872709073 100755 --- a/docker_db.sh +++ b/docker_db.sh @@ -22,7 +22,7 @@ postgresql_9_5() { postgis(){ docker rm -f postgis || true - docker run --name postgis -e POSTGRES_USER=hibernate_orm_test -e POSTGRES_PASSWORD=hibernate_orm_test -e POSTGRES_DB=hibernate_orm_test -p5432:5432 -d postgis/postgis + docker run --name postgis -e POSTGRES_USER=hibernate_orm_test -e POSTGRES_PASSWORD=hibernate_orm_test -e POSTGRES_DB=hibernate_orm_test -p5432:5432 -d postgis/postgis:11-2.5 } db2() { From 0b951ef803bc697c7f89a9ec187cb26cff904f32 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Mon, 15 Feb 2021 11:08:12 +0100 Subject: [PATCH 023/644] Fix ulimit when starting Oracle Express MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit See https://stackoverflow.com/questions/62574379/su-permission-denied-despite-being-root-in-oracle-container Signed-off-by: Yoann Rodière --- docker_db.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker_db.sh b/docker_db.sh index 770872709073..a496ea5ca6a3 100755 --- a/docker_db.sh +++ b/docker_db.sh @@ -122,7 +122,7 @@ oracle() { docker rm -f oracle || true # We need to use the defaults # SYSTEM/Oracle18 - docker run --shm-size=1536m --name oracle -d -p 1521:1521 quillbuilduser/oracle-18-xe + docker run --shm-size=1536m --name oracle -d -p 1521:1521 --ulimit nofile=1048576:1048576 quillbuilduser/oracle-18-xe until [ "`docker inspect -f {{.State.Health.Status}} oracle`" == "healthy" ]; do echo "Waiting for Oracle to start..." From 91a68c6746deb060745c24d3f9c11af29c6dae29 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Tue, 16 Feb 2021 15:11:43 +0100 Subject: [PATCH 024/644] HHH-14460 Validate setter exists for persistent property also with mixed access strategy --- .../internal/PropertyAccessMixedImpl.java | 4 +- .../MissingSetterWithEnhancementTest.java | 92 +++++++++++++++++++ 2 files changed, 94 insertions(+), 2 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/proxy/MissingSetterWithEnhancementTest.java diff --git a/hibernate-core/src/main/java/org/hibernate/property/access/internal/PropertyAccessMixedImpl.java b/hibernate-core/src/main/java/org/hibernate/property/access/internal/PropertyAccessMixedImpl.java index 594930b855b5..23077d7b82f8 100644 --- a/hibernate-core/src/main/java/org/hibernate/property/access/internal/PropertyAccessMixedImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/property/access/internal/PropertyAccessMixedImpl.java @@ -25,7 +25,7 @@ import org.hibernate.property.access.spi.SetterMethodImpl; import static org.hibernate.internal.util.ReflectHelper.getterMethodOrNull; -import static org.hibernate.internal.util.ReflectHelper.setterMethodOrNull; +import static org.hibernate.internal.util.ReflectHelper.findSetterMethod; /** * A PropertyAccess based on mix of getter/setter method and/or field. @@ -65,7 +65,7 @@ public PropertyAccessMixedImpl( "Could not locate getter for property named [" + containerJavaType.getName() + "#" + propertyName + "]" ); } - Method setterMethod = setterMethodOrNull( containerJavaType, propertyName, getterMethod.getReturnType() ); + Method setterMethod = findSetterMethod( containerJavaType, propertyName, getterMethod.getReturnType() ); this.getter = propertyGetter( containerJavaType, propertyName, getterMethod ); this.setter = propertySetter( containerJavaType, propertyName, setterMethod ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/proxy/MissingSetterWithEnhancementTest.java b/hibernate-core/src/test/java/org/hibernate/test/proxy/MissingSetterWithEnhancementTest.java new file mode 100644 index 000000000000..4cb59b1ad873 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/proxy/MissingSetterWithEnhancementTest.java @@ -0,0 +1,92 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.proxy; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; + +import org.hibernate.MappingException; +import org.hibernate.SessionFactory; +import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.service.ServiceRegistry; + +import org.hibernate.testing.ServiceRegistryBuilder; +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +/** + * + * @author Christian Beikov + */ +@TestForIssue(jiraKey = "HHH-14460") +@RunWith( BytecodeEnhancerRunner.class ) +public class MissingSetterWithEnhancementTest { + private ServiceRegistry serviceRegistry; + + @Before + public void setUp() { + final BootstrapServiceRegistryBuilder builder = new BootstrapServiceRegistryBuilder(); + builder.applyClassLoader( getClass().getClassLoader() ); + serviceRegistry = new StandardServiceRegistryBuilder( builder.build() ) + .applySettings( Environment.getProperties() ) + .build(); + } + + @After + public void tearDown() { + if ( serviceRegistry != null ) { + ServiceRegistryBuilder.destroy( serviceRegistry ); + } + } + + @Test + public void testEnhancedClassMissesSetterForProperty() { + Configuration cfg = new Configuration(); + cfg.addAnnotatedClass( EntityWithMissingSetter.class ); + try (SessionFactory sf = cfg.buildSessionFactory( serviceRegistry )) { + fail( "Setter is missing for `name`. SessionFactory creation should fail." ); + } + catch (MappingException e) { + assertEquals( + "Could not locate setter method for property [" + EntityWithMissingSetter.class.getName() + "#name]", + e.getCause().getCause().getCause().getMessage() + ); + } + } + + @Entity + public static class EntityWithMissingSetter { + private Long id; + @Column + private int someInt; + + @Id + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return null; + } + + } +} From db54fe44dba33389c73ea42bc10c938e0649a028 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Wed, 10 Feb 2021 13:44:38 -0600 Subject: [PATCH 025/644] HHH-13658 : Make LazyToOne optional HHH-13134 : JOIN FETCH does not work properly with enhanced entities --- ...tecodeLogger.java => BytecodeLogging.java} | 7 +- .../BytecodeInterceptorLogging.java | 43 +++ ...EnhancementAsProxyLazinessInterceptor.java | 6 +- .../spi/interceptor/EnhancementHelper.java | 120 ++++++-- .../LazyAttributeLoadingInterceptor.java | 2 +- .../interceptor/LazyAttributesMetadata.java | 11 +- .../org/hibernate/cfg/AnnotationBinder.java | 3 +- .../org/hibernate/internal/SessionImpl.java | 43 ++- .../java/org/hibernate/mapping/ToOne.java | 13 + .../entity/AbstractEntityPersister.java | 15 +- .../org/hibernate/tuple/PropertyFactory.java | 11 +- .../BytecodeEnhancementMetadataPojoImpl.java | 6 +- .../tuple/entity/EntityMetamodel.java | 18 +- .../orm/test/mapping/lazytoone/Flight.java | 2 +- .../lazytoone/InstrumentedLazyToOneTest.java | 94 ------- .../InstrumentedProxyLazyToOneTest.java | 103 ------- .../JoinFetchedManyToOneAllowProxyTests.java | 196 +++++++++++++ .../manytoone/ManyToOneAllowProxyTests.java | 216 ++++++++++++++ .../ManyToOneExplicitOptionTests.java | 215 ++++++++++++++ .../mappedby/InverseToOneAllowProxyTests.java | 227 +++++++++++++++ .../InverseToOneExplicitOptionTests.java | 242 ++++++++++++++++ ...oinFetchedInverseToOneAllowProxyTests.java | 225 +++++++++++++++ .../JoinFetchedOneToOneAllowProxyTests.java | 197 +++++++++++++ .../onetoone/OneToOneAllowProxyTests.java | 216 ++++++++++++++ .../onetoone/OneToOneExplicitOptionTests.java | 218 +++++++++++++++ .../test/mapping/lazytoone/package-info.java | 12 + .../JoinFetchedPolymorphicToOneTests.java | 236 ++++++++++++++++ .../PolymorphicToOneExplicitOptionTests.java | 264 ++++++++++++++++++ .../PolymorphicToOneImplicitOptionTests.java | 235 ++++++++++++++++ .../cascade/CascadeDeleteManyToOneTest.java | 124 +++----- .../cascade/CascadeOnUninitializedTest.java | 105 ++++--- .../lazy/BidirectionalLazyTest.java | 139 +++++---- ...turalIdInUninitializedAssociationTest.java | 44 +-- .../UninitializedAssociationsInCacheTest.java | 116 ++++---- .../group/BidirectionalLazyGroupsTest.java | 35 +-- .../enhancement/lazy/group/LazyGroupTest.java | 249 +++++++++-------- ...anyToOneNonUpdatableNonInsertableTest.java | 12 +- ...OneToOneNonUpdatableNonInsertableTest.java | 1 + .../notfound/LazyNotFoundOneToOneTest.java | 25 +- .../lazy/proxy/FetchGraphTest.java | 1 - .../proxy/LazyGroupWithInheritanceTest.java | 37 ++- .../test/legacy/CustomPersister.java | 2 +- .../testing/jdbc/SQLStatementInterceptor.java | 20 ++ 43 files changed, 3435 insertions(+), 671 deletions(-) rename hibernate-core/src/main/java/org/hibernate/bytecode/{BytecodeLogger.java => BytecodeLogging.java} (81%) create mode 100644 hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/BytecodeInterceptorLogging.java delete mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/InstrumentedLazyToOneTest.java delete mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/InstrumentedProxyLazyToOneTest.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/manytoone/JoinFetchedManyToOneAllowProxyTests.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/manytoone/ManyToOneAllowProxyTests.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/manytoone/ManyToOneExplicitOptionTests.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/mappedby/InverseToOneAllowProxyTests.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/mappedby/InverseToOneExplicitOptionTests.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/mappedby/JoinFetchedInverseToOneAllowProxyTests.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/onetoone/JoinFetchedOneToOneAllowProxyTests.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/onetoone/OneToOneAllowProxyTests.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/onetoone/OneToOneExplicitOptionTests.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/package-info.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/polymorphic/JoinFetchedPolymorphicToOneTests.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/polymorphic/PolymorphicToOneExplicitOptionTests.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/polymorphic/PolymorphicToOneImplicitOptionTests.java diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/BytecodeLogger.java b/hibernate-core/src/main/java/org/hibernate/bytecode/BytecodeLogging.java similarity index 81% rename from hibernate-core/src/main/java/org/hibernate/bytecode/BytecodeLogger.java rename to hibernate-core/src/main/java/org/hibernate/bytecode/BytecodeLogging.java index 203d7d2929bf..8fddd862bfaf 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/BytecodeLogger.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/BytecodeLogging.java @@ -6,17 +6,20 @@ */ package org.hibernate.bytecode; -import org.jboss.logging.BasicLogger; import org.jboss.logging.Logger; /** * @author Steve Ebersole */ -public interface BytecodeLogger extends BasicLogger { +public interface BytecodeLogging { String NAME = "org.hibernate.orm.bytecode"; Logger LOGGER = Logger.getLogger( NAME ); + static String subLoggerName(String subName) { + return NAME + "." + subName; + } + boolean TRACE_ENABLED = LOGGER.isTraceEnabled(); boolean DEBUG_ENABLED = LOGGER.isDebugEnabled(); } diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/BytecodeInterceptorLogging.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/BytecodeInterceptorLogging.java new file mode 100644 index 000000000000..4ae37a10453a --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/BytecodeInterceptorLogging.java @@ -0,0 +1,43 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.bytecode.enhance.spi.interceptor; + +import org.hibernate.bytecode.BytecodeLogging; + +import org.jboss.logging.BasicLogger; +import org.jboss.logging.Logger; +import org.jboss.logging.annotations.LogMessage; +import org.jboss.logging.annotations.Message; +import org.jboss.logging.annotations.MessageLogger; +import org.jboss.logging.annotations.ValidIdRange; + +import static org.jboss.logging.Logger.Level.WARN; + +/** + * Logging related to bytecode enhancement interceptors + */ +@MessageLogger(projectCode = "HHH") +@ValidIdRange(min = 90005901, max = 90006000) +public interface BytecodeInterceptorLogging extends BasicLogger { + String SUB_NAME = "interceptor"; + String NAME = BytecodeLogging.subLoggerName(SUB_NAME); + + Logger LOGGER = Logger.getLogger(NAME); + BytecodeInterceptorLogging MESSAGE_LOGGER = Logger.getMessageLogger(BytecodeInterceptorLogging.class, NAME); + + boolean TRACE_ENABLED = LOGGER.isTraceEnabled(); + boolean DEBUG_ENABLED = LOGGER.isDebugEnabled(); + + @LogMessage(level = WARN) + @Message( + id = 90005901, + value = "`%s#%s` was mapped with explicit lazy-group (`%s`). Hibernate will ignore the lazy-group - this is generally " + + "not a good idea for to-one associations as it would lead to 2 separate SQL selects to initialize the association. " + + "This is expected to be improved in future versions of Hibernate" + ) + void lazyGroupIgnoredForToOne(String ownerName, String attributeName, String requestedLazyGroup); +} diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/EnhancementAsProxyLazinessInterceptor.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/EnhancementAsProxyLazinessInterceptor.java index 0e88ce052372..e5a65e356579 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/EnhancementAsProxyLazinessInterceptor.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/EnhancementAsProxyLazinessInterceptor.java @@ -13,7 +13,7 @@ import org.hibernate.EntityMode; import org.hibernate.HibernateException; import org.hibernate.LockMode; -import org.hibernate.bytecode.BytecodeLogger; +import org.hibernate.bytecode.BytecodeLogging; import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer; import org.hibernate.engine.spi.EntityKey; import org.hibernate.engine.spi.SelfDirtinessTracker; @@ -170,7 +170,7 @@ private Object extractIdValue(Object target, String attributeName) { } public Object forceInitialize(Object target, String attributeName) { - BytecodeLogger.LOGGER.tracef( + BytecodeLogging.LOGGER.tracef( "EnhancementAsProxyLazinessInterceptor#forceInitialize : %s#%s -> %s )", entityKey.getEntityName(), entityKey.getIdentifier(), @@ -186,7 +186,7 @@ public Object forceInitialize(Object target, String attributeName) { } public Object forceInitialize(Object target, String attributeName, SharedSessionContractImplementor session, boolean isTemporarySession) { - BytecodeLogger.LOGGER.tracef( + BytecodeLogging.LOGGER.tracef( "EnhancementAsProxyLazinessInterceptor#forceInitialize : %s#%s -> %s )", entityKey.getEntityName(), entityKey.getIdentifier(), diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/EnhancementHelper.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/EnhancementHelper.java index d7ebc605e872..6ab3f00330e1 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/EnhancementHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/EnhancementHelper.java @@ -11,12 +11,11 @@ import org.hibernate.FlushMode; import org.hibernate.LazyInitializationException; -import org.hibernate.bytecode.BytecodeLogger; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.internal.SessionFactoryRegistry; import org.hibernate.mapping.Collection; -import org.hibernate.mapping.OneToOne; +import org.hibernate.mapping.ManyToOne; import org.hibernate.mapping.Property; import org.hibernate.mapping.ToOne; import org.hibernate.mapping.Value; @@ -25,19 +24,26 @@ * @author Steve Ebersole */ public class EnhancementHelper { + + @FunctionalInterface + public interface InheritanceChecker { + boolean hasSubclasses(String entityName); + } + /** * Should the given property be included in the owner's base fetch group? */ public static boolean includeInBaseFetchGroup( Property bootMapping, boolean isEnhanced, + InheritanceChecker inheritanceChecker, boolean collectionsInDefaultFetchGroupEnabled) { final Value value = bootMapping.getValue(); if ( ! isEnhanced ) { if ( value instanceof ToOne ) { if ( ( (ToOne) value ).isUnwrapProxy() ) { - BytecodeLogger.LOGGER.debugf( + BytecodeInterceptorLogging.MESSAGE_LOGGER.debugf( "To-one property `%s#%s` was mapped with LAZY + NO_PROXY but the class was not enhanced", bootMapping.getPersistentClass().getEntityName(), bootMapping.getName() @@ -47,27 +53,89 @@ public static boolean includeInBaseFetchGroup( return true; } + // if we get here, we know the property owner is enhanced for laziness + // + // NOTE : we make the (potentially untrue) assumption here that + // if the owner is enhanced, then all classes are enhanced.. + if ( value instanceof ToOne ) { final ToOne toOne = (ToOne) value; - if ( toOne.isLazy() ) { - if ( toOne.isUnwrapProxy() ) { - if ( toOne instanceof OneToOne ) { - return false; - } - // include it in the base fetch group so long as the config allows - // using the FK to create an "enhancement proxy" - //return allowEnhancementAsProxy; - // ^^ previously we had to explicitly enable use of enhanced proxies. - // for the moment just return `true` assuming we can. - // - // there are cases where this block overall misses quite a few cases - // where it returns the least optimal value. This is true even outside - // this enhanced-proxy point - // - // those will all be addressed in the commits for HHH-13658 - return true; + + if ( ! toOne.isLazy() ) { + // its not lazy... select it + return true; + } + + // it is lazy. see if we should select the FK + + if ( bootMapping.getLazyGroup() != null ) { + // a non-base fetch group was explicitly specified + // + // really this should indicate to not select it as part of the base group. + // however, at the time being that leads to inefficient SQL - so for now + // we simply log a message that we are ignoring the `@LazyGroup` for to-ones + + BytecodeInterceptorLogging.MESSAGE_LOGGER.lazyGroupIgnoredForToOne( + bootMapping.getPersistentClass().getEntityName(), + bootMapping.getName(), + bootMapping.getLazyGroup() + ); + + // at a later time - for example 6.0 when we can implement the join solution + // todo (6.0) : implement this + // return false; + + // for now, fall through + } + + if ( ! toOne.isReferenceToPrimaryKey() ) { + // we do not have a reference to the associated primary-key + return false; + } + + if ( toOne.getColumnSpan() == 0 ) { + // generally this would indicate a "shared PK" on-to-one and there + // is no column for the association on the owner table - do not add + // the association to the base group (which would force an immediate + // select from the association table effectively making this + // association non-lazy) + return false; + } + + final boolean unwrapExplicitlyRequested = toOne.isUnwrapProxy() && !toOne.isUnwrapProxyImplicit(); + + if ( inheritanceChecker.hasSubclasses( toOne.getReferencedEntityName() ) ) { + // the associated type has subclasses - we cannot use the enhanced proxy and will generate a HibernateProxy + if ( unwrapExplicitlyRequested ) { + // NO_PROXY was explicitly requested + BytecodeInterceptorLogging.LOGGER.debugf( + "`%s#%s` was mapped with LAZY and explicit NO_PROXY but the associated entity (`%s`) has subclasses", + bootMapping.getPersistentClass().getEntityName(), + bootMapping.getName(), + toOne.getReferencedEntityName() + ); } + // however, select the fk to create the enhanced-proxy + return true; + } + + if ( toOne instanceof ManyToOne && ( (ManyToOne) toOne ).isIgnoreNotFound() ) { + if ( unwrapExplicitlyRequested ) { + BytecodeInterceptorLogging.LOGGER.debugf( + "%s#%s specified NotFoundAction.IGNORE & LazyToOneOption.NO_PROXY; " + + "skipping FK selection to more efficiently handle NotFoundAction.IGNORE", + bootMapping.getPersistentClass().getEntityName(), + bootMapping.getName() + ); + return false; + } + } + if ( unwrapExplicitlyRequested ) { + // NO_PROXY was explicitly requested... + // - we return true here based on the assumption that `isEnhanced` + // is true for all classes - select the FK so we can build the enhanced-proxy + return true; } return true; @@ -118,7 +186,7 @@ else if ( !session.isConnected() ) { // If we are using a temporary Session, begin a transaction if necessary if ( isTempSession ) { - BytecodeLogger.LOGGER.debug( "Enhancement interception Helper#performWork started temporary Session" ); + BytecodeInterceptorLogging.LOGGER.debug( "Enhancement interception Helper#performWork started temporary Session" ); isJta = session.getTransactionCoordinator().getTransactionCoordinatorBuilder().isJta(); @@ -128,7 +196,7 @@ else if ( !session.isConnected() ) { // be created even if a current session and transaction are // open (ex: session.clear() was used). We must prevent // multiple transactions. - BytecodeLogger.LOGGER.debug( "Enhancement interception Helper#performWork starting transaction on temporary Session" ); + BytecodeInterceptorLogging.LOGGER.debug( "Enhancement interception Helper#performWork starting transaction on temporary Session" ); session.beginTransaction(); } } @@ -142,12 +210,12 @@ else if ( !session.isConnected() ) { try { // Commit the JDBC transaction if we started one. if ( !isJta ) { - BytecodeLogger.LOGGER.debug( "Enhancement interception Helper#performWork committing transaction on temporary Session" ); + BytecodeInterceptorLogging.LOGGER.debug( "Enhancement interception Helper#performWork committing transaction on temporary Session" ); session.getTransaction().commit(); } } catch (Exception e) { - BytecodeLogger.LOGGER.warn( + BytecodeInterceptorLogging.LOGGER.warn( "Unable to commit JDBC transaction on temporary session used to load lazy " + "collection associated to no session" ); @@ -155,11 +223,11 @@ else if ( !session.isConnected() ) { // Close the just opened temp Session try { - BytecodeLogger.LOGGER.debug( "Enhancement interception Helper#performWork closing temporary Session" ); + BytecodeInterceptorLogging.LOGGER.debug( "Enhancement interception Helper#performWork closing temporary Session" ); session.close(); } catch (Exception e) { - BytecodeLogger.LOGGER.warn( "Unable to close temporary session used to load lazy collection associated to no session" ); + BytecodeInterceptorLogging.LOGGER.warn( "Unable to close temporary session used to load lazy collection associated to no session" ); } } } diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/LazyAttributeLoadingInterceptor.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/LazyAttributeLoadingInterceptor.java index 74d58a7d96bf..7880edbb578f 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/LazyAttributeLoadingInterceptor.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/LazyAttributeLoadingInterceptor.java @@ -128,7 +128,7 @@ private boolean isInitializedLazyField(String fieldName) { } public boolean hasAnyUninitializedAttributes() { - if ( lazyFields == null ) { + if ( lazyFields == null || lazyFields.isEmpty() ) { return false; } diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/LazyAttributesMetadata.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/LazyAttributesMetadata.java index a7edad7aea7f..00d7dc41f5bb 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/LazyAttributesMetadata.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/LazyAttributesMetadata.java @@ -17,8 +17,10 @@ import java.util.Map; import java.util.Set; +import org.hibernate.boot.spi.MetadataImplementor; import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.Property; +import org.hibernate.persister.spi.PersisterCreationContext; /** * Information about all of the bytecode lazy attributes for an entity @@ -34,7 +36,8 @@ public class LazyAttributesMetadata implements Serializable { public static LazyAttributesMetadata from( PersistentClass mappedEntity, boolean isEnhanced, - boolean collectionsInDefaultFetchGroupEnabled) { + boolean collectionsInDefaultFetchGroupEnabled, + PersisterCreationContext creationContext) { final Map lazyAttributeDescriptorMap = new LinkedHashMap<>(); final Map> fetchGroupToAttributesMap = new HashMap<>(); @@ -47,6 +50,12 @@ public static LazyAttributesMetadata from( final boolean lazy = ! EnhancementHelper.includeInBaseFetchGroup( property, isEnhanced, + (entityName) -> { + final MetadataImplementor metadata = creationContext.getMetadata(); + final PersistentClass entityBinding = metadata.getEntityBinding( entityName ); + assert entityBinding != null; + return entityBinding.hasSubclasses(); + }, collectionsInDefaultFetchGroupEnabled ); if ( lazy ) { diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java b/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java index 762678ebcc07..46df157133c8 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java @@ -3163,7 +3163,8 @@ else if ( oneToOne != null ) { } else { toOne.setLazy( fetchType == FetchType.LAZY ); - toOne.setUnwrapProxy( false ); + toOne.setUnwrapProxy( fetchType != FetchType.LAZY ); + toOne.setUnwrapProxyImplicit( true ); } if ( fetch != null ) { if ( fetch.value() == org.hibernate.annotations.FetchMode.JOIN ) { diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java index a81bd3fc382c..a2af475246cc 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java @@ -69,6 +69,10 @@ import org.hibernate.TypeMismatchException; import org.hibernate.UnknownProfileException; import org.hibernate.UnresolvableObjectException; +import org.hibernate.bytecode.enhance.spi.interceptor.BytecodeLazyAttributeInterceptor; +import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor; +import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor; +import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata; import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.criterion.NaturalIdentifier; import org.hibernate.engine.internal.StatefulPersistenceContext; @@ -87,6 +91,8 @@ import org.hibernate.engine.spi.LoadQueryInfluencers; import org.hibernate.engine.spi.NamedQueryDefinition; import org.hibernate.engine.spi.PersistenceContext; +import org.hibernate.engine.spi.PersistentAttributeInterceptable; +import org.hibernate.engine.spi.PersistentAttributeInterceptor; import org.hibernate.engine.spi.QueryParameters; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionImplementor; @@ -2776,7 +2782,11 @@ protected final T doLoad(Serializable id) { if ( this.lockOptions != null ) { LoadEvent event = new LoadEvent( id, entityPersister.getEntityName(), lockOptions, SessionImpl.this, getReadOnlyFromLoadQueryInfluencers() ); fireLoad( event, LoadEventListener.GET ); - return (T) event.getResult(); + + final Object result = event.getResult(); + initializeIfNecessary( result ); + + return (T) result; } LoadEvent event = new LoadEvent( id, entityPersister.getEntityName(), false, SessionImpl.this, getReadOnlyFromLoadQueryInfluencers() ); @@ -2791,7 +2801,36 @@ protected final T doLoad(Serializable id) { finally { afterOperation( success ); } - return (T) event.getResult(); + + final Object result = event.getResult(); + initializeIfNecessary( result ); + + return (T) result; + } + + private void initializeIfNecessary(Object result) { + if ( result == null ) { + return; + } + + if ( result instanceof HibernateProxy ) { + final HibernateProxy hibernateProxy = (HibernateProxy) result; + final LazyInitializer initializer = hibernateProxy.getHibernateLazyInitializer(); + if ( initializer.isUninitialized() ) { + initializer.initialize(); + } + return; + } + + final BytecodeEnhancementMetadata enhancementMetadata = entityPersister.getEntityMetamodel().getBytecodeEnhancementMetadata(); + if ( ! enhancementMetadata.isEnhancedForLazyLoading() ) { + return; + } + + final BytecodeLazyAttributeInterceptor interceptor = enhancementMetadata.extractLazyInterceptor(result); + if ( interceptor instanceof EnhancementAsProxyLazinessInterceptor ) { + ( (EnhancementAsProxyLazinessInterceptor) interceptor ).forceInitialize( result, null ); + } } } diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/ToOne.java b/hibernate-core/src/main/java/org/hibernate/mapping/ToOne.java index 3c4f62ee10d8..7ef8abac16f9 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/ToOne.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/ToOne.java @@ -29,6 +29,7 @@ public abstract class ToOne extends SimpleValue implements Fetchable { private boolean embedded; private boolean lazy = true; protected boolean unwrapProxy; + protected boolean isUnwrapProxyImplicit; protected boolean referenceToPrimaryKey = true; /** @@ -133,6 +134,18 @@ public void setUnwrapProxy(boolean unwrapProxy) { this.unwrapProxy = unwrapProxy; } + public boolean isUnwrapProxyImplicit() { + return isUnwrapProxyImplicit; + } + + /** + * Related to HHH-13658 - keep track of whether `unwrapProxy` is an implicit value + * for reference later + */ + public void setUnwrapProxyImplicit(boolean unwrapProxyImplicit) { + isUnwrapProxyImplicit = unwrapProxyImplicit; + } + public boolean isReferenceToPrimaryKey() { return referenceToPrimaryKey; } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index 635bfe096e5d..835467781451 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -36,6 +36,7 @@ import org.hibernate.Session; import org.hibernate.StaleObjectStateException; import org.hibernate.StaleStateException; +import org.hibernate.boot.spi.MetadataImplementor; import org.hibernate.boot.spi.SessionFactoryOptions; import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer; import org.hibernate.bytecode.enhance.spi.interceptor.BytecodeLazyAttributeInterceptor; @@ -606,7 +607,7 @@ public AbstractEntityPersister( this.naturalIdRegionAccessStrategy = null; } - this.entityMetamodel = new EntityMetamodel( persistentClass, this, factory ); + this.entityMetamodel = new EntityMetamodel( persistentClass, this, creationContext ); this.entityTuplizer = this.entityMetamodel.getTuplizer(); if ( entityMetamodel.isMutable() ) { @@ -743,6 +744,12 @@ public AbstractEntityPersister( final boolean lazy = ! EnhancementHelper.includeInBaseFetchGroup( prop, entityMetamodel.isInstrumented(), + (entityName) -> { + final MetadataImplementor metadata = creationContext.getMetadata(); + final PersistentClass entityBinding = metadata.getEntityBinding( entityName ); + assert entityBinding != null; + return entityBinding.hasSubclasses(); + }, sessionFactoryOptions.isCollectionsInDefaultFetchGroupEnabled() ); @@ -820,6 +827,12 @@ public AbstractEntityPersister( final boolean lazy = ! EnhancementHelper.includeInBaseFetchGroup( prop, entityMetamodel.isInstrumented(), + (entityName) -> { + final MetadataImplementor metadata = creationContext.getMetadata(); + final PersistentClass entityBinding = metadata.getEntityBinding( entityName ); + assert entityBinding != null; + return entityBinding.hasSubclasses(); + }, sessionFactoryOptions.isCollectionsInDefaultFetchGroupEnabled() ); while ( colIter.hasNext() ) { diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/PropertyFactory.java b/hibernate-core/src/main/java/org/hibernate/tuple/PropertyFactory.java index 0d7b3a166846..48fac277ce67 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/PropertyFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/PropertyFactory.java @@ -10,6 +10,7 @@ import org.hibernate.EntityMode; import org.hibernate.HibernateException; +import org.hibernate.boot.spi.MetadataImplementor; import org.hibernate.boot.spi.SessionFactoryOptions; import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementHelper; import org.hibernate.engine.internal.UnsavedValueFactory; @@ -22,6 +23,7 @@ import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.Property; import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.persister.spi.PersisterCreationContext; import org.hibernate.property.access.spi.Getter; import org.hibernate.property.access.spi.PropertyAccess; import org.hibernate.property.access.spi.PropertyAccessStrategy; @@ -155,7 +157,8 @@ public static NonIdentifierAttribute buildEntityBasedAttribute( SessionFactoryImplementor sessionFactory, int attributeNumber, Property property, - boolean lazyAvailable) { + boolean lazyAvailable, + PersisterCreationContext creationContext) { final Type type = property.getValue().getType(); final NonIdentifierAttributeNature nature = decode( type ); @@ -174,6 +177,12 @@ public static NonIdentifierAttribute buildEntityBasedAttribute( final boolean lazy = ! EnhancementHelper.includeInBaseFetchGroup( property, lazyAvailable, + (entityName) -> { + final MetadataImplementor metadata = creationContext.getMetadata(); + final PersistentClass entityBinding = metadata.getEntityBinding( entityName ); + assert entityBinding != null; + return entityBinding.hasSubclasses(); + }, sessionFactoryOptions.isCollectionsInDefaultFetchGroupEnabled() ); diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/BytecodeEnhancementMetadataPojoImpl.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/BytecodeEnhancementMetadataPojoImpl.java index 19720a10a3de..8f4eec445da5 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/entity/BytecodeEnhancementMetadataPojoImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/entity/BytecodeEnhancementMetadataPojoImpl.java @@ -25,6 +25,7 @@ import org.hibernate.engine.spi.Status; import org.hibernate.mapping.PersistentClass; import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.persister.spi.PersisterCreationContext; import org.hibernate.type.CompositeType; /** @@ -38,11 +39,12 @@ public static BytecodeEnhancementMetadata from( PersistentClass persistentClass, Set identifierAttributeNames, CompositeType nonAggregatedCidMapper, - boolean collectionsInDefaultFetchGroupEnabled) { + boolean collectionsInDefaultFetchGroupEnabled, + PersisterCreationContext creationContext) { final Class mappedClass = persistentClass.getMappedClass(); final boolean enhancedForLazyLoading = PersistentAttributeInterceptable.class.isAssignableFrom( mappedClass ); final LazyAttributesMetadata lazyAttributesMetadata = enhancedForLazyLoading - ? LazyAttributesMetadata.from( persistentClass, true, collectionsInDefaultFetchGroupEnabled ) + ? LazyAttributesMetadata.from( persistentClass, true, collectionsInDefaultFetchGroupEnabled, creationContext ) : LazyAttributesMetadata.nonEnhanced( persistentClass.getEntityName() ); return new BytecodeEnhancementMetadataPojoImpl( diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java index 62afe53c8ff3..6075fb1ae197 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java @@ -20,6 +20,7 @@ import org.hibernate.EntityMode; import org.hibernate.HibernateException; import org.hibernate.MappingException; +import org.hibernate.boot.spi.MetadataImplementor; import org.hibernate.boot.spi.SessionFactoryOptions; import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementHelper; import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata; @@ -36,6 +37,7 @@ import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.Property; import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.persister.spi.PersisterCreationContext; import org.hibernate.tuple.GenerationTiming; import org.hibernate.tuple.IdentifierProperty; import org.hibernate.tuple.InDatabaseValueGenerationStrategy; @@ -131,8 +133,8 @@ public class EntityMetamodel implements Serializable { public EntityMetamodel( PersistentClass persistentClass, EntityPersister persister, - SessionFactoryImplementor sessionFactory) { - this.sessionFactory = sessionFactory; + PersisterCreationContext creationContext) { + this.sessionFactory = creationContext.getSessionFactory(); name = persistentClass.getEntityName(); rootName = persistentClass.getRootClass().getEntityName(); @@ -169,7 +171,8 @@ public EntityMetamodel( persistentClass, idAttributeNames, nonAggregatedCidMapper, - sessionFactoryOptions.isCollectionsInDefaultFetchGroupEnabled() + sessionFactoryOptions.isCollectionsInDefaultFetchGroupEnabled(), + creationContext ); } else { @@ -232,7 +235,8 @@ public EntityMetamodel( sessionFactory, i, prop, - bytecodeEnhancementMetadata.isEnhancedForLazyLoading() + bytecodeEnhancementMetadata.isEnhancedForLazyLoading(), + creationContext ); } @@ -251,6 +255,12 @@ public EntityMetamodel( boolean lazy = ! EnhancementHelper.includeInBaseFetchGroup( prop, bytecodeEnhancementMetadata.isEnhancedForLazyLoading(), + (entityName) -> { + final MetadataImplementor metadata = creationContext.getMetadata(); + final PersistentClass entityBinding = metadata.getEntityBinding( entityName ); + assert entityBinding != null; + return entityBinding.hasSubclasses(); + }, sessionFactoryOptions.isCollectionsInDefaultFetchGroupEnabled() ); diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/Flight.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/Flight.java index 960a7c284fe9..eff5143a04fe 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/Flight.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/Flight.java @@ -25,7 +25,7 @@ public class Flight { @Id private Integer id; - @Column(name = "flight_number") + @Column( name = "flight_number" ) private String number; @ManyToOne( fetch = LAZY ) diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/InstrumentedLazyToOneTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/InstrumentedLazyToOneTest.java deleted file mode 100644 index 7f309a447418..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/InstrumentedLazyToOneTest.java +++ /dev/null @@ -1,94 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.orm.test.mapping.lazytoone; - -import org.hibernate.Hibernate; -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import org.hibernate.cfg.AvailableSettings; -import org.hibernate.stat.spi.StatisticsImplementor; - -import org.hibernate.testing.FailureExpected; -import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; -import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; -import org.junit.Test; -import org.junit.runner.RunWith; - -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.MatcherAssert.assertThat; - -/** - * Same as {@link LazyToOneTest} except here we have bytecode-enhanced entities - * via {@link BytecodeEnhancerRunner} - */ -@RunWith( BytecodeEnhancerRunner.class ) -public class InstrumentedLazyToOneTest extends BaseNonConfigCoreFunctionalTestCase { - - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] { Airport.class, Flight.class }; - } - - @Override - protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { - ssrb.applySetting( AvailableSettings.GENERATE_STATISTICS, "true" ); - } - - @Override - protected void prepareTest() throws Exception { - inTransaction( - (session) -> { - final Airport austin = new Airport( 1, "AUS" ); - final Airport baltimore = new Airport( 2, "BWI" ); - - final Flight flight1 = new Flight( 1, "ABC-123", austin, baltimore ); - final Flight flight2 = new Flight( 2, "ABC-987", baltimore, austin ); - - session.persist( austin ); - session.persist( baltimore ); - - session.persist( flight1 ); - session.persist( flight2 ); - } - ); - } - - @Override - protected void cleanupTestData() throws Exception { - inTransaction( - (session) -> { - session.createQuery( "delete Flight" ).executeUpdate(); - session.createQuery( "delete Airport" ).executeUpdate(); - } - ); - } - - @Test - @FailureExpected( jiraKey = "HHH-13658", message = "Flight#origination is not treated as lazy. Not sure why exactly" ) - public void testEnhancedButProxyNotAllowed() { - final StatisticsImplementor statistics = sessionFactory().getStatistics(); - statistics.clear(); - - inTransaction( - (session) -> { - final Flight flight1 = session.byId( Flight.class ).load( 1 ); - - // unlike the other 2 tests we should get 2 db queries here - assertThat( statistics.getPrepareStatementCount(), is( 2L ) ); - - assertThat( Hibernate.isInitialized( flight1 ), is( true ) ); - - assertThat( Hibernate.isPropertyInitialized( flight1, "origination" ), is( true ) ); - // this should be a non-enhanced proxy - assertThat( Hibernate.isInitialized( flight1.getOrigination() ), is( false ) ); - - assertThat( Hibernate.isPropertyInitialized( flight1, "destination" ), is( false ) ); - // the NO_PROXY here should trigger an EAGER load - assertThat( Hibernate.isInitialized( flight1.getDestination() ), is( false ) ); - } - ); - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/InstrumentedProxyLazyToOneTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/InstrumentedProxyLazyToOneTest.java deleted file mode 100644 index ff9c9bb20a7d..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/InstrumentedProxyLazyToOneTest.java +++ /dev/null @@ -1,103 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.orm.test.mapping.lazytoone; - -import org.hibernate.Hibernate; -import org.hibernate.boot.registry.StandardServiceRegistryBuilder; -import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor; -import org.hibernate.cfg.AvailableSettings; -import org.hibernate.engine.spi.PersistentAttributeInterceptable; -import org.hibernate.stat.spi.StatisticsImplementor; - -import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; -import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; -import org.junit.Test; -import org.junit.runner.RunWith; - -import static org.hamcrest.CoreMatchers.instanceOf; -import static org.hamcrest.CoreMatchers.is; -import static org.hamcrest.CoreMatchers.notNullValue; -import static org.hamcrest.MatcherAssert.assertThat; - -/** - * Same as {@link InstrumentedLazyToOneTest} except here we enable bytecode-enhanced proxies - */ -@RunWith( BytecodeEnhancerRunner.class ) -public class InstrumentedProxyLazyToOneTest extends BaseNonConfigCoreFunctionalTestCase { - - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] { Airport.class, Flight.class }; - } - - @Override - protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { - ssrb.applySetting( AvailableSettings.GENERATE_STATISTICS, "true" ); - } - - @Override - protected void prepareTest() throws Exception { - inTransaction( - (session) -> { - final Airport austin = new Airport( 1, "AUS" ); - final Airport baltimore = new Airport( 2, "BWI" ); - - final Flight flight1 = new Flight( 1, "ABC-123", austin, baltimore ); - final Flight flight2 = new Flight( 2, "ABC-987", baltimore, austin ); - - session.persist( austin ); - session.persist( baltimore ); - - session.persist( flight1 ); - session.persist( flight2 ); - } - ); - } - - @Override - protected void cleanupTestData() throws Exception { - inTransaction( - (session) -> { - session.createQuery( "delete Flight" ).executeUpdate(); - session.createQuery( "delete Airport" ).executeUpdate(); - } - ); - } - - @Test - public void testEnhancedWithProxy() { - final StatisticsImplementor statistics = sessionFactory().getStatistics(); - statistics.clear(); - - inTransaction( - (session) -> { - final Flight flight1 = session.byId( Flight.class ).load( 1 ); - - assertThat( statistics.getPrepareStatementCount(), is( 1L ) ); - - assertThat( Hibernate.isInitialized( flight1 ), is( true ) ); - - assertThat( Hibernate.isPropertyInitialized( flight1, "origination" ), is( true ) ); - assertThat( Hibernate.isInitialized( flight1.getOrigination() ), is( false ) ); - // let's make sure these `Hibernate` calls pass for the right reasons... - assertThat( flight1.getOrigination(), instanceOf( PersistentAttributeInterceptable.class ) ); - final PersistentAttributeInterceptable originationProxy = (PersistentAttributeInterceptable) flight1.getOrigination(); - assertThat( originationProxy.$$_hibernate_getInterceptor(), notNullValue() ); - assertThat( originationProxy.$$_hibernate_getInterceptor(), instanceOf( EnhancementAsProxyLazinessInterceptor.class ) ); - - assertThat( Hibernate.isPropertyInitialized( flight1, "destination" ), is( true ) ); - assertThat( Hibernate.isInitialized( flight1.getDestination() ), is( false ) ); - // let's make sure these `Hibernate` calls pass for the right reasons... - assertThat( flight1.getDestination(), instanceOf( PersistentAttributeInterceptable.class ) ); - final PersistentAttributeInterceptable destinationProxy = (PersistentAttributeInterceptable) flight1.getDestination(); - assertThat( destinationProxy.$$_hibernate_getInterceptor(), notNullValue() ); - assertThat( destinationProxy.$$_hibernate_getInterceptor(), instanceOf( EnhancementAsProxyLazinessInterceptor.class ) ); - } - ); - } - -} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/manytoone/JoinFetchedManyToOneAllowProxyTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/manytoone/JoinFetchedManyToOneAllowProxyTests.java new file mode 100644 index 000000000000..70354ce1c15d --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/manytoone/JoinFetchedManyToOneAllowProxyTests.java @@ -0,0 +1,196 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.orm.test.mapping.lazytoone.manytoone; + +import java.math.BigDecimal; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.ManyToOne; +import javax.persistence.Table; + +import org.hibernate.Hibernate; +import org.hibernate.annotations.Fetch; +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.bytecode.enhance.spi.interceptor.BytecodeLazyAttributeInterceptor; +import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor; +import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.persister.entity.EntityPersister; + +import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; +import org.hibernate.testing.bytecode.enhancement.EnhancementOptions; +import org.hibernate.testing.jdbc.SQLStatementInterceptor; +import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static javax.persistence.FetchType.LAZY; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.sameInstance; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hibernate.annotations.FetchMode.JOIN; + +/** + * Test for lazy uni-directional to-one (with JOIN fetching) when enhanced proxies are allowed + */ +@RunWith( BytecodeEnhancerRunner.class) +@EnhancementOptions( lazyLoading = true ) +public class JoinFetchedManyToOneAllowProxyTests extends BaseNonConfigCoreFunctionalTestCase { + private SQLStatementInterceptor sqlStatementInterceptor; + + @Override + protected void applyMetadataSources(MetadataSources sources) { + super.applyMetadataSources( sources ); + sources.addAnnotatedClass( Customer.class ); + sources.addAnnotatedClass( Order.class ); + } + + @Override + protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { + super.configureStandardServiceRegistryBuilder( ssrb ); + ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, true ); + sqlStatementInterceptor = new SQLStatementInterceptor( ssrb ); + } + + @Test + public void testOwnerIsProxy() { + inTransaction( + (session) -> { + final Customer customer = new Customer( 1, "Acme Brick" ); + session.persist( customer ); + final Order order = new Order( 1, customer, BigDecimal.ONE ); + session.persist( order ); + } + ); + + sqlStatementInterceptor.clear(); + + final EntityPersister orderDescriptor = sessionFactory().getMetamodel().entityPersister( Order.class ); + final BytecodeEnhancementMetadata orderEnhancementMetadata = orderDescriptor.getBytecodeEnhancementMetadata(); + assertThat( orderEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) ); + + final EntityPersister customerDescriptor = sessionFactory().getMetamodel().entityPersister( Customer.class ); + final BytecodeEnhancementMetadata customerEnhancementMetadata = customerDescriptor.getBytecodeEnhancementMetadata(); + assertThat( customerEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) ); + + inTransaction( + (session) -> { + final Order order = session.byId( Order.class ).getReference( 1 ); + + // we should have an uninitialized enhanced proxy - therefore no SQL statements should have been executed + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 0 ) ); + + final BytecodeLazyAttributeInterceptor initialInterceptor = orderEnhancementMetadata.extractLazyInterceptor( order ); + assertThat( initialInterceptor, instanceOf( EnhancementAsProxyLazinessInterceptor.class ) ); + + // access the id - should do nothing with db + order.getId(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 0 ) ); + assertThat( initialInterceptor, sameInstance( orderEnhancementMetadata.extractLazyInterceptor( order ) ) ); + + // this should trigger loading the entity's base state which includes customer. + // and since customer is defined for join fetch we + order.getAmount(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) ); + assertThat( initialInterceptor, not( sameInstance( orderEnhancementMetadata.extractLazyInterceptor( order ) ) ) ); + + // should not trigger a load - Order's base fetch state includes customer + final Customer customer = order.getCustomer(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) ); + + // and since Order#customer is mapped for JOIN fetching, Customer should be fully initialized as well + assertThat( Hibernate.isInitialized( customer ), is( true ) ); + + // just as above, accessing id should trigger no loads + customer.getId(); + customer.getName(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) ); + } + ); + } + + @Entity( name = "Customer" ) + @Table( name = "customer" ) + public static class Customer { + @Id + private Integer id; + private String name; + + public Customer() { + } + + public Customer(Integer id, String name) { + this.id = id; + this.name = name; + } + + public Integer getId() { + return id; + } + + private void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } + + @Entity( name = "Order") + @Table( name = "`order`") + public static class Order { + @Id + private Integer id; + @ManyToOne( fetch = LAZY ) + @Fetch( JOIN ) + //we want it to behave as if... + //@LazyToOne( NO_PROXY ) + private Customer customer; + private BigDecimal amount; + + public Order() { + } + + public Order(Integer id, Customer customer, BigDecimal amount) { + this.id = id; + this.customer = customer; + this.amount = amount; + } + + public Integer getId() { + return id; + } + + private void setId(Integer id) { + this.id = id; + } + + public Customer getCustomer() { + return customer; + } + + public void setCustomer(Customer customer) { + this.customer = customer; + } + + public BigDecimal getAmount() { + return amount; + } + + public void setAmount(BigDecimal amount) { + this.amount = amount; + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/manytoone/ManyToOneAllowProxyTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/manytoone/ManyToOneAllowProxyTests.java new file mode 100644 index 000000000000..085ae6388833 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/manytoone/ManyToOneAllowProxyTests.java @@ -0,0 +1,216 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.orm.test.mapping.lazytoone.manytoone; + +import java.math.BigDecimal; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.ManyToOne; +import javax.persistence.Table; + +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.bytecode.enhance.spi.interceptor.BytecodeLazyAttributeInterceptor; +import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor; +import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor; +import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.persister.entity.EntityPersister; + +import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; +import org.hibernate.testing.bytecode.enhancement.EnhancementOptions; +import org.hibernate.testing.jdbc.SQLStatementInterceptor; +import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static javax.persistence.FetchType.LAZY; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.sameInstance; +import static org.hamcrest.MatcherAssert.assertThat; + +/** + * Test for lazy uni-directional to-one (with SELECT fetching) when enhanced proxies are allowed + */ +@RunWith( BytecodeEnhancerRunner.class) +@EnhancementOptions( lazyLoading = true ) +public class ManyToOneAllowProxyTests extends BaseNonConfigCoreFunctionalTestCase { + private SQLStatementInterceptor sqlStatementInterceptor; + + @Override + protected void applyMetadataSources(MetadataSources sources) { + super.applyMetadataSources( sources ); + sources.addAnnotatedClass( Customer.class ); + sources.addAnnotatedClass( Order.class ); + } + + @Override + protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { + super.configureStandardServiceRegistryBuilder( ssrb ); + ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, true ); + sqlStatementInterceptor = new SQLStatementInterceptor( ssrb ); + } + + @Test + public void testOwnerIsProxy() { + sqlStatementInterceptor.clear(); + + final EntityPersister orderDescriptor = sessionFactory().getMetamodel().entityPersister( Order.class ); + final BytecodeEnhancementMetadata orderEnhancementMetadata = orderDescriptor.getBytecodeEnhancementMetadata(); + assertThat( orderEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) ); + + final EntityPersister customerDescriptor = sessionFactory().getMetamodel().entityPersister( Customer.class ); + final BytecodeEnhancementMetadata customerEnhancementMetadata = customerDescriptor.getBytecodeEnhancementMetadata(); + assertThat( customerEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) ); + + inTransaction( + (session) -> { + final Order order = session.byId( Order.class ).getReference( 1 ); + + // we should have just the uninitialized proxy of the owner - and + // therefore no SQL statements should have been executed + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 0 ) ); + + final BytecodeLazyAttributeInterceptor initialInterceptor = orderEnhancementMetadata.extractLazyInterceptor( order ); + assertThat( initialInterceptor, instanceOf( EnhancementAsProxyLazinessInterceptor.class ) ); + + // access the id - should do nothing with db + order.getId(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 0 ) ); + assertThat( initialInterceptor, sameInstance( orderEnhancementMetadata.extractLazyInterceptor( order ) ) ); + + // this should trigger loading the entity's base state + order.getAmount(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) ); + final BytecodeLazyAttributeInterceptor interceptor = orderEnhancementMetadata.extractLazyInterceptor( order ); + assertThat( initialInterceptor, not( sameInstance( interceptor ) ) ); + assertThat( interceptor, instanceOf( LazyAttributeLoadingInterceptor.class ) ); + final LazyAttributeLoadingInterceptor attrInterceptor = (LazyAttributeLoadingInterceptor) interceptor; + assertThat( attrInterceptor.hasAnyUninitializedAttributes(), is( false ) ); + + // should not trigger a load and the `customer` reference should be an uninitialized enhanced proxy + final Customer customer = order.getCustomer(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) ); + + final BytecodeLazyAttributeInterceptor initialCustomerInterceptor = customerEnhancementMetadata.extractLazyInterceptor( customer ); + assertThat( initialCustomerInterceptor, instanceOf( EnhancementAsProxyLazinessInterceptor.class ) ); + + // just as above, accessing id should trigger no loads + customer.getId(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) ); + assertThat( initialCustomerInterceptor, sameInstance( customerEnhancementMetadata.extractLazyInterceptor( customer ) ) ); + + customer.getName(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 2 ) ); + assertThat( customerEnhancementMetadata.extractLazyInterceptor( customer ), instanceOf( LazyAttributeLoadingInterceptor.class ) ); + } + ); + } + + @Before + public void createTestData() { + inTransaction( + (session) -> { + final Customer customer = new Customer( 1, "Acme Brick" ); + session.persist( customer ); + final Order order = new Order( 1, customer, BigDecimal.ONE ); + session.persist( order ); + } + ); + } + + @After + public void dropTestData() { + inTransaction( + (session) -> { + session.createQuery( "delete Order" ).executeUpdate(); + session.createQuery( "delete Customer" ).executeUpdate(); + } + ); + } + + @Entity( name = "Customer" ) + @Table( name = "customer" ) + public static class Customer { + @Id + private Integer id; + private String name; + + public Customer() { + } + + public Customer(Integer id, String name) { + this.id = id; + this.name = name; + } + + public Integer getId() { + return id; + } + + private void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } + + @Entity( name = "Order") + @Table( name = "`order`") + public static class Order { + @Id + private Integer id; + @ManyToOne( fetch = LAZY ) + //we want it to behave as if... + //@LazyToOne( NO_PROXY ) + private Customer customer; + private BigDecimal amount; + + public Order() { + } + + public Order(Integer id, Customer customer, BigDecimal amount) { + this.id = id; + this.customer = customer; + this.amount = amount; + } + + public Integer getId() { + return id; + } + + private void setId(Integer id) { + this.id = id; + } + + public Customer getCustomer() { + return customer; + } + + public void setCustomer(Customer customer) { + this.customer = customer; + } + + public BigDecimal getAmount() { + return amount; + } + + public void setAmount(BigDecimal amount) { + this.amount = amount; + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/manytoone/ManyToOneExplicitOptionTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/manytoone/ManyToOneExplicitOptionTests.java new file mode 100644 index 000000000000..b88991d0763f --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/manytoone/ManyToOneExplicitOptionTests.java @@ -0,0 +1,215 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.orm.test.mapping.lazytoone.manytoone; + +import java.math.BigDecimal; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.ManyToOne; +import javax.persistence.Table; + +import org.hibernate.annotations.LazyToOne; +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.bytecode.enhance.spi.interceptor.BytecodeLazyAttributeInterceptor; +import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor; +import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor; +import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.persister.entity.EntityPersister; + +import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; +import org.hibernate.testing.bytecode.enhancement.EnhancementOptions; +import org.hibernate.testing.jdbc.SQLStatementInterceptor; +import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; +import org.junit.After; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static javax.persistence.FetchType.LAZY; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.sameInstance; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hibernate.annotations.LazyToOneOption.NO_PROXY; + +/** + * Baseline test for uni-directional to-one, using an explicit @LazyToOne(NO_PROXY) + * + * @author Steve Ebersole + */ +@RunWith( BytecodeEnhancerRunner.class) +@EnhancementOptions( lazyLoading = true ) +public class ManyToOneExplicitOptionTests extends BaseNonConfigCoreFunctionalTestCase { + private SQLStatementInterceptor sqlStatementInterceptor; + + @Override + protected void applyMetadataSources(MetadataSources sources) { + super.applyMetadataSources( sources ); + sources.addAnnotatedClass( Customer.class ); + sources.addAnnotatedClass( Order.class ); + } + + @Override + protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { + super.configureStandardServiceRegistryBuilder( ssrb ); + ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, true ); + sqlStatementInterceptor = new SQLStatementInterceptor( ssrb ); + } + + @Test + public void testOwnerIsProxy() { + inTransaction( + (session) -> { + final Customer customer = new Customer( 1, "Acme Brick" ); + session.persist( customer ); + final Order order = new Order( 1, customer, BigDecimal.ONE ); + session.persist( order ); + } + ); + + sqlStatementInterceptor.clear(); + + final EntityPersister orderDescriptor = sessionFactory().getMetamodel().entityPersister( Order.class ); + final BytecodeEnhancementMetadata orderEnhancementMetadata = orderDescriptor.getBytecodeEnhancementMetadata(); + assertThat( orderEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) ); + + final EntityPersister customerDescriptor = sessionFactory().getMetamodel().entityPersister( Customer.class ); + final BytecodeEnhancementMetadata customerEnhancementMetadata = customerDescriptor.getBytecodeEnhancementMetadata(); + assertThat( customerEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) ); + + inTransaction( + (session) -> { + final Order order = session.byId( Order.class ).getReference( 1 ); + + // we should have just the uninitialized proxy of the owner - and + // therefore no SQL statements should have been executed + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 0 ) ); + + final BytecodeLazyAttributeInterceptor initialInterceptor = orderEnhancementMetadata.extractLazyInterceptor( order ); + assertThat( initialInterceptor, instanceOf( EnhancementAsProxyLazinessInterceptor.class ) ); + + // access the id - should do nothing with db + order.getId(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 0 ) ); + assertThat( initialInterceptor, sameInstance( orderEnhancementMetadata.extractLazyInterceptor( order ) ) ); + + // this should trigger loading the entity's base state + order.getAmount(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) ); + final BytecodeLazyAttributeInterceptor interceptor = orderEnhancementMetadata.extractLazyInterceptor( order ); + assertThat( initialInterceptor, not( sameInstance( interceptor ) ) ); + assertThat( interceptor, instanceOf( LazyAttributeLoadingInterceptor.class ) ); + final LazyAttributeLoadingInterceptor attrInterceptor = (LazyAttributeLoadingInterceptor) interceptor; + assertThat( attrInterceptor.hasAnyUninitializedAttributes(), is( false ) ); + + // should not trigger a load and the `customer` reference should be an uninitialized enhanced proxy + final Customer customer = order.getCustomer(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) ); + + final BytecodeLazyAttributeInterceptor initialCustomerInterceptor = customerEnhancementMetadata.extractLazyInterceptor( customer ); + assertThat( initialCustomerInterceptor, instanceOf( EnhancementAsProxyLazinessInterceptor.class ) ); + + // just as above, accessing id should trigger no loads + customer.getId(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) ); + assertThat( initialCustomerInterceptor, sameInstance( customerEnhancementMetadata.extractLazyInterceptor( customer ) ) ); + + customer.getName(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 2 ) ); + assertThat( customerEnhancementMetadata.extractLazyInterceptor( customer ), instanceOf( LazyAttributeLoadingInterceptor.class ) ); + } + ); + } + + @After + public void dropTestData() { + inTransaction( + (session) -> { + session.createQuery( "delete Order" ).executeUpdate(); + session.createQuery( "delete Customer" ).executeUpdate(); + } + ); + } + + @Entity( name = "Customer" ) + @Table( name = "customer" ) + public static class Customer { + @Id + private Integer id; + private String name; + + public Customer() { + } + + public Customer(Integer id, String name) { + this.id = id; + this.name = name; + } + + public Integer getId() { + return id; + } + + private void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } + + @Entity( name = "Order") + @Table( name = "`order`") + public static class Order { + @Id + private Integer id; + @ManyToOne( fetch = LAZY ) + @LazyToOne( NO_PROXY ) + private Customer customer; + private BigDecimal amount; + + public Order() { + } + + public Order(Integer id, Customer customer, BigDecimal amount) { + this.id = id; + this.customer = customer; + this.amount = amount; + } + + public Integer getId() { + return id; + } + + private void setId(Integer id) { + this.id = id; + } + + public Customer getCustomer() { + return customer; + } + + public void setCustomer(Customer customer) { + this.customer = customer; + } + + public BigDecimal getAmount() { + return amount; + } + + public void setAmount(BigDecimal amount) { + this.amount = amount; + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/mappedby/InverseToOneAllowProxyTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/mappedby/InverseToOneAllowProxyTests.java new file mode 100644 index 000000000000..9f27598f1452 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/mappedby/InverseToOneAllowProxyTests.java @@ -0,0 +1,227 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.orm.test.mapping.lazytoone.mappedby; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.OneToOne; +import javax.persistence.Table; + +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.bytecode.enhance.spi.interceptor.BytecodeLazyAttributeInterceptor; +import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor; +import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor; +import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.persister.entity.EntityPersister; + +import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; +import org.hibernate.testing.bytecode.enhancement.EnhancementOptions; +import org.hibernate.testing.jdbc.SQLStatementInterceptor; +import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static javax.persistence.FetchType.LAZY; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.sameInstance; +import static org.hamcrest.MatcherAssert.assertThat; + +/** + * @author Steve Ebersole + */ +@RunWith( BytecodeEnhancerRunner.class) +@EnhancementOptions( lazyLoading = true ) +public class InverseToOneAllowProxyTests extends BaseNonConfigCoreFunctionalTestCase { + private SQLStatementInterceptor sqlStatementInterceptor; + + @Override + protected void applyMetadataSources(MetadataSources sources) { + super.applyMetadataSources( sources ); + sources.addAnnotatedClass( Customer.class ); + sources.addAnnotatedClass( SupplementalInfo.class ); + } + + @Override + protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { + super.configureStandardServiceRegistryBuilder( ssrb ); + ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, true ); + sqlStatementInterceptor = new SQLStatementInterceptor( ssrb ); + } + + @Test + public void testOwnerIsProxy() { + sqlStatementInterceptor.clear(); + + final EntityPersister supplementalInfoDescriptor = sessionFactory().getMetamodel().entityPersister( SupplementalInfo.class ); + final BytecodeEnhancementMetadata supplementalInfoEnhancementMetadata = supplementalInfoDescriptor.getBytecodeEnhancementMetadata(); + assertThat( supplementalInfoEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) ); + + final EntityPersister customerDescriptor = sessionFactory().getMetamodel().entityPersister( Customer.class ); + final BytecodeEnhancementMetadata customerEnhancementMetadata = customerDescriptor.getBytecodeEnhancementMetadata(); + assertThat( customerEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) ); + + inTransaction( + (session) -> { + + // Get a reference to the SupplementalInfo we created + + final SupplementalInfo supplementalInfo = session.byId( SupplementalInfo.class ).getReference( 1 ); + + // 1) we should have just the uninitialized SupplementalInfo enhanced proxy + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 0 ) ); + final BytecodeLazyAttributeInterceptor initialInterceptor = supplementalInfoEnhancementMetadata.extractLazyInterceptor( supplementalInfo ); + assertThat( initialInterceptor, instanceOf( EnhancementAsProxyLazinessInterceptor.class ) ); + + // (2) Access the SupplementalInfo's id value - should trigger no SQL + + supplementalInfo.getId(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 0 ) ); + assertThat( initialInterceptor, sameInstance( supplementalInfoEnhancementMetadata.extractLazyInterceptor( supplementalInfo ) ) ); + + // 3) Access SupplementalInfo's `something` state + // - should trigger loading the "base group" state, which only include `something`. + // NOTE: `customer` is not part of this lazy group because we do not know the + // Customer PK from this side + supplementalInfo.getSomething(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) ); + final BytecodeLazyAttributeInterceptor interceptor = supplementalInfoEnhancementMetadata.extractLazyInterceptor( supplementalInfo ); + assertThat( initialInterceptor, not( sameInstance( interceptor ) ) ); + assertThat( interceptor, instanceOf( LazyAttributeLoadingInterceptor.class ) ); + + // 4) Access SupplementalInfo's `customer` state + // - should trigger load from Customer table, by FK + final Customer customer = supplementalInfo.getCustomer(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 2 ) ); + + // just as above, accessing id should trigger no loads + customer.getId(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 2 ) ); + + customer.getName(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 2 ) ); + } + ); + } + + @Before + public void createTestData() { + inTransaction( + (session) -> { + final Customer customer = new Customer( 1, "Acme Brick" ); + session.persist( customer ); + final SupplementalInfo supplementalInfo = new SupplementalInfo( 1, customer, "extra details" ); + session.persist( supplementalInfo ); + } + ); + } + + @After + public void dropTestData() { + inTransaction( + (session) -> { + session.createQuery( "delete Customer" ).executeUpdate(); + session.createQuery( "delete SupplementalInfo" ).executeUpdate(); + } + ); + } + + @Entity( name = "Customer" ) + @Table( name = "customer" ) + public static class Customer { + @Id + private Integer id; + private String name; + @OneToOne( fetch = LAZY ) + private SupplementalInfo supplementalInfo; + + public Customer() { + } + + public Customer(Integer id, String name) { + this.id = id; + this.name = name; + } + + public Integer getId() { + return id; + } + + private void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public SupplementalInfo getSupplementalInfo() { + return supplementalInfo; + } + + public void setSupplementalInfo(SupplementalInfo supplementalInfo) { + this.supplementalInfo = supplementalInfo; + } + } + + @Entity( name = "SupplementalInfo" ) + @Table( name = "supplemental" ) + public static class SupplementalInfo { + @Id + private Integer id; + + @OneToOne( fetch = LAZY, mappedBy = "supplementalInfo", optional = false ) +// @LazyToOne( value = NO_PROXY ) + private Customer customer; + + private String something; + + public SupplementalInfo() { + } + + public SupplementalInfo(Integer id, Customer customer, String something) { + this.id = id; + this.customer = customer; + this.something = something; + + customer.setSupplementalInfo( this ); + } + + public Integer getId() { + return id; + } + + private void setId(Integer id) { + this.id = id; + } + + public Customer getCustomer() { + return customer; + } + + public void setCustomer(Customer customer) { + this.customer = customer; + } + + public String getSomething() { + return something; + } + + public void setSomething(String something) { + this.something = something; + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/mappedby/InverseToOneExplicitOptionTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/mappedby/InverseToOneExplicitOptionTests.java new file mode 100644 index 000000000000..6c19c1139a1e --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/mappedby/InverseToOneExplicitOptionTests.java @@ -0,0 +1,242 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.orm.test.mapping.lazytoone.mappedby; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.OneToOne; +import javax.persistence.Table; + +import org.hibernate.annotations.LazyToOne; +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor; +import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor; +import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.persister.entity.EntityPersister; + +import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; +import org.hibernate.testing.bytecode.enhancement.EnhancementOptions; +import org.hibernate.testing.jdbc.SQLStatementInterceptor; +import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; +import org.junit.After; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static javax.persistence.FetchType.LAZY; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hibernate.annotations.LazyToOneOption.NO_PROXY; + +/** + * Baseline test for inverse (mappedBy) to-one, using an explicit @LazyToOne(NO_PROXY) + */ +@RunWith( BytecodeEnhancerRunner.class) +@EnhancementOptions( lazyLoading = true ) +public class InverseToOneExplicitOptionTests extends BaseNonConfigCoreFunctionalTestCase { + private SQLStatementInterceptor sqlStatementInterceptor; + + @Override + protected void applyMetadataSources(MetadataSources sources) { + super.applyMetadataSources( sources ); + sources.addAnnotatedClass( Customer.class ); + sources.addAnnotatedClass( SupplementalInfo.class ); + } + + @Override + protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { + super.configureStandardServiceRegistryBuilder( ssrb ); + ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, true ); + sqlStatementInterceptor = new SQLStatementInterceptor( ssrb ); + } + + @Test + public void testOwnerIsProxy() { + inTransaction( + (session) -> { + final Customer customer = new Customer( 1, "Acme Brick" ); + session.persist( customer ); + final SupplementalInfo supplementalInfo = new SupplementalInfo( 1, customer, "extra details" ); + session.persist( supplementalInfo ); + } + ); + + sqlStatementInterceptor.clear(); + + final EntityPersister supplementalInfoDescriptor = sessionFactory().getMetamodel().entityPersister( SupplementalInfo.class ); + final BytecodeEnhancementMetadata supplementalInfoEnhancementMetadata = supplementalInfoDescriptor.getBytecodeEnhancementMetadata(); + assertThat( supplementalInfoEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) ); + + final EntityPersister customerDescriptor = sessionFactory().getMetamodel().entityPersister( Customer.class ); + final BytecodeEnhancementMetadata customerEnhancementMetadata = customerDescriptor.getBytecodeEnhancementMetadata(); + assertThat( customerEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) ); + + inTransaction( + (session) -> { + + // 1) Get a reference to the SupplementalInfo we created + // - at that point there should be no SQL executed + // 2) Access the SupplementalInfo's id value + // - should trigger no SQL + // 3) Access SupplementalInfo's `something` state + // - should trigger loading the "base group" state, which only include `something`. + // NOTE: `customer` is not part of this lazy group because we do not know the + // Customer PK from this side + // 4) Access SupplementalInfo's `customer` state + // - should trigger load from Customer table + + final SupplementalInfo supplementalInfo = session.byId( SupplementalInfo.class ).getReference( 1 ); + + // we should have just the uninitialized SupplementalInfo proxy + // - therefore no SQL statements should have been executed + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 0 ) ); + + assertThat( + supplementalInfoEnhancementMetadata.extractLazyInterceptor( supplementalInfo ), + instanceOf( EnhancementAsProxyLazinessInterceptor.class ) + ); + + // access the id - should do nothing with db + supplementalInfo.getId(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 0 ) ); + assertThat( + supplementalInfoEnhancementMetadata.extractLazyInterceptor( supplementalInfo ), + instanceOf( EnhancementAsProxyLazinessInterceptor.class ) + ); + + // this should trigger loading the entity's base state + supplementalInfo.getSomething(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) ); + assertThat( + supplementalInfoEnhancementMetadata.extractLazyInterceptor( supplementalInfo ), + instanceOf( LazyAttributeLoadingInterceptor.class ) + ); + + // because we do not know the customer FK from the SupplementalInfo side + // it is considered part of SupplementalInfo's non-base state. + // + // here we access customer which triggers a load from customer table + final Customer customer = supplementalInfo.getCustomer(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 2 ) ); + + assertThat( + customerEnhancementMetadata.extractLazyInterceptor( customer ), + instanceOf( LazyAttributeLoadingInterceptor.class ) + ); + + // just as above, accessing id should trigger no loads + customer.getId(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 2 ) ); + + customer.getName(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 2 ) ); + } + ); + } + + @After + public void dropTestData() { + inTransaction( + (session) -> { + session.createQuery( "delete Customer" ).executeUpdate(); + session.createQuery( "delete SupplementalInfo" ).executeUpdate(); + } + ); + } + + @Entity( name = "Customer" ) + @Table( name = "customer" ) + public static class Customer { + @Id + private Integer id; + private String name; + @OneToOne( fetch = LAZY ) + private SupplementalInfo supplementalInfo; + + public Customer() { + } + + public Customer(Integer id, String name) { + this.id = id; + this.name = name; + } + + public Integer getId() { + return id; + } + + private void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public SupplementalInfo getSupplementalInfo() { + return supplementalInfo; + } + + public void setSupplementalInfo(SupplementalInfo supplementalInfo) { + this.supplementalInfo = supplementalInfo; + } + } + + @Entity( name = "SupplementalInfo" ) + @Table( name = "supplemental" ) + public static class SupplementalInfo { + @Id + private Integer id; + + @OneToOne( fetch = LAZY, mappedBy = "supplementalInfo", optional = false ) + @LazyToOne( value = NO_PROXY ) + private Customer customer; + + private String something; + + public SupplementalInfo() { + } + + public SupplementalInfo(Integer id, Customer customer, String something) { + this.id = id; + this.customer = customer; + this.something = something; + + customer.setSupplementalInfo( this ); + } + + public Integer getId() { + return id; + } + + private void setId(Integer id) { + this.id = id; + } + + public Customer getCustomer() { + return customer; + } + + public void setCustomer(Customer customer) { + this.customer = customer; + } + + public String getSomething() { + return something; + } + + public void setSomething(String something) { + this.something = something; + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/mappedby/JoinFetchedInverseToOneAllowProxyTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/mappedby/JoinFetchedInverseToOneAllowProxyTests.java new file mode 100644 index 000000000000..036a1f247dec --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/mappedby/JoinFetchedInverseToOneAllowProxyTests.java @@ -0,0 +1,225 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.orm.test.mapping.lazytoone.mappedby; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.OneToOne; +import javax.persistence.Table; + +import org.hibernate.annotations.Fetch; +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.bytecode.enhance.spi.interceptor.BytecodeLazyAttributeInterceptor; +import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor; +import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor; +import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.persister.entity.EntityPersister; + +import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; +import org.hibernate.testing.bytecode.enhancement.EnhancementOptions; +import org.hibernate.testing.jdbc.SQLStatementInterceptor; +import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static javax.persistence.FetchType.LAZY; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.sameInstance; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hibernate.annotations.FetchMode.JOIN; + +/** + * @author Steve Ebersole + */ +@RunWith( BytecodeEnhancerRunner.class) +@EnhancementOptions( lazyLoading = true ) +public class JoinFetchedInverseToOneAllowProxyTests extends BaseNonConfigCoreFunctionalTestCase { + private SQLStatementInterceptor sqlStatementInterceptor; + + @Override + protected void applyMetadataSources(MetadataSources sources) { + super.applyMetadataSources( sources ); + sources.addAnnotatedClass( Customer.class ); + sources.addAnnotatedClass( SupplementalInfo.class ); + } + + @Override + protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { + super.configureStandardServiceRegistryBuilder( ssrb ); + ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, true ); + sqlStatementInterceptor = new SQLStatementInterceptor( ssrb ); + } + + @Test + public void testOwnerIsProxy() { + sqlStatementInterceptor.clear(); + + final EntityPersister supplementalInfoDescriptor = sessionFactory().getMetamodel().entityPersister( SupplementalInfo.class ); + final BytecodeEnhancementMetadata supplementalInfoEnhancementMetadata = supplementalInfoDescriptor.getBytecodeEnhancementMetadata(); + assertThat( supplementalInfoEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) ); + + final EntityPersister customerDescriptor = sessionFactory().getMetamodel().entityPersister( Customer.class ); + final BytecodeEnhancementMetadata customerEnhancementMetadata = customerDescriptor.getBytecodeEnhancementMetadata(); + assertThat( customerEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) ); + + inTransaction( + (session) -> { + + // Get a reference to the SupplementalInfo we created + + final SupplementalInfo supplementalInfo = session.byId( SupplementalInfo.class ).getReference( 1 ); + + // 1) we should have just the uninitialized SupplementalInfo enhanced proxy + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 0 ) ); + final BytecodeLazyAttributeInterceptor initialInterceptor = supplementalInfoEnhancementMetadata.extractLazyInterceptor( supplementalInfo ); + assertThat( initialInterceptor, instanceOf( EnhancementAsProxyLazinessInterceptor.class ) ); + + // 2) Access the SupplementalInfo's id value - should trigger no SQL + + supplementalInfo.getId(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 0 ) ); + assertThat( initialInterceptor, sameInstance( supplementalInfoEnhancementMetadata.extractLazyInterceptor( supplementalInfo ) ) ); + + // 3) Access SupplementalInfo's `something` state + // - should trigger loading the "base group" state + // - customer should be join fetched as part of loading this base state + supplementalInfo.getSomething(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) ); + final BytecodeLazyAttributeInterceptor interceptor = supplementalInfoEnhancementMetadata.extractLazyInterceptor( supplementalInfo ); + assertThat( initialInterceptor, not( sameInstance( interceptor ) ) ); + assertThat( interceptor, instanceOf( LazyAttributeLoadingInterceptor.class ) ); + + // 4) Access SupplementalInfo's `customer` state + final Customer customer = supplementalInfo.getCustomer(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) ); + + customer.getId(); + customer.getName(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) ); + } + ); + } + + @Before + public void createTestData() { + inTransaction( + (session) -> { + final Customer customer = new Customer( 1, "Acme Brick" ); + session.persist( customer ); + final SupplementalInfo supplementalInfo = new SupplementalInfo( 1, customer, "extra details" ); + session.persist( supplementalInfo ); + } + ); + } + + @After + public void dropTestData() { + inTransaction( + (session) -> { + session.createQuery( "delete Customer" ).executeUpdate(); + session.createQuery( "delete SupplementalInfo" ).executeUpdate(); + } + ); + } + + @Entity( name = "Customer" ) + @Table( name = "customer" ) + public static class Customer { + @Id + private Integer id; + private String name; + @OneToOne( fetch = LAZY ) + private SupplementalInfo supplementalInfo; + + public Customer() { + } + + public Customer(Integer id, String name) { + this.id = id; + this.name = name; + } + + public Integer getId() { + return id; + } + + private void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public SupplementalInfo getSupplementalInfo() { + return supplementalInfo; + } + + public void setSupplementalInfo(SupplementalInfo supplementalInfo) { + this.supplementalInfo = supplementalInfo; + } + } + + @Entity( name = "SupplementalInfo" ) + @Table( name = "supplemental" ) + public static class SupplementalInfo { + @Id + private Integer id; + + @OneToOne( fetch = LAZY, mappedBy = "supplementalInfo", optional = false ) +// @LazyToOne( value = NO_PROXY ) + @Fetch( JOIN ) + private Customer customer; + + private String something; + + public SupplementalInfo() { + } + + public SupplementalInfo(Integer id, Customer customer, String something) { + this.id = id; + this.customer = customer; + this.something = something; + + customer.setSupplementalInfo( this ); + } + + public Integer getId() { + return id; + } + + private void setId(Integer id) { + this.id = id; + } + + public Customer getCustomer() { + return customer; + } + + public void setCustomer(Customer customer) { + this.customer = customer; + } + + public String getSomething() { + return something; + } + + public void setSomething(String something) { + this.something = something; + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/onetoone/JoinFetchedOneToOneAllowProxyTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/onetoone/JoinFetchedOneToOneAllowProxyTests.java new file mode 100644 index 000000000000..6b5c0cfada64 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/onetoone/JoinFetchedOneToOneAllowProxyTests.java @@ -0,0 +1,197 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.orm.test.mapping.lazytoone.onetoone; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.OneToOne; +import javax.persistence.Table; + +import org.hibernate.annotations.Fetch; +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.persister.entity.EntityPersister; + +import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; +import org.hibernate.testing.bytecode.enhancement.EnhancementOptions; +import org.hibernate.testing.jdbc.SQLStatementInterceptor; +import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static javax.persistence.FetchType.LAZY; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hibernate.annotations.FetchMode.JOIN; + +/** + * @author Steve Ebersole + */ +@RunWith( BytecodeEnhancerRunner.class) +@EnhancementOptions( lazyLoading = true ) +public class JoinFetchedOneToOneAllowProxyTests extends BaseNonConfigCoreFunctionalTestCase { + private SQLStatementInterceptor sqlStatementInterceptor; + + @Override + protected void applyMetadataSources(MetadataSources sources) { + super.applyMetadataSources( sources ); + sources.addAnnotatedClass( Customer.class ); + sources.addAnnotatedClass( SupplementalInfo.class ); + } + + @Override + protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { + super.configureStandardServiceRegistryBuilder( ssrb ); + ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, true ); + sqlStatementInterceptor = new SQLStatementInterceptor( ssrb ); + } + + @Test + public void testOwnerIsProxy() { + sqlStatementInterceptor.clear(); + + final EntityPersister supplementalInfoDescriptor = sessionFactory().getMetamodel().entityPersister( SupplementalInfo.class ); + final BytecodeEnhancementMetadata supplementalInfoEnhancementMetadata = supplementalInfoDescriptor.getBytecodeEnhancementMetadata(); + assertThat( supplementalInfoEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) ); + + final EntityPersister customerDescriptor = sessionFactory().getMetamodel().entityPersister( Customer.class ); + final BytecodeEnhancementMetadata customerEnhancementMetadata = customerDescriptor.getBytecodeEnhancementMetadata(); + assertThat( customerEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) ); + + inTransaction( + (session) -> { + final SupplementalInfo supplementalInfo = session.byId( SupplementalInfo.class ).getReference( 1 ); + + // we should have just the uninitialized SupplementalInfo proxy + // - therefore no SQL statements should have been executed + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 0 ) ); + + // access the id - should do nothing with db + supplementalInfo.getId(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 0 ) ); + + // this should trigger loading the entity's base state which should include join fetching Customer + supplementalInfo.getSomething(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) ); + + // should not trigger a load and the `customer` reference should be an uninitialized enhanced proxy + final Customer customer = supplementalInfo.getCustomer(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) ); + + // just as above, accessing id should trigger no loads + customer.getId(); + customer.getName(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) ); + } + ); + } + + @Before + public void createTestData() { + inTransaction( + (session) -> { + final Customer customer = new Customer( 1, "Acme Brick" ); + session.persist( customer ); + final SupplementalInfo supplementalInfo = new SupplementalInfo( 1, customer, "extra details" ); + session.persist( supplementalInfo ); + } + ); + } + + @After + public void dropTestData() { + inTransaction( + (session) -> { + session.createQuery( "delete SupplementalInfo" ).executeUpdate(); + session.createQuery( "delete Customer" ).executeUpdate(); + } + ); + } + + @Entity( name = "Customer" ) + @Table( name = "customer" ) + public static class Customer { + @Id + private Integer id; + private String name; + + public Customer() { + } + + public Customer(Integer id, String name) { + this.id = id; + this.name = name; + } + + public Integer getId() { + return id; + } + + private void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } + + @Entity( name = "SupplementalInfo" ) + @Table( name = "supplemental" ) + public static class SupplementalInfo { + @Id + private Integer id; + + @OneToOne( fetch = LAZY, optional = false ) + @Fetch( JOIN ) + //@LazyToOne( value = NO_PROXY ) + private Customer customer; + + private String something; + + public SupplementalInfo() { + } + + public SupplementalInfo(Integer id, Customer customer, String something) { + this.id = id; + this.customer = customer; + this.something = something; + } + + public Integer getId() { + return id; + } + + private void setId(Integer id) { + this.id = id; + } + + public Customer getCustomer() { + return customer; + } + + public void setCustomer(Customer customer) { + this.customer = customer; + } + + public String getSomething() { + return something; + } + + public void setSomething(String something) { + this.something = something; + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/onetoone/OneToOneAllowProxyTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/onetoone/OneToOneAllowProxyTests.java new file mode 100644 index 000000000000..a0c577d6339d --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/onetoone/OneToOneAllowProxyTests.java @@ -0,0 +1,216 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.orm.test.mapping.lazytoone.onetoone; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.OneToOne; +import javax.persistence.Table; + +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.bytecode.enhance.spi.interceptor.BytecodeLazyAttributeInterceptor; +import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor; +import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor; +import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.persister.entity.EntityPersister; + +import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; +import org.hibernate.testing.bytecode.enhancement.EnhancementOptions; +import org.hibernate.testing.jdbc.SQLStatementInterceptor; +import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static javax.persistence.FetchType.LAZY; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.sameInstance; +import static org.hamcrest.MatcherAssert.assertThat; + +/** + * @author Steve Ebersole + */ +@RunWith( BytecodeEnhancerRunner.class) +@EnhancementOptions( lazyLoading = true ) +public class OneToOneAllowProxyTests extends BaseNonConfigCoreFunctionalTestCase { + private SQLStatementInterceptor sqlStatementInterceptor; + + @Override + protected void applyMetadataSources(MetadataSources sources) { + super.applyMetadataSources( sources ); + sources.addAnnotatedClass( Customer.class ); + sources.addAnnotatedClass( SupplementalInfo.class ); + } + + @Override + protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { + super.configureStandardServiceRegistryBuilder( ssrb ); + ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, true ); + sqlStatementInterceptor = new SQLStatementInterceptor( ssrb ); + } + + @Test + public void testOwnerIsProxy() { + sqlStatementInterceptor.clear(); + + final EntityPersister supplementalInfoDescriptor = sessionFactory().getMetamodel().entityPersister( SupplementalInfo.class ); + final BytecodeEnhancementMetadata supplementalInfoEnhancementMetadata = supplementalInfoDescriptor.getBytecodeEnhancementMetadata(); + assertThat( supplementalInfoEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) ); + + final EntityPersister customerDescriptor = sessionFactory().getMetamodel().entityPersister( Customer.class ); + final BytecodeEnhancementMetadata customerEnhancementMetadata = customerDescriptor.getBytecodeEnhancementMetadata(); + assertThat( customerEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) ); + + inTransaction( + (session) -> { + final SupplementalInfo supplementalInfo = session.byId( SupplementalInfo.class ).getReference( 1 ); + + // we should have just the uninitialized SupplementalInfo proxy + // - therefore no SQL statements should have been executed + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 0 ) ); + + final BytecodeLazyAttributeInterceptor initialInterceptor = supplementalInfoEnhancementMetadata.extractLazyInterceptor( supplementalInfo ); + assertThat( initialInterceptor, instanceOf( EnhancementAsProxyLazinessInterceptor.class ) ); + + // access the id - should do nothing with db + supplementalInfo.getId(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 0 ) ); + assertThat( supplementalInfoEnhancementMetadata.extractLazyInterceptor( supplementalInfo ), sameInstance( initialInterceptor ) ); + + // this should trigger loading the entity's base state + supplementalInfo.getSomething(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) ); + final BytecodeLazyAttributeInterceptor interceptor = supplementalInfoEnhancementMetadata.extractLazyInterceptor( supplementalInfo ); + assertThat( initialInterceptor, not( sameInstance( interceptor ) ) ); + assertThat( interceptor, instanceOf( LazyAttributeLoadingInterceptor.class ) ); + final LazyAttributeLoadingInterceptor attrInterceptor = (LazyAttributeLoadingInterceptor) interceptor; + assertThat( attrInterceptor.hasAnyUninitializedAttributes(), is( false ) ); + + // should not trigger a load and the `customer` reference should be an uninitialized enhanced proxy + final Customer customer = supplementalInfo.getCustomer(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) ); + + final BytecodeLazyAttributeInterceptor initialCustomerInterceptor = customerEnhancementMetadata.extractLazyInterceptor( customer ); + assertThat( initialCustomerInterceptor, instanceOf( EnhancementAsProxyLazinessInterceptor.class ) ); + + // just as above, accessing id should trigger no loads + customer.getId(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) ); + assertThat( initialCustomerInterceptor, sameInstance( customerEnhancementMetadata.extractLazyInterceptor( customer ) ) ); + + customer.getName(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 2 ) ); + assertThat( customerEnhancementMetadata.extractLazyInterceptor( customer ), instanceOf( LazyAttributeLoadingInterceptor.class ) ); + } + ); + } + + @Before + public void createTestData() { + inTransaction( + (session) -> { + final Customer customer = new Customer( 1, "Acme Brick" ); + session.persist( customer ); + final SupplementalInfo supplementalInfo = new SupplementalInfo( 1, customer, "extra details" ); + session.persist( supplementalInfo ); + } + ); + } + + @After + public void dropTestData() { + inTransaction( + (session) -> { + session.createQuery( "delete SupplementalInfo" ).executeUpdate(); + session.createQuery( "delete Customer" ).executeUpdate(); + } + ); + } + + @Entity( name = "Customer" ) + @Table( name = "customer" ) + public static class Customer { + @Id + private Integer id; + private String name; + + public Customer() { + } + + public Customer(Integer id, String name) { + this.id = id; + this.name = name; + } + + public Integer getId() { + return id; + } + + private void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } + + @Entity( name = "SupplementalInfo" ) + @Table( name = "supplemental" ) + public static class SupplementalInfo { + @Id + private Integer id; + + @OneToOne( fetch = LAZY, optional = false ) + //@LazyToOne( value = NO_PROXY ) + private Customer customer; + + private String something; + + public SupplementalInfo() { + } + + public SupplementalInfo(Integer id, Customer customer, String something) { + this.id = id; + this.customer = customer; + this.something = something; + } + + public Integer getId() { + return id; + } + + private void setId(Integer id) { + this.id = id; + } + + public Customer getCustomer() { + return customer; + } + + public void setCustomer(Customer customer) { + this.customer = customer; + } + + public String getSomething() { + return something; + } + + public void setSomething(String something) { + this.something = something; + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/onetoone/OneToOneExplicitOptionTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/onetoone/OneToOneExplicitOptionTests.java new file mode 100644 index 000000000000..47bd908f8881 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/onetoone/OneToOneExplicitOptionTests.java @@ -0,0 +1,218 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.orm.test.mapping.lazytoone.onetoone; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.OneToOne; +import javax.persistence.Table; + +import org.hibernate.annotations.LazyToOne; +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.bytecode.enhance.spi.interceptor.BytecodeLazyAttributeInterceptor; +import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor; +import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor; +import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.persister.entity.EntityPersister; + +import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; +import org.hibernate.testing.bytecode.enhancement.EnhancementOptions; +import org.hibernate.testing.jdbc.SQLStatementInterceptor; +import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static javax.persistence.FetchType.LAZY; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.sameInstance; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hibernate.annotations.LazyToOneOption.NO_PROXY; + +/** + * Baseline test for uni-directional one-to-one, using an explicit @LazyToOne(NO_PROXY) and allowing enhanced proxies + */ +@RunWith( BytecodeEnhancerRunner.class) +@EnhancementOptions( lazyLoading = true ) +public class OneToOneExplicitOptionTests extends BaseNonConfigCoreFunctionalTestCase { + private SQLStatementInterceptor sqlStatementInterceptor; + + @Override + protected void applyMetadataSources(MetadataSources sources) { + super.applyMetadataSources( sources ); + sources.addAnnotatedClass( Customer.class ); + sources.addAnnotatedClass( SupplementalInfo.class ); + } + + @Override + protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { + super.configureStandardServiceRegistryBuilder( ssrb ); + ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, true ); + sqlStatementInterceptor = new SQLStatementInterceptor( ssrb ); + } + + @Test + public void testOwnerIsProxy() { + sqlStatementInterceptor.clear(); + + final EntityPersister supplementalInfoDescriptor = sessionFactory().getMetamodel().entityPersister( SupplementalInfo.class ); + final BytecodeEnhancementMetadata supplementalInfoEnhancementMetadata = supplementalInfoDescriptor.getBytecodeEnhancementMetadata(); + assertThat( supplementalInfoEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) ); + + final EntityPersister customerDescriptor = sessionFactory().getMetamodel().entityPersister( Customer.class ); + final BytecodeEnhancementMetadata customerEnhancementMetadata = customerDescriptor.getBytecodeEnhancementMetadata(); + assertThat( customerEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) ); + + inTransaction( + (session) -> { + final SupplementalInfo supplementalInfo = session.byId( SupplementalInfo.class ).getReference( 1 ); + + // we should have just the uninitialized SupplementalInfo proxy + // - therefore no SQL statements should have been executed + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 0 ) ); + + final BytecodeLazyAttributeInterceptor initialInterceptor = supplementalInfoEnhancementMetadata.extractLazyInterceptor( supplementalInfo ); + assertThat( initialInterceptor, instanceOf( EnhancementAsProxyLazinessInterceptor.class ) ); + + // access the id - should do nothing with db + supplementalInfo.getId(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 0 ) ); + assertThat( supplementalInfoEnhancementMetadata.extractLazyInterceptor( supplementalInfo ), sameInstance( initialInterceptor ) ); + + // this should trigger loading the entity's base state + supplementalInfo.getSomething(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) ); + final BytecodeLazyAttributeInterceptor interceptor = supplementalInfoEnhancementMetadata.extractLazyInterceptor( supplementalInfo ); + assertThat( initialInterceptor, not( sameInstance( interceptor ) ) ); + assertThat( interceptor, instanceOf( LazyAttributeLoadingInterceptor.class ) ); + final LazyAttributeLoadingInterceptor attrInterceptor = (LazyAttributeLoadingInterceptor) interceptor; + assertThat( attrInterceptor.hasAnyUninitializedAttributes(), is( false ) ); + + // should not trigger a load and the `customer` reference should be an uninitialized enhanced proxy + final Customer customer = supplementalInfo.getCustomer(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) ); + + final BytecodeLazyAttributeInterceptor initialCustomerInterceptor = customerEnhancementMetadata.extractLazyInterceptor( customer ); + assertThat( initialCustomerInterceptor, instanceOf( EnhancementAsProxyLazinessInterceptor.class ) ); + + // just as above, accessing id should trigger no loads + customer.getId(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) ); + assertThat( initialCustomerInterceptor, sameInstance( customerEnhancementMetadata.extractLazyInterceptor( customer ) ) ); + + customer.getName(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 2 ) ); + assertThat( customerEnhancementMetadata.extractLazyInterceptor( customer ), instanceOf( LazyAttributeLoadingInterceptor.class ) ); + } + ); + } + + @Before + public void createTestData() { + inTransaction( + (session) -> { + final Customer customer = new Customer( 1, "Acme Brick" ); + session.persist( customer ); + final SupplementalInfo supplementalInfo = new SupplementalInfo( 1, customer, "extra details" ); + session.persist( supplementalInfo ); + } + ); + } + + @After + public void dropTestData() { + inTransaction( + (session) -> { + session.createQuery( "delete SupplementalInfo" ).executeUpdate(); + session.createQuery( "delete Customer" ).executeUpdate(); + } + ); + } + + @Entity( name = "Customer" ) + @Table( name = "customer" ) + public static class Customer { + @Id + private Integer id; + private String name; + + public Customer() { + } + + public Customer(Integer id, String name) { + this.id = id; + this.name = name; + } + + public Integer getId() { + return id; + } + + private void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } + + @Entity( name = "SupplementalInfo" ) + @Table( name = "supplemental" ) + public static class SupplementalInfo { + @Id + private Integer id; + + @OneToOne( fetch = LAZY, optional = false ) + @LazyToOne( value = NO_PROXY ) + private Customer customer; + + private String something; + + public SupplementalInfo() { + } + + public SupplementalInfo(Integer id, Customer customer, String something) { + this.id = id; + this.customer = customer; + this.something = something; + } + + public Integer getId() { + return id; + } + + private void setId(Integer id) { + this.id = id; + } + + public Customer getCustomer() { + return customer; + } + + public void setCustomer(Customer customer) { + this.customer = customer; + } + + public String getSomething() { + return something; + } + + public void setSomething(String something) { + this.something = something; + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/package-info.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/package-info.java new file mode 100644 index 000000000000..2cc953d55c24 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/package-info.java @@ -0,0 +1,12 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ + +/** + * Tests related to {@link org.hibernate.annotations.LazyToOne}, especially + * regarding handling of {@link org.hibernate.annotations.LazyToOneOption#NO_PROXY} + */ +package org.hibernate.orm.test.mapping.lazytoone; \ No newline at end of file diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/polymorphic/JoinFetchedPolymorphicToOneTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/polymorphic/JoinFetchedPolymorphicToOneTests.java new file mode 100644 index 000000000000..13b57b5ea2a9 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/polymorphic/JoinFetchedPolymorphicToOneTests.java @@ -0,0 +1,236 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.orm.test.mapping.lazytoone.polymorphic; + +import java.math.BigDecimal; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Inheritance; +import javax.persistence.InheritanceType; +import javax.persistence.ManyToOne; +import javax.persistence.Table; + +import org.hibernate.Hibernate; +import org.hibernate.annotations.Fetch; +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.cfg.AvailableSettings; + +import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; +import org.hibernate.testing.bytecode.enhancement.EnhancementOptions; +import org.hibernate.testing.jdbc.SQLStatementInterceptor; +import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static javax.persistence.FetchType.LAZY; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hibernate.annotations.FetchMode.JOIN; +import static org.junit.Assert.assertTrue; + +/** + * @author Steve Ebersole + */ +@RunWith( BytecodeEnhancerRunner.class) +@EnhancementOptions( lazyLoading = true ) +public class JoinFetchedPolymorphicToOneTests extends BaseNonConfigCoreFunctionalTestCase { + @Test + public void testInheritedToOneLaziness() { + inTransaction( + (session) -> { + sqlStatementInterceptor.clear(); + + final Order order = session.byId( Order.class ).getReference( 1 ); + assertThat( sqlStatementInterceptor.getQueryCount(), is( 0 ) ); + + System.out.println( "Order # " + order.getId() ); + assertThat( sqlStatementInterceptor.getQueryCount(), is( 0 ) ); + + System.out.println( " - amount : " + order.getAmount() ); + // triggers load of base fetch state + assertThat( sqlStatementInterceptor.getQueryCount(), is( 1 ) ); + + final Customer customer = order.getCustomer(); + // customer is part of base fetch state + assertThat( sqlStatementInterceptor.getQueryCount(), is( 1 ) ); + assertTrue( Hibernate.isInitialized( customer ) ); + + System.out.println( " - customer : " + customer.getId() ); + assertThat( sqlStatementInterceptor.getQueryCount(), is( 1 ) ); + + customer.getName(); + // customer base fetch state should also have been loaded above + assertThat( sqlStatementInterceptor.getQueryCount(), is( 1 ) ); + } + ); + } + + @Before + public void createTestData() { + inTransaction( + (session) -> { + final DomesticCustomer customer = new DomesticCustomer( 1, "them", "123" ); + session.persist( customer ); + final Order order = new Order( 1, BigDecimal.ONE, customer ); + session.persist( order ); + } + ); + } + + @After + public void dropTestData() { + inTransaction( + (session) -> { + session.createQuery( "delete Order" ).executeUpdate(); + session.createQuery( "delete Customer" ).executeUpdate(); + } + ); + } + + private SQLStatementInterceptor sqlStatementInterceptor; + + @Override + protected void applyMetadataSources(MetadataSources sources) { + super.applyMetadataSources( sources ); + sources.addAnnotatedClass( Order.class ); + sources.addAnnotatedClass( Customer.class ); + sources.addAnnotatedClass( ForeignCustomer.class ); + sources.addAnnotatedClass( DomesticCustomer.class ); + } + + @Override + protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { + super.configureStandardServiceRegistryBuilder( ssrb ); + ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, true ); + sqlStatementInterceptor = new SQLStatementInterceptor( ssrb ); + } + + @Entity( name = "Order" ) + @Table( name = "`order`" ) + public static class Order { + @Id + private Integer id; + private BigDecimal amount; + @ManyToOne( fetch = LAZY, optional = false ) + @Fetch( JOIN ) + private Customer customer; + + public Order() { + } + + public Order(Integer id, BigDecimal amount, Customer customer) { + this.id = id; + this.amount = amount; + this.customer = customer; + } + + public Integer getId() { + return id; + } + + private void setId(Integer id) { + this.id = id; + } + + public BigDecimal getAmount() { + return amount; + } + + public void setAmount(BigDecimal amount) { + this.amount = amount; + } + + public Customer getCustomer() { + return customer; + } + + public void setCustomer(Customer customer) { + this.customer = customer; + } + } + + @Entity( name = "Customer" ) + @Inheritance( strategy = InheritanceType.TABLE_PER_CLASS ) + public static abstract class Customer { + @Id + private Integer id; + private String name; + + public Customer() { + } + + public Customer(Integer id, String name) { + this.id = id; + this.name = name; + } + + public Integer getId() { + return id; + } + + private void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } + + @Entity(name = "ForeignCustomer") + @Table(name = "foreign_cust") + public static class ForeignCustomer extends Customer { + private String vat; + + public ForeignCustomer() { + super(); + } + + public ForeignCustomer(Integer id, String name, String vat) { + super( id, name ); + this.vat = vat; + } + + public String getVat() { + return vat; + } + + public void setVat(String vat) { + this.vat = vat; + } + } + + @Entity(name = "DomesticCustomer") + @Table(name = "domestic_cust") + public static class DomesticCustomer extends Customer { + private String taxId; + + public DomesticCustomer() { + super(); + } + + public DomesticCustomer(Integer id, String name, String taxId) { + super( id, name ); + this.taxId = taxId; + } + + public String getTaxId() { + return taxId; + } + + public void setTaxId(String taxId) { + this.taxId = taxId; + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/polymorphic/PolymorphicToOneExplicitOptionTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/polymorphic/PolymorphicToOneExplicitOptionTests.java new file mode 100644 index 000000000000..60c0837bba65 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/polymorphic/PolymorphicToOneExplicitOptionTests.java @@ -0,0 +1,264 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.orm.test.mapping.lazytoone.polymorphic; + +import java.math.BigDecimal; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Inheritance; +import javax.persistence.InheritanceType; +import javax.persistence.ManyToOne; +import javax.persistence.Table; + +import org.hibernate.Hibernate; +import org.hibernate.annotations.LazyToOne; +import org.hibernate.annotations.LazyToOneOption; +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.proxy.HibernateProxy; + +import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; +import org.hibernate.testing.bytecode.enhancement.EnhancementOptions; +import org.hibernate.testing.jdbc.SQLStatementInterceptor; +import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static javax.persistence.FetchType.LAZY; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertFalse; + +/** + * @author Steve Ebersole + */ +@RunWith( BytecodeEnhancerRunner.class) +@EnhancementOptions( lazyLoading = true ) +public class PolymorphicToOneExplicitOptionTests extends BaseNonConfigCoreFunctionalTestCase { + @Test + public void testInheritedToOneLaziness() { + inTransaction( + (session) -> { + sqlStatementInterceptor.clear(); + + // NOTE : this test shows an edge case that does not work the way it + // should. Because we have a polymorphic to-one, we will have to + // generate a HibernateProxy for the laziness. However, the explicit + // NO_PROXY should force the proxy to be immediately initialized + // and the target returned. + // + // this is the old behavior as well - these HHH-13658 changes did not cause this + // + // its an odd edge case however and maybe not that critical. it essentially + // asks for the association to be lazy and to also be eager + // + // The assertions here are based on what *does* happen. Whether that is right/wrong + // is a different discussion + + final Order order = session.byId( Order.class ).getReference( 1 ); + assertThat( sqlStatementInterceptor.getQueryCount(), is( 0 ) ); + + System.out.println( "Order # " + order.getId() ); + assertThat( sqlStatementInterceptor.getQueryCount(), is( 0 ) ); + + System.out.println( " - amount : " + order.getAmount() ); + // triggers load of base fetch state + assertThat( sqlStatementInterceptor.getQueryCount(), is( 1 ) ); + + final Customer customer = order.getCustomer(); + // this *should* be 2 - the customer should get loaded + //int expectedCount = 2; + // but it is 1 because we get back a HibernateProxy + int expectedCount = 1; + assertThat( sqlStatementInterceptor.getQueryCount(), is( expectedCount ) ); + // should be true... + //assertTrue( Hibernate.isInitialized( customer ) ); + // but is false + assertFalse( Hibernate.isInitialized( customer ) ); + // should not be a HibernateProxy + //assertThat( customer, not( instanceOf( HibernateProxy.class ) ) ); + // but is + assertThat( customer, instanceOf( HibernateProxy.class ) ); + + System.out.println( " - customer : " + customer.getId() ); + assertThat( sqlStatementInterceptor.getQueryCount(), is( expectedCount ) ); + + customer.getName(); + // this should not trigger SQL because the customer ought to already be initialized + // but again that is not the case + expectedCount++; + assertThat( sqlStatementInterceptor.getQueryCount(), is( expectedCount ) ); + } + ); + } + + @Before + public void createTestData() { + inTransaction( + (session) -> { + final DomesticCustomer customer = new DomesticCustomer( 1, "them", "123" ); + session.persist( customer ); + final Order order = new Order( 1, BigDecimal.ONE, customer ); + session.persist( order ); + } + ); + } + + @After + public void dropTestData() { + inTransaction( + (session) -> { + session.createQuery( "delete Order" ).executeUpdate(); + session.createQuery( "delete Customer" ).executeUpdate(); + } + ); + } + + private SQLStatementInterceptor sqlStatementInterceptor; + + @Override + protected void applyMetadataSources(MetadataSources sources) { + super.applyMetadataSources( sources ); + sources.addAnnotatedClass( Order.class ); + sources.addAnnotatedClass( Customer.class ); + sources.addAnnotatedClass( ForeignCustomer.class ); + sources.addAnnotatedClass( DomesticCustomer.class ); + } + + @Override + protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { + super.configureStandardServiceRegistryBuilder( ssrb ); + ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, true ); + sqlStatementInterceptor = new SQLStatementInterceptor( ssrb ); + } + + @Entity( name = "Order" ) + @Table( name = "`order`" ) + public static class Order { + @Id + private Integer id; + private BigDecimal amount; + @ManyToOne( fetch = LAZY, optional = false ) + @LazyToOne( LazyToOneOption.NO_PROXY ) + private Customer customer; + + public Order() { + } + + public Order(Integer id, BigDecimal amount, Customer customer) { + this.id = id; + this.amount = amount; + this.customer = customer; + } + + public Integer getId() { + return id; + } + + private void setId(Integer id) { + this.id = id; + } + + public BigDecimal getAmount() { + return amount; + } + + public void setAmount(BigDecimal amount) { + this.amount = amount; + } + + public Customer getCustomer() { + return customer; + } + + public void setCustomer(Customer customer) { + this.customer = customer; + } + } + + @Entity( name = "Customer" ) + @Inheritance( strategy = InheritanceType.TABLE_PER_CLASS ) + public static abstract class Customer { + @Id + private Integer id; + private String name; + + public Customer() { + } + + public Customer(Integer id, String name) { + this.id = id; + this.name = name; + } + + public Integer getId() { + return id; + } + + private void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } + + @Entity(name = "ForeignCustomer") + @Table(name = "foreign_cust") + public static class ForeignCustomer extends Customer { + private String vat; + + public ForeignCustomer() { + super(); + } + + public ForeignCustomer(Integer id, String name, String vat) { + super( id, name ); + this.vat = vat; + } + + public String getVat() { + return vat; + } + + public void setVat(String vat) { + this.vat = vat; + } + } + + @Entity(name = "DomesticCustomer") + @Table(name = "domestic_cust") + public static class DomesticCustomer extends Customer { + private String taxId; + + public DomesticCustomer() { + super(); + } + + public DomesticCustomer(Integer id, String name, String taxId) { + super( id, name ); + this.taxId = taxId; + } + + public String getTaxId() { + return taxId; + } + + public void setTaxId(String taxId) { + this.taxId = taxId; + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/polymorphic/PolymorphicToOneImplicitOptionTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/polymorphic/PolymorphicToOneImplicitOptionTests.java new file mode 100644 index 000000000000..038fcdd8df88 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/polymorphic/PolymorphicToOneImplicitOptionTests.java @@ -0,0 +1,235 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.orm.test.mapping.lazytoone.polymorphic; + +import java.math.BigDecimal; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Inheritance; +import javax.persistence.InheritanceType; +import javax.persistence.ManyToOne; +import javax.persistence.Table; + +import org.hibernate.Hibernate; +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.proxy.HibernateProxy; + +import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; +import org.hibernate.testing.bytecode.enhancement.EnhancementOptions; +import org.hibernate.testing.jdbc.SQLStatementInterceptor; +import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static javax.persistence.FetchType.LAZY; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertFalse; + +/** + * @author Steve Ebersole + */ +@RunWith( BytecodeEnhancerRunner.class) +@EnhancementOptions( lazyLoading = true ) +public class PolymorphicToOneImplicitOptionTests extends BaseNonConfigCoreFunctionalTestCase { + @Test + public void testInheritedToOneLaziness() { + inTransaction( + (session) -> { + sqlStatementInterceptor.clear(); + + final Order order = session.byId( Order.class ).getReference( 1 ); + assertThat( sqlStatementInterceptor.getQueryCount(), is( 0 ) ); + + System.out.println( "Order # " + order.getId() ); + assertThat( sqlStatementInterceptor.getQueryCount(), is( 0 ) ); + + System.out.println( " - amount : " + order.getAmount() ); + // triggers load of base fetch state + assertThat( sqlStatementInterceptor.getQueryCount(), is( 1 ) ); + + final Customer customer = order.getCustomer(); + assertThat( sqlStatementInterceptor.getQueryCount(), is( 1 ) ); + // customer is part of base fetch state + assertFalse( Hibernate.isInitialized( customer ) ); + assertThat( customer, instanceOf( HibernateProxy.class ) ); + + System.out.println( " - customer : " + customer.getId() ); + assertThat( sqlStatementInterceptor.getQueryCount(), is( 1 ) ); + + customer.getName(); + assertThat( sqlStatementInterceptor.getQueryCount(), is( 2 ) ); + } + ); + } + + @Before + public void createTestData() { + inTransaction( + (session) -> { + final DomesticCustomer customer = new DomesticCustomer( 1, "them", "123" ); + session.persist( customer ); + final Order order = new Order( 1, BigDecimal.ONE, customer ); + session.persist( order ); + } + ); + } + + @After + public void dropTestData() { + inTransaction( + (session) -> { + session.createQuery( "delete Order" ).executeUpdate(); + session.createQuery( "delete Customer" ).executeUpdate(); + } + ); + } + + private SQLStatementInterceptor sqlStatementInterceptor; + + @Override + protected void applyMetadataSources(MetadataSources sources) { + super.applyMetadataSources( sources ); + sources.addAnnotatedClass( Order.class ); + sources.addAnnotatedClass( Customer.class ); + sources.addAnnotatedClass( ForeignCustomer.class ); + sources.addAnnotatedClass( DomesticCustomer.class ); + } + + @Override + protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { + super.configureStandardServiceRegistryBuilder( ssrb ); + ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, true ); + sqlStatementInterceptor = new SQLStatementInterceptor( ssrb ); + } + + @Entity( name = "Order" ) + @Table( name = "`order`" ) + public static class Order { + @Id + private Integer id; + private BigDecimal amount; + @ManyToOne( fetch = LAZY, optional = false ) + private Customer customer; + + public Order() { + } + + public Order(Integer id, BigDecimal amount, Customer customer) { + this.id = id; + this.amount = amount; + this.customer = customer; + } + + public Integer getId() { + return id; + } + + private void setId(Integer id) { + this.id = id; + } + + public BigDecimal getAmount() { + return amount; + } + + public void setAmount(BigDecimal amount) { + this.amount = amount; + } + + public Customer getCustomer() { + return customer; + } + + public void setCustomer(Customer customer) { + this.customer = customer; + } + } + + @Entity( name = "Customer" ) + @Inheritance( strategy = InheritanceType.TABLE_PER_CLASS ) + public static abstract class Customer { + @Id + private Integer id; + private String name; + + public Customer() { + } + + public Customer(Integer id, String name) { + this.id = id; + this.name = name; + } + + public Integer getId() { + return id; + } + + private void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } + + @Entity(name = "ForeignCustomer") + @Table(name = "foreign_cust") + public static class ForeignCustomer extends Customer { + private String vat; + + public ForeignCustomer() { + super(); + } + + public ForeignCustomer(Integer id, String name, String vat) { + super( id, name ); + this.vat = vat; + } + + public String getVat() { + return vat; + } + + public void setVat(String vat) { + this.vat = vat; + } + } + + @Entity(name = "DomesticCustomer") + @Table(name = "domestic_cust") + public static class DomesticCustomer extends Customer { + private String taxId; + + public DomesticCustomer() { + super(); + } + + public DomesticCustomer(Integer id, String name, String taxId) { + super( id, name ); + this.taxId = taxId; + } + + public String getTaxId() { + return taxId; + } + + public void setTaxId(String taxId) { + this.taxId = taxId; + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/cascade/CascadeDeleteManyToOneTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/cascade/CascadeDeleteManyToOneTest.java index 13179fd805c1..138e3aa9c0d4 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/cascade/CascadeDeleteManyToOneTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/cascade/CascadeDeleteManyToOneTest.java @@ -21,19 +21,26 @@ import org.hibernate.annotations.LazyToOne; import org.hibernate.annotations.LazyToOneOption; import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata; +import org.hibernate.cfg.Configuration; +import org.hibernate.proxy.HibernateProxy; -import org.hibernate.testing.FailureExpected; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; +import org.hibernate.testing.jdbc.SQLStatementInterceptor; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; +import static org.hibernate.testing.transaction.TransactionUtil2.fromTransaction; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; /** @@ -42,6 +49,7 @@ @TestForIssue(jiraKey = "HHH-10252") @RunWith(BytecodeEnhancerRunner.class) public class CascadeDeleteManyToOneTest extends BaseCoreFunctionalTestCase { + private SQLStatementInterceptor sqlInterceptor; private Child originalChild; @Override @@ -49,6 +57,12 @@ protected Class[] getAnnotatedClasses() { return new Class[] { Parent.class, Child.class }; } + @Override + protected void configure(Configuration configuration) { + super.configure( configuration ); + sqlInterceptor = new SQLStatementInterceptor( configuration ); + } + @Before public void prepare() { // Create a Parent with one Child @@ -64,77 +78,28 @@ public void prepare() { ); } - @Test - @FailureExpected( - jiraKey = "HHH-13658", - message = "Assertions specific to enhanced lazy loading but disallowing enhanced proxies, which is no longer valid" - ) - public void testManagedWithUninitializedAssociation() { - // Delete the Child - doInHibernate( - this::sessionFactory, s -> { - Child loadedChild = (Child) s.createQuery( "SELECT c FROM Child c WHERE name=:name" ) - .setParameter( "name", "CHILD" ) - .uniqueResult(); - checkInterceptor( loadedChild, false ); - assertFalse( Hibernate.isPropertyInitialized( loadedChild, "parent" ) ); - s.delete( loadedChild ); - } - ); - // Explicitly check that both got deleted - doInHibernate( - this::sessionFactory, s -> { - assertNull( s.createQuery( "FROM Child c" ).uniqueResult() ); - assertNull( s.createQuery( "FROM Parent p" ).uniqueResult() ); - } - ); - } - @Test public void testManagedWithInitializedAssociation() { + sqlInterceptor.clear(); + // Delete the Child - doInHibernate( - this::sessionFactory, s -> { - Child loadedChild = (Child) s.createQuery( "SELECT c FROM Child c WHERE name=:name" ) + inTransaction( + (s) -> { + final Child managedChild = (Child) s.createQuery( "SELECT c FROM Child c WHERE name=:name" ) .setParameter( "name", "CHILD" ) .uniqueResult(); - checkInterceptor( loadedChild, false ); - loadedChild.getParent(); - assertTrue( Hibernate.isPropertyInitialized( loadedChild, "parent" ) ); - s.delete( loadedChild ); - } - ); - // Explicitly check that both got deleted - doInHibernate( - this::sessionFactory, s -> { - assertNull( s.createQuery( "FROM Child c" ).uniqueResult() ); - assertNull( s.createQuery( "FROM Parent p" ).uniqueResult() ); - } - ); - } - @Test - @FailureExpected( - jiraKey = "HHH-13658", - message = "Assertions specific to enhanced lazy loading but disallowing enhanced proxies, which is no longer valid" - ) - public void testDetachedWithUninitializedAssociation() { - final Child detachedChild = doInHibernate( - this::sessionFactory, s -> { - return s.get( Child.class, originalChild.getId() ); - } - ); - - assertFalse( Hibernate.isPropertyInitialized( detachedChild, "parent" ) ); + assertThat( sqlInterceptor.getQueryCount(), is( 1 ) ); - checkInterceptor( detachedChild, false ); + // parent should be an uninitialized enhanced-proxy + assertTrue( Hibernate.isPropertyInitialized( managedChild, "parent" ) ); + assertThat( managedChild.getParent(), not( instanceOf( HibernateProxy.class ) ) ); + assertFalse( Hibernate.isInitialized( managedChild.getParent() ) ); - // Delete the detached Child with uninitialized parent - doInHibernate( - this::sessionFactory, s -> { - s.delete( detachedChild ); + s.delete( managedChild ); } ); + // Explicitly check that both got deleted doInHibernate( this::sessionFactory, s -> { @@ -145,18 +110,21 @@ public void testDetachedWithUninitializedAssociation() { } @Test - @FailureExpected( - jiraKey = "HHH-13658", - message = "Assertions specific to enhanced lazy loading but disallowing enhanced proxies, which is no longer valid" - ) public void testDetachedWithInitializedAssociation() { - final Child detachedChild = doInHibernate( - this::sessionFactory, s -> { + sqlInterceptor.clear(); + + final Child detachedChild = fromTransaction( + sessionFactory(), + (s) -> { Child child = s.get( Child.class, originalChild.getId() ); - assertFalse( Hibernate.isPropertyInitialized( child, "parent" ) ); - // initialize parent before detaching - child.getParent(); + assertThat( sqlInterceptor.getQueryCount(), is( 1 ) ); + + // parent should be an uninitialized enhanced-proxy + assertTrue( Hibernate.isPropertyInitialized( child, "parent" ) ); + assertThat( child.getParent(), not( instanceOf( HibernateProxy.class ) ) ); + assertFalse( Hibernate.isInitialized( child.getParent() ) ); + return child; } ); @@ -166,14 +134,13 @@ public void testDetachedWithInitializedAssociation() { checkInterceptor( detachedChild, false ); // Delete the detached Child with initialized parent - doInHibernate( - this::sessionFactory, s -> { - s.delete( detachedChild ); - } + inTransaction( + (s) -> s.delete( detachedChild ) ); + // Explicitly check that both got deleted - doInHibernate( - this::sessionFactory, s -> { + inTransaction( + (s) -> { assertNull( s.createQuery( "FROM Child c" ).uniqueResult() ); assertNull( s.createQuery( "FROM Parent p" ).uniqueResult() ); } @@ -204,8 +171,7 @@ public void testDetachedOriginal() { } private void checkInterceptor(Child child, boolean isNullExpected) { - final BytecodeEnhancementMetadata bytecodeEnhancementMetadata = - sessionFactory() + final BytecodeEnhancementMetadata bytecodeEnhancementMetadata = sessionFactory() .getMetamodel() .entityPersister( Child.class ) .getEntityMetamodel() diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/cascade/CascadeOnUninitializedTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/cascade/CascadeOnUninitializedTest.java index adbf88cf8d33..c9ac10d5cf9d 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/cascade/CascadeOnUninitializedTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/cascade/CascadeOnUninitializedTest.java @@ -18,18 +18,23 @@ import org.hibernate.annotations.LazyToOne; import org.hibernate.annotations.LazyToOneOption; import org.hibernate.cfg.AvailableSettings; +import org.hibernate.proxy.HibernateProxy; -import org.hibernate.testing.FailureExpected; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; +import org.hibernate.testing.jdbc.SQLStatementInterceptor; import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; import org.hibernate.testing.transaction.TransactionUtil; import org.junit.Test; import org.junit.runner.RunWith; import static junit.framework.TestCase.assertEquals; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; /** @@ -39,81 +44,97 @@ @RunWith(BytecodeEnhancerRunner.class) @TestForIssue(jiraKey = "HHH-13129") public class CascadeOnUninitializedTest extends BaseNonConfigCoreFunctionalTestCase { + private SQLStatementInterceptor sqlInterceptor; + @Override protected Class[] getAnnotatedClasses() { - return new Class[] { - Person.class, - Address.class, - }; + return new Class[] { Person.class, Address.class }; } @Override protected void addSettings(Map settings) { super.addSettings( settings ); - settings.put( AvailableSettings.SHOW_SQL, "true" ); settings.put( AvailableSettings.FORMAT_SQL, "true" ); + sqlInterceptor = new SQLStatementInterceptor( settings ); } @Test - @FailureExpected( - jiraKey = "HHH-13658", - message = "Assertions specific to enhanced lazy loading but disallowing enhanced proxies, which is no longer valid" - ) public void testMergeDetachedEnhancedEntityWithUninitializedManyToOne() { + final Person person = persistPersonWithManyToOne(); - Person person = persistPersonWithManyToOne(); + sqlInterceptor.clear(); // get a detached Person - Person detachedPerson = TransactionUtil.doInHibernate( - this::sessionFactory, session -> { - return session.get( Person.class, person.getId() ); - } + final Person detachedPerson = fromTransaction( + session -> session.get( Person.class, person.getId() ) ); - // address should not be initialized - assertFalse( Hibernate.isPropertyInitialized( detachedPerson, "primaryAddress" ) ); + // loading Person should lead to one SQL + assertThat( sqlInterceptor.getQueryCount(), is( 1 ) ); + + // primaryAddress should be "initialized" as an enhanced-proxy + assertTrue( Hibernate.isPropertyInitialized( detachedPerson, "primaryAddress" ) ); + assertThat( detachedPerson.getPrimaryAddress(), not( instanceOf( HibernateProxy.class ) ) ); + assertFalse( Hibernate.isInitialized( detachedPerson.getPrimaryAddress() ) ); + + // alter the detached reference detachedPerson.setName( "newName" ); - Person mergedPerson = TransactionUtil.doInHibernate( - this::sessionFactory, session -> { - return (Person) session.merge( detachedPerson ); - } + final Person mergedPerson = fromTransaction( + session -> (Person) session.merge( detachedPerson ) ); - // address should not be initialized - assertFalse( Hibernate.isPropertyInitialized( mergedPerson, "primaryAddress" ) ); + // 1) select Person#addresses + // 2) select Person#primaryAddress + // 3) update Person + + assertThat( sqlInterceptor.getQueryCount(), is( 3 ) ); + + // primaryAddress should not be initialized + assertTrue( Hibernate.isPropertyInitialized( detachedPerson, "primaryAddress" ) ); + assertThat( detachedPerson.getPrimaryAddress(), not( instanceOf( HibernateProxy.class ) ) ); + assertFalse( Hibernate.isInitialized( detachedPerson.getPrimaryAddress() ) ); + assertEquals( "newName", mergedPerson.getName() ); } @Test - @FailureExpected( - jiraKey = "HHH-13658", - message = "Assertions specific to enhanced lazy loading but disallowing enhanced proxies, which is no longer valid" - ) public void testDeleteEnhancedEntityWithUninitializedManyToOne() { Person person = persistPersonWithManyToOne(); + sqlInterceptor.clear(); + // get a detached Person - Person detachedPerson = TransactionUtil.doInHibernate( - this::sessionFactory, session -> { - return session.get( Person.class, person.getId() ); - } + Person detachedPerson = fromTransaction( + session -> session.get( Person.class, person.getId() ) ); - // address should not be initialized - assertFalse( Hibernate.isPropertyInitialized( detachedPerson, "primaryAddress" ) ); + // loading Person should lead to one SQL + assertThat( sqlInterceptor.getQueryCount(), is( 1 ) ); - // deleting detachedPerson should result in detachedPerson.address being initialized, + // primaryAddress should be initialized as an enhance-proxy + assertTrue( Hibernate.isPropertyInitialized( detachedPerson, "primaryAddress" ) ); + assertThat( detachedPerson, not( instanceOf( HibernateProxy.class ) ) ); + assertFalse( Hibernate.isInitialized( detachedPerson.getPrimaryAddress() ) ); + + sqlInterceptor.clear(); + + // deleting detachedPerson should result in detachedPerson.primaryAddress being initialized, // so that the DELETE operation can be cascaded to it. - TransactionUtil.doInHibernate( - this::sessionFactory, session -> { - session.delete( detachedPerson ); - } + inTransaction( + session -> session.delete( detachedPerson ) ); + // 1) select Person#addresses + // 2) select Person#primaryAddress + // 3) delete Person + // 4) select primary Address + + assertThat( sqlInterceptor.getQueryCount(), is( 4 ) ); + // both the Person and its Address should be deleted - TransactionUtil.doInHibernate( - this::sessionFactory, session -> { + inTransaction( + session -> { assertNull( session.get( Person.class, person.getId() ) ); assertNull( session.get( Person.class, person.getPrimaryAddress().getId() ) ); } @@ -223,12 +244,12 @@ public static class Person { private String name; @ManyToOne(cascade = { CascadeType.ALL }, fetch = FetchType.LAZY) - @JoinColumn(name = "ADDRESS_ID") + @JoinColumn(name = "primary_address_id") @LazyToOne(LazyToOneOption.NO_PROXY) private Address primaryAddress; @OneToMany(cascade = CascadeType.ALL, fetch = FetchType.LAZY) - @JoinColumn + @JoinColumn( name = "person_id" ) private Set

addresses = new HashSet<>(); public Long getId() { diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/BidirectionalLazyTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/BidirectionalLazyTest.java index 5b11dd827ccf..5b9431a0255b 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/BidirectionalLazyTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/BidirectionalLazyTest.java @@ -20,13 +20,14 @@ import org.hibernate.annotations.LazyToOne; import org.hibernate.annotations.LazyToOneOption; import org.hibernate.bytecode.enhance.spi.DefaultEnhancementContext; -import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer; import org.hibernate.bytecode.enhance.spi.UnloadedClass; import org.hibernate.bytecode.enhance.spi.UnloadedField; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.cfg.Configuration; import org.hibernate.engine.spi.EntityEntry; import org.hibernate.engine.spi.SessionImplementor; +import org.hibernate.proxy.HibernateProxy; -import org.hibernate.testing.FailureExpected; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; import org.hibernate.testing.bytecode.enhancement.CustomEnhancementContext; @@ -35,7 +36,10 @@ import org.junit.Test; import org.junit.runner.RunWith; -import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.not; +import static org.hamcrest.CoreMatchers.sameInstance; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; @@ -54,21 +58,26 @@ EnhancerTestContext.class, // supports laziness and dirty-checking BidirectionalLazyTest.NoDirtyCheckEnhancementContext.class // supports laziness; does not support dirty-checking }) -@FailureExpected( - jiraKey = "HHH-13658", - message = "Assertions specific to enhanced lazy loading but disallowing enhanced proxies, which is no longer valid" -) public class BidirectionalLazyTest extends BaseCoreFunctionalTestCase { + // NOTE : tests in this class seem redundant because they assert things that happened + // in previous versions that have been fixed + public Class[] getAnnotatedClasses() { return new Class[] { Employer.class, Employee.class, Unrelated.class }; } + @Override + protected void configure(Configuration configuration) { + super.configure( configuration ); + configuration.setProperty( AvailableSettings.USE_SECOND_LEVEL_CACHE, "false" ); + } + @Test public void testRemoveWithDeletedAssociatedEntity() { - doInHibernate( - this::sessionFactory, session -> { + inTransaction( + (session) -> { Employer employer = new Employer( "RedHat" ); session.persist( employer ); @@ -81,27 +90,27 @@ public void testRemoveWithDeletedAssociatedEntity() { } ); - doInHibernate( - this::sessionFactory, session -> { + inTransaction( + (session) -> { Employer employer = session.get( Employer.class, "RedHat" ); // Delete the associated entity first session.remove( employer ); for ( Employee employee : employer.getEmployees() ) { - assertFalse( Hibernate.isPropertyInitialized( employee, "employer" ) ); - session.remove( employee ); - // Should be initialized because at least one entity was deleted beforehand assertTrue( Hibernate.isPropertyInitialized( employee, "employer" ) ); + session.remove( employee ); + assertSame( employer, employee.getEmployer() ); + // employee.getEmployer was initialized, and should be nullified in EntityEntry#deletedState checkEntityEntryState( session, employee, employer, true ); } } ); - doInHibernate( - this::sessionFactory, session -> { + inTransaction( + (session) -> { assertNull( session.find( Employer.class, "RedHat" ) ); assertTrue( session.createQuery( "from Employee e", Employee.class ).getResultList().isEmpty() ); } @@ -111,8 +120,8 @@ public void testRemoveWithDeletedAssociatedEntity() { @Test public void testRemoveWithNonAssociatedRemovedEntity() { - doInHibernate( - this::sessionFactory, session -> { + inTransaction( + (session) -> { Employer employer = new Employer( "RedHat" ); session.persist( employer ); Employee employee = new Employee( "Jack" ); @@ -122,22 +131,22 @@ public void testRemoveWithNonAssociatedRemovedEntity() { } ); - doInHibernate( - this::sessionFactory, session -> { + inTransaction( + (session) -> { // Delete an entity that is not associated with Employee session.remove( session.get( Unrelated.class, 1 ) ); final Employee employee = session.get( Employee.class, "Jack" ); - assertFalse( Hibernate.isPropertyInitialized( employee, "employer" ) ); - session.remove( employee ); - // Should be initialized because at least one entity was deleted beforehand assertTrue( Hibernate.isPropertyInitialized( employee, "employer" ) ); + + session.remove( employee ); + // employee.getEmployer was initialized, and should not be nullified in EntityEntry#deletedState checkEntityEntryState( session, employee, employee.getEmployer(), false ); } ); - doInHibernate( - this::sessionFactory, session -> { + inTransaction( + (session) -> { assertNull( session.find( Unrelated.class, 1 ) ); assertNull( session.find( Employee.class, "Jack" ) ); session.remove( session.find( Employer.class, "RedHat" ) ); @@ -148,8 +157,8 @@ public void testRemoveWithNonAssociatedRemovedEntity() { @Test public void testRemoveWithNoRemovedEntities() { - doInHibernate( - this::sessionFactory, session -> { + inTransaction( + (session) -> { Employer employer = new Employer( "RedHat" ); session.persist( employer ); Employee employee = new Employee( "Jack" ); @@ -158,22 +167,25 @@ public void testRemoveWithNoRemovedEntities() { } ); - doInHibernate( - this::sessionFactory, session -> { + inTransaction( + (session) -> { // Don't delete any entities before deleting the Employee final Employee employee = session.get( Employee.class, "Jack" ); - assertFalse( Hibernate.isPropertyInitialized( employee, "employer" ) ); + verifyBaseState( employee ); + session.remove( employee ); - // There were no other deleted entities before employee was deleted, - // so there was no need to initialize employee.employer. - assertFalse( Hibernate.isPropertyInitialized( employee, "employer" ) ); - // employee.getEmployer was not initialized, and should not be nullified in EntityEntry#deletedState - checkEntityEntryState( session, employee, LazyPropertyInitializer.UNFETCHED_PROPERTY, false ); + + Employer employer = session.get( Employer.class, "RedHat" ); + verifyBaseState( employer ); + + assertThat( employee.getEmployer(), sameInstance( employer ) ); + + checkEntityEntryState( session, employee, employer, false ); } ); - doInHibernate( - this::sessionFactory, session -> { + inTransaction( + (session) -> { assertNull( session.find( Employee.class, "Jack" ) ); session.remove( session.find( Employer.class, "RedHat" ) ); } @@ -183,8 +195,8 @@ public void testRemoveWithNoRemovedEntities() { @Test public void testRemoveEntityWithNullLazyManyToOne() { - doInHibernate( - this::sessionFactory, session -> { + inTransaction( + (session) -> { Employer employer = new Employer( "RedHat" ); session.persist( employer ); Employee employee = new Employee( "Jack" ); @@ -192,22 +204,17 @@ public void testRemoveEntityWithNullLazyManyToOne() { } ); - doInHibernate( - this::sessionFactory, session -> { + inTransaction( + (session) -> { Employee employee = session.get( Employee.class, "Jack" ); - assertFalse( Hibernate.isPropertyInitialized( employee, "employer" ) ); + verifyBaseState( employee ); // Get and delete an Employer that is not associated with employee Employer employer = session.get( Employer.class, "RedHat" ); - session.remove( employer ); + verifyBaseState( employer ); - // employee.employer is uninitialized. Since the column for employee.employer - // is a foreign key, and there is an Employer that has already been removed, - // employee.employer will need to be iniitialized to determine if - // employee.employer is nullifiable. - assertFalse( Hibernate.isPropertyInitialized( employee, "employer" ) ); + session.remove( employer ); session.remove( employee ); - assertTrue( Hibernate.isPropertyInitialized( employee, "employer" ) ); } ); } @@ -231,23 +238,37 @@ public void testRemoveEntityWithLinkedLazyManyToOne() { inTransaction( session -> { Employee employee = session.get( Employee.class, "Jack" ); - assertFalse( Hibernate.isPropertyInitialized( employee, "employer" ) ); + verifyBaseState( employee ); // Get and delete an Employer that is not associated with employee Employer employer = session.get( Employer.class, "RedHat" ); - session.remove( employer ); + verifyBaseState( employer ); - // employee.employer is uninitialized. Since the column for employee.employer - // is a foreign key, and there is an Employer that has already been removed, - // employee.employer will need to be iniitialized to determine if - // employee.employer is nullifiable. - assertFalse( Hibernate.isPropertyInitialized( employee, "employer" ) ); + assertThat( employee.getEmployer(), sameInstance( employer ) ); + + session.remove( employer ); session.remove( employee ); - assertTrue( Hibernate.isPropertyInitialized( employee, "employer" ) ); } ); } + private void verifyBaseState(Employer employer) { + assertTrue( Hibernate.isPropertyInitialized( employer, "name" ) ); + } + + private void verifyBaseState(Employee employee) { + assertTrue( Hibernate.isPropertyInitialized( employee, "name" ) ); + + // employer will be either null or an uninitialized enhanced-proxy + assertTrue( Hibernate.isPropertyInitialized( employee, "employer" ) ); + + final Employer employer = employee.getEmployer(); + if ( employer != null ) { + assertFalse( Hibernate.isInitialized( employer ) ); + assertThat(employer, not( instanceOf( HibernateProxy.class ) ) ); + } + } + private void checkEntityEntryState( final Session session, final Employee employee, @@ -261,7 +282,7 @@ private void checkEntityEntryState( entityEntry.getLoadedState()[propertyNumber] ); if ( isEmployerNullified ) { - assertEquals( null, entityEntry.getDeletedState()[propertyNumber] ); + assertNull( entityEntry.getDeletedState()[ propertyNumber ] ); } else { assertEquals( @@ -372,7 +393,7 @@ public boolean equals(Object o) { return true; } else if ( o instanceof Employee ) { - Employee other = Employee.class.cast( o ); + Employee other = (Employee) o; if ( name != null ) { return getName().equals( other.getName() ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/NaturalIdInUninitializedAssociationTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/NaturalIdInUninitializedAssociationTest.java index dec35dcb8297..7fe20e03e0cb 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/NaturalIdInUninitializedAssociationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/NaturalIdInUninitializedAssociationTest.java @@ -21,7 +21,6 @@ import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cfg.AvailableSettings; -import org.hibernate.testing.FailureExpected; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; import org.hibernate.testing.bytecode.enhancement.EnhancementOptions; @@ -33,6 +32,8 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; /** * @author Gail Badner @@ -44,36 +45,39 @@ public class NaturalIdInUninitializedAssociationTest extends BaseNonConfigCoreFunctionalTestCase { @Test - @FailureExpected( - jiraKey = "HHH-13658", - message = "Assertions specific to enhanced lazy loading but disallowing enhanced proxies, which is no longer valid" - ) - public void testImmutableNaturalId() { + public void testLoad() { inTransaction( session -> { - final AnEntity e = session.get( AnEntity.class, 3 ); - assertFalse( Hibernate.isPropertyInitialized( e,"entityImmutableNaturalId" ) ); - } - ); + final AnEntity e = session.byId( AnEntity.class ).load(3 ); + assertTrue( Hibernate.isInitialized( e ) ); - inTransaction( - session -> { - final AnEntity e = session.get( AnEntity.class, 3 ); + // because we can (enhanced) proxy both EntityMutableNaturalId and EntityImmutableNaturalId + // we will select their FKs and all attributes will be "bytecode initialized" + assertTrue( Hibernate.isPropertyInitialized( e,"entityMutableNaturalId" ) ); + assertTrue( Hibernate.isPropertyInitialized( e,"entityImmutableNaturalId" ) ); + + assertEquals( "mutable name", e.entityMutableNaturalId.name ); assertEquals( "immutable name", e.entityImmutableNaturalId.name ); } ); } @Test - @FailureExpected( - jiraKey = "HHH-13658", - message = "Assertions specific to enhanced lazy loading but disallowing enhanced proxies, which is no longer valid" - ) - public void testMutableNaturalId() { + public void testGetReference() { inTransaction( session -> { - final AnEntity e = session.get( AnEntity.class, 3 ); - assertFalse( Hibernate.isPropertyInitialized( e,"entityMutableNaturalId" ) ); + final AnEntity e = session.byId( AnEntity.class ).getReference( 3 ); + assertFalse( Hibernate.isInitialized( e ) ); + + // trigger initialization + Hibernate.initialize( e ); + // silly, but... + assertTrue( Hibernate.isInitialized( e ) ); + + // because we can (enhanced) proxy both EntityMutableNaturalId and EntityImmutableNaturalId + // we will select their FKs and all attributes will be "bytecode initialized" + assertTrue( Hibernate.isPropertyInitialized( e,"entityMutableNaturalId" ) ); + assertTrue( Hibernate.isPropertyInitialized( e,"entityImmutableNaturalId" ) ); } ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/cache/UninitializedAssociationsInCacheTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/cache/UninitializedAssociationsInCacheTest.java index 7659cca0baf1..53830b12fc96 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/cache/UninitializedAssociationsInCacheTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/cache/UninitializedAssociationsInCacheTest.java @@ -1,20 +1,16 @@ package org.hibernate.test.bytecode.enhancement.lazy.cache; +import java.util.ArrayList; +import java.util.List; import javax.persistence.Basic; import javax.persistence.Cacheable; import javax.persistence.Entity; import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; import javax.persistence.Id; import javax.persistence.JoinColumn; import javax.persistence.ManyToOne; import javax.persistence.OneToMany; import javax.persistence.Table; -import javax.validation.constraints.AssertTrue; -import java.util.ArrayList; -import java.util.List; -import java.util.concurrent.atomic.AtomicLong; import org.hibernate.Hibernate; import org.hibernate.annotations.Cache; @@ -23,18 +19,21 @@ import org.hibernate.annotations.LazyToOneOption; import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.Configuration; +import org.hibernate.proxy.HibernateProxy; import org.hibernate.stat.CacheRegionStatistics; -import org.hibernate.testing.FailureExpected; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; -import org.hibernate.testing.transaction.TransactionUtil; import org.junit.Assert; import org.junit.Test; import org.junit.runner.RunWith; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.not; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; @RunWith(BytecodeEnhancerRunner.class) public class UninitializedAssociationsInCacheTest extends BaseCoreFunctionalTestCase { @@ -53,33 +52,21 @@ protected void configure(Configuration configuration) { @Test @TestForIssue( jiraKey = "HHH-11766") - @FailureExpected( - jiraKey = "HHH-13658", - message = "Assertions specific to enhanced lazy loading but disallowing enhanced proxies, which is no longer valid" - ) public void attributeLoadingFromCache() { - final AtomicLong bossId = new AtomicLong(); - final AtomicLong teamleaderId = new AtomicLong(); - final AtomicLong teammemberId = new AtomicLong(); - - TransactionUtil.doInHibernate( - this::sessionFactory, (s) -> { - Employee boss = new Employee(); - Employee teamleader = new Employee(); - Employee teammember = new Employee(); - boss.regularString = "boss"; - teamleader.regularString = "leader"; - teammember.regularString = "member"; + inTransaction( + (s) -> { + Employee boss = new Employee( 1, "boss" ); + Employee teamleader = new Employee( 2, "leader" ); + Employee teammember = new Employee( 3, "member" ); s.persist( boss ); s.persist( teamleader ); s.persist( teammember ); + boss.subordinates.add( teamleader ); teamleader.superior = boss; + teamleader.subordinates.add( teammember ); teammember.superior = teamleader; - bossId.set( boss.id ); - teamleaderId.set( teamleader.id ); - teammemberId.set( teammember.id ); } ); @@ -87,19 +74,28 @@ public void attributeLoadingFromCache() { sessionFactory().getStatistics().clear(); CacheRegionStatistics regionStatistics = sessionFactory().getStatistics().getCacheRegionStatistics( "Employee" ); - TransactionUtil.doInHibernate( - this::sessionFactory, (s) -> { - final Employee boss = s.find( Employee.class, bossId.get() ); + inTransaction( + (s) -> { + final Employee boss = s.find( Employee.class, 1 ); Assert.assertEquals( "boss", boss.regularString ); - final Employee leader = s.find( Employee.class, teamleaderId.get() ); + final Employee leader = s.find( Employee.class, 2 ); Assert.assertEquals( "leader", leader.regularString ); - final Employee member = s.find( Employee.class, teammemberId.get() ); + final Employee member = s.find( Employee.class, 3 ); Assert.assertEquals( "member", member.regularString ); - Assert.assertFalse( Hibernate.isPropertyInitialized( boss, "superior" ) ); + + assertTrue( Hibernate.isPropertyInitialized( boss, "superior" ) ); + assertTrue( Hibernate.isInitialized( boss.superior ) ); + assertThat( boss.superior, not( instanceOf( HibernateProxy.class ) ) ); Assert.assertFalse( Hibernate.isPropertyInitialized( boss, "subordinates" ) ); - Assert.assertFalse( Hibernate.isPropertyInitialized( leader, "superior" ) ); + + assertTrue( Hibernate.isPropertyInitialized( leader, "superior" ) ); + assertTrue( Hibernate.isInitialized( leader.superior ) ); + assertThat( leader.superior, not( instanceOf( HibernateProxy.class ) ) ); Assert.assertFalse( Hibernate.isPropertyInitialized( leader, "subordinates" ) ); - Assert.assertFalse( Hibernate.isPropertyInitialized( member, "superior" ) ); + + assertTrue( Hibernate.isPropertyInitialized( member, "superior" ) ); + assertTrue( Hibernate.isInitialized( member.superior ) ); + assertThat( member.superior, not( instanceOf( HibernateProxy.class ) ) ); Assert.assertFalse( Hibernate.isPropertyInitialized( member, "subordinates" ) ); } ); @@ -108,37 +104,34 @@ public void attributeLoadingFromCache() { assertEquals( 3, regionStatistics.getMissCount() ); assertEquals( 3, regionStatistics.getPutCount() ); - TransactionUtil.doInHibernate( - this::sessionFactory, (s) -> { - final Employee boss = s.find( Employee.class, bossId.get() ); - final Employee leader = s.find( Employee.class, teamleaderId.get() ); - final Employee member = s.find( Employee.class, teammemberId.get() ); - Assert.assertFalse( Hibernate.isPropertyInitialized( boss, "superior" ) ); + inTransaction( + (s) -> { + final Employee boss = s.find( Employee.class, 1 ); + final Employee leader = s.find( Employee.class, 2 ); + final Employee member = s.find( Employee.class, 3 ); + Assert.assertTrue( Hibernate.isPropertyInitialized( boss, "superior" ) ); Assert.assertFalse( Hibernate.isPropertyInitialized( boss, "subordinates" ) ); - Assert.assertFalse( Hibernate.isPropertyInitialized( member, "superior" ) ); + Assert.assertTrue( Hibernate.isPropertyInitialized( member, "superior" ) ); Assert.assertFalse( Hibernate.isPropertyInitialized( member, "subordinates" ) ); Assert.assertNull( boss.superior ); - Assert.assertTrue( Hibernate.isPropertyInitialized( boss, "superior" ) ); + + assertTrue( Hibernate.isPropertyInitialized( boss, "superior" ) ); Assert.assertFalse( Hibernate.isPropertyInitialized( boss, "subordinates" ) ); Assert.assertEquals( leader, boss.subordinates.iterator().next() ); - Assert.assertTrue( Hibernate.isPropertyInitialized( boss, "subordinates" ) ); + assertTrue( Hibernate.isPropertyInitialized( boss, "subordinates" ) ); - Assert.assertFalse( Hibernate.isPropertyInitialized( leader, "superior" ) ); - Assert.assertFalse( Hibernate.isPropertyInitialized( leader, "subordinates" ) ); - Assert.assertEquals( boss, leader.superior ); Assert.assertTrue( Hibernate.isPropertyInitialized( leader, "superior" ) ); Assert.assertFalse( Hibernate.isPropertyInitialized( leader, "subordinates" ) ); + Assert.assertEquals( boss, leader.superior ); Assert.assertEquals( member, leader.subordinates.iterator().next() ); - Assert.assertTrue( Hibernate.isPropertyInitialized( leader, "subordinates" ) ); + assertTrue( Hibernate.isPropertyInitialized( leader, "subordinates" ) ); - Assert.assertFalse( Hibernate.isPropertyInitialized( member, "superior" ) ); - Assert.assertFalse( Hibernate.isPropertyInitialized( member, "subordinates" ) ); - Assert.assertEquals( leader, member.superior ); Assert.assertTrue( Hibernate.isPropertyInitialized( member, "superior" ) ); Assert.assertFalse( Hibernate.isPropertyInitialized( member, "subordinates" ) ); - Assert.assertTrue( member.subordinates.isEmpty() ); - Assert.assertTrue( Hibernate.isPropertyInitialized( member, "subordinates" ) ); + Assert.assertEquals( leader, member.superior ); + assertTrue( member.subordinates.isEmpty() ); + assertTrue( Hibernate.isPropertyInitialized( member, "subordinates" ) ); } ); @@ -152,10 +145,8 @@ public void attributeLoadingFromCache() { @Cacheable @Cache(usage = CacheConcurrencyStrategy.NONSTRICT_READ_WRITE, region = "Employee") private static class Employee { - @Id - @GeneratedValue(strategy = GenerationType.AUTO) - Long id; + Integer id; @ManyToOne(fetch = FetchType.LAZY) @JoinColumn(name = "SUPERIOR") @@ -167,5 +158,18 @@ private static class Employee { @Basic String regularString; + + private Employee() { + } + + public Employee(Integer id, String regularString) { + this.id = id; + this.regularString = regularString; + } + + @Override + public String toString() { + return String.format( "Employee( %s, %s )", id, regularString ) + "@" + System.identityHashCode( this ); + } } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/group/BidirectionalLazyGroupsTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/group/BidirectionalLazyGroupsTest.java index 9fa36a539ea6..4fdeee8d4a3c 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/group/BidirectionalLazyGroupsTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/group/BidirectionalLazyGroupsTest.java @@ -23,7 +23,6 @@ import org.hibernate.bytecode.enhance.spi.DefaultEnhancementContext; import org.hibernate.bytecode.enhance.spi.UnloadedClass; -import org.hibernate.testing.FailureExpected; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; import org.hibernate.testing.bytecode.enhancement.CustomEnhancementContext; @@ -32,9 +31,10 @@ import org.junit.Test; import org.junit.runner.RunWith; -import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; -import static org.junit.Assert.assertFalse; +import org.hamcrest.CoreMatchers; + import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThat; import static org.junit.Assert.assertTrue; /** @@ -49,10 +49,6 @@ EnhancerTestContext.class, BidirectionalLazyGroupsTest.NoDirtyCheckEnhancementContext.class }) -@FailureExpected( - jiraKey = "HHH-13658", - message = "Assertions specific to enhanced lazy loading but disallowing enhanced proxies, which is no longer valid" -) public class BidirectionalLazyGroupsTest extends BaseCoreFunctionalTestCase { public Class[] getAnnotatedClasses() { @@ -61,11 +57,9 @@ public Class[] getAnnotatedClasses() { @Test public void testRemoveCollectionOwnerNoCascade() { - - doInHibernate( - this::sessionFactory, session -> { - - Employer employer = new Employer( "RedHat" ); + inTransaction( + (session) -> { + final Employer employer = new Employer( "RedHat" ); session.persist( employer ); employer.addEmployee( new Employee( "Jack" ) ); employer.addEmployee( new Employee( "Jill" ) ); @@ -76,20 +70,21 @@ public void testRemoveCollectionOwnerNoCascade() { } ); - doInHibernate( - this::sessionFactory, session -> { - Employer employer = session.createQuery( "from Employer e", Employer.class ).getSingleResult(); + inTransaction( + (session) -> { + final Employer employer = session.createQuery( "from Employer e", Employer.class ).getSingleResult(); session.remove( employer ); for ( Employee employee : employer.getEmployees() ) { - assertFalse( Hibernate.isPropertyInitialized( employee, "employer") ); + assertTrue( Hibernate.isPropertyInitialized( employee, "employer") ); + assertThat( employee.getEmployer(), CoreMatchers.sameInstance( employer ) ); + session.remove( employee ); - assertTrue( Hibernate.isPropertyInitialized( employee, "employer" ) ); } } ); - doInHibernate( - this::sessionFactory, session -> { + inTransaction( + (session) -> { assertNull( session.find( Employer.class, "RedHat" ) ); assertNull( session.createQuery( "from Employee e", Employee.class ).uniqueResult() ); } @@ -200,7 +195,7 @@ public boolean equals(Object o) { return true; } else if ( o instanceof Employee ) { - Employee other = Employee.class.cast( o ); + Employee other = (Employee) o; if ( name != null ) { return getName().equals( other.getName() ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/group/LazyGroupTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/group/LazyGroupTest.java index 3501d1e2dbb5..cff8ab8a656f 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/group/LazyGroupTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/group/LazyGroupTest.java @@ -6,6 +6,20 @@ */ package org.hibernate.test.bytecode.enhancement.lazy.group; +import java.util.ArrayList; +import java.util.List; +import javax.persistence.Basic; +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import javax.persistence.Table; + +import org.hibernate.Hibernate; import org.hibernate.annotations.LazyGroup; import org.hibernate.annotations.LazyToOne; import org.hibernate.annotations.LazyToOneOption; @@ -13,45 +27,30 @@ import org.hibernate.cfg.Configuration; import org.hibernate.proxy.HibernateProxy; -import org.hibernate.testing.FailureExpected; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; +import org.hibernate.testing.jdbc.SQLStatementInterceptor; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; -import javax.persistence.Basic; -import javax.persistence.CascadeType; -import javax.persistence.Entity; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.ManyToOne; -import javax.persistence.OneToMany; -import javax.persistence.Table; -import java.util.ArrayList; -import java.util.List; - -import static org.hibernate.testing.bytecode.enhancement.EnhancerTestUtils.getFieldByReflection; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.CoreMatchers.not; import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; -import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; /** * @author Steve Ebersole */ @TestForIssue( jiraKey = "HHH-11155" ) @RunWith( BytecodeEnhancerRunner.class ) -@FailureExpected( - jiraKey = "HHH-13658", - message = "Assertions specific to enhanced lazy loading but disallowing enhanced proxies, which is no longer valid" -) public class LazyGroupTest extends BaseCoreFunctionalTestCase { + private SQLStatementInterceptor sqlInterceptor; @Override public Class[] getAnnotatedClasses() { @@ -62,6 +61,7 @@ public Class[] getAnnotatedClasses() { protected void configure(Configuration configuration) { configuration.setProperty( AvailableSettings.USE_SECOND_LEVEL_CACHE, "false" ); configuration.setProperty( AvailableSettings.ENABLE_LAZY_LOAD_NO_TRANS, "true" ); + sqlInterceptor = new SQLStatementInterceptor( configuration ); } @Before @@ -93,39 +93,50 @@ public void prepare() { @Test @TestForIssue( jiraKey = "HHH-10267" ) public void testAccess() { - doInHibernate( this::sessionFactory, s -> { - Child c1 = (Child) s.createQuery( "from Child c where c.name = :name" ).setParameter( "name", "steve" ).uniqueResult(); - - // verify the expected initial loaded state - assertLoaded( c1, "name" ); - assertNotLoaded( c1, "nickName" ); - assertNotLoaded( c1, "parent" ); - assertNotLoaded( c1, "alternateParent" ); - - // Now lets access nickName which ought to initialize nickName and parent, but not alternateParent - c1.getNickName(); - assertLoaded( c1, "nickName" ); - assertLoaded( c1, "parent" ); - assertNotLoaded( c1, "alternateParent" ); - assertEquals( "Hibernate", c1.parent.nombre ); - assertFalse( c1.parent instanceof HibernateProxy ); - - Child c2 = (Child) s.createQuery( "from Child c where c.name = :name" ).setParameter( "name", "sally" ).uniqueResult(); - - // verify the expected initial loaded state - assertLoaded( c2, "name" ); - assertNotLoaded( c2, "nickName" ); - assertNotLoaded( c2, "parent" ); - assertNotLoaded( c2, "alternateParent" ); - - // Now lets access alternateParent which ought to initialize alternateParent and nothing else - c2.getAlternateParent(); - assertNotLoaded( c2, "nickName" ); - assertNotLoaded( c2, "parent" ); - assertLoaded( c2, "alternateParent" ); - assertEquals( "Hibernate", c2.alternateParent.nombre ); - assertFalse( c2.alternateParent instanceof HibernateProxy ); - } ); + sqlInterceptor.clear(); + + inTransaction( + (s) -> { + final Child c1 = s.createQuery( "from Child c where c.name = :name", Child.class ) + .setParameter( "name", "steve" ) + .uniqueResult(); + + assertThat( sqlInterceptor.getQueryCount(), is( 1 ) ); + + assertTrue( Hibernate.isPropertyInitialized( c1, "name" ) ); + + assertFalse( Hibernate.isPropertyInitialized( c1, "nickName" ) ); + + // parent should be an uninitialized enhanced-proxy + assertTrue( Hibernate.isPropertyInitialized( c1, "parent" ) ); + assertThat( c1.getParent(), not( instanceOf( HibernateProxy.class ) ) ); + assertFalse( Hibernate.isInitialized( c1.getParent() ) ); + + // alternateParent should be an uninitialized enhanced-proxy + assertTrue( Hibernate.isPropertyInitialized( c1, "alternateParent" ) ); + assertThat( c1.getAlternateParent(), not( instanceOf( HibernateProxy.class ) ) ); + assertFalse( Hibernate.isInitialized( c1.getAlternateParent() ) ); + + // Now lets access nickName which ought to initialize nickName + c1.getNickName(); + assertThat( sqlInterceptor.getQueryCount(), is( 2 ) ); + + assertTrue( Hibernate.isPropertyInitialized( c1, "nickName" ) ); + + // parent should be an uninitialized enhanced-proxy + assertTrue( Hibernate.isPropertyInitialized( c1, "parent" ) ); + assertThat( c1.getParent(), not( instanceOf( HibernateProxy.class ) ) ); + assertFalse( Hibernate.isInitialized( c1.getParent() ) ); + + // alternateParent should be an uninitialized enhanced-proxy + assertTrue( Hibernate.isPropertyInitialized( c1, "alternateParent" ) ); + assertThat( c1.getAlternateParent(), not( instanceOf( HibernateProxy.class ) ) ); + assertFalse( Hibernate.isInitialized( c1.getAlternateParent() ) ); + + + sqlInterceptor.clear(); + } + ); } @Test @@ -134,64 +145,66 @@ public void testUpdate() { Parent p1New = new Parent(); p1New.nombre = "p1New"; - doInHibernate( this::sessionFactory, s -> { - Child c1 = (Child) s.createQuery( "from Child c where c.name = :name" ).setParameter( "name", "steve" ).uniqueResult(); - - // verify the expected initial loaded state - assertLoaded( c1, "name" ); - assertNotLoaded( c1, "nickName" ); - assertNotLoaded( c1, "parent" ); - assertNotLoaded( c1, "alternateParent" ); - - // Now lets update nickName which ought to initialize nickName and parent, but not alternateParent - c1.nickName = "new nickName"; - assertLoaded( c1, "nickName" ); - assertNotLoaded( c1, "parent" ); - assertNotLoaded( c1, "alternateParent" ); - assertEquals( "Hibernate", c1.parent.nombre ); - assertFalse( c1.parent instanceof HibernateProxy ); - - // Now update c1.parent - c1.parent.children.remove( c1 ); - c1.parent = p1New; - p1New.children.add( c1 ); - } ); + inTransaction( + (s) -> { + sqlInterceptor.clear(); - // verify updates - doInHibernate( this::sessionFactory, s -> { - Child c1 = (Child) s.createQuery( "from Child c where c.name = :name" ).setParameter( "name", "steve" ).uniqueResult(); - assertEquals( "new nickName", c1.getNickName() ); - assertEquals( "p1New", c1.parent.nombre ); - assertFalse( c1.parent instanceof HibernateProxy ); - } ); + final Child c1 = s.createQuery( "from Child c where c.name = :name", Child.class ) + .setParameter( "name", "steve" ) + .uniqueResult(); + assertThat( sqlInterceptor.getQueryCount(), is( 1 ) ); - doInHibernate( this::sessionFactory, s -> { - Child c2 = (Child) s.createQuery( "from Child c where c.name = :name" ).setParameter( "name", "sally" ).uniqueResult(); - - // verify the expected initial loaded state - assertLoaded( c2, "name" ); - assertNotLoaded( c2, "nickName" ); - assertNotLoaded( c2, "parent" ); - assertNotLoaded( c2, "alternateParent" ); - - // Now lets access and update alternateParent which ought to initialize alternateParent and nothing else - Parent p1 = c2.getAlternateParent(); - c2.alternateParent = p1New; - assertNotLoaded( c2, "nickName" ); - assertNotLoaded( c2, "parent" ); - assertLoaded( c2, "alternateParent" ); - assertEquals( "p1New", c2.getAlternateParent().nombre ); - assertFalse( c2.getAlternateParent() instanceof HibernateProxy ); - - p1.alternateChildren.remove( c2 ); - p1New.alternateChildren.add( c2 ); - } ); + assertTrue( Hibernate.isPropertyInitialized( c1, "name" ) ); - // verify update - doInHibernate( this::sessionFactory, s -> { - Child c2 = (Child) s.createQuery( "from Child c where c.name = :name" ).setParameter( "name", "sally" ).uniqueResult(); - assertEquals( "p1New", c2.getAlternateParent().nombre ); - } ); + assertFalse( Hibernate.isPropertyInitialized( c1, "nickName" ) ); + + // parent should be an uninitialized enhanced-proxy + assertTrue( Hibernate.isPropertyInitialized( c1, "parent" ) ); + assertThat( c1.getParent(), not( instanceOf( HibernateProxy.class ) ) ); + assertFalse( Hibernate.isInitialized( c1.getParent() ) ); + + // alternateParent should be an uninitialized enhanced-proxy + assertTrue( Hibernate.isPropertyInitialized( c1, "alternateParent" ) ); + assertThat( c1.getAlternateParent(), not( instanceOf( HibernateProxy.class ) ) ); + assertFalse( Hibernate.isInitialized( c1.getAlternateParent() ) ); + + // Now lets update nickName + c1.nickName = "new nickName"; + + assertThat( sqlInterceptor.getQueryCount(), is( 1 ) ); + + assertTrue( Hibernate.isPropertyInitialized( c1, "name" ) ); + + assertTrue( Hibernate.isPropertyInitialized( c1, "nickName" ) ); + + // parent should be an uninitialized enhanced-proxy + assertTrue( Hibernate.isPropertyInitialized( c1, "parent" ) ); + assertThat( c1.getParent(), not( instanceOf( HibernateProxy.class ) ) ); + assertFalse( Hibernate.isInitialized( c1.getParent() ) ); + + // alternateParent should be an uninitialized enhanced-proxy + assertTrue( Hibernate.isPropertyInitialized( c1, "alternateParent" ) ); + assertThat( c1.getAlternateParent(), not( instanceOf( HibernateProxy.class ) ) ); + assertFalse( Hibernate.isInitialized( c1.getAlternateParent() ) ); + + // Now update c1.parent + c1.parent.children.remove( c1 ); + c1.parent = p1New; + p1New.children.add( c1 ); + } + ); + + // verify updates + inTransaction( + (s) -> { + final Child c1 = s.createQuery( "from Child c where c.name = :name", Child.class ) + .setParameter( "name", "steve" ) + .uniqueResult(); + + assertThat( c1.getNickName(), is( "new nickName" ) ); + assertThat( c1.parent.nombre, is( "p1New" ) ); + } + ); } @After @@ -204,18 +217,6 @@ public void cleanup() { // --- // - private void assertLoaded(Object owner, String name) { - // NOTE we assume null == not-loaded - Object fieldByReflection = getFieldByReflection( owner, name ); - assertNotNull( "Expecting field '" + name + "' to be loaded, but it was not", fieldByReflection ); - } - - private void assertNotLoaded(Object owner, String name) { - // NOTE we assume null == not-loaded - Object fieldByReflection = getFieldByReflection( owner, name ); - assertNull( "Expecting field '" + name + "' to be not loaded, but it was", fieldByReflection ); - } - // --- // @Entity( name = "Parent" ) @@ -271,6 +272,10 @@ private static class Child { this.nickName = nickName; } + public Parent getParent() { + return parent; + } + Parent getAlternateParent() { return alternateParent; } diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/notfound/LazyNotFoundManyToOneNonUpdatableNonInsertableTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/notfound/LazyNotFoundManyToOneNonUpdatableNonInsertableTest.java index 05ace8cdfce6..3b22a0598efb 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/notfound/LazyNotFoundManyToOneNonUpdatableNonInsertableTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/notfound/LazyNotFoundManyToOneNonUpdatableNonInsertableTest.java @@ -6,10 +6,6 @@ */ package org.hibernate.test.bytecode.enhancement.lazy.notfound; -/** - * @author Gail Badner - */ - import javax.persistence.CascadeType; import javax.persistence.ConstraintMode; import javax.persistence.Entity; @@ -26,7 +22,6 @@ import org.hibernate.annotations.NotFound; import org.hibernate.annotations.NotFoundAction; -import org.hibernate.testing.FailureExpected; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; @@ -37,6 +32,9 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; +/** + * @author Gail Badner + */ @TestForIssue( jiraKey = "HHH-12226") @RunWith( BytecodeEnhancerRunner.class ) public class LazyNotFoundManyToOneNonUpdatableNonInsertableTest extends BaseCoreFunctionalTestCase { @@ -51,10 +49,6 @@ protected Class[] getAnnotatedClasses() { } @Test - @FailureExpected( - jiraKey = "HHH-13658", - message = "Assertions specific to enhanced lazy loading but disallowing enhanced proxies, which is no longer valid" - ) public void test() { doInHibernate( this::sessionFactory, session -> { diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/notfound/LazyNotFoundOneToOneNonUpdatableNonInsertableTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/notfound/LazyNotFoundOneToOneNonUpdatableNonInsertableTest.java index e71c0e483449..33673f001f22 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/notfound/LazyNotFoundOneToOneNonUpdatableNonInsertableTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/notfound/LazyNotFoundOneToOneNonUpdatableNonInsertableTest.java @@ -28,6 +28,7 @@ import org.hibernate.testing.TestForIssue; import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; +import org.hibernate.testing.bytecode.enhancement.EnhancementOptions; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; import org.junit.Test; import org.junit.runner.RunWith; diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/notfound/LazyNotFoundOneToOneTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/notfound/LazyNotFoundOneToOneTest.java index 5b00fb227f5b..7d6676a7ac0d 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/notfound/LazyNotFoundOneToOneTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/notfound/LazyNotFoundOneToOneTest.java @@ -6,10 +6,6 @@ */ package org.hibernate.test.bytecode.enhancement.lazy.notfound; -/** - * @author Gail Badner - */ - import javax.persistence.CascadeType; import javax.persistence.ConstraintMode; import javax.persistence.Entity; @@ -28,23 +24,29 @@ import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.Configuration; -import org.hibernate.testing.FailureExpected; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; +import org.hibernate.testing.jdbc.SQLStatementInterceptor; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; import org.junit.Test; import org.junit.runner.RunWith; +import static org.hamcrest.CoreMatchers.is; import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertThat; +/** + * @author Gail Badner + */ @TestForIssue( jiraKey = "HHH-12226") @RunWith( BytecodeEnhancerRunner.class ) public class LazyNotFoundOneToOneTest extends BaseCoreFunctionalTestCase { private static int ID = 1; + private SQLStatementInterceptor sqlInterceptor; + @Override protected Class[] getAnnotatedClasses() { return new Class[] { @@ -56,14 +58,10 @@ protected Class[] getAnnotatedClasses() { @Override protected void configure(Configuration configuration) { super.configure(configuration); - configuration.setProperty( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); + sqlInterceptor = new SQLStatementInterceptor( configuration ); } @Test - @FailureExpected( - jiraKey = "HHH-13658", - message = "Assertions specific to enhanced lazy loading but disallowing enhanced proxies, which is no longer valid" - ) public void test() { doInHibernate( this::sessionFactory, session -> { @@ -82,10 +80,15 @@ public void test() { } ); + sqlInterceptor.clear(); + doInHibernate( this::sessionFactory, session -> { User user = session.find( User.class, ID ); + + assertThat( sqlInterceptor.getQueryCount(), is( 1 ) ); assertFalse( Hibernate.isPropertyInitialized( user, "lazy" ) ); + assertNull( user.getLazy() ); } ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/FetchGraphTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/FetchGraphTest.java index 5913890382e1..ed15d06e9c18 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/FetchGraphTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/FetchGraphTest.java @@ -200,7 +200,6 @@ assert sessionFactory().getMetamodel() } @Test - @FailureExpected( jiraKey = "HHH-13658") public void testRandomAccess() { final StatisticsImplementor stats = sessionFactory().getStatistics(); stats.clear(); diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LazyGroupWithInheritanceTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LazyGroupWithInheritanceTest.java index bfb41f7a60cb..08f13c174c76 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LazyGroupWithInheritanceTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/LazyGroupWithInheritanceTest.java @@ -10,24 +10,28 @@ import java.util.Set; import java.util.concurrent.atomic.AtomicInteger; +import org.hibernate.Hibernate; import org.hibernate.boot.MetadataSources; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.bytecode.enhance.spi.interceptor.BytecodeLazyAttributeInterceptor; import org.hibernate.cfg.AvailableSettings; +import org.hibernate.engine.spi.PersistentAttributeInterceptable; +import org.hibernate.engine.spi.PersistentAttributeInterceptor; import org.hibernate.stat.Statistics; import org.hibernate.testing.FailureExpected; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; -import org.hibernate.testing.bytecode.enhancement.CustomEnhancementContext; import org.hibernate.testing.bytecode.enhancement.EnhancementOptions; -import org.hibernate.testing.bytecode.enhancement.EnhancerTestContext; import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; -import org.hibernate.test.bytecode.enhancement.lazy.group.BidirectionalLazyGroupsInEmbeddableTest; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertEquals; /** @@ -39,10 +43,25 @@ @EnhancementOptions( lazyLoading = true ) public class LazyGroupWithInheritanceTest extends BaseNonConfigCoreFunctionalTestCase { @Test - @FailureExpected( - jiraKey = "HHH-13658", - message = "Assertions specific to enhanced lazy loading but disallowing enhanced proxies, which is no longer valid" - ) + public void loadEntityWithAssociationToAbstract() { + final Statistics stats = sessionFactory().getStatistics(); + stats.clear(); + + inTransaction( + (session) -> { + final Order loaded = session.byId( Order.class ).load( 1 ); + assert Hibernate.isPropertyInitialized( loaded, "customer" ); + assertThat( stats.getPrepareStatementCount(), is( 1L ) ); + assertThat( loaded, instanceOf( PersistentAttributeInterceptable.class ) ); + final PersistentAttributeInterceptor interceptor = ((PersistentAttributeInterceptable) loaded).$$_hibernate_getInterceptor(); + assertThat( interceptor, instanceOf( BytecodeLazyAttributeInterceptor.class ) ); + final BytecodeLazyAttributeInterceptor interceptor1 = (BytecodeLazyAttributeInterceptor) interceptor; + + } + ); + } + + @Test public void queryEntityWithAssociationToAbstract() { final Statistics stats = sessionFactory().getStatistics(); stats.clear(); @@ -61,8 +80,8 @@ public void queryEntityWithAssociationToAbstract() { // The only viable solution I see would be to join to the "other side" and read the // version/discriminator[1]. But of course that means doing the join which is generally // what the application is trying to avoid in the first place - //expectedQueryCount.set( 1 ); - expectedQueryCount.set( 4 ); + expectedQueryCount.set( 1 ); + //expectedQueryCount.set( 4 ); assertEquals( expectedQueryCount.get(), stats.getPrepareStatementCount() ); for ( Order order : orders ) { diff --git a/hibernate-core/src/test/java/org/hibernate/test/legacy/CustomPersister.java b/hibernate-core/src/test/java/org/hibernate/test/legacy/CustomPersister.java index 9615248f4f16..d79fa014e8ce 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/legacy/CustomPersister.java +++ b/hibernate-core/src/test/java/org/hibernate/test/legacy/CustomPersister.java @@ -71,7 +71,7 @@ public CustomPersister( NaturalIdDataAccess naturalIdRegionAccessStrategy, PersisterCreationContext creationContext) { this.factory = creationContext.getSessionFactory(); - this.entityMetamodel = new EntityMetamodel( model, this, factory ); + this.entityMetamodel = new EntityMetamodel( model, this, creationContext ); } public boolean hasLazyProperties() { diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/jdbc/SQLStatementInterceptor.java b/hibernate-testing/src/main/java/org/hibernate/testing/jdbc/SQLStatementInterceptor.java index 43b114f01446..9955a8acc8f8 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/jdbc/SQLStatementInterceptor.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/jdbc/SQLStatementInterceptor.java @@ -10,7 +10,9 @@ import java.util.Map; import org.hibernate.boot.SessionFactoryBuilder; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cfg.AvailableSettings; +import org.hibernate.cfg.Configuration; import org.hibernate.resource.jdbc.spi.StatementInspector; import static org.junit.Assert.assertEquals; @@ -37,6 +39,20 @@ public SQLStatementInterceptor(Map settings) { } ); } + public SQLStatementInterceptor(StandardServiceRegistryBuilder ssrb) { + ssrb.applySetting( + AvailableSettings.STATEMENT_INSPECTOR, + (StatementInspector) sql -> { + sqlQueries.add( sql ); + return sql; + } + ); + } + + public SQLStatementInterceptor(Configuration configuration) { + this( configuration.getProperties() ); + } + public LinkedList getSqlQueries() { return sqlQueries; } @@ -52,4 +68,8 @@ public void assertExecuted(String expected) { public void assertExecutedCount(int expected) { assertEquals(expected, sqlQueries.size()); } + + public int getQueryCount() { + return sqlQueries.size(); + } } From 578edbfd9f60917d407d4f03a306c528282c7b78 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Tue, 23 Feb 2021 00:47:04 +0100 Subject: [PATCH 026/644] HHH-14464 Make two methods of AbstractEntityPersister protected for the benefit of Hibernate Reeactive --- .../hibernate/persister/entity/AbstractEntityPersister.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index 835467781451..fcffca53e243 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -3897,7 +3897,7 @@ protected boolean isAllOrDirtyOptLocking() { || entityMetamodel.getOptimisticLockStyle() == OptimisticLockStyle.ALL; } - private String[] generateSQLDeleteStrings(Object[] loadedState) { + protected String[] generateSQLDeleteStrings(Object[] loadedState) { int span = getTableSpan(); String[] deleteStrings = new String[span]; for ( int j = span - 1; j >= 0; j-- ) { @@ -5598,7 +5598,7 @@ private boolean[] determineValueNullness(Object[] naturalIdValues) { private Boolean naturalIdIsNonNullable; private String cachedPkByNonNullableNaturalIdQuery; - private String determinePkByNaturalIdQuery(boolean[] valueNullness) { + protected String determinePkByNaturalIdQuery(boolean[] valueNullness) { if ( !hasNaturalIdentifier() ) { throw new HibernateException( "Attempt to build natural-id -> PK resolution query for entity that does not define natural id" From e38df7ed593af7dc124d10c30eea5389c76af124 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Tue, 23 Feb 2021 10:26:55 +0100 Subject: [PATCH 027/644] HHH-14464 Expose useful things to enable cleanup of HR code - expose useful static-y methods in AbstractEntityPersister - add methods to OptimisticLockStyle to reduce verbosity - add a useful method to ValueGeneration --- .../hibernate/engine/OptimisticLockStyle.java | 20 ++++++ .../entity/AbstractEntityPersister.java | 68 ++++++++----------- .../entity/JoinedSubclassEntityPersister.java | 3 +- .../org/hibernate/tuple/ValueGeneration.java | 9 +++ .../tuple/entity/EntityMetamodel.java | 4 +- 5 files changed, 58 insertions(+), 46 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/engine/OptimisticLockStyle.java b/hibernate-core/src/main/java/org/hibernate/engine/OptimisticLockStyle.java index aca8aaac16aa..8398770a81e7 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/OptimisticLockStyle.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/OptimisticLockStyle.java @@ -39,6 +39,26 @@ public int getOldCode() { return oldCode; } + public boolean isAllOrDirty() { + return isAll() || isDirty(); + } + + public boolean isAll() { + return this == ALL; + } + + public boolean isDirty() { + return this == DIRTY; + } + + public boolean isVersion() { + return this == VERSION; + } + + public boolean isNone() { + return this == NONE; + } + /** * Given an old code (one of the int constants from Cascade), interpret it as one of the new enums. * diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index fcffca53e243..ebc334da4498 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -1386,8 +1386,8 @@ protected boolean initializeLazyProperty( } public boolean isBatchable() { - return optimisticLockStyle() == OptimisticLockStyle.NONE - || ( !isVersioned() && optimisticLockStyle() == OptimisticLockStyle.VERSION ) + return optimisticLockStyle().isNone() + || !isVersioned() && optimisticLockStyle().isVersion() || getFactory().getSessionFactoryOptions().isJdbcBatchVersionedData(); } @@ -1757,14 +1757,13 @@ private String generateGeneratedValuesSelectString(final GenerationTiming genera // rather than trying to handle the individual generated portions. String selectClause = concretePropertySelectFragment( getRootAlias(), - new InclusionChecker() { - @Override - public boolean includeProperty(int propertyNumber) { - final InDatabaseValueGenerationStrategy generationStrategy - = entityMetamodel.getInDatabaseValueGenerationStrategies()[propertyNumber]; - return generationStrategy != null - && timingsMatch( generationStrategy.getGenerationTiming(), generationTimingToMatch ); - } + propertyNumber -> { + final InDatabaseValueGenerationStrategy generationStrategy + = entityMetamodel.getInDatabaseValueGenerationStrategies()[propertyNumber]; + GenerationTiming timing = generationStrategy.getGenerationTiming(); + return generationStrategy != null + && (generationTimingToMatch == GenerationTiming.INSERT && timing.includesInsert() + || generationTimingToMatch == GenerationTiming.ALWAYS && timing.includesUpdate()); } ); selectClause = selectClause.substring( 2 ); @@ -1792,11 +1791,7 @@ protected interface InclusionChecker { protected String concretePropertySelectFragment(String alias, final boolean[] includeProperty) { return concretePropertySelectFragment( alias, - new InclusionChecker() { - public boolean includeProperty(int propertyNumber) { - return includeProperty[propertyNumber]; - } - } + propertyNumber -> includeProperty[propertyNumber] ); } @@ -2726,7 +2721,7 @@ public String generateUpdateString( update.addPrimaryKeyColumns( getKeyColumns( j ) ); } - if ( j == 0 && isVersioned() && entityMetamodel.getOptimisticLockStyle() == OptimisticLockStyle.VERSION ) { + if ( j == 0 && isVersioned() && entityMetamodel.getOptimisticLockStyle().isVersion() ) { // this is the root (versioned) table, and we are using version-based // optimistic locking; if we are not updating the version, also don't // check it (unless this is a "generated" version column)! @@ -2738,12 +2733,11 @@ public String generateUpdateString( else if ( isAllOrDirtyOptLocking() && oldFields != null ) { // we are using "all" or "dirty" property-based optimistic locking - boolean[] includeInWhere = entityMetamodel.getOptimisticLockStyle() == OptimisticLockStyle.ALL - ? - getPropertyUpdateability() + boolean[] includeInWhere = entityMetamodel.getOptimisticLockStyle().isAll() //optimistic-lock="all", include all updatable properties - : - includeProperty; //optimistic-lock="dirty", include all properties we are updating this time + ? getPropertyUpdateability() + //optimistic-lock="dirty", include all properties we are updating this time + : includeProperty; boolean[] versionability = getPropertyVersionability(); Type[] types = getPropertyTypes(); @@ -3470,14 +3464,14 @@ public boolean update( ); // Write any appropriate versioning conditional parameters - if ( useVersion && entityMetamodel.getOptimisticLockStyle() == OptimisticLockStyle.VERSION ) { + if ( useVersion && entityMetamodel.getOptimisticLockStyle().isVersion()) { if ( checkVersion( includeProperty ) ) { getVersionType().nullSafeSet( update, oldVersion, index, session ); } } else if ( isAllOrDirtyOptLocking() && oldFields != null ) { boolean[] versionability = getPropertyVersionability(); //TODO: is this really necessary???? - boolean[] includeOldField = entityMetamodel.getOptimisticLockStyle() == OptimisticLockStyle.ALL + boolean[] includeOldField = entityMetamodel.getOptimisticLockStyle().isAll() ? getPropertyUpdateability() : includeProperty; Type[] types = getPropertyTypes(); @@ -3893,8 +3887,7 @@ public void delete(Serializable id, Object version, Object object, SharedSession } protected boolean isAllOrDirtyOptLocking() { - return entityMetamodel.getOptimisticLockStyle() == OptimisticLockStyle.DIRTY - || entityMetamodel.getOptimisticLockStyle() == OptimisticLockStyle.ALL; + return entityMetamodel.getOptimisticLockStyle().isAllOrDirty(); } protected String[] generateSQLDeleteStrings(Object[] loadedState) { @@ -5378,12 +5371,11 @@ rs, getPropertyAliases( } - private boolean isValueGenerationRequired(NonIdentifierAttribute attribute, GenerationTiming matchTiming) { - if ( attribute.getType() instanceof ComponentType ) { + public static boolean isValueGenerationRequired(NonIdentifierAttribute attribute, GenerationTiming matchTiming) { + if ( attribute.getType() instanceof ComponentType) { final ComponentType type = (ComponentType) attribute.getType(); - final ValueGeneration[] propertyValueGenerationStrategies = type.getPropertyValueGenerationStrategies(); - for ( ValueGeneration propertyValueGenerationStrategie : propertyValueGenerationStrategies ) { - if ( isReadRequired( propertyValueGenerationStrategie, matchTiming ) ) { + for ( ValueGeneration valueGenerationStrategy : type.getPropertyValueGenerationStrategies() ) { + if ( isReadRequired( valueGenerationStrategy, matchTiming ) ) { return true; } } @@ -5397,16 +5389,10 @@ private boolean isValueGenerationRequired(NonIdentifierAttribute attribute, Gene /** * Whether the given value generation strategy requires to read the value from the database or not. */ - private boolean isReadRequired(ValueGeneration valueGeneration, GenerationTiming matchTiming) { - return valueGeneration != null && - valueGeneration.getValueGenerator() == null && - timingsMatch( valueGeneration.getGenerationTiming(), matchTiming ); - } - - private boolean timingsMatch(GenerationTiming timing, GenerationTiming matchTiming) { - return - ( matchTiming == GenerationTiming.INSERT && timing.includesInsert() ) || - ( matchTiming == GenerationTiming.ALWAYS && timing.includesUpdate() ); + private static boolean isReadRequired(ValueGeneration valueGeneration, GenerationTiming matchTiming) { + return valueGeneration != null + && valueGeneration.getValueGenerator() == null + && valueGeneration.timingMatches( matchTiming ); } public String getIdentifierPropertyName() { @@ -5587,7 +5573,7 @@ public Serializable loadEntityIdByNaturalId( } } - private boolean[] determineValueNullness(Object[] naturalIdValues) { + public static boolean[] determineValueNullness(Object[] naturalIdValues) { boolean[] nullness = new boolean[naturalIdValues.length]; for ( int i = 0; i < naturalIdValues.length; i++ ) { nullness[i] = naturalIdValues[i] == null; diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java index 883dc716b54c..8fb627946786 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java @@ -13,7 +13,6 @@ import org.hibernate.boot.model.relational.Database; import org.hibernate.cache.spi.access.EntityDataAccess; import org.hibernate.cache.spi.access.NaturalIdDataAccess; -import org.hibernate.engine.OptimisticLockStyle; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle; import org.hibernate.engine.spi.SessionFactoryImplementor; @@ -200,7 +199,7 @@ else if ( persistentClass.isDiscriminatorValueNotNull() ) { discriminatorSQLString = null; } - if ( optimisticLockStyle() == OptimisticLockStyle.ALL || optimisticLockStyle() == OptimisticLockStyle.DIRTY ) { + if ( optimisticLockStyle().isAllOrDirty() ) { throw new MappingException( "optimistic-lock=all|dirty not supported for joined-subclass mappings [" + getEntityName() + "]" ); } diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/ValueGeneration.java b/hibernate-core/src/main/java/org/hibernate/tuple/ValueGeneration.java index 11529d063bbe..bc02ab284adf 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/ValueGeneration.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/ValueGeneration.java @@ -53,4 +53,13 @@ public interface ValueGeneration extends Serializable { * @return The column value to be used in the SQL. */ public String getDatabaseGeneratedReferencedColumnValue(); + + /** + * Does this value generation occur with the given timing? + */ + default boolean timingMatches(GenerationTiming timing) { + GenerationTiming generationTiming = getGenerationTiming(); + return timing == GenerationTiming.INSERT && generationTiming.includesInsert() + || timing == GenerationTiming.ALWAYS && generationTiming.includesUpdate(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java index 6075fb1ae197..5606e1d47dbb 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityMetamodel.java @@ -395,9 +395,7 @@ else if ( timing == GenerationTiming.ALWAYS ) { hasSubclasses = persistentClass.hasSubclasses(); optimisticLockStyle = persistentClass.getOptimisticLockStyle(); - final boolean isAllOrDirty = - optimisticLockStyle == OptimisticLockStyle.ALL - || optimisticLockStyle == OptimisticLockStyle.DIRTY; + final boolean isAllOrDirty = optimisticLockStyle.isAllOrDirty(); if ( isAllOrDirty && !dynamicUpdate ) { throw new MappingException( "optimistic-lock=all|dirty requires dynamic-update=\"true\": " + name ); } From e61eff291320f83af6552eec7cf3a7bb7ddd9f59 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Tue, 23 Feb 2021 13:24:31 +0000 Subject: [PATCH 028/644] HHH-14463 Upgrade to ByteBuddy 1.10.21: OOB support for JDK17 --- gradle/java-module.gradle | 4 ++-- gradle/libraries.gradle | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gradle/java-module.gradle b/gradle/java-module.gradle index 8e286469af59..fee82c2567cb 100644 --- a/gradle/java-module.gradle +++ b/gradle/java-module.gradle @@ -291,9 +291,9 @@ test { jvmArgs '-XX:+StartAttachListener' } -// Enable the experimental features of ByteBuddy with JDK 15+ +// Enable the experimental features of ByteBuddy with JDK 18+ test { - if ( gradle.ext.javaVersions.test.release.asInt() >= 15 ) { + if ( gradle.ext.javaVersions.test.release.asInt() >= 18 ) { logger.warn( "The version of Java bytecode that will be tested is not supported by Bytebuddy by default. " + " Setting 'net.bytebuddy.experimental=true'." ) systemProperty 'net.bytebuddy.experimental', true diff --git a/gradle/libraries.gradle b/gradle/libraries.gradle index c57070452381..f10acd124cb7 100644 --- a/gradle/libraries.gradle +++ b/gradle/libraries.gradle @@ -23,7 +23,7 @@ ext { weldVersion = '3.1.5.Final' javassistVersion = '3.27.0-GA' - byteBuddyVersion = '1.10.17' + byteBuddyVersion = '1.10.21' agroalVersion = '1.9' From 725083b7677d2e773823f89f060ac96a17fcc91a Mon Sep 17 00:00:00 2001 From: Gavin King Date: Tue, 23 Feb 2021 15:05:29 +0100 Subject: [PATCH 029/644] more efficient loading by @NaturalId For entities with a single @NaturalId property only. Uses a unique key EntityLoader instead of two selects. --- .../DefaultResolveNaturalIdEventListener.java | 58 +++++++++++++------ .../entity/AbstractEntityPersister.java | 17 ++++++ .../persister/entity/UniqueKeyLoadable.java | 15 ++++- .../cache/InheritedNaturalIdNoCacheTest.java | 22 +++++-- 4 files changed, 88 insertions(+), 24 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultResolveNaturalIdEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultResolveNaturalIdEventListener.java index e1c856cb32e0..737d278b13e4 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultResolveNaturalIdEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultResolveNaturalIdEventListener.java @@ -7,11 +7,12 @@ package org.hibernate.event.internal; import java.io.Serializable; +import java.util.Map; import java.util.concurrent.TimeUnit; import org.hibernate.HibernateException; -import org.hibernate.cache.spi.access.NaturalIdDataAccess; -import org.hibernate.engine.spi.PersistenceContext; +import org.hibernate.LockOptions; +import org.hibernate.WrongClassException; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.event.spi.EventSource; import org.hibernate.event.spi.ResolveNaturalIdEvent; @@ -19,6 +20,7 @@ import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.persister.entity.UniqueKeyLoadable; import org.hibernate.pretty.MessageHelper; import org.hibernate.stat.spi.StatisticsImplementor; @@ -96,10 +98,11 @@ protected Serializable resolveNaturalId(final ResolveNaturalIdEvent event) { * @return The entity from the cache, or null. */ protected Serializable resolveFromCache(final ResolveNaturalIdEvent event) { - return event.getSession().getPersistenceContextInternal().getNaturalIdHelper().findCachedNaturalIdResolution( - event.getEntityPersister(), - event.getOrderedNaturalIdValues() - ); + return event.getSession().getPersistenceContextInternal().getNaturalIdHelper() + .findCachedNaturalIdResolution( + event.getEntityPersister(), + event.getOrderedNaturalIdValues() + ); } /** @@ -120,29 +123,48 @@ protected Serializable loadFromDatasource(final ResolveNaturalIdEvent event) { startTime = System.nanoTime(); } - final Serializable pk = event.getEntityPersister().loadEntityIdByNaturalId( - event.getOrderedNaturalIdValues(), - event.getLockOptions(), - session - ); + Object[] naturalIdValues = event.getOrderedNaturalIdValues(); + + final Serializable pk; + EntityPersister persister = event.getEntityPersister(); + LockOptions lockOptions = event.getLockOptions(); + if ( persister instanceof UniqueKeyLoadable + && naturalIdValues.length==1 ) { + UniqueKeyLoadable rootPersister = (UniqueKeyLoadable) + persister.getFactory().getMetamodel().entityPersister( persister.getRootEntityName() ); + Map.Entry e = event.getNaturalIdValues().entrySet().iterator().next(); + Object entity = rootPersister.loadByUniqueKey( e.getKey(), e.getValue(), lockOptions, session ); + if ( entity == null ) { + pk = null; + } + else { + if ( !persister.isInstance(entity) ) { + throw new WrongClassException( + "loaded object was of wrong class " + entity.getClass(), + e.getKey(), + persister.getEntityName() + ); + } + pk = persister.getIdentifier( entity, session ); + } + } + else { + pk = persister.loadEntityIdByNaturalId( naturalIdValues, lockOptions, session ); + } if ( stats ) { final long endTime = System.nanoTime(); final long milliseconds = TimeUnit.MILLISECONDS.convert( endTime - startTime, TimeUnit.NANOSECONDS ); statistics.naturalIdQueryExecuted( - event.getEntityPersister().getRootEntityName(), + persister.getRootEntityName(), milliseconds ); } //PK can be null if the entity doesn't exist if (pk != null) { - final PersistenceContext persistenceContext = session.getPersistenceContextInternal(); - persistenceContext.getNaturalIdHelper().cacheNaturalIdCrossReferenceFromLoad( - event.getEntityPersister(), - pk, - event.getOrderedNaturalIdValues() - ); + session.getPersistenceContextInternal().getNaturalIdHelper() + .cacheNaturalIdCrossReferenceFromLoad( persister, pk, naturalIdValues ); } return pk; diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index ebc334da4498..b01049aef95c 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -2481,6 +2481,23 @@ public Object loadByUniqueKey( return getAppropriateUniqueKeyLoader( propertyName, session ).loadByUniqueKey( session, uniqueKey ); } + public Object loadByUniqueKey( + String propertyName, + Object uniqueKey, + LockOptions lockOptions, + SharedSessionContractImplementor session) throws HibernateException { + //TODO: cache this + return new EntityLoader( + this, + propertyMapping.toColumns( propertyName ), + propertyMapping.toType( propertyName ), + 1, + lockOptions, + getFactory(), + session.getLoadQueryInfluencers() + ).loadByUniqueKey( session, uniqueKey ); + } + private EntityLoader getAppropriateUniqueKeyLoader(String propertyName, SharedSessionContractImplementor session) { final boolean useStaticLoader = !session.getLoadQueryInfluencers().hasEnabledFilters() && !session.getLoadQueryInfluencers().hasEnabledFetchProfiles() diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/UniqueKeyLoadable.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/UniqueKeyLoadable.java index 2c73653eff50..f7c90226cea4 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/UniqueKeyLoadable.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/UniqueKeyLoadable.java @@ -6,6 +6,7 @@ */ package org.hibernate.persister.entity; +import org.hibernate.LockOptions; import org.hibernate.engine.spi.SharedSessionContractImplementor; /** @@ -16,7 +17,19 @@ public interface UniqueKeyLoadable extends Loadable { * Load an instance of the persistent class, by a unique key other * than the primary key. */ - Object loadByUniqueKey(String propertyName, Object uniqueKey, SharedSessionContractImplementor session); + Object loadByUniqueKey( + String propertyName, + Object uniqueKey, + SharedSessionContractImplementor session); + + /** + * Load an instance of the persistent class, by a natural id. + */ + Object loadByUniqueKey( + String propertyName, + Object uniqueKey, + LockOptions lockOptions, + SharedSessionContractImplementor session); /** * Get the property number of the unique key property diff --git a/hibernate-core/src/test/java/org/hibernate/test/naturalid/inheritance/cache/InheritedNaturalIdNoCacheTest.java b/hibernate-core/src/test/java/org/hibernate/test/naturalid/inheritance/cache/InheritedNaturalIdNoCacheTest.java index 9098619f8e55..549734e200be 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/naturalid/inheritance/cache/InheritedNaturalIdNoCacheTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/naturalid/inheritance/cache/InheritedNaturalIdNoCacheTest.java @@ -6,6 +6,7 @@ */ package org.hibernate.test.naturalid.inheritance.cache; +import org.hibernate.WrongClassException; import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.Configuration; @@ -14,7 +15,7 @@ import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; public class InheritedNaturalIdNoCacheTest extends BaseCoreFunctionalTestCase { @@ -57,10 +58,21 @@ public void testLoadExtendedByNormal() { }); doInHibernate( this::sessionFactory, session -> { - ExtendedEntity user = session.byNaturalId( ExtendedEntity.class ) - .using( "uid", "base" ) - .load(); - assertNull( user ); + try { + session.byNaturalId( ExtendedEntity.class ) + .using( "uid", "base" ) + .load(); + fail( "Expecting WrongClassException" ); + } + catch (WrongClassException expected) { + // expected outcome + } + catch (Exception other) { + throw new AssertionError( + "Unexpected exception type : " + other.getClass().getName(), + other + ); + } }); } } From e368ac5babec6bec77aa33793fcc212e059e94c1 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Tue, 23 Feb 2021 18:35:54 +0100 Subject: [PATCH 030/644] more efficient loading by multiple @NaturalIds --- .../DefaultResolveNaturalIdEventListener.java | 9 +- .../util/collections/ArrayHelper.java | 9 + .../hibernate/loader/entity/EntityLoader.java | 183 +++++++++++++++++- .../entity/AbstractEntityPersister.java | 10 +- .../persister/entity/UniqueKeyLoadable.java | 5 +- 5 files changed, 199 insertions(+), 17 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultResolveNaturalIdEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultResolveNaturalIdEventListener.java index 737d278b13e4..cdfdbd18c6fc 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultResolveNaturalIdEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultResolveNaturalIdEventListener.java @@ -7,7 +7,6 @@ package org.hibernate.event.internal; import java.io.Serializable; -import java.util.Map; import java.util.concurrent.TimeUnit; import org.hibernate.HibernateException; @@ -128,12 +127,10 @@ protected Serializable loadFromDatasource(final ResolveNaturalIdEvent event) { final Serializable pk; EntityPersister persister = event.getEntityPersister(); LockOptions lockOptions = event.getLockOptions(); - if ( persister instanceof UniqueKeyLoadable - && naturalIdValues.length==1 ) { + if ( persister instanceof UniqueKeyLoadable) { UniqueKeyLoadable rootPersister = (UniqueKeyLoadable) persister.getFactory().getMetamodel().entityPersister( persister.getRootEntityName() ); - Map.Entry e = event.getNaturalIdValues().entrySet().iterator().next(); - Object entity = rootPersister.loadByUniqueKey( e.getKey(), e.getValue(), lockOptions, session ); + Object entity = rootPersister.loadByNaturalId( naturalIdValues, lockOptions, session ); if ( entity == null ) { pk = null; } @@ -141,7 +138,7 @@ protected Serializable loadFromDatasource(final ResolveNaturalIdEvent event) { if ( !persister.isInstance(entity) ) { throw new WrongClassException( "loaded object was of wrong class " + entity.getClass(), - e.getKey(), + naturalIdValues, persister.getEntityName() ); } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/util/collections/ArrayHelper.java b/hibernate-core/src/main/java/org/hibernate/internal/util/collections/ArrayHelper.java index 5f575275ef90..d7673b3c9ac8 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/util/collections/ArrayHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/util/collections/ArrayHelper.java @@ -237,6 +237,15 @@ public static boolean isAllFalse(boolean... array) { return true; } + public static boolean[] negate(boolean[] valueNullness) { + boolean[] result = new boolean[valueNullness.length]; + for (int i = 0; i < valueNullness.length; i++) { + result[i] = !valueNullness[i]; + } + return result; + } + + public static void addAll(Collection collection, T[] array) { collection.addAll( Arrays.asList( array ) ); } diff --git a/hibernate-core/src/main/java/org/hibernate/loader/entity/EntityLoader.java b/hibernate-core/src/main/java/org/hibernate/loader/entity/EntityLoader.java index 4039bfe3b419..074f975994dc 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/entity/EntityLoader.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/entity/EntityLoader.java @@ -6,15 +6,28 @@ */ package org.hibernate.loader.entity; +import org.hibernate.HibernateException; import org.hibernate.LockMode; import org.hibernate.LockOptions; import org.hibernate.MappingException; +import org.hibernate.engine.jdbc.Size; import org.hibernate.engine.spi.LoadQueryInfluencers; +import org.hibernate.engine.spi.Mapping; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.internal.util.collections.ArrayHelper; import org.hibernate.persister.entity.OuterJoinLoadable; +import org.hibernate.type.AbstractType; import org.hibernate.type.Type; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; + /** * Loads an entity instance using outerjoin fetching to fetch associated entities. *
@@ -97,7 +110,7 @@ public EntityLoader( loadQueryInfluencers ); initFromWalker( walker ); - this.compositeKeyManyToOneTargetIndices = walker.getCompositeKeyManyToOneTargetIndices(); + compositeKeyManyToOneTargetIndices = walker.getCompositeKeyManyToOneTargetIndices(); postInstantiate(); batchLoader = batchSize > 1; @@ -126,7 +139,7 @@ public EntityLoader( loadQueryInfluencers ); initFromWalker( walker ); - this.compositeKeyManyToOneTargetIndices = walker.getCompositeKeyManyToOneTargetIndices(); + compositeKeyManyToOneTargetIndices = walker.getCompositeKeyManyToOneTargetIndices(); postInstantiate(); batchLoader = batchSize > 1; @@ -140,6 +153,58 @@ public EntityLoader( } } + public EntityLoader( + OuterJoinLoadable persister, + boolean[] valueNullness, + int batchSize, + LockOptions lockOptions, + SessionFactoryImplementor factory, + LoadQueryInfluencers loadQueryInfluencers) throws MappingException { + super( persister, new NaturalIdType( persister, valueNullness ), factory, loadQueryInfluencers ); + + EntityJoinWalker walker = new EntityJoinWalker( + persister, + naturalIdColumns( valueNullness ), + batchSize, + lockOptions, + factory, + loadQueryInfluencers + ) { + @Override + protected StringBuilder whereString(String alias, String[] columnNames, int batchSize) { + StringBuilder sql = super.whereString(alias, columnNames, batchSize); + for (String nullCol : naturalIdColumns( ArrayHelper.negate( valueNullness ) ) ) { + sql.append(" and ").append( getAlias() ).append('.').append(nullCol).append(" is null"); + } + return sql; + } + }; + initFromWalker( walker ); + compositeKeyManyToOneTargetIndices = walker.getCompositeKeyManyToOneTargetIndices(); + postInstantiate(); + + batchLoader = batchSize > 1; + + if ( LOG.isDebugEnabled() ) { + LOG.debugf( "Static select for entity %s [%s:%s]: %s", + entityName, + lockOptions.getLockMode(), + lockOptions.getTimeOut(), + getSQLString() ); + } + } + + private String[] naturalIdColumns(boolean[] valueNullness) { + int i = 0; + List columns = new ArrayList<>(); + for ( int p : persister.getNaturalIdentifierProperties() ) { + if ( !valueNullness[i++] ) { + columns.addAll( Arrays.asList( persister.getPropertyColumnNames(p) ) ); + } + } + return columns.toArray(ArrayHelper.EMPTY_STRING_ARRAY); + } + public Object loadByUniqueKey(SharedSessionContractImplementor session, Object key) { return loadByUniqueKey( session, key, null ); } @@ -157,4 +222,118 @@ protected boolean isSingleRowLoader() { public int[][] getCompositeKeyManyToOneTargetIndices() { return compositeKeyManyToOneTargetIndices; } + + static class NaturalIdType extends AbstractType { + private OuterJoinLoadable persister; + private boolean[] valueNullness; + + NaturalIdType(OuterJoinLoadable persister, boolean[] valueNullness) { + this.persister = persister; + this.valueNullness = valueNullness; + } + + @Override + public int getColumnSpan(Mapping mapping) throws MappingException { + int span = 0; + int i = 0; + for ( int p : persister.getNaturalIdentifierProperties() ) { + if ( !valueNullness[i++] ) { + span += persister.getPropertyColumnNames(p).length; + } + } + return span; + } + + @Override + public int[] sqlTypes(Mapping mapping) throws MappingException { + throw new UnsupportedOperationException(); + } + + @Override + public Size[] dictatedSizes(Mapping mapping) throws MappingException { + throw new UnsupportedOperationException(); + } + + @Override + public Size[] defaultSizes(Mapping mapping) throws MappingException { + throw new UnsupportedOperationException(); + } + + @Override + public Class getReturnedClass() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isDirty(Object oldState, Object currentState, boolean[] checkable, SharedSessionContractImplementor session) + throws HibernateException { + throw new UnsupportedOperationException(); + } + + @Override + public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) + throws HibernateException, SQLException { + throw new UnsupportedOperationException(); + } + + @Override + public Object nullSafeGet(ResultSet rs, String name, SharedSessionContractImplementor session, Object owner) + throws HibernateException, SQLException { + throw new UnsupportedOperationException(); + } + + @Override + public void nullSafeSet(PreparedStatement st, Object value, int index, boolean[] settable, SharedSessionContractImplementor session) + throws HibernateException, SQLException { + throw new UnsupportedOperationException(); + } + + @Override + public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session) + throws HibernateException, SQLException { + Object[] keys = (Object[]) value; + int i = 0; + for ( int p : persister.getNaturalIdentifierProperties() ) { + if ( !valueNullness[i] ) { + persister.getPropertyTypes()[p].nullSafeSet( st, keys[i], index++, session ); + } + i++; + } + } + + @Override + public String toLoggableString(Object value, SessionFactoryImplementor factory) { + return "natural id"; + } + + @Override + public String getName() { + throw new UnsupportedOperationException(); + } + + @Override + public Object deepCopy(Object value, SessionFactoryImplementor factory) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isMutable() { + throw new UnsupportedOperationException(); + } + + @Override + public Object resolve(Object value, SharedSessionContractImplementor session, Object owner, Boolean overridingEager) { + throw new UnsupportedOperationException(); + } + + @Override + public Object replace(Object original, Object target, SharedSessionContractImplementor session, Object owner, Map copyCache) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean[] toColumnNullness(Object value, Mapping mapping) { + throw new UnsupportedOperationException(); + } + } } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index b01049aef95c..b0bab9f994d7 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -2481,21 +2481,19 @@ public Object loadByUniqueKey( return getAppropriateUniqueKeyLoader( propertyName, session ).loadByUniqueKey( session, uniqueKey ); } - public Object loadByUniqueKey( - String propertyName, - Object uniqueKey, + public Object loadByNaturalId( + Object[] naturalIdValues, LockOptions lockOptions, SharedSessionContractImplementor session) throws HibernateException { //TODO: cache this return new EntityLoader( this, - propertyMapping.toColumns( propertyName ), - propertyMapping.toType( propertyName ), + determineValueNullness( naturalIdValues ), 1, lockOptions, getFactory(), session.getLoadQueryInfluencers() - ).loadByUniqueKey( session, uniqueKey ); + ).loadByUniqueKey( session, naturalIdValues ); } private EntityLoader getAppropriateUniqueKeyLoader(String propertyName, SharedSessionContractImplementor session) { diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/UniqueKeyLoadable.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/UniqueKeyLoadable.java index f7c90226cea4..8a7c52279a44 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/UniqueKeyLoadable.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/UniqueKeyLoadable.java @@ -25,9 +25,8 @@ Object loadByUniqueKey( /** * Load an instance of the persistent class, by a natural id. */ - Object loadByUniqueKey( - String propertyName, - Object uniqueKey, + Object loadByNaturalId( + Object[] naturalIds, LockOptions lockOptions, SharedSessionContractImplementor session); From e0ee9f5b0af6c0d09cae602307e3172f10ec11bd Mon Sep 17 00:00:00 2001 From: Gavin King Date: Tue, 23 Feb 2021 19:12:59 +0100 Subject: [PATCH 031/644] make it easy for Hibernate Reactive to reuse the @NaturalId stuff --- .../hibernate/loader/entity/EntityLoader.java | 152 +----------------- .../entity/NaturalIdEntityJoinWalker.java | 56 +++++++ .../loader/entity/NaturalIdType.java | 142 ++++++++++++++++ 3 files changed, 201 insertions(+), 149 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/loader/entity/NaturalIdEntityJoinWalker.java create mode 100644 hibernate-core/src/main/java/org/hibernate/loader/entity/NaturalIdType.java diff --git a/hibernate-core/src/main/java/org/hibernate/loader/entity/EntityLoader.java b/hibernate-core/src/main/java/org/hibernate/loader/entity/EntityLoader.java index 074f975994dc..d7be98e4262c 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/entity/EntityLoader.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/entity/EntityLoader.java @@ -6,28 +6,15 @@ */ package org.hibernate.loader.entity; -import org.hibernate.HibernateException; import org.hibernate.LockMode; import org.hibernate.LockOptions; import org.hibernate.MappingException; -import org.hibernate.engine.jdbc.Size; import org.hibernate.engine.spi.LoadQueryInfluencers; -import org.hibernate.engine.spi.Mapping; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.internal.util.collections.ArrayHelper; import org.hibernate.persister.entity.OuterJoinLoadable; -import org.hibernate.type.AbstractType; import org.hibernate.type.Type; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import java.util.Map; - /** * Loads an entity instance using outerjoin fetching to fetch associated entities. *
@@ -162,23 +149,14 @@ public EntityLoader( LoadQueryInfluencers loadQueryInfluencers) throws MappingException { super( persister, new NaturalIdType( persister, valueNullness ), factory, loadQueryInfluencers ); - EntityJoinWalker walker = new EntityJoinWalker( + EntityJoinWalker walker = new NaturalIdEntityJoinWalker( persister, - naturalIdColumns( valueNullness ), + valueNullness, batchSize, lockOptions, factory, loadQueryInfluencers - ) { - @Override - protected StringBuilder whereString(String alias, String[] columnNames, int batchSize) { - StringBuilder sql = super.whereString(alias, columnNames, batchSize); - for (String nullCol : naturalIdColumns( ArrayHelper.negate( valueNullness ) ) ) { - sql.append(" and ").append( getAlias() ).append('.').append(nullCol).append(" is null"); - } - return sql; - } - }; + ); initFromWalker( walker ); compositeKeyManyToOneTargetIndices = walker.getCompositeKeyManyToOneTargetIndices(); postInstantiate(); @@ -194,17 +172,6 @@ protected StringBuilder whereString(String alias, String[] columnNames, int batc } } - private String[] naturalIdColumns(boolean[] valueNullness) { - int i = 0; - List columns = new ArrayList<>(); - for ( int p : persister.getNaturalIdentifierProperties() ) { - if ( !valueNullness[i++] ) { - columns.addAll( Arrays.asList( persister.getPropertyColumnNames(p) ) ); - } - } - return columns.toArray(ArrayHelper.EMPTY_STRING_ARRAY); - } - public Object loadByUniqueKey(SharedSessionContractImplementor session, Object key) { return loadByUniqueKey( session, key, null ); } @@ -223,117 +190,4 @@ public int[][] getCompositeKeyManyToOneTargetIndices() { return compositeKeyManyToOneTargetIndices; } - static class NaturalIdType extends AbstractType { - private OuterJoinLoadable persister; - private boolean[] valueNullness; - - NaturalIdType(OuterJoinLoadable persister, boolean[] valueNullness) { - this.persister = persister; - this.valueNullness = valueNullness; - } - - @Override - public int getColumnSpan(Mapping mapping) throws MappingException { - int span = 0; - int i = 0; - for ( int p : persister.getNaturalIdentifierProperties() ) { - if ( !valueNullness[i++] ) { - span += persister.getPropertyColumnNames(p).length; - } - } - return span; - } - - @Override - public int[] sqlTypes(Mapping mapping) throws MappingException { - throw new UnsupportedOperationException(); - } - - @Override - public Size[] dictatedSizes(Mapping mapping) throws MappingException { - throw new UnsupportedOperationException(); - } - - @Override - public Size[] defaultSizes(Mapping mapping) throws MappingException { - throw new UnsupportedOperationException(); - } - - @Override - public Class getReturnedClass() { - throw new UnsupportedOperationException(); - } - - @Override - public boolean isDirty(Object oldState, Object currentState, boolean[] checkable, SharedSessionContractImplementor session) - throws HibernateException { - throw new UnsupportedOperationException(); - } - - @Override - public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) - throws HibernateException, SQLException { - throw new UnsupportedOperationException(); - } - - @Override - public Object nullSafeGet(ResultSet rs, String name, SharedSessionContractImplementor session, Object owner) - throws HibernateException, SQLException { - throw new UnsupportedOperationException(); - } - - @Override - public void nullSafeSet(PreparedStatement st, Object value, int index, boolean[] settable, SharedSessionContractImplementor session) - throws HibernateException, SQLException { - throw new UnsupportedOperationException(); - } - - @Override - public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session) - throws HibernateException, SQLException { - Object[] keys = (Object[]) value; - int i = 0; - for ( int p : persister.getNaturalIdentifierProperties() ) { - if ( !valueNullness[i] ) { - persister.getPropertyTypes()[p].nullSafeSet( st, keys[i], index++, session ); - } - i++; - } - } - - @Override - public String toLoggableString(Object value, SessionFactoryImplementor factory) { - return "natural id"; - } - - @Override - public String getName() { - throw new UnsupportedOperationException(); - } - - @Override - public Object deepCopy(Object value, SessionFactoryImplementor factory) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean isMutable() { - throw new UnsupportedOperationException(); - } - - @Override - public Object resolve(Object value, SharedSessionContractImplementor session, Object owner, Boolean overridingEager) { - throw new UnsupportedOperationException(); - } - - @Override - public Object replace(Object original, Object target, SharedSessionContractImplementor session, Object owner, Map copyCache) { - throw new UnsupportedOperationException(); - } - - @Override - public boolean[] toColumnNullness(Object value, Mapping mapping) { - throw new UnsupportedOperationException(); - } - } } diff --git a/hibernate-core/src/main/java/org/hibernate/loader/entity/NaturalIdEntityJoinWalker.java b/hibernate-core/src/main/java/org/hibernate/loader/entity/NaturalIdEntityJoinWalker.java new file mode 100644 index 000000000000..46ea96e9e5ec --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/loader/entity/NaturalIdEntityJoinWalker.java @@ -0,0 +1,56 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.loader.entity; + +import org.hibernate.LockOptions; +import org.hibernate.MappingException; +import org.hibernate.engine.spi.LoadQueryInfluencers; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.persister.entity.Loadable; +import org.hibernate.persister.entity.OuterJoinLoadable; + +import java.util.ArrayList; +import java.util.List; + +import static java.util.Arrays.asList; +import static org.hibernate.internal.util.collections.ArrayHelper.EMPTY_STRING_ARRAY; +import static org.hibernate.internal.util.collections.ArrayHelper.negate; + +/** + * An {@link EntityJoinWalker} that uses 'is null' predicates to match + * null {@link org.hibernate.annotations.NaturalId} properties. + * + * @author Gavin King + */ +public class NaturalIdEntityJoinWalker extends EntityJoinWalker { + + private static String[] naturalIdColumns(Loadable persister, boolean[] valueNullness) { + int i = 0; + List columns = new ArrayList<>(); + for ( int p : persister.getNaturalIdentifierProperties() ) { + if ( !valueNullness[i++] ) { + columns.addAll( asList( persister.getPropertyColumnNames(p) ) ); + } + } + return columns.toArray(EMPTY_STRING_ARRAY); + } + + public NaturalIdEntityJoinWalker( + OuterJoinLoadable persister, + boolean[] valueNullness, + int batchSize, + LockOptions lockOptions, + SessionFactoryImplementor factory, + LoadQueryInfluencers loadQueryInfluencers) throws MappingException { + super(persister, naturalIdColumns( persister, valueNullness ), batchSize, lockOptions, factory, loadQueryInfluencers); + StringBuilder sql = new StringBuilder( getSQLString() ); + for ( String nullCol : naturalIdColumns( getPersister(), negate( valueNullness ) ) ) { + sql.append(" and ").append( getAlias() ).append('.').append( nullCol ).append(" is null"); + } + setSql( sql.toString() ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/loader/entity/NaturalIdType.java b/hibernate-core/src/main/java/org/hibernate/loader/entity/NaturalIdType.java new file mode 100644 index 000000000000..c515660d5ce7 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/loader/entity/NaturalIdType.java @@ -0,0 +1,142 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.loader.entity; + +import org.hibernate.HibernateException; +import org.hibernate.MappingException; +import org.hibernate.engine.jdbc.Size; +import org.hibernate.engine.spi.Mapping; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.persister.entity.OuterJoinLoadable; +import org.hibernate.type.AbstractType; + +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.util.Map; + +/** + * Workaround for the fact that we don't have a well-defined Hibernate + * type when loading by multiple {@link org.hibernate.annotations.NaturalId} + * properties. + * + * @author Gavin King + */ +public class NaturalIdType extends AbstractType { + private OuterJoinLoadable persister; + private boolean[] valueNullness; + + public NaturalIdType(OuterJoinLoadable persister, boolean[] valueNullness) { + this.persister = persister; + this.valueNullness = valueNullness; + } + + @Override + public int getColumnSpan(Mapping mapping) throws MappingException { + int span = 0; + int i = 0; + for (int p : persister.getNaturalIdentifierProperties() ) { + if ( !valueNullness[i++] ) { + span += persister.getPropertyColumnNames(p).length; + } + } + return span; + } + + @Override + public int[] sqlTypes(Mapping mapping) throws MappingException { + throw new UnsupportedOperationException(); + } + + @Override + public Size[] dictatedSizes(Mapping mapping) throws MappingException { + throw new UnsupportedOperationException(); + } + + @Override + public Size[] defaultSizes(Mapping mapping) throws MappingException { + throw new UnsupportedOperationException(); + } + + @Override + public Class getReturnedClass() { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isDirty(Object oldState, Object currentState, boolean[] checkable, SharedSessionContractImplementor session) + throws HibernateException { + throw new UnsupportedOperationException(); + } + + @Override + public Object nullSafeGet(ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner) + throws HibernateException, SQLException { + throw new UnsupportedOperationException(); + } + + @Override + public Object nullSafeGet(ResultSet rs, String name, SharedSessionContractImplementor session, Object owner) + throws HibernateException, SQLException { + throw new UnsupportedOperationException(); + } + + @Override + public void nullSafeSet(PreparedStatement st, Object value, int index, boolean[] settable, SharedSessionContractImplementor session) + throws HibernateException, SQLException { + throw new UnsupportedOperationException(); + } + + @Override + public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session) + throws HibernateException, SQLException { + Object[] keys = (Object[]) value; + int i = 0; + for ( int p : persister.getNaturalIdentifierProperties() ) { + if ( !valueNullness[i] ) { + persister.getPropertyTypes()[p].nullSafeSet( st, keys[i], index++, session ); + } + i++; + } + } + + @Override + public String toLoggableString(Object value, SessionFactoryImplementor factory) { + return "natural id"; + } + + @Override + public String getName() { + throw new UnsupportedOperationException(); + } + + @Override + public Object deepCopy(Object value, SessionFactoryImplementor factory) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean isMutable() { + throw new UnsupportedOperationException(); + } + + @Override + public Object resolve(Object value, SharedSessionContractImplementor session, Object owner, Boolean overridingEager) { + throw new UnsupportedOperationException(); + } + + @Override + public Object replace(Object original, Object target, SharedSessionContractImplementor session, Object owner, Map copyCache) { + throw new UnsupportedOperationException(); + } + + @Override + public boolean[] toColumnNullness(Object value, Mapping mapping) { + throw new UnsupportedOperationException(); + } +} From 3a24c700fc57cd0427077be4c5c537004cd8ddb6 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Tue, 23 Feb 2021 22:57:10 +0100 Subject: [PATCH 032/644] cache the @NaturalId loaders and clean up some of the other loader caching code --- .../entity/AbstractEntityPersister.java | 160 ++++++++++++------ 1 file changed, 107 insertions(+), 53 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index b0bab9f994d7..86298536d2be 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -257,6 +257,7 @@ public abstract class AbstractEntityPersister private final EntityLoaderLazyCollection loaders = new EntityLoaderLazyCollection(); private volatile Map uniqueKeyLoaders; + private volatile Map naturalIdLoaders; // SQL strings private String sqlVersionSelectString; @@ -2478,40 +2479,56 @@ public Object loadByUniqueKey( String propertyName, Object uniqueKey, SharedSessionContractImplementor session) throws HibernateException { - return getAppropriateUniqueKeyLoader( propertyName, session ).loadByUniqueKey( session, uniqueKey ); + return getAppropriateUniqueKeyLoader( propertyName, session ) + .loadByUniqueKey( session, uniqueKey ); } public Object loadByNaturalId( Object[] naturalIdValues, LockOptions lockOptions, SharedSessionContractImplementor session) throws HibernateException { - //TODO: cache this - return new EntityLoader( - this, - determineValueNullness( naturalIdValues ), - 1, - lockOptions, - getFactory(), - session.getLoadQueryInfluencers() - ).loadByUniqueKey( session, naturalIdValues ); + return getAppropriateNaturalIdLoader( determineValueNullness( naturalIdValues ), lockOptions, session ) + .loadByUniqueKey( session, naturalIdValues ); } - private EntityLoader getAppropriateUniqueKeyLoader(String propertyName, SharedSessionContractImplementor session) { - final boolean useStaticLoader = !session.getLoadQueryInfluencers().hasEnabledFilters() - && !session.getLoadQueryInfluencers().hasEnabledFetchProfiles() - && propertyName.indexOf( '.' ) < 0; //ugly little workaround for fact that createUniqueKeyLoaders() does not handle component properties + private EntityLoader getAppropriateNaturalIdLoader( + boolean[] valueNullness, + LockOptions lockOptions, + SharedSessionContractImplementor session) { + LoadQueryInfluencers loadQueryInfluencers = session.getLoadQueryInfluencers(); + return useStaticNaturalIdLoader( valueNullness, lockOptions, loadQueryInfluencers ) + ? naturalIdLoaders.get( lockOptions.getLockMode() ) : + createNaturalIdLoader( valueNullness, lockOptions, loadQueryInfluencers ); + } - if ( useStaticLoader ) { - final Map uniqueKeyLoaders = this.uniqueKeyLoaders; - return uniqueKeyLoaders == null ? null : uniqueKeyLoaders.get( propertyName ); - } - else { - return createUniqueKeyLoader( - propertyMapping.toType( propertyName ), - propertyMapping.toColumns( propertyName ), - session.getLoadQueryInfluencers() - ); - } + private boolean useStaticNaturalIdLoader( + boolean[] valueNullness, + LockOptions lockOptions, + LoadQueryInfluencers loadQueryInfluencers) { + return lockOptions.getTimeOut() == LockOptions.WAIT_FOREVER + && ArrayHelper.isAllFalse( valueNullness ) + && !loadQueryInfluencers.hasEnabledFilters() + && !loadQueryInfluencers.hasEnabledFetchProfiles(); + } + + private EntityLoader getAppropriateUniqueKeyLoader( + String propertyName, + SharedSessionContractImplementor session) { + LoadQueryInfluencers loadQueryInfluencers = session.getLoadQueryInfluencers(); + return useStaticUniqueKeyLoader( propertyName, loadQueryInfluencers ) + ? uniqueKeyLoaders.get( propertyName ) + : createUniqueKeyLoader( + propertyMapping.toType( propertyName ), + propertyMapping.toColumns( propertyName ), + loadQueryInfluencers + ); + } + + private boolean useStaticUniqueKeyLoader(String propertyName, LoadQueryInfluencers loadQueryInfluencers) { + return !loadQueryInfluencers.hasEnabledFilters() + && !loadQueryInfluencers.hasEnabledFetchProfiles() + //ugly little workaround for fact that createUniqueKeyLoaders() does not handle component properties + && propertyName.indexOf( '.' ) < 0; } public int getPropertyIndex(String propertyName) { @@ -2521,10 +2538,10 @@ public int getPropertyIndex(String propertyName) { protected void createUniqueKeyLoaders() throws MappingException { Type[] propertyTypes = getPropertyTypes(); String[] propertyNames = getPropertyNames(); - for ( int i = 0; i < entityMetamodel.getPropertySpan(); i++ ) { + for ( int i = 0; i < propertyUniqueness.length; i++ ) { if ( propertyUniqueness[i] ) { if ( uniqueKeyLoaders == null ) { - this.uniqueKeyLoaders = new HashMap<>(); + uniqueKeyLoaders = new HashMap<>(); } //don't need filters for the static loaders uniqueKeyLoaders.put( @@ -2538,6 +2555,9 @@ protected void createUniqueKeyLoaders() throws MappingException { //TODO: create uk loaders for component properties } } + if ( uniqueKeyLoaders == null ) { + uniqueKeyLoaders = Collections.emptyMap(); + } } private EntityLoader createUniqueKeyLoader( @@ -2559,6 +2579,40 @@ private EntityLoader createUniqueKeyLoader( ); } + protected void createNaturalIdLoaders() throws MappingException { + if ( hasNaturalIdentifier() ) { + naturalIdLoaders = new HashMap<>(); + boolean[] valueNullness = new boolean[ getNaturalIdentifierProperties().length ]; + for ( LockMode lockMode : LockMode.values() ) { + naturalIdLoaders.put( + lockMode, + createNaturalIdLoader( + valueNullness, + new LockOptions(lockMode), + LoadQueryInfluencers.NONE + ) + ); + } + } + else { + naturalIdLoaders = Collections.emptyMap(); + } + } + + private EntityLoader createNaturalIdLoader( + boolean[] valueNullness, + LockOptions lockOptions, + LoadQueryInfluencers loadQueryInfluencers) { + return new EntityLoader( + this, + valueNullness, + 1, + lockOptions, + getFactory(), + loadQueryInfluencers + ); + } + protected String getSQLWhereString(String alias) { return StringHelper.replace( sqlWhereStringTemplate, Template.TEMPLATE, alias ); } @@ -4356,6 +4410,7 @@ public final void postInstantiate() throws MappingException { createLoaders(); createUniqueKeyLoaders(); + createNaturalIdLoaders(); createQueryLoader(); doPostInstantiate(); @@ -4570,33 +4625,32 @@ protected UniqueEntityLoader getAppropriateLoader(LockOptions lockOptions, Share // regardless of any other consideration return queryLoader; } - else if ( isAffectedByEnabledFilters( session ) ) { - // because filters affect the rows returned (because they add - // restrictions) these need to be next in precedence - return createEntityLoader( lockOptions, session.getLoadQueryInfluencers() ); - } - else if ( session.getLoadQueryInfluencers().getInternalFetchProfile() != null && LockMode.UPGRADE.greaterThan( - lockOptions.getLockMode() - ) ) { - // Next, we consider whether an 'internal' fetch profile has been set. - // This indicates a special fetch profile Hibernate needs applied - // (for its merge loading process e.g.). - final String internalFetchProfile = session.getLoadQueryInfluencers().getInternalFetchProfile(); - return getLoaderByString( internalFetchProfile ); - } - else if ( isAffectedByEnabledFetchProfiles( session ) ) { - // If the session has associated influencers we need to adjust the - // SQL query used for loading based on those influencers - return createEntityLoader( lockOptions, session.getLoadQueryInfluencers() ); - } - else if ( isAffectedByEntityGraph( session ) ) { - return createEntityLoader( lockOptions, session.getLoadQueryInfluencers() ); - } - else if ( lockOptions.getTimeOut() != LockOptions.WAIT_FOREVER ) { - return createEntityLoader( lockOptions, session.getLoadQueryInfluencers() ); - } else { - return getLoaderByLockMode( lockOptions.getLockMode() ); + LoadQueryInfluencers loadQueryInfluencers = session.getLoadQueryInfluencers(); + if ( isAffectedByEnabledFilters( session ) ) { + // because filters affect the rows returned (because they add + // restrictions) these need to be next in precedence + return createEntityLoader( lockOptions, loadQueryInfluencers ); + } + else if ( loadQueryInfluencers.getInternalFetchProfile() != null + && LockMode.UPGRADE.greaterThan( lockOptions.getLockMode() ) ) { + // Next, we consider whether an 'internal' fetch profile has been set. + // This indicates a special fetch profile Hibernate needs applied + // (for its merge loading process e.g.). + return getLoaderByString( loadQueryInfluencers.getInternalFetchProfile() ); + } + else if ( isAffectedByEnabledFetchProfiles( session ) + || isAffectedByEntityGraph( session ) ) { + // If the session has associated influencers we need to adjust the + // SQL query used for loading based on those influencers + return createEntityLoader( lockOptions, loadQueryInfluencers ); + } + else if ( lockOptions.getTimeOut() != LockOptions.WAIT_FOREVER ) { + return createEntityLoader( lockOptions, loadQueryInfluencers ); + } + else { + return getLoaderByLockMode( lockOptions.getLockMode() ); + } } } From 496e5995b2c07853953d05540a8368ec18ac7c02 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Tue, 23 Feb 2021 23:10:41 +0100 Subject: [PATCH 033/644] deprecate old code for fetching id by natural id --- .../hibernate/persister/entity/AbstractEntityPersister.java | 4 +++- .../java/org/hibernate/persister/entity/EntityPersister.java | 3 +++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index 86298536d2be..e447b10ed292 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -5578,7 +5578,7 @@ rs, getPropertyAliases( } } - @Override + @Override @Deprecated public Serializable loadEntityIdByNaturalId( Object[] naturalIdValues, LockOptions lockOptions, @@ -5653,6 +5653,7 @@ public static boolean[] determineValueNullness(Object[] naturalIdValues) { private Boolean naturalIdIsNonNullable; private String cachedPkByNonNullableNaturalIdQuery; + @Deprecated protected String determinePkByNaturalIdQuery(boolean[] valueNullness) { if ( !hasNaturalIdentifier() ) { throw new HibernateException( @@ -5694,6 +5695,7 @@ private boolean determineNaturalIdNullability() { return true; } + @Deprecated private String generateEntityIdByNaturalIdSql(boolean[] valueNullness) { EntityPersister rootPersister = getFactory().getEntityPersister( getRootEntityName() ); if ( rootPersister != this ) { diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java index 2829adfe8d95..ec4a492433a9 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/EntityPersister.java @@ -365,7 +365,10 @@ default Object initializeEnhancedEntityUsedAsProxy( /** * Load the id for the entity based on the natural id. + * + * @deprecated use {@link UniqueKeyLoadable#loadByNaturalId(Object[], LockOptions, SharedSessionContractImplementor)} */ + @Deprecated Serializable loadEntityIdByNaturalId( Object[] naturalIdValues, LockOptions lockOptions, SharedSessionContractImplementor session); From 9b991310b52612c5e1ec8c6c92e4caad55b45d92 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Tue, 23 Feb 2021 18:27:37 +0100 Subject: [PATCH 034/644] HHH-14467 Fix relative ordering of second pass for associations and derived IDs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Always execute second pass for associations referencing an entity with derived ID after the second pass for that entity's derived ID. Signed-off-by: Yoann Rodière --- .../org/hibernate/cfg/ToOneFkSecondPass.java | 37 +++++++++++++------ 1 file changed, 25 insertions(+), 12 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/ToOneFkSecondPass.java b/hibernate-core/src/main/java/org/hibernate/cfg/ToOneFkSecondPass.java index 906d1827b0b3..f4df4aa8e86d 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/ToOneFkSecondPass.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/ToOneFkSecondPass.java @@ -66,19 +66,32 @@ else if ( property != null) { //try explicit identifier property return path.startsWith( property.getName() + "." ); } - else { - //try the embedded property - //embedded property starts their path with 'id.' See PropertyPreloadedData( ) use when idClass != null in AnnotationSourceProcessor - if ( path.startsWith( "id." ) ) { - KeyValue valueIdentifier = persistentClass.getIdentifier(); - String localPath = path.substring( 3 ); - if ( valueIdentifier instanceof Component ) { - Iterator it = ( (Component) valueIdentifier ).getPropertyIterator(); - while ( it.hasNext() ) { - Property idProperty = (Property) it.next(); - if ( localPath.startsWith( idProperty.getName() ) ) return true; + //try the embedded property + //embedded property starts their path with 'id.' See PropertyPreloadedData( ) use when idClass != null in AnnotationSourceProcessor + else if ( path.startsWith( "id." ) ) { + KeyValue valueIdentifier = persistentClass.getIdentifier(); + String localPath = path.substring( 3 ); + if ( valueIdentifier instanceof Component ) { + Iterator it = ( (Component) valueIdentifier ).getPropertyIterator(); + while ( it.hasNext() ) { + Property idProperty = (Property) it.next(); + if ( localPath.startsWith( idProperty.getName() ) ) { + return true; + } + } + } + } + // Try the case where a @ManyToOne is also an ID property + // E.g. @ManyToOne @Id SomeEntity other; + else if ( !path.contains( "." ) ) { + KeyValue valueIdentifier = persistentClass.getIdentifier(); + if ( valueIdentifier instanceof Component ) { + Iterator it = ( (Component) valueIdentifier ).getPropertyIterator(); + while ( it.hasNext() ) { + Property idProperty = (Property) it.next(); + if ( path.equals( idProperty.getName() ) ) { + return true; } - } } } From b6b83536e61d5cea0496f6913f47d99de5e40e1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Wed, 24 Feb 2021 11:57:24 +0100 Subject: [PATCH 035/644] HHH-14467 Test referencing an entity whose ID is derived MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Yoann Rodière --- ...ParentSimpleDepSecondPassOrderingTest.java | 273 ++++++++++++++++++ .../org/hibernate/test/util/SchemaUtil.java | 16 + 2 files changed, 289 insertions(+) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e4/c/DerivedIdentitySimpleParentSimpleDepSecondPassOrderingTest.java diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e4/c/DerivedIdentitySimpleParentSimpleDepSecondPassOrderingTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e4/c/DerivedIdentitySimpleParentSimpleDepSecondPassOrderingTest.java new file mode 100644 index 000000000000..e3bf9a60b0fc --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/e4/c/DerivedIdentitySimpleParentSimpleDepSecondPassOrderingTest.java @@ -0,0 +1,273 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.annotations.derivedidentities.e4.c; + +import java.io.Serializable; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.ManyToOne; +import javax.persistence.OneToOne; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hibernate.test.util.SchemaUtil.getColumnNames; + +/** + * Test that when an entity with derived identity is referenced from a third entity, + * associations on that third entity are bound in a second pass *after* the derived identity is bound. + * + * This test used to fail on bootstrap with the following error: + * + * org.hibernate.MappingException: Foreign key (FK2m2b1kaetxfvcsaih4raaocn8:ref_mto_derived [])) must have same number of columns as the referenced primary key (mto_derived [idsource_id]) + */ +@TestForIssue(jiraKey = "HHH-14467") +public class DerivedIdentitySimpleParentSimpleDepSecondPassOrderingTest extends BaseNonConfigCoreFunctionalTestCase { + @Test + public void testOneToOne() { + assertThat( getColumnNames( "oto_derived", metadata() ) ) + .contains( "idsource_id" ) + .doesNotContain( "id", "idSource", "idsource" ); + + inTransaction( s -> { + EntityWithSimpleId simple = new EntityWithSimpleId( 1 ); + s.persist( simple ); + EntityWithOneToOneDerivedId derived = new EntityWithOneToOneDerivedId( simple ); + s.persist( derived ); + } ); + + inTransaction( s -> { + EntityWithOneToOneDerivedId derived = s.get( EntityWithOneToOneDerivedId.class, 1 ); + assertThat( derived.getIdsource().getId() ).isEqualTo( 1 ); + derived.setData( "something" ); + } ); + + inTransaction( s -> { + EntityWithOneToOneDerivedId derived = s.get( EntityWithOneToOneDerivedId.class, 1 ); + assertThat( derived.getData() ).isNotNull(); + } ); + + inTransaction( s -> { + EntityWithOneToOneDerivedId derived = s.get( EntityWithOneToOneDerivedId.class, 1 ); + EntityReferencingEntityWithOneToOneDerivedId referencing = + new EntityReferencingEntityWithOneToOneDerivedId( 1, derived ); + s.persist( referencing ); + } ); + + inTransaction( s -> { + EntityReferencingEntityWithOneToOneDerivedId referencing = + s.get( EntityReferencingEntityWithOneToOneDerivedId.class, 1 ); + assertThat( referencing.getRef().getIdsource().getId() ).isEqualTo( 1 ); + } ); + } + + @Test + public void testManyToOne() { + assertThat( getColumnNames( "mto_derived", metadata() ) ) + .contains( "idsource_id" ) + .doesNotContain( "id", "idSource", "idsource" ); + + inTransaction( s -> { + EntityWithSimpleId simple = new EntityWithSimpleId( 2 ); + s.persist( simple ); + EntityWithManyToOneDerivedId derived = new EntityWithManyToOneDerivedId( simple ); + s.persist( derived ); + } ); + + inTransaction( s -> { + EntityWithManyToOneDerivedId derived = s.get( EntityWithManyToOneDerivedId.class, 2 ); + assertThat( derived.getIdsource().getId() ).isEqualTo( 2 ); + derived.setData( "something" ); + } ); + + inTransaction( s -> { + EntityWithManyToOneDerivedId derived = s.get( EntityWithManyToOneDerivedId.class, 2 ); + assertThat( derived.getData() ).isNotNull(); + } ); + + inTransaction( s -> { + EntityWithManyToOneDerivedId derived = s.get( EntityWithManyToOneDerivedId.class, 2 ); + EntityReferencingEntityWithManyToOneDerivedId referencing = + new EntityReferencingEntityWithManyToOneDerivedId( 2, derived ); + s.persist( referencing ); + } ); + + inTransaction( s -> { + EntityReferencingEntityWithManyToOneDerivedId referencing = + s.get( EntityReferencingEntityWithManyToOneDerivedId.class, 2 ); + assertThat( referencing.getRef().getIdsource().getId() ).isEqualTo( 2 ); + } ); + } + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + // These two must be mentioned first in order to trigger the bug. + // In a real application this would happen randomly, depending on how JARs are scanned. + EntityReferencingEntityWithOneToOneDerivedId.class, + EntityReferencingEntityWithManyToOneDerivedId.class, + + EntityWithSimpleId.class, + EntityWithOneToOneDerivedId.class, + EntityWithManyToOneDerivedId.class + }; + } + + @Entity(name = "simple") + public static class EntityWithSimpleId { + @Id + private Integer id; + + public EntityWithSimpleId() { + } + + public EntityWithSimpleId(Integer id) { + this.id = id; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + } + + @Entity(name = "oto_derived") + public static class EntityWithOneToOneDerivedId implements Serializable { + @Id + @OneToOne + private EntityWithSimpleId idsource; + + private String data; + + public EntityWithOneToOneDerivedId() { + } + + public EntityWithOneToOneDerivedId(EntityWithSimpleId idsource) { + this.idsource = idsource; + } + + public EntityWithSimpleId getIdsource() { + return idsource; + } + + public void setIdsource(EntityWithSimpleId idsource) { + this.idsource = idsource; + } + + public String getData() { + return data; + } + + public void setData(String data) { + this.data = data; + } + } + + @Entity(name = "ref_oto_derived") + public static class EntityReferencingEntityWithOneToOneDerivedId implements Serializable { + @Id + private Integer id; + + @ManyToOne + private EntityWithOneToOneDerivedId ref; + + public EntityReferencingEntityWithOneToOneDerivedId() { + } + + public EntityReferencingEntityWithOneToOneDerivedId(Integer id, EntityWithOneToOneDerivedId ref) { + this.id = id; + this.ref = ref; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public EntityWithOneToOneDerivedId getRef() { + return ref; + } + + public void setRef(EntityWithOneToOneDerivedId ref) { + this.ref = ref; + } + } + + @Entity(name = "mto_derived") + public static class EntityWithManyToOneDerivedId implements Serializable { + @Id + @ManyToOne + private EntityWithSimpleId idsource; + + private String data; + + public EntityWithManyToOneDerivedId() { + } + + public EntityWithManyToOneDerivedId(EntityWithSimpleId idsource) { + this.idsource = idsource; + } + + public EntityWithSimpleId getIdsource() { + return idsource; + } + + public void setIdsource(EntityWithSimpleId idsource) { + this.idsource = idsource; + } + + public String getData() { + return data; + } + + public void setData(String data) { + this.data = data; + } + } + + @Entity(name = "ref_mto_derived") + public static class EntityReferencingEntityWithManyToOneDerivedId implements Serializable { + @Id + private Integer id; + + @ManyToOne + private EntityWithManyToOneDerivedId ref; + + public EntityReferencingEntityWithManyToOneDerivedId() { + } + + public EntityReferencingEntityWithManyToOneDerivedId(Integer id, EntityWithManyToOneDerivedId ref) { + this.id = id; + this.ref = ref; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public EntityWithManyToOneDerivedId getRef() { + return ref; + } + + public void setRef(EntityWithManyToOneDerivedId ref) { + this.ref = ref; + } + } + +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/util/SchemaUtil.java b/hibernate-core/src/test/java/org/hibernate/test/util/SchemaUtil.java index 769446d5aec0..3cdb27891ee6 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/util/SchemaUtil.java +++ b/hibernate-core/src/test/java/org/hibernate/test/util/SchemaUtil.java @@ -6,7 +6,9 @@ */ package org.hibernate.test.util; +import java.util.HashSet; import java.util.Iterator; +import java.util.Set; import org.hibernate.boot.Metadata; import org.hibernate.mapping.Column; @@ -18,6 +20,20 @@ * @author Emmanuel Bernard */ public abstract class SchemaUtil { + public static Set getColumnNames(String tableName, Metadata metadata) { + Set result = new HashSet<>(); + for ( Table table : metadata.collectTableMappings() ) { + if (tableName.equals( table.getName() ) ) { + Iterator columns = table.getColumnIterator(); + while ( columns.hasNext() ) { + Column column = columns.next(); + result.add( column.getName() ); + } + } + } + return result; + } + @SuppressWarnings("unchecked") public static boolean isColumnPresent(String tableName, String columnName, Metadata metadata) { for ( Table table : metadata.collectTableMappings() ) { From 021b2741ab6ec43c03c71990bf52140c3240c0dc Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Wed, 24 Feb 2021 20:11:48 -0800 Subject: [PATCH 036/644] HHH-14467 Simplify detection of *ToOne associations that are part of the entity identifier --- .../org/hibernate/cfg/ToOneFkSecondPass.java | 26 ++++++------------- 1 file changed, 8 insertions(+), 18 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/ToOneFkSecondPass.java b/hibernate-core/src/main/java/org/hibernate/cfg/ToOneFkSecondPass.java index f4df4aa8e86d..e849bd62006f 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/ToOneFkSecondPass.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/ToOneFkSecondPass.java @@ -67,29 +67,19 @@ else if ( property != null) { return path.startsWith( property.getName() + "." ); } //try the embedded property - //embedded property starts their path with 'id.' See PropertyPreloadedData( ) use when idClass != null in AnnotationSourceProcessor - else if ( path.startsWith( "id." ) ) { - KeyValue valueIdentifier = persistentClass.getIdentifier(); - String localPath = path.substring( 3 ); + else { + final KeyValue valueIdentifier = persistentClass.getIdentifier(); if ( valueIdentifier instanceof Component ) { - Iterator it = ( (Component) valueIdentifier ).getPropertyIterator(); - while ( it.hasNext() ) { - Property idProperty = (Property) it.next(); - if ( localPath.startsWith( idProperty.getName() ) ) { - return true; - } + // Embedded property starts their path with 'id.' + // See PropertyPreloadedData( ) use when idClass != null in AnnotationSourceProcessor + String localPath = path; + if ( path.startsWith( "id." ) ) { + localPath = path.substring( 3 ); } - } - } - // Try the case where a @ManyToOne is also an ID property - // E.g. @ManyToOne @Id SomeEntity other; - else if ( !path.contains( "." ) ) { - KeyValue valueIdentifier = persistentClass.getIdentifier(); - if ( valueIdentifier instanceof Component ) { Iterator it = ( (Component) valueIdentifier ).getPropertyIterator(); while ( it.hasNext() ) { Property idProperty = (Property) it.next(); - if ( path.equals( idProperty.getName() ) ) { + if ( localPath.startsWith( idProperty.getName() ) ) { return true; } } From a90aaa48b40dffe223c7daf5b167884d605ac1b7 Mon Sep 17 00:00:00 2001 From: gbadner Date: Thu, 25 Feb 2021 08:55:45 -0800 Subject: [PATCH 037/644] HHH-14467 Avoid false positives when detecting *ToOne associations that are part of the identifier MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Yoann Rodière --- .../src/main/java/org/hibernate/cfg/ToOneFkSecondPass.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/ToOneFkSecondPass.java b/hibernate-core/src/main/java/org/hibernate/cfg/ToOneFkSecondPass.java index e849bd62006f..b04c27d16e18 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/ToOneFkSecondPass.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/ToOneFkSecondPass.java @@ -79,7 +79,7 @@ else if ( property != null) { Iterator it = ( (Component) valueIdentifier ).getPropertyIterator(); while ( it.hasNext() ) { Property idProperty = (Property) it.next(); - if ( localPath.startsWith( idProperty.getName() ) ) { + if ( localPath.equals( idProperty.getName() ) || localPath.startsWith( idProperty.getName() + "." ) ) { return true; } } From de3f3c1d74f43692e7bf50f7cf967406db1535ab Mon Sep 17 00:00:00 2001 From: Francois van Delft Date: Mon, 8 Feb 2021 12:17:38 +0100 Subject: [PATCH 038/644] HHH-14443 Add hashcode to ObjectTypeCacheEntry, so query cache can do a successfull lookup for queryies with AnyTypes --- .../src/main/java/org/hibernate/type/AnyType.java | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/hibernate-core/src/main/java/org/hibernate/type/AnyType.java b/hibernate-core/src/main/java/org/hibernate/type/AnyType.java index 0b5161235871..2c56bc269400 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/AnyType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/AnyType.java @@ -13,6 +13,7 @@ import java.sql.SQLException; import java.util.Arrays; import java.util.Map; +import java.util.Objects; import java.util.Set; import org.hibernate.EntityMode; @@ -519,5 +520,18 @@ public static final class ObjectTypeCacheEntry implements Serializable { this.entityName = entityName; this.id = id; } + + public int hashCode() { + return Objects.hash(entityName, id); + } + + public boolean equals(Object object) { + if (object instanceof ObjectTypeCacheEntry) { + ObjectTypeCacheEntry objectTypeCacheEntry = (ObjectTypeCacheEntry)object; + return Objects.equals(objectTypeCacheEntry.entityName, entityName) && Objects.equals(objectTypeCacheEntry.id, id); + } + return false; + } + } } From 6868c68278b1b93d0ac56fc8d57d1b31bee295fe Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Mon, 1 Mar 2021 16:13:02 +0000 Subject: [PATCH 039/644] HHH-14443 Formatting and style fixes --- .../src/main/java/org/hibernate/type/AnyType.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/type/AnyType.java b/hibernate-core/src/main/java/org/hibernate/type/AnyType.java index 2c56bc269400..b321f2cff55e 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/AnyType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/AnyType.java @@ -522,13 +522,13 @@ public static final class ObjectTypeCacheEntry implements Serializable { } public int hashCode() { - return Objects.hash(entityName, id); + return Objects.hash( entityName, id ); } public boolean equals(Object object) { - if (object instanceof ObjectTypeCacheEntry) { + if (object instanceof ObjectTypeCacheEntry) { ObjectTypeCacheEntry objectTypeCacheEntry = (ObjectTypeCacheEntry)object; - return Objects.equals(objectTypeCacheEntry.entityName, entityName) && Objects.equals(objectTypeCacheEntry.id, id); + return Objects.equals( objectTypeCacheEntry.entityName, entityName ) && Objects.equals( objectTypeCacheEntry.id, id ); } return false; } From 4fad616d4bfe144349cabe055229dc54e53f3c08 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Sun, 14 Feb 2021 01:42:49 +0100 Subject: [PATCH 040/644] HHH-14474 Refactor internal visibility to allow Hibernate Reactive to implement non-primary key associations see https://github.com/hibernate/hibernate-reactive/issues/565 --- .../hibernate/loader/entity/AbstractEntityLoader.java | 5 +++++ .../java/org/hibernate/loader/entity/EntityLoader.java | 8 ++++++++ .../hibernate/loader/entity/UniqueEntityLoader.java | 7 +++++++ .../persister/entity/AbstractEntityPersister.java | 10 +++++----- 4 files changed, 25 insertions(+), 5 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/loader/entity/AbstractEntityLoader.java b/hibernate-core/src/main/java/org/hibernate/loader/entity/AbstractEntityLoader.java index f0716eae1cf0..a3d66e67559b 100755 --- a/hibernate-core/src/main/java/org/hibernate/loader/entity/AbstractEntityLoader.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/entity/AbstractEntityLoader.java @@ -61,6 +61,11 @@ public Object load(Serializable id, Object optionalObject, SharedSessionContract return load( session, id, optionalObject, id, lockOptions, readOnly ); } + @Override + public Object load(Object id, SharedSessionContractImplementor session, LockOptions lockOptions) { + return load( session, id, null, null, lockOptions, null ); + } + protected Object load( SharedSessionContractImplementor session, Object id, diff --git a/hibernate-core/src/main/java/org/hibernate/loader/entity/EntityLoader.java b/hibernate-core/src/main/java/org/hibernate/loader/entity/EntityLoader.java index d7be98e4262c..4515bc6e9582 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/entity/EntityLoader.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/entity/EntityLoader.java @@ -172,10 +172,18 @@ public EntityLoader( } } + /** + * @deprecated will be removed. Use one of the load methods on {@link AbstractEntityLoader} instead. + */ + @Deprecated public Object loadByUniqueKey(SharedSessionContractImplementor session, Object key) { return loadByUniqueKey( session, key, null ); } + /** + * @deprecated will be removed. Use one of the load methods on {@link AbstractEntityLoader} instead. + */ + @Deprecated public Object loadByUniqueKey(SharedSessionContractImplementor session, Object key, Boolean readOnly) { return load( session, key, null, null, LockOptions.NONE, readOnly ); } diff --git a/hibernate-core/src/main/java/org/hibernate/loader/entity/UniqueEntityLoader.java b/hibernate-core/src/main/java/org/hibernate/loader/entity/UniqueEntityLoader.java index 97637034863d..87167eb877a5 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/entity/UniqueEntityLoader.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/entity/UniqueEntityLoader.java @@ -60,4 +60,11 @@ default Object load( Boolean readOnly) { return load( id, optionalObject, session, lockOptions ); } + + default Object load( + Object id, + SharedSessionContractImplementor session, + LockOptions lockOptions) { + throw new UnsupportedOperationException(); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index e447b10ed292..c01caa20f15f 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -256,7 +256,7 @@ public abstract class AbstractEntityPersister private final EntityLoaderLazyCollection loaders = new EntityLoaderLazyCollection(); - private volatile Map uniqueKeyLoaders; + private volatile Map uniqueKeyLoaders; private volatile Map naturalIdLoaders; // SQL strings @@ -2480,7 +2480,7 @@ public Object loadByUniqueKey( Object uniqueKey, SharedSessionContractImplementor session) throws HibernateException { return getAppropriateUniqueKeyLoader( propertyName, session ) - .loadByUniqueKey( session, uniqueKey ); + .load( uniqueKey, session, LockOptions.NONE ); } public Object loadByNaturalId( @@ -2488,7 +2488,7 @@ public Object loadByNaturalId( LockOptions lockOptions, SharedSessionContractImplementor session) throws HibernateException { return getAppropriateNaturalIdLoader( determineValueNullness( naturalIdValues ), lockOptions, session ) - .loadByUniqueKey( session, naturalIdValues ); + .load( naturalIdValues, session, LockOptions.NONE ); } private EntityLoader getAppropriateNaturalIdLoader( @@ -2511,7 +2511,7 @@ private boolean useStaticNaturalIdLoader( && !loadQueryInfluencers.hasEnabledFetchProfiles(); } - private EntityLoader getAppropriateUniqueKeyLoader( + private UniqueEntityLoader getAppropriateUniqueKeyLoader( String propertyName, SharedSessionContractImplementor session) { LoadQueryInfluencers loadQueryInfluencers = session.getLoadQueryInfluencers(); @@ -2560,7 +2560,7 @@ protected void createUniqueKeyLoaders() throws MappingException { } } - private EntityLoader createUniqueKeyLoader( + protected UniqueEntityLoader createUniqueKeyLoader( Type uniqueKeyType, String[] columns, LoadQueryInfluencers loadQueryInfluencers) { From 17bffb08a5587ea5da3152e28887d2da5e3ad032 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Mon, 1 Mar 2021 20:08:42 +0000 Subject: [PATCH 041/644] HHH-14474 Style and formatting improvements --- .../loader/entity/UniqueEntityLoader.java | 19 ++++++++++++++----- 1 file changed, 14 insertions(+), 5 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/loader/entity/UniqueEntityLoader.java b/hibernate-core/src/main/java/org/hibernate/loader/entity/UniqueEntityLoader.java index 87167eb877a5..eb3769f23eae 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/entity/UniqueEntityLoader.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/entity/UniqueEntityLoader.java @@ -23,15 +23,16 @@ public interface UniqueEntityLoader { * Load an entity instance. If optionalObject is supplied, * load the entity state into the given (uninitialized) object. * + * @throws HibernateException indicates problem performing the load. + * * @deprecated use {@link #load(java.io.Serializable, Object, SharedSessionContractImplementor, LockOptions)} instead. */ @SuppressWarnings( {"JavaDoc"}) @Deprecated - Object load(Serializable id, Object optionalObject, SharedSessionContractImplementor session) throws HibernateException; - - default Object load(Serializable id, Object optionalObject, SharedSessionContractImplementor session, Boolean readOnly) throws HibernateException { - return load( id, optionalObject, session ); - } + Object load( + Serializable id, + Object optionalObject, + SharedSessionContractImplementor session); /** * Load an entity instance by id. If optionalObject is supplied (non-null, @@ -52,6 +53,14 @@ Object load( SharedSessionContractImplementor session, LockOptions lockOptions); + default Object load( + Serializable id, + Object optionalObject, + SharedSessionContractImplementor session, + Boolean readOnly) { + return load( id, optionalObject, session ); + } + default Object load( Serializable id, Object optionalObject, From eb639a2d95cc5d8c5c86f35afe407da6a5dc296a Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Tue, 2 Mar 2021 13:25:59 +0000 Subject: [PATCH 042/644] HHH-14474 Method AbstractEntityPersister#getAppropriateUniqueKeyLoader also need to change in protected --- .../org/hibernate/persister/entity/AbstractEntityPersister.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index c01caa20f15f..1a3a43a1c804 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -2511,7 +2511,7 @@ private boolean useStaticNaturalIdLoader( && !loadQueryInfluencers.hasEnabledFetchProfiles(); } - private UniqueEntityLoader getAppropriateUniqueKeyLoader( + protected UniqueEntityLoader getAppropriateUniqueKeyLoader( String propertyName, SharedSessionContractImplementor session) { LoadQueryInfluencers loadQueryInfluencers = session.getLoadQueryInfluencers(); From 1714c022e271c7faf64b7993de9d06ad457ec4c2 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Tue, 2 Mar 2021 11:36:54 +0100 Subject: [PATCH 043/644] HHH-11076 Log a warning if uninitialized collection unsets session when filters are enabled --- .../collection/internal/AbstractPersistentCollection.java | 4 ++++ .../main/java/org/hibernate/internal/CoreMessageLogger.java | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/hibernate-core/src/main/java/org/hibernate/collection/internal/AbstractPersistentCollection.java b/hibernate-core/src/main/java/org/hibernate/collection/internal/AbstractPersistentCollection.java index 047f414d4422..eee4af75d1fb 100644 --- a/hibernate-core/src/main/java/org/hibernate/collection/internal/AbstractPersistentCollection.java +++ b/hibernate-core/src/main/java/org/hibernate/collection/internal/AbstractPersistentCollection.java @@ -656,6 +656,10 @@ public final boolean unsetSession(SharedSessionContractImplementor currentSessio LOG.queuedOperationWhenDetachFromSession( collectionInfoString ); } } + if ( allowLoadOutsideTransaction && !initialized && session.getLoadQueryInfluencers().hasEnabledFilters() ) { + final String collectionInfoString = MessageHelper.collectionInfoString( getRole(), getKey() ); + LOG.enabledFiltersWhenDetachFromSession( collectionInfoString ); + } this.session = null; } return true; diff --git a/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java b/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java index a95a767ee5e0..096aa3ec3d38 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java @@ -1856,4 +1856,8 @@ void attemptToAssociateProxyWithTwoOpenSessions( @Message(value = "Ignoring ServiceConfigurationError caught while trying to instantiate service '%s'.", id = 505) void ignoringServiceConfigurationError(Class serviceContract, @Cause ServiceConfigurationError error); + @LogMessage(level = WARN) + @Message(value = "Detaching an uninitialized collection with enabled filters from a session: %s", id = 506) + void enabledFiltersWhenDetachFromSession(String collectionInfoString); + } From 59735d2329f4e0c1c829634cd9e561e35212ab88 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Mon, 1 Mar 2021 09:53:43 +0100 Subject: [PATCH 044/644] HHH-14471 Fix concurrency issue due to builder sharing in DynamicBatchingEntityLoader --- .../entity/plan/DynamicBatchingEntityLoader.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/loader/entity/plan/DynamicBatchingEntityLoader.java b/hibernate-core/src/main/java/org/hibernate/loader/entity/plan/DynamicBatchingEntityLoader.java index 6f51a942bd35..6bc11cb8cdb8 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/entity/plan/DynamicBatchingEntityLoader.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/entity/plan/DynamicBatchingEntityLoader.java @@ -27,7 +27,7 @@ public class DynamicBatchingEntityLoader extends BatchingEntityLoader { private static final Logger log = Logger.getLogger( DynamicBatchingEntityLoader.class ); private final int maxBatchSize; - private final EntityLoader.Builder entityLoaderBuilder; + private final LoadQueryInfluencers loadQueryInfluencers; public DynamicBatchingEntityLoader( OuterJoinLoadable persister, @@ -37,10 +37,7 @@ public DynamicBatchingEntityLoader( LoadQueryInfluencers loadQueryInfluencers) { super( persister ); this.maxBatchSize = maxBatchSize; - - entityLoaderBuilder = EntityLoader.forEntity( persister ) - .withInfluencers( loadQueryInfluencers ) - .withLockOptions( lockOptions ); + this.loadQueryInfluencers = loadQueryInfluencers; } @Override @@ -67,7 +64,12 @@ public Object load(Serializable id, Object optionalObject, SharedSessionContract log.debugf( "Batch loading entity: %s", MessageHelper.infoString( persister(), idsToLoad, session.getFactory() ) ); } - final EntityLoader dynamicLoader = entityLoaderBuilder.withBatchSize( idsToLoad.length ).byPrimaryKey(); + + final EntityLoader dynamicLoader = EntityLoader.forEntity( (OuterJoinLoadable) persister() ) + .withInfluencers( loadQueryInfluencers ) + .withLockOptions( lockOptions ) + .withBatchSize( idsToLoad.length ) + .byPrimaryKey(); final List results = dynamicLoader.loadEntityBatch( session, From 2bacaabc378472bd5a4a7341bcb77a50332249ae Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Tue, 23 Feb 2021 18:23:07 -0800 Subject: [PATCH 045/644] HHH-14466 : StackOverflowError loading an entity with eager one-to-many if bidirectional and many-to-one side is the ID --- ...BuildingAssociationVisitationStrategy.java | 63 ++++- ...yToOneEagerDerivedIdFetchModeJoinTest.java | 236 ++++++++++++++++++ 2 files changed, 296 insertions(+), 3 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/bidirectional/ManyToOneEagerDerivedIdFetchModeJoinTest.java diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan/build/internal/FetchStyleLoadPlanBuildingAssociationVisitationStrategy.java b/hibernate-core/src/main/java/org/hibernate/loader/plan/build/internal/FetchStyleLoadPlanBuildingAssociationVisitationStrategy.java index 52e3762e7f91..923cf41d9038 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/plan/build/internal/FetchStyleLoadPlanBuildingAssociationVisitationStrategy.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/plan/build/internal/FetchStyleLoadPlanBuildingAssociationVisitationStrategy.java @@ -16,13 +16,20 @@ import org.hibernate.internal.CoreLogging; import org.hibernate.loader.plan.spi.CollectionReturn; import org.hibernate.loader.plan.spi.EntityReturn; +import org.hibernate.loader.plan.spi.FetchSource; import org.hibernate.loader.plan.spi.LoadPlan; import org.hibernate.loader.plan.spi.Return; +import org.hibernate.persister.collection.CollectionPersister; +import org.hibernate.persister.entity.EntityPersister; import org.hibernate.persister.walking.spi.AssociationAttributeDefinition; import org.hibernate.persister.walking.spi.EncapsulatedEntityIdentifierDefinition; import org.hibernate.persister.walking.spi.EntityIdentifierDefinition; import org.hibernate.persister.walking.spi.NonEncapsulatedEntityIdentifierDefinition; import org.hibernate.persister.walking.spi.WalkingException; +import org.hibernate.type.CompositeType; +import org.hibernate.type.EmbeddedComponentType; +import org.hibernate.type.EntityType; +import org.hibernate.type.Type; import org.jboss.logging.Logger; @@ -190,9 +197,59 @@ protected FetchStrategy adjustJoinFetchIfNeeded( return new FetchStrategy( fetchStrategy.getTiming(), FetchStyle.SELECT ); } - if ( attributeDefinition.getType().isCollectionType() && isTooManyCollections() ) { - // todo : have this revert to batch or subselect fetching once "sql gen redesign" is in place - return new FetchStrategy( fetchStrategy.getTiming(), FetchStyle.SELECT ); + final FetchSource currentSource = currentSource(); + final Type attributeType = attributeDefinition.getType(); + + + if ( attributeType.isCollectionType() ) { + if ( isTooManyCollections() ) { + // todo : have this revert to batch or subselect fetching once "sql gen redesign" is in place + return new FetchStrategy( fetchStrategy.getTiming(), FetchStyle.SELECT ); + } + if ( currentSource.resolveEntityReference() != null ) { + CollectionPersister collectionPersister = + (CollectionPersister) attributeDefinition.getType().getAssociatedJoinable( sessionFactory() ); + // Check if this is an eager "mappedBy" (inverse) side of a bidirectional + // one-to-many/many-to-one association, with the many-to-one side + // being the associated entity's ID as in: + // + // @Entity + // public class Foo { + // ... + // @OneToMany(mappedBy = "foo", fetch = FetchType.EAGER) + // private Set bars = new HashSet<>(); + // } + // @Entity + // public class Bar implements Serializable { + // @Id + // @ManyToOne(fetch = FetchType.EAGER) + // private Foo foo; + // ... + // } + // + if ( fetchStrategy.getTiming() == FetchTiming.IMMEDIATE && + fetchStrategy.getStyle() == FetchStyle.JOIN && + collectionPersister.isOneToMany() && + collectionPersister.isInverse() ) { + // This is an eager "mappedBy" (inverse) side of a bidirectional + // one-to-many/many-to-one association + final EntityType elementType = (EntityType) collectionPersister.getElementType(); + final Type elementIdType = ( (EntityPersister) elementType.getAssociatedJoinable( sessionFactory() ) ).getIdentifierType(); + if ( elementIdType.isComponentType() && ( (CompositeType) elementIdType ).isEmbedded() ) { + final EmbeddedComponentType elementIdTypeEmbedded = (EmbeddedComponentType) elementIdType; + if ( elementIdTypeEmbedded.getSubtypes().length == 1 && + elementIdTypeEmbedded.getPropertyNames()[ 0 ].equals( collectionPersister.getMappedByProperty() ) ) { + // The associated entity's ID is the other (many-to-one) side of the association. + // The one-to-many side must be set to FetchMode.SELECT; otherwise, + // there will be an infinite loop because the current entity + // would need to be loaded before the associated entity can be loaded, + // but the associated entity cannot be loaded until after the current + // entity is loaded (since the current entity is the associated entity's ID). + return new FetchStrategy( fetchStrategy.getTiming(), FetchStyle.SELECT ); + } + } + } + } } return fetchStrategy; diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/bidirectional/ManyToOneEagerDerivedIdFetchModeJoinTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/bidirectional/ManyToOneEagerDerivedIdFetchModeJoinTest.java new file mode 100644 index 000000000000..a8e1b55376e8 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/derivedidentities/bidirectional/ManyToOneEagerDerivedIdFetchModeJoinTest.java @@ -0,0 +1,236 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.annotations.derivedidentities.bidirectional; + +import java.io.Serializable; +import java.util.HashSet; +import java.util.Objects; +import java.util.Set; +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; + +import org.hibernate.Hibernate; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; + +public class ManyToOneEagerDerivedIdFetchModeJoinTest extends BaseCoreFunctionalTestCase { + private Foo foo; + + @Test + @TestForIssue(jiraKey = "HHH-14466") + public void testQuery() { + doInHibernate( this::sessionFactory, session -> { + Bar newBar = (Bar) session.createQuery( "SELECT b FROM Bar b WHERE b.foo.id = :id" ) + .setParameter( "id", foo.getId() ) + .uniqueResult(); + assertNotNull( newBar ); + assertNotNull( newBar.getFoo() ); + assertTrue( Hibernate.isInitialized( newBar.getFoo() ) ); + assertEquals( foo.getId(), newBar.getFoo().getId() ); + assertTrue( Hibernate.isInitialized( newBar.getFoo().getBars() ) ); + assertEquals( 1, newBar.getFoo().getBars().size() ); + assertSame( newBar, newBar.getFoo().getBars().iterator().next() ); + assertEquals( "Some details", newBar.getDetails() ); + }); + } + + @Test + @TestForIssue(jiraKey = "HHH-14466") + public void testQueryById() { + + doInHibernate( this::sessionFactory, session -> { + Bar newBar = (Bar) session.createQuery( "SELECT b FROM Bar b WHERE b.foo = :foo" ) + .setParameter( "foo", foo ) + .uniqueResult(); + assertNotNull( newBar ); + assertNotNull( newBar.getFoo() ); + assertTrue( Hibernate.isInitialized( newBar.getFoo() ) ); + assertEquals( foo.getId(), newBar.getFoo().getId() ); + assertTrue( Hibernate.isInitialized( newBar.getFoo().getBars() ) ); + assertEquals( 1, newBar.getFoo().getBars().size() ); + assertSame( newBar, newBar.getFoo().getBars().iterator().next() ); + assertEquals( "Some details", newBar.getDetails() ); + }); + } + + @Test + @TestForIssue(jiraKey = "HHH-14466") + public void testFindByPrimaryKey() { + + doInHibernate( this::sessionFactory, session -> { + Bar newBar = session.find( Bar.class, foo.getId() ); + assertNotNull( newBar ); + assertNotNull( newBar.getFoo() ); + assertTrue( Hibernate.isInitialized( newBar.getFoo() ) ); + assertEquals( foo.getId(), newBar.getFoo().getId() ); + assertTrue( Hibernate.isInitialized( newBar.getFoo().getBars() ) ); + assertEquals( 1, newBar.getFoo().getBars().size() ); + assertSame( newBar, newBar.getFoo().getBars().iterator().next() ); + assertEquals( "Some details", newBar.getDetails() ); + }); + } + + @Test + @TestForIssue(jiraKey = "HHH-14466") + public void testFindByInversePrimaryKey() { + + doInHibernate( this::sessionFactory, session -> { + Foo newFoo = session.find( Foo.class, foo.getId() ); + assertNotNull( newFoo ); + assertNotNull( newFoo.getBars() ); + assertTrue( Hibernate.isInitialized( newFoo.getBars() ) ); + assertEquals( 1, newFoo.getBars().size() ); + assertSame( newFoo, newFoo.getBars().iterator().next().getFoo() ); + assertEquals( "Some details", newFoo.getBars().iterator().next().getDetails() ); + }); + + } + + @Before + public void setupData() { + this.foo = doInHibernate( this::sessionFactory, session -> { + Foo foo = new Foo(); + foo.id = 1L; + session.persist( foo ); + + Bar bar = new Bar(); + bar.setFoo( foo ); + bar.setDetails( "Some details" ); + + foo.getBars().add( bar ); + + session.persist( bar ); + + session.flush(); + + assertNotNull( foo.getId() ); + assertEquals( foo.getId(), bar.getFoo().getId() ); + + return foo; + }); + } + + @After + public void cleanupData() { + doInHibernate( this::sessionFactory, session -> { + session.delete( session.find( Foo.class, foo.id ) ); + }); + this.foo = null; + } + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + Foo.class, + Bar.class, + }; + } + + @Entity(name = "Foo") + public static class Foo { + + @Id + private Long id; + + private String name; + + @OneToMany(mappedBy = "foo", cascade = CascadeType.ALL, fetch = FetchType.EAGER, orphanRemoval = true) + private Set bars = new HashSet<>(); + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Set getBars() { + return bars; + } + + public void setBars(Set bars) { + this.bars = bars; + } + + @Override + public boolean equals(Object o) { + if ( this == o ) { + return true; + } + if ( o == null || getClass() != o.getClass() ) { + return false; + } + Foo foo = (Foo) o; + return id.equals( foo.id ); + } + + @Override + public int hashCode() { + return Objects.hash( id ); + } + } + + @Entity(name = "Bar") + public static class Bar implements Serializable { + + @Id + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "BAR_ID") + private Foo foo; + + private String details; + + public Foo getFoo() { + return foo; + } + + public void setFoo(Foo foo) { + this.foo = foo; + } + + public String getDetails() { + return details; + } + + public void setDetails(String details) { + this.details = details; + } + + @Override + public boolean equals(Object o) { + if ( this == o ) { + return true; + } + if ( o == null || getClass() != o.getClass() ) { + return false; + } + Bar bar = (Bar) o; + return foo.equals( bar.foo ); + } + + @Override + public int hashCode() { + return Objects.hash( foo ); + } + } +} From cb18fdb4f7ddbe6ed6bf2db7c9399173d6318a9d Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Wed, 24 Feb 2021 17:43:43 -0800 Subject: [PATCH 046/644] HHH-14390 : StackOverflowError with @Fetch(FetchMode.SELECT) mapped for entity with an ID that is a bidirectional one-to-one eager association Move fix into FetchStyleLoadPlanBuildingAssociationVisitationStrategy --- .../org/hibernate/cfg/OneToOneSecondPass.java | 12 ----- ...BuildingAssociationVisitationStrategy.java | 49 +++++++++++++++++++ 2 files changed, 49 insertions(+), 12 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/OneToOneSecondPass.java b/hibernate-core/src/main/java/org/hibernate/cfg/OneToOneSecondPass.java index a8778fb224aa..7a376ee894b4 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/OneToOneSecondPass.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/OneToOneSecondPass.java @@ -237,18 +237,6 @@ else if ( otherSideProperty.getValue() instanceof ManyToOne ) { boolean referenceToPrimaryKey = referencesDerivedId || mappedBy == null; value.setReferenceToPrimaryKey( referenceToPrimaryKey ); - // If the other side is an entity with an ID that is derived from - // this side's owner entity, and both sides of the association are eager, - // then this side must be set to FetchMode.SELECT; otherwise, - // there will be an infinite loop attempting to load the derived ID on - // the opposite side. - if ( referencesDerivedId && - !value.isLazy() && - value.getFetchMode() == FetchMode.JOIN && - !otherSideProperty.isLazy() ) { - value.setFetchMode( FetchMode.SELECT ); - } - String propertyRef = value.getReferencedPropertyName(); if ( propertyRef != null ) { buildingContext.getMetadataCollector().addUniquePropertyReference( diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan/build/internal/FetchStyleLoadPlanBuildingAssociationVisitationStrategy.java b/hibernate-core/src/main/java/org/hibernate/loader/plan/build/internal/FetchStyleLoadPlanBuildingAssociationVisitationStrategy.java index 923cf41d9038..0c616e5fed49 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/plan/build/internal/FetchStyleLoadPlanBuildingAssociationVisitationStrategy.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/plan/build/internal/FetchStyleLoadPlanBuildingAssociationVisitationStrategy.java @@ -15,6 +15,7 @@ import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.internal.CoreLogging; import org.hibernate.loader.plan.spi.CollectionReturn; +import org.hibernate.loader.plan.spi.EntityReference; import org.hibernate.loader.plan.spi.EntityReturn; import org.hibernate.loader.plan.spi.FetchSource; import org.hibernate.loader.plan.spi.LoadPlan; @@ -29,6 +30,8 @@ import org.hibernate.type.CompositeType; import org.hibernate.type.EmbeddedComponentType; import org.hibernate.type.EntityType; +import org.hibernate.type.ForeignKeyDirection; +import org.hibernate.type.OneToOneType; import org.hibernate.type.Type; import org.jboss.logging.Logger; @@ -252,6 +255,52 @@ protected FetchStrategy adjustJoinFetchIfNeeded( } } + if ( attributeType.isEntityType() && + fetchStrategy.getTiming() == FetchTiming.IMMEDIATE && + fetchStrategy.getStyle() == FetchStyle.JOIN ) { + final EntityType entityType = (EntityType) attributeType; + final EntityReference currentEntityReference = currentSource.resolveEntityReference(); + if ( currentEntityReference != null ) { + final EntityPersister currentEntityPersister = currentEntityReference.getEntityPersister(); + if ( entityType.isOneToOne() && entityType.getForeignKeyDirection() == ForeignKeyDirection.TO_PARENT ) { + // attributeDefinition is the "mappedBy" (inverse) side of a + // bidirectional one-to-one association. + final OneToOneType oneToOneType = (OneToOneType) attributeType; + final String associatedUniqueKeyPropertyName = oneToOneType.getIdentifierOrUniqueKeyPropertyName( + sessionFactory() + ); + if ( associatedUniqueKeyPropertyName == null ) { + // The foreign key for the other side of the association is the ID. + // Now check if the ID itself is the other side of the association. + final EntityPersister associatedEntityPersister = (EntityPersister) oneToOneType.getAssociatedJoinable( + sessionFactory() + ); + final Type associatedIdentifierType = associatedEntityPersister.getIdentifierType(); + if ( associatedIdentifierType.isComponentType() && + ( (CompositeType) associatedIdentifierType ).isEmbedded() ) { + final EmbeddedComponentType associatedNonEncapsulatedIdentifierType = + (EmbeddedComponentType) associatedIdentifierType; + if ( associatedNonEncapsulatedIdentifierType.getSubtypes().length == 1 && + EntityType.class.isInstance( associatedNonEncapsulatedIdentifierType.getSubtypes()[0] ) ) { + final EntityType otherSideEntityType = + ( (EntityType) associatedNonEncapsulatedIdentifierType.getSubtypes()[0] ); + if ( otherSideEntityType.isLogicalOneToOne() && + otherSideEntityType.isReferenceToPrimaryKey() && + otherSideEntityType.getAssociatedEntityName().equals( currentEntityPersister.getEntityName() ) ) { + // The associated entity's ID is the other side of the association. + // This side must be set to FetchMode.SELECT; otherwise, + // there will be an infinite loop because the current entity + // would need to be loaded before the associated entity can be loaded, + // but the associated entity cannot be loaded until after the current + // entity is loaded (since the current entity is the associated entity's ID). + return new FetchStrategy( fetchStrategy.getTiming(), FetchStyle.SELECT ); + } + } + } + } + } + } + } return fetchStrategy; } From 34a361058de2f4ae3ae0f6ec8d662537b63d2bfd Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Tue, 2 Mar 2021 14:09:16 -0800 Subject: [PATCH 047/644] HHH-14390 HHH-14466 : StackOverflowError loading inverse side of associations owned by associated entity ID Improved code comments as recommended by Steve Ebersole. --- ...BuildingAssociationVisitationStrategy.java | 22 +++++++++---------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan/build/internal/FetchStyleLoadPlanBuildingAssociationVisitationStrategy.java b/hibernate-core/src/main/java/org/hibernate/loader/plan/build/internal/FetchStyleLoadPlanBuildingAssociationVisitationStrategy.java index 0c616e5fed49..0cbe181ef3ad 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/plan/build/internal/FetchStyleLoadPlanBuildingAssociationVisitationStrategy.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/plan/build/internal/FetchStyleLoadPlanBuildingAssociationVisitationStrategy.java @@ -242,12 +242,11 @@ protected FetchStrategy adjustJoinFetchIfNeeded( final EmbeddedComponentType elementIdTypeEmbedded = (EmbeddedComponentType) elementIdType; if ( elementIdTypeEmbedded.getSubtypes().length == 1 && elementIdTypeEmbedded.getPropertyNames()[ 0 ].equals( collectionPersister.getMappedByProperty() ) ) { - // The associated entity's ID is the other (many-to-one) side of the association. - // The one-to-many side must be set to FetchMode.SELECT; otherwise, - // there will be an infinite loop because the current entity - // would need to be loaded before the associated entity can be loaded, - // but the associated entity cannot be loaded until after the current - // entity is loaded (since the current entity is the associated entity's ID). + // The owning side of the inverse collection is defined by the associated entity's id. + // + // Because of how Loaders process ids when processing the ResultSet, this condition would + // lead to an infinite loop. Adjust the fetch to use a SELECT fetch instead of JOIN to + // avoid the infinite loop. return new FetchStrategy( fetchStrategy.getTiming(), FetchStyle.SELECT ); } } @@ -287,12 +286,11 @@ protected FetchStrategy adjustJoinFetchIfNeeded( if ( otherSideEntityType.isLogicalOneToOne() && otherSideEntityType.isReferenceToPrimaryKey() && otherSideEntityType.getAssociatedEntityName().equals( currentEntityPersister.getEntityName() ) ) { - // The associated entity's ID is the other side of the association. - // This side must be set to FetchMode.SELECT; otherwise, - // there will be an infinite loop because the current entity - // would need to be loaded before the associated entity can be loaded, - // but the associated entity cannot be loaded until after the current - // entity is loaded (since the current entity is the associated entity's ID). + // The owning side of the inverse to-one is defined by the associated entity's id. + // + // Because of how Loaders process ids when processing the ResultSet, this condition + // would lead to an infinite loop. Adjust the fetch to use a SELECT fetch instead + // of JOIN to avoid the infinite loop. return new FetchStrategy( fetchStrategy.getTiming(), FetchStyle.SELECT ); } } From 44f4f93a294eea75635c3ebfac473db146029291 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Mon, 1 Mar 2021 18:34:09 +0100 Subject: [PATCH 048/644] HHH-9182 Test and fix HQL rules to allow more expression types in aggregate functions --- hibernate-core/src/main/antlr/hql.g | 4 +- .../test/hql/CountExpressionTest.java | 149 ++++++++++++++++++ 2 files changed, 151 insertions(+), 2 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/hql/CountExpressionTest.java diff --git a/hibernate-core/src/main/antlr/hql.g b/hibernate-core/src/main/antlr/hql.g index 321dda67a846..bd05e70aea26 100644 --- a/hibernate-core/src/main/antlr/hql.g +++ b/hibernate-core/src/main/antlr/hql.g @@ -842,9 +842,9 @@ castedIdentPrimaryBase ; aggregate - : ( SUM^ | AVG^ | MAX^ | MIN^ ) OPEN! ( additiveExpression | selectStatement ) CLOSE! { #aggregate.setType(AGGREGATE); } + : ( SUM^ | AVG^ | MAX^ | MIN^ ) OPEN! ( concatenation | subQuery ) CLOSE! { #aggregate.setType(AGGREGATE); } // Special case for count - It's 'parameters' can be keywords. - | COUNT^ OPEN! ( STAR { #STAR.setType(ROW_STAR); } | ( ( DISTINCT | ALL )? ( path | collectionExpr | NUM_INT | caseExpression ) ) ) CLOSE! + | COUNT^ OPEN! ( STAR { #STAR.setType(ROW_STAR); } | ( ( DISTINCT | ALL )? ( concatenation | subQuery ) ) ) CLOSE! | collectionExpr ; diff --git a/hibernate-core/src/test/java/org/hibernate/test/hql/CountExpressionTest.java b/hibernate-core/src/test/java/org/hibernate/test/hql/CountExpressionTest.java new file mode 100644 index 000000000000..3c6df4c7cb26 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/hql/CountExpressionTest.java @@ -0,0 +1,149 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.hql; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.persistence.CollectionTable; +import javax.persistence.ElementCollection; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.MapKeyColumn; +import javax.persistence.OneToMany; + +import org.hibernate.dialect.DerbyDialect; +import org.hibernate.dialect.H2Dialect; + +import org.hibernate.testing.RequiresDialect; +import org.hibernate.testing.SkipForDialect; +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.Test; + +import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; +import static org.junit.Assert.assertEquals; + +/** + * @author Christian Beikov + */ +public class CountExpressionTest extends BaseCoreFunctionalTestCase { + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + Document.class, + Person.class + }; + } + + @Override + protected void prepareTest() throws Exception { + doInHibernate( this::sessionFactory, session -> { + Document document = new Document(); + document.setId( 1 ); + + Person p1 = new Person(); + Person p2 = new Person(); + + p1.getLocalized().put(1, "p1.1"); + p1.getLocalized().put(2, "p1.2"); + p2.getLocalized().put(1, "p2.1"); + p2.getLocalized().put(2, "p2.2"); + + document.getContacts().put(1, p1); + document.getContacts().put(2, p2); + + session.persist(p1); + session.persist(p2); + session.persist(document); + } ); + } + + @Override + protected boolean isCleanupTestDataRequired() { + return true; + } + + @Test + @TestForIssue(jiraKey = "HHH-9182") + @SkipForDialect(value = DerbyDialect.class, comment = "Derby can't cast from integer to varchar i.e. it requires an intermediary step") + public void testCountDistinctExpression() { + doInHibernate( this::sessionFactory, session -> { + List results = session.createQuery( + "SELECT " + + " d.id, " + + " COUNT(DISTINCT CONCAT(CAST(KEY(l) AS java.lang.String), 'test')) " + + "FROM Document d " + + "LEFT JOIN d.contacts c " + + "LEFT JOIN c.localized l " + + "GROUP BY d.id") + .getResultList(); + + assertEquals(1, results.size()); + Object[] tuple = (Object[]) results.get( 0 ); + assertEquals(1, tuple[0]); + } ); + } + + @Entity(name = "Document") + public static class Document { + + private Integer id; + private Map contacts = new HashMap<>(); + + @Id + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + @OneToMany + @CollectionTable + @MapKeyColumn(name = "position") + public Map getContacts() { + return contacts; + } + + public void setContacts(Map contacts) { + this.contacts = contacts; + } + } + + + @Entity(name = "Person") + public static class Person { + + private Integer id; + + private Map localized = new HashMap<>(); + + @Id + @GeneratedValue + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + @ElementCollection + public Map getLocalized() { + return localized; + } + + public void setLocalized(Map localized) { + this.localized = localized; + } + } + +} From f7c85fad4ae650d7ec98bf3c71f4c319b1d19c66 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Wed, 3 Mar 2021 10:44:29 +0000 Subject: [PATCH 049/644] HHH-14477 Log warnings about the use of Javassist as BytecodeProvider being deprecated --- .../main/asciidoc/userguide/appendices/Configurations.adoc | 2 +- .../bytecode/internal/javassist/BytecodeProviderImpl.java | 4 ++++ .../src/main/java/org/hibernate/cfg/Environment.java | 1 + .../main/java/org/hibernate/internal/CoreMessageLogger.java | 5 +++++ 4 files changed, 11 insertions(+), 1 deletion(-) diff --git a/documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc b/documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc index e70b11b4207f..75ff5d99c96a 100644 --- a/documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc +++ b/documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc @@ -434,7 +434,7 @@ Enable lazy loading feature in runtime bytecode enhancement. This way, even basi Enable association management feature in runtime bytecode enhancement which automatically synchronizes a bidirectional association when only one side is changed. `*hibernate.bytecode.provider*` (e.g. `bytebuddy` (default value)):: -The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/bytecode/spi/BytecodeProvider.html[`BytecodeProvider`] built-in implementation flavor. Currently, only `bytebuddy` and `javassist` are valid values. +The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/bytecode/spi/BytecodeProvider.html[`BytecodeProvider`] built-in implementation flavor. Currently, only `bytebuddy` and `javassist` are valid values; `bytebuddy` is the default and recommended choice; `javassist` will be removed soon. `*hibernate.bytecode.use_reflection_optimizer*` (e.g. `true` or `false` (default value)):: Should we use reflection optimization? The reflection optimizer implements the https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/bytecode/spi/ReflectionOptimizer.html[`ReflectionOptimizer`] interface and improves entity instantiation and property getter/setter calls. diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/BytecodeProviderImpl.java b/hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/BytecodeProviderImpl.java index 995ab83f497c..ca588e25199b 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/BytecodeProviderImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/BytecodeProviderImpl.java @@ -21,9 +21,13 @@ /** * Bytecode provider implementation for Javassist. + * @deprecated The Javassist based enhancer will be removed soon, + * please use the one based on ByteBuddy (which is the default since + * version 5.3 of Hibernate ORM) * * @author Steve Ebersole */ +@Deprecated public class BytecodeProviderImpl implements BytecodeProvider { private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/Environment.java b/hibernate-core/src/main/java/org/hibernate/cfg/Environment.java index 824f556d1f3c..892a07f350ae 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/Environment.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/Environment.java @@ -346,6 +346,7 @@ private static BytecodeProvider buildBytecodeProvider(String providerName) { } if ( BYTECODE_PROVIDER_NAME_JAVASSIST.equals( providerName ) ) { + LOG.warnUsingJavassistBytecodeProviderIsDeprecated(); return new org.hibernate.bytecode.internal.javassist.BytecodeProviderImpl(); } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java b/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java index 096aa3ec3d38..04083199e97a 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java @@ -1860,4 +1860,9 @@ void attemptToAssociateProxyWithTwoOpenSessions( @Message(value = "Detaching an uninitialized collection with enabled filters from a session: %s", id = 506) void enabledFiltersWhenDetachFromSession(String collectionInfoString); + @LogMessage(level = WARN) + @Message(value = "The Javassist based BytecodeProvider is deprecated. Please switch to using the ByteBuddy based BytecodeProvider, " + + "which is the default since Hibernate ORM 5.3. The Javassist one will be removed soon.", id = 507) + void warnUsingJavassistBytecodeProviderIsDeprecated(); + } From f03dd44107c7c0cf287022d6b02c06690715570f Mon Sep 17 00:00:00 2001 From: johnniang Date: Tue, 2 Mar 2021 18:40:40 +0800 Subject: [PATCH 050/644] HHH-14473 Resolve managed class name with class loader as well --- .../process/internal/ScanningCoordinator.java | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/process/internal/ScanningCoordinator.java b/hibernate-core/src/main/java/org/hibernate/boot/model/process/internal/ScanningCoordinator.java index 04e34f0bfc60..c2179e53fea8 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/process/internal/ScanningCoordinator.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/process/internal/ScanningCoordinator.java @@ -30,9 +30,9 @@ import org.hibernate.boot.jaxb.Origin; import org.hibernate.boot.jaxb.SourceType; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; +import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; import org.hibernate.boot.spi.BootstrapContext; import org.hibernate.boot.spi.ClassLoaderAccess; -import org.hibernate.boot.spi.MetadataBuildingOptions; import org.hibernate.boot.spi.XmlMappingBinderAccess; import org.hibernate.cfg.AttributeConverterDefinition; import org.hibernate.service.ServiceRegistry; @@ -112,7 +112,7 @@ private static Scanner buildScanner(BootstrapContext bootstrapContext, ClassLoad return (Scanner) scannerSetting; } - final Class scannerImplClass; + final Class scannerImplClass; if ( Class.class.isInstance( scannerSetting ) ) { scannerImplClass = (Class) scannerSetting; } @@ -270,6 +270,16 @@ else if ( classDescriptor.getCategorization() == ClassDescriptor.Categorization. continue; } + // Last, try it by loading the class + try { + Class clazz = classLoaderService.classForName( unresolvedListedClassName ); + managedResources.addAnnotatedClassReference( clazz ); + continue; + } + catch (ClassLoadingException ignore) { + // ignore this error + } + log.debugf( "Unable to resolve class [%s] named in persistence unit [%s]", unresolvedListedClassName, From 2d5d6061c50be3d7b0c87281651029a69d0178d3 Mon Sep 17 00:00:00 2001 From: johnniang Date: Wed, 3 Mar 2021 10:58:48 +0800 Subject: [PATCH 051/644] HHH-14473 add test case --- .../internal/ScanningCoordinatorTest.java | 45 +++++++++++++++---- 1 file changed, 36 insertions(+), 9 deletions(-) diff --git a/hibernate-core/src/test/java/org/hibernate/boot/model/process/internal/ScanningCoordinatorTest.java b/hibernate-core/src/test/java/org/hibernate/boot/model/process/internal/ScanningCoordinatorTest.java index 4c55e3742b5c..fe844255ac9e 100644 --- a/hibernate-core/src/test/java/org/hibernate/boot/model/process/internal/ScanningCoordinatorTest.java +++ b/hibernate-core/src/test/java/org/hibernate/boot/model/process/internal/ScanningCoordinatorTest.java @@ -24,10 +24,10 @@ import org.hibernate.boot.archive.spi.InputStreamAccess; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; +import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; import org.hibernate.boot.spi.BootstrapContext; import org.hibernate.boot.spi.XmlMappingBinderAccess; import org.hibernate.internal.CoreMessageLogger; - import org.hibernate.testing.TestForIssue; import org.hibernate.testing.junit4.BaseUnitTestCase; import org.hibernate.testing.logger.LoggerInspectionRule; @@ -41,6 +41,11 @@ import org.mockito.Mockito; import static org.junit.Assert.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.same; +import static org.mockito.Mockito.times; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; /** @@ -66,10 +71,12 @@ public class ScanningCoordinatorTest extends BaseUnitTestCase { Logger.getMessageLogger( CoreMessageLogger.class, ScanningCoordinator.class.getName() ) ); @Before - public void init(){ + public void init() { + Mockito.reset( managedResources ); Mockito.reset( scanResult ); Mockito.reset( bootstrapContext ); Mockito.reset( scanEnvironment ); + Mockito.reset( classLoaderService ); when( bootstrapContext.getScanEnvironment() ).thenReturn( scanEnvironment ); when( bootstrapContext.getServiceRegistry() ).thenReturn( serviceRegistry ); @@ -78,7 +85,9 @@ public void init(){ when( scanEnvironment.getExplicitlyListedClassNames() ).thenReturn( Arrays.asList( "a.b.C" ) ); - when( classLoaderService.classForName( "a.b.C" ) ).thenReturn( Object.class ); + when( classLoaderService.classForName( eq( "a.b.C" ) ) ).thenThrow( ClassLoadingException.class ); + when( classLoaderService.locateResource( eq( "a/b/c.class" ) ) ).thenReturn( null ); + when( classLoaderService.locateResource( eq( "a/b/c/package-info.class" ) ) ).thenReturn( null ); triggerable = logInspection.watchForLogMessages( "Unable" ); triggerable.reset(); @@ -111,22 +120,40 @@ public void testApplyScanResultsToManagedResourcesWithNotNullRootUrl() } @Test - @TestForIssue( jiraKey = "HHH-12505" ) + @TestForIssue(jiraKey = "HHH-14473") + public void testApplyScanResultsToManagedResultsWhileExplicitClassNameLoadable() { + Class expectedClass = Object.class; + when( classLoaderService.classForName( eq( "a.b.C" ) ) ).thenReturn( expectedClass ); + + ScanningCoordinator.INSTANCE.applyScanResultsToManagedResources( + managedResources, + scanResult, + bootstrapContext, + xmlMappingBinderAccess + ); + + verify( managedResources, times( 0 ) ).addAnnotatedClassName( any() ); + verify( managedResources, times( 1 ) ).addAnnotatedClassReference( same( expectedClass ) ); + verify( classLoaderService, times( 1 ) ).classForName( eq( "a.b.C" ) ); + } + + @Test + @TestForIssue(jiraKey = "HHH-12505") public void testManagedResourcesAfterCoordinateScanWithDisabledScanner() { assertManagedResourcesAfterCoordinateScanWithScanner( new DisabledScanner(), true ); } @Test - @TestForIssue( jiraKey = "HHH-12505" ) + @TestForIssue(jiraKey = "HHH-12505") public void testManagedResourcesAfterCoordinateScanWithCustomEnabledScanner() { final Scanner scanner = new Scanner() { @Override public ScanResult scan(final ScanEnvironment environment, final ScanOptions options, final ScanParameters parameters) { final InputStreamAccess dummyInputStreamAccess = new ByteArrayInputStreamAccess( "dummy", new byte[0] ); return new ScanResultImpl( - Collections.singleton( new PackageDescriptorImpl( "dummy", dummyInputStreamAccess ) ), - Collections.singleton( new ClassDescriptorImpl( "dummy", ClassDescriptor.Categorization.MODEL, dummyInputStreamAccess ) ), - Collections.singleton( new MappingFileDescriptorImpl( "dummy", dummyInputStreamAccess ) ) + Collections.singleton( new PackageDescriptorImpl( "dummy", dummyInputStreamAccess ) ), + Collections.singleton( new ClassDescriptorImpl( "dummy", ClassDescriptor.Categorization.MODEL, dummyInputStreamAccess ) ), + Collections.singleton( new MappingFileDescriptorImpl( "dummy", dummyInputStreamAccess ) ) ); } }; @@ -184,7 +211,7 @@ private void assertManagedResourcesAfterCoordinateScanWithScanner(final Scanner ScanningCoordinator.INSTANCE.coordinateScan( managedResources, bootstrapContext, xmlMappingBinderAccess ); assertEquals( 1, scanEnvironment.getExplicitlyListedClassNames().size() ); - assertEquals( "a.b.C", scanEnvironment.getExplicitlyListedClassNames().get(0) ); + assertEquals( "a.b.C", scanEnvironment.getExplicitlyListedClassNames().get( 0 ) ); assertEquals( true, managedResources.getAttributeConverterDefinitions().isEmpty() ); assertEquals( true, managedResources.getAnnotatedClassReferences().isEmpty() ); From ed3bbf15e476b064b6a55a80ac0c1570a4287bf0 Mon Sep 17 00:00:00 2001 From: Vlad Mihalcea Date: Mon, 12 Nov 2018 13:35:21 +0200 Subject: [PATCH 052/644] HHH-13077 - Optimize query plan call count --- .../AbstractSharedSessionContract.java | 21 +-- .../org/hibernate/internal/SessionImpl.java | 2 +- .../main/java/org/hibernate/query/Query.java | 2 +- .../query/internal/AbstractProducedQuery.java | 19 +- .../hibernate/query/internal/QueryImpl.java | 41 ++++- .../QueryPlanCacheStatisticsTest.java | 173 +++++++++++++++++- 6 files changed, 233 insertions(+), 25 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java b/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java index 00b5b698af7f..6b7a9277657a 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java @@ -647,11 +647,11 @@ public QueryImplementor getNamedQuery(String name) { throw getExceptionConverter().convert( new IllegalArgumentException( "No query defined for that name [" + name + "]" ) ); } - protected QueryImplementor createQuery(NamedQueryDefinition queryDefinition) { + protected QueryImpl createQuery(NamedQueryDefinition queryDefinition) { String queryString = queryDefinition.getQueryString(); final QueryImpl query = new QueryImpl( this, - getQueryPlan( queryString, false ).getParameterMetadata(), + getQueryPlan( queryString, false ), queryString ); applyQuerySettingsAndHints( query ); @@ -723,7 +723,7 @@ protected void initQueryFromNamedDefinition(Query query, NamedQueryDefinition nq } @Override - public QueryImplementor createQuery(String queryString) { + public QueryImpl createQuery(String queryString) { checkOpen(); pulseTransactionCoordinator(); delayedAfterCompletion(); @@ -731,7 +731,7 @@ public QueryImplementor createQuery(String queryString) { try { final QueryImpl query = new QueryImpl( this, - getQueryPlan( queryString, false ).getParameterMetadata(), + getQueryPlan( queryString, false ), queryString ); applyQuerySettingsAndHints( query ); @@ -831,7 +831,7 @@ public QueryImplementor createQuery(String queryString, Class resultCl try { // do the translation - final QueryImplementor query = createQuery( queryString ); + final QueryImpl query = createQuery( queryString ); resultClassChecking( resultClass, query ); return query; } @@ -841,13 +841,10 @@ public QueryImplementor createQuery(String queryString, Class resultCl } @SuppressWarnings({"unchecked", "WeakerAccess", "StatementWithEmptyBody"}) - protected void resultClassChecking(Class resultClass, org.hibernate.Query hqlQuery) { + protected void resultClassChecking(Class resultClass, QueryImpl hqlQuery) { // make sure the query is a select -> HHH-7192 - final HQLQueryPlan queryPlan = getFactory().getQueryPlanCache().getHQLQueryPlan( - hqlQuery.getQueryString(), - false, - getLoadQueryInfluencers().getEnabledFilters() - ); + HQLQueryPlan queryPlan = hqlQuery.getQueryPlan(); + if ( queryPlan.getTranslators()[0].isManipulationStatement() ) { throw new IllegalArgumentException( "Update/delete queries cannot be typed" ); } @@ -923,7 +920,7 @@ protected QueryImplementor buildQueryFromName(String name, Class resu @SuppressWarnings({"WeakerAccess", "unchecked"}) protected QueryImplementor createQuery(NamedQueryDefinition namedQueryDefinition, Class resultType) { - final QueryImplementor query = createQuery( namedQueryDefinition ); + final QueryImpl query = createQuery( namedQueryDefinition ); if ( resultType != null ) { resultClassChecking( resultType, query ); } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java index a2af475246cc..6cef2427fa62 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java @@ -1528,7 +1528,7 @@ public Iterator iterate(String query, QueryParameters queryParameters) throws Hi queryParameters.validateParameters(); HQLQueryPlan plan = queryParameters.getQueryPlan(); - if ( plan == null ) { + if ( plan == null || !plan.isShallow() ) { plan = getQueryPlan( query, true ); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/Query.java b/hibernate-core/src/main/java/org/hibernate/query/Query.java index c56e1ea1a02e..9dfc5f77a8a7 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/Query.java +++ b/hibernate-core/src/main/java/org/hibernate/query/Query.java @@ -67,7 +67,7 @@ * @author Steve Ebersole * @author Gavin King */ -@SuppressWarnings("UnusedDeclaration") +@SuppressWarnings("UnusedDeclaratiqon") public interface Query extends TypedQuery, org.hibernate.Query, CommonQueryContract { /** * Get the QueryProducer this Query originates from. diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/AbstractProducedQuery.java b/hibernate-core/src/main/java/org/hibernate/query/internal/AbstractProducedQuery.java index 87a28dfbeacc..1ca1739101ef 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/internal/AbstractProducedQuery.java +++ b/hibernate-core/src/main/java/org/hibernate/query/internal/AbstractProducedQuery.java @@ -1434,8 +1434,8 @@ protected QueryParameters makeQueryParametersForExecution(String hql) { ); } - QueryParameters queryParameters = new QueryParameters( - getQueryParameterBindings(), + QueryParameters queryParameters = new QueryParameters( + getQueryParameterBindings(), getLockOptions(), queryOptions, true, @@ -1450,13 +1450,24 @@ protected QueryParameters makeQueryParametersForExecution(String hql) { optionalId, resultTransformer ); - queryParameters.setQueryPlan( entityGraphHintedQueryPlan ); + + appendQueryPlanToQueryParameters( hql, queryParameters, entityGraphHintedQueryPlan ); + if ( passDistinctThrough != null ) { queryParameters.setPassDistinctThrough( passDistinctThrough ); } return queryParameters; } + protected void appendQueryPlanToQueryParameters( + String hql, + QueryParameters queryParameters, + HQLQueryPlan queryPlan) { + if ( queryPlan != null ) { + queryParameters.setQueryPlan( queryPlan ); + } + } + public QueryParameters getQueryParameters() { final String expandedQuery = getQueryParameterBindings().expandListValuedParameters( getQueryString(), getProducer() ); return makeQueryParametersForExecution( expandedQuery ); @@ -1732,7 +1743,7 @@ public Type determineProperBooleanType(int position, Object value, Type defaultT : defaultType; } - private boolean isSelect() { + protected boolean isSelect() { return getProducer().getFactory().getQueryPlanCache() .getHQLQueryPlan( getQueryString(), false, Collections.emptyMap() ) .isSelect(); diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/QueryImpl.java b/hibernate-core/src/main/java/org/hibernate/query/internal/QueryImpl.java index cda7388a8cad..35d8ad55dd1e 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/internal/QueryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/internal/QueryImpl.java @@ -6,8 +6,10 @@ */ package org.hibernate.query.internal; +import org.hibernate.engine.query.spi.HQLQueryPlan; +import org.hibernate.engine.query.spi.ReturnMetadata; +import org.hibernate.engine.spi.QueryParameters; import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.query.ParameterMetadata; import org.hibernate.query.Query; import org.hibernate.query.spi.QueryParameterBindings; import org.hibernate.type.Type; @@ -18,16 +20,19 @@ public class QueryImpl extends AbstractProducedQuery implements Query { private final String queryString; + private final HQLQueryPlan hqlQueryPlan; + private final QueryParameterBindingsImpl queryParameterBindings; public QueryImpl( SharedSessionContractImplementor producer, - ParameterMetadata parameterMetadata, + HQLQueryPlan hqlQueryPlan, String queryString) { - super( producer, parameterMetadata ); + super( producer, hqlQueryPlan.getParameterMetadata() ); + this.hqlQueryPlan = hqlQueryPlan; this.queryString = queryString; this.queryParameterBindings = QueryParameterBindingsImpl.from( - parameterMetadata, + hqlQueryPlan.getParameterMetadata(), producer.getFactory(), producer.isQueryParametersValidationEnabled() ); @@ -43,6 +48,10 @@ public String getQueryString() { return queryString; } + public HQLQueryPlan getQueryPlan() { + return hqlQueryPlan; + } + @Override protected boolean isNativeQuery() { return false; @@ -50,12 +59,14 @@ protected boolean isNativeQuery() { @Override public Type[] getReturnTypes() { - return getProducer().getFactory().getReturnTypes( queryString ); + final ReturnMetadata metadata = hqlQueryPlan.getReturnMetadata(); + return metadata == null ? null : metadata.getReturnTypes(); } @Override public String[] getReturnAliases() { - return getProducer().getFactory().getReturnAliases( queryString ); + final ReturnMetadata metadata = hqlQueryPlan.getReturnMetadata(); + return metadata == null ? null : metadata.getReturnAliases(); } @Override @@ -67,4 +78,22 @@ public Query setEntity(int position, Object val) { public Query setEntity(String name, Object val) { return setParameter( name, val, getProducer().getFactory().getTypeHelper().entity( resolveEntityName( val ) ) ); } + + @Override + protected boolean isSelect() { + return hqlQueryPlan.isSelect(); + } + + @Override + protected void appendQueryPlanToQueryParameters( + String hql, + QueryParameters queryParameters, + HQLQueryPlan queryPlan) { + if ( queryPlan != null ) { + queryParameters.setQueryPlan( queryPlan ); + } + else if ( hql.equals( getQueryString() ) ) { + queryParameters.setQueryPlan( getQueryPlan() ); + } + } } diff --git a/hibernate-core/src/test/java/org/hibernate/stat/internal/QueryPlanCacheStatisticsTest.java b/hibernate-core/src/test/java/org/hibernate/stat/internal/QueryPlanCacheStatisticsTest.java index a0a02b1705dc..5974b976b012 100644 --- a/hibernate-core/src/test/java/org/hibernate/stat/internal/QueryPlanCacheStatisticsTest.java +++ b/hibernate-core/src/test/java/org/hibernate/stat/internal/QueryPlanCacheStatisticsTest.java @@ -6,22 +6,28 @@ */ package org.hibernate.stat.internal; +import java.util.List; import java.util.Map; + import javax.persistence.Entity; import javax.persistence.GeneratedValue; import javax.persistence.Id; +import javax.persistence.LockModeType; +import javax.persistence.NamedQuery; +import javax.persistence.Tuple; +import javax.persistence.TypedQuery; import org.hibernate.SessionFactory; import org.hibernate.cfg.Environment; import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; import org.hibernate.stat.QueryStatistics; import org.hibernate.stat.Statistics; - import org.hibernate.testing.TestForIssue; import org.junit.Test; import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; /** @@ -39,6 +45,7 @@ public Class[] getAnnotatedClasses() { }; } + @Override protected void addConfigOptions(Map options) { options.put( Environment.GENERATE_STATISTICS, "true" ); } @@ -63,6 +70,7 @@ protected void afterEntityManagerFactoryBuilt() { @Test public void test() { + statistics.clear(); assertEquals( 0, statistics.getQueryPlanCacheHitCount() ); assertEquals( 0, statistics.getQueryPlanCacheMissCount() ); @@ -115,6 +123,165 @@ public void test() { } ); } + @Test + @TestForIssue( jiraKey = "HHH-13077" ) + public void testCreateQueryHitCount() { + statistics.clear(); + + doInJPA( this::entityManagerFactory, entityManager -> { + + List employees = entityManager.createQuery( + "select e from Employee e", Employee.class ) + .getResultList(); + + assertEquals( 5, employees.size() ); + + //First time, we get a cache miss, so the query is compiled + assertEquals( 1, statistics.getQueryPlanCacheMissCount() ); + //The hit count should be 0 as we don't need to go to the cache after we already compiled the query + assertEquals( 0, statistics.getQueryPlanCacheHitCount() ); + } ); + + doInJPA( this::entityManagerFactory, entityManager -> { + + List employees = entityManager.createQuery( + "select e from Employee e", Employee.class ) + .getResultList(); + + assertEquals( 5, employees.size() ); + + //The miss count is still 1, as no we got the query plan from the cache + assertEquals( 1, statistics.getQueryPlanCacheMissCount() ); + //And the cache hit count increases. + assertEquals( 1, statistics.getQueryPlanCacheHitCount() ); + } ); + + doInJPA( this::entityManagerFactory, entityManager -> { + + List employees = entityManager.createQuery( + "select e from Employee e", Employee.class ) + .getResultList(); + + assertEquals( 5, employees.size() ); + + //The miss count is still 1, as no we got the query plan from the cache + assertEquals( 1, statistics.getQueryPlanCacheMissCount() ); + //And the cache hit count increases. + assertEquals( 2, statistics.getQueryPlanCacheHitCount() ); + } ); + } + + @Test + @TestForIssue( jiraKey = "HHH-13077" ) + public void testCreateNamedQueryHitCount() { + //This is for the NamedQuery that gets compiled + assertEquals( 1, statistics.getQueryPlanCacheMissCount() ); + statistics.clear(); + + doInJPA( this::entityManagerFactory, entityManager -> { + + Employee employees = entityManager.createNamedQuery( + "find_employee_by_name", Employee.class ) + .setParameter( "name", "Employee: 1" ) + .getSingleResult(); + + //The miss count is 0 because the plan was compiled when the EMF was built, and we cleared the Statistics + assertEquals( 0, statistics.getQueryPlanCacheMissCount() ); + //The hit count is 1 since we got the plan from the cache + assertEquals( 1, statistics.getQueryPlanCacheHitCount() ); + } ); + + doInJPA( this::entityManagerFactory, entityManager -> { + + Employee employees = entityManager.createNamedQuery( + "find_employee_by_name", Employee.class ) + .setParameter( "name", "Employee: 1" ) + .getSingleResult(); + + //The miss count is still 0 because the plan was compiled when the EMF was built, and we cleared the Statistics + assertEquals( 0, statistics.getQueryPlanCacheMissCount() ); + //The hit count is 2 since we got the plan from the cache twice + assertEquals( 2, statistics.getQueryPlanCacheHitCount() ); + } ); + } + + @Test + @TestForIssue( jiraKey = "HHH-13077" ) + public void testCreateQueryTupleHitCount() { + statistics.clear(); + + doInJPA( this::entityManagerFactory, entityManager -> { + + List employees = entityManager.createQuery( + "select e.id, e.name from Employee e", Tuple.class ) + .getResultList(); + + assertEquals( 5, employees.size() ); + + //First time, we get a cache miss, so the query is compiled + assertEquals( 1, statistics.getQueryPlanCacheMissCount() ); + //The hit count should be 0 as we don't need to go to the cache after we already compiled the query + assertEquals( 0, statistics.getQueryPlanCacheHitCount() ); + } ); + + doInJPA( this::entityManagerFactory, entityManager -> { + + List employees = entityManager.createQuery( + "select e.id, e.name from Employee e", Tuple.class ) + .getResultList(); + + assertEquals( 5, employees.size() ); + + //The miss count is still 1, as no we got the query plan from the cache + assertEquals( 1, statistics.getQueryPlanCacheMissCount() ); + //And the cache hit count increases. + assertEquals( 1, statistics.getQueryPlanCacheHitCount() ); + } ); + + doInJPA( this::entityManagerFactory, entityManager -> { + + List employees = entityManager.createQuery( + "select e.id, e.name from Employee e", Tuple.class ) + .getResultList(); + + assertEquals( 5, employees.size() ); + + //The miss count is still 1, as no we got the query plan from the cache + assertEquals( 1, statistics.getQueryPlanCacheMissCount() ); + //And the cache hit count increases. + assertEquals( 2, statistics.getQueryPlanCacheHitCount() ); + } ); + } + + @Test + @TestForIssue(jiraKey = "HHH-13077") + public void testLockModeHitCount() { + statistics.clear(); + + doInJPA( this::entityManagerFactory, entityManager -> { + TypedQuery typedQuery = entityManager.createQuery( "select e from Employee e", Employee.class ); + + List employees = typedQuery.getResultList(); + + assertEquals( 5, employees.size() ); + + //First time, we get a cache miss, so the query is compiled + assertEquals( 1, statistics.getQueryPlanCacheMissCount() ); + //The hit count should be 0 as we don't need to go to the cache after we already compiled the query + assertEquals( 0, statistics.getQueryPlanCacheHitCount() ); + + typedQuery.setLockMode( LockModeType.READ ); + + //The hit count should still be 0 as setLockMode() shouldn't trigger a cache hit + assertEquals( 0, statistics.getQueryPlanCacheHitCount() ); + + assertNotNull( typedQuery.getLockMode() ); + + //The hit count should still be 0 as getLockMode() shouldn't trigger a cache hit + assertEquals( 0, statistics.getQueryPlanCacheHitCount() ); + } ); + } + private void assertQueryStatistics(String hql, int hitCount) { QueryStatistics queryStatistics = statistics.getQueryStatistics( hql ); @@ -125,6 +292,10 @@ private void assertQueryStatistics(String hql, int hitCount) { } @Entity(name = "Employee") + @NamedQuery( + name = "find_employee_by_name", + query = "select e from Employee e where e.name = :name" + ) public static class Employee { @Id From 81071a4594d4347279222632bdc76a1ded44bebe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Wed, 24 Feb 2021 15:24:14 +0100 Subject: [PATCH 053/644] HHH-14439 Clean up expanded list parameters before re-executing a query MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Yoann Rodière --- .../internal/QueryParameterBindingsImpl.java | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/QueryParameterBindingsImpl.java b/hibernate-core/src/main/java/org/hibernate/query/internal/QueryParameterBindingsImpl.java index d5122e03ae63..7759c145203d 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/internal/QueryParameterBindingsImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/internal/QueryParameterBindingsImpl.java @@ -63,6 +63,7 @@ public class QueryParameterBindingsImpl implements QueryParameterBindings { private Map parameterBindingMap; private Map parameterListBindingMap; private Set parametersConvertedToListBindings; + private Set syntheticParametersFromListBindings; public static QueryParameterBindingsImpl from( ParameterMetadata parameterMetadata, @@ -514,6 +515,12 @@ public String expandListValuedParameters(String queryString, SharedSessionContra return null; } + if ( syntheticParametersFromListBindings != null ) { + // Clean up parameters from previous query executions + parameterBindingMap.keySet().removeAll( syntheticParametersFromListBindings ); + syntheticParametersFromListBindings.clear(); + } + if ( parameterListBindingMap == null || parameterListBindingMap.isEmpty() ) { return queryString; } @@ -644,6 +651,7 @@ public String expandListValuedParameters(String queryString, SharedSessionContra expansionList.append( "?" ).append( syntheticParam.getPosition() ); } + registerSyntheticParamFromListBindings( syntheticParam ); final QueryParameterBinding syntheticBinding = makeBinding( entry.getValue().getBindType() ); syntheticBinding.setBindValue( bindValue ); parameterBindingMap.put( syntheticParam, syntheticBinding ); @@ -669,6 +677,13 @@ public String expandListValuedParameters(String queryString, SharedSessionContra return queryString; } + private void registerSyntheticParamFromListBindings(QueryParameter syntheticParam) { + if ( syntheticParametersFromListBindings == null ) { + syntheticParametersFromListBindings = new HashSet<>(); + } + syntheticParametersFromListBindings.add( syntheticParam ); + } + private int getMaxOrdinalPosition() { int maxOrdinalPosition = 0; for ( QueryParameter queryParameter : parameterBindingMap.keySet() ) { From fb079d077cf34e206084d796d7c53e5e606a6436 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Wed, 24 Feb 2021 14:18:26 +0100 Subject: [PATCH 054/644] HHH-14439 Test executing the same query with subselects a second time with different list parameters MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Yoann Rodière --- ...yListParametersWithFetchSubSelectTest.java | 215 ++++++++++++++++++ 1 file changed, 215 insertions(+) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/query/QueryListParametersWithFetchSubSelectTest.java diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/query/QueryListParametersWithFetchSubSelectTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/query/QueryListParametersWithFetchSubSelectTest.java new file mode 100644 index 000000000000..fe6402ba944b --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/query/QueryListParametersWithFetchSubSelectTest.java @@ -0,0 +1,215 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.test.annotations.query; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import javax.persistence.TypedQuery; + +import org.hibernate.Hibernate; +import org.hibernate.annotations.Fetch; +import org.hibernate.annotations.FetchMode; +import org.hibernate.cfg.Configuration; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.jdbc.SQLStatementInterceptor; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Tests the handling and expansion of list parameters, + * particularly when using {@code @Fetch(FetchMode.SUBSELECT)} + * (because this fetch mode involves building a map of parameters). + */ +public class QueryListParametersWithFetchSubSelectTest extends BaseCoreFunctionalTestCase { + + private SQLStatementInterceptor sqlStatementInterceptor; + + @Override + protected void configure(Configuration configuration) { + sqlStatementInterceptor = new SQLStatementInterceptor( configuration ); + } + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { Parent.class, Child.class }; + } + + @Override + protected void afterSessionFactoryBuilt() { + inTransaction( s -> { + for ( int i = 0; i < 10; i++ ) { + Parent parent = new Parent( i ); + s.persist( parent ); + for ( int j = 0; j < 10; j++ ) { + Child child = new Child( i * 100 + j, parent ); + parent.children.add( child ); + s.persist( child ); + } + } + } ); + } + + @Test + public void simple() { + sqlStatementInterceptor.clear(); + + inTransaction( s -> { + TypedQuery query = s.createQuery( "select p from Parent p where id in :ids", Parent.class ); + query.setParameter( "ids", Arrays.asList( 0, 1, 2 ) ); + List results = query.getResultList(); + assertThat( results ) + .allSatisfy( parent -> assertThat( Hibernate.isInitialized( parent.getChildren() ) ).isTrue() ) + .extracting( Parent::getId ).containsExactly( 0, 1, 2 ); + } ); + + // If we get here, children were initialized eagerly. + // Did ORM actually use subselects? + assertThat( sqlStatementInterceptor.getSqlQueries() ).hasSize( 2 ); + } + + @Test + @TestForIssue(jiraKey = "HHH-14439") + public void reusingQueryWithFewerNamedParameters() { + sqlStatementInterceptor.clear(); + + inTransaction( s -> { + TypedQuery query = s.createQuery( "select p from Parent p where id in :ids", Parent.class ); + + query.setParameter( "ids", Arrays.asList( 0, 1, 2, 3 ) ); + List results = query.getResultList(); + assertThat( results ) + .allSatisfy( parent -> assertThat( Hibernate.isInitialized( parent.getChildren() ) ).isTrue() ) + .extracting( Parent::getId ).containsExactly( 0, 1, 2, 3 ); + + query.setParameter( "ids", Arrays.asList( 4, 5, 6 ) ); + results = query.getResultList(); + assertThat( results ) + .allSatisfy( parent -> assertThat( Hibernate.isInitialized( parent.getChildren() ) ).isTrue() ) + .extracting( Parent::getId ).containsExactly( 4, 5, 6 ); + + query.setParameter( "ids", Arrays.asList( 7, 8 ) ); + results = query.getResultList(); + assertThat( results ) + .allSatisfy( parent -> assertThat( Hibernate.isInitialized( parent.getChildren() ) ).isTrue() ) + .extracting( Parent::getId ).containsExactly( 7, 8 ); + } ); + + // If we get here, children were initialized eagerly. + // Did ORM actually use subselects? + assertThat( sqlStatementInterceptor.getSqlQueries() ).hasSize( 3 * 2 ); + } + + + @Test + @TestForIssue(jiraKey = "HHH-14439") + public void reusingQueryWithFewerOrdinalParameters() { + sqlStatementInterceptor.clear(); + + inTransaction( s -> { + TypedQuery query = s.createQuery( "select p from Parent p where id in ?0", Parent.class ); + + query.setParameter( 0, Arrays.asList( 0, 1, 2, 3 ) ); + List results = query.getResultList(); + assertThat( results ) + .allSatisfy( parent -> assertThat( Hibernate.isInitialized( parent.getChildren() ) ).isTrue() ) + .extracting( Parent::getId ).containsExactly( 0, 1, 2, 3 ); + + query.setParameter( 0, Arrays.asList( 4, 5, 6 ) ); + results = query.getResultList(); + assertThat( results ) + .allSatisfy( parent -> assertThat( Hibernate.isInitialized( parent.getChildren() ) ).isTrue() ) + .extracting( Parent::getId ).containsExactly( 4, 5, 6 ); + + query.setParameter( 0, Arrays.asList( 7, 8 ) ); + results = query.getResultList(); + assertThat( results ) + .allSatisfy( parent -> assertThat( Hibernate.isInitialized( parent.getChildren() ) ).isTrue() ) + .extracting( Parent::getId ).containsExactly( 7, 8 ); + } ); + + // If we get here, children were initialized eagerly. + // Did ORM actually use subselects? + assertThat( sqlStatementInterceptor.getSqlQueries() ).hasSize( 3 * 2 ); + } + + @Entity(name = "Parent") + public static class Parent { + @Id + private Integer id; + + @OneToMany(mappedBy = "parent", fetch = FetchType.EAGER) + @Fetch(FetchMode.SUBSELECT) + private List children = new ArrayList<>(); + + public Parent() { + } + + public Parent(Integer id) { + this.id = id; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public List getChildren() { + return children; + } + + public void setChildren(List children) { + this.children = children; + } + } + + @Entity(name = "Child") + public static class Child { + + @Id + private Integer id; + + @ManyToOne + private Parent parent; + + public Child() { + } + + public Child(Integer id, Parent parent) { + this.id = id; + this.parent = parent; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Parent getParent() { + return parent; + } + + public void setParent(Parent parent) { + this.parent = parent; + } + } + +} From 17c5fab50e9a1c90a96a01498b8c95b1646194cc Mon Sep 17 00:00:00 2001 From: Vlad Mihalcea Date: Fri, 21 Feb 2020 10:11:12 +0200 Subject: [PATCH 055/644] HHH-12338 - Incorrect metamodel for basic collections --- .../MetaAttributeGenerationVisitor.java | 17 ++++ .../CollectionAsBasicTypeTest.java | 89 +++++++++++++++++++ 2 files changed, 106 insertions(+) create mode 100644 tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/collectionbasictype/CollectionAsBasicTypeTest.java diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/MetaAttributeGenerationVisitor.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/MetaAttributeGenerationVisitor.java index 5a1117b85032..58226681d764 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/MetaAttributeGenerationVisitor.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/annotation/MetaAttributeGenerationVisitor.java @@ -138,6 +138,23 @@ private AnnotationMetaAttribute createMetaCollectionAttribute(DeclaredType decla accessTypeInfo.setDefaultAccessType( entity.getEntityAccessTypeInfo().getAccessType() ); } } + if ( TypeUtils.containsAnnotation( + element, + Constants.BASIC, + Constants.CONVERT, + Constants.HIBERNATE_TYPE + ) && !TypeUtils.containsAnnotation( + element, + Constants.ONE_TO_MANY, + Constants.MANY_TO_MANY, + Constants.ELEMENT_COLLECTION + ) ) { + return new AnnotationMetaSingleAttribute( + entity, + element, + TypeUtils.toTypeString( declaredType ) + ); + } if ( collection.equals( Constants.MAP_ATTRIBUTE ) ) { return createAnnotationMetaAttributeForMap( declaredType, element, collection, targetEntity ); } diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/collectionbasictype/CollectionAsBasicTypeTest.java b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/collectionbasictype/CollectionAsBasicTypeTest.java new file mode 100644 index 000000000000..10b436c51090 --- /dev/null +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/collectionbasictype/CollectionAsBasicTypeTest.java @@ -0,0 +1,89 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.jpamodelgen.test.collectionbasictype; + +import org.hibernate.jpamodelgen.test.util.CompilationTest; +import org.hibernate.jpamodelgen.test.util.TestForIssue; +import org.hibernate.jpamodelgen.test.util.WithClasses; + +import org.junit.Test; + +import static org.hibernate.jpamodelgen.test.util.TestUtil.assertAttributeTypeInMetaModelFor; +import static org.hibernate.jpamodelgen.test.util.TestUtil.assertListAttributeTypeInMetaModelFor; +import static org.hibernate.jpamodelgen.test.util.TestUtil.assertMetamodelClassGeneratedFor; + +/** + * @author helloztt + */ +public class CollectionAsBasicTypeTest extends CompilationTest { + + @Test + @TestForIssue(jiraKey = "HHH-12338") + @WithClasses({Goods.class, Product.class}) + public void testConvert() throws ClassNotFoundException, NoSuchFieldException { + assertMetamodelClassGeneratedFor(Product.class); + assertMetamodelClassGeneratedFor(Goods.class); + assertListAttributeTypeInMetaModelFor( + Goods.class, + "productList", + Product.class, + "ListAttribute generic type should be Product" + ); + assertAttributeTypeInMetaModelFor( + Goods.class, + "tags", + Goods.class.getDeclaredField("tags").getGenericType(), + "Wrong meta model type" + ); + + } + + @Test + @TestForIssue(jiraKey = "HHH-12338") + @WithClasses({Person.class}) + public void testListType() throws ClassNotFoundException, NoSuchFieldException { + assertMetamodelClassGeneratedFor(Person.class); + + assertAttributeTypeInMetaModelFor( + Person.class, + "phones", + Person.class.getDeclaredField("phones").getGenericType(), + "Wrong meta model type" + ); + + } + + @Test + @TestForIssue(jiraKey = "HHH-12338") + @WithClasses({PersonPhone.class}) + public void testListTypeWithImport() throws ClassNotFoundException, NoSuchFieldException { + assertMetamodelClassGeneratedFor(PersonPhone.class); + + assertAttributeTypeInMetaModelFor( + PersonPhone.class, + "phones", + PersonPhone.class.getDeclaredField("phones").getGenericType(), + "Wrong meta model type" + ); + + } + + @Test + @TestForIssue(jiraKey = "HHH-12338") + @WithClasses({PhoneBook.class}) + public void testMapType() throws ClassNotFoundException, NoSuchFieldException { + assertMetamodelClassGeneratedFor(PhoneBook.class); + + assertAttributeTypeInMetaModelFor( + PhoneBook.class, + "phones", + PhoneBook.class.getDeclaredField("phones").getGenericType(), + "Wrong meta model type" + ); + + } +} From a514460bb9b686d1e4e9aad86acd5eb86ca15bcb Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Fri, 5 Mar 2021 12:28:45 +0100 Subject: [PATCH 056/644] HHH-9182 Cleanup grammar ambiguity issues --- hibernate-core/src/main/antlr/hql.g | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/hibernate-core/src/main/antlr/hql.g b/hibernate-core/src/main/antlr/hql.g index bd05e70aea26..3f2782263107 100644 --- a/hibernate-core/src/main/antlr/hql.g +++ b/hibernate-core/src/main/antlr/hql.g @@ -596,8 +596,8 @@ equalityExpression // token type. When traversing the AST, use the token type, and not the // token text to interpret the semantics of these nodes. relationalExpression - : concatenation ( - ( ( ( LT^ | GT^ | LE^ | GE^ ) additiveExpression )* ) + : ( concatenation | quantifiedExpression ) ( + ( ( ( LT^ | GT^ | LE^ | GE^ ) ( additiveExpression | quantifiedExpression ) )* ) // Disable node production for the optional 'not'. | (n:NOT!)? ( // Represent the optional NOT prefix using the token type by @@ -668,7 +668,6 @@ unaryExpression : MINUS^ {#MINUS.setType(UNARY_MINUS);} unaryExpression | PLUS^ {#PLUS.setType(UNARY_PLUS);} unaryExpression | caseExpression - | quantifiedExpression | atom ; @@ -842,9 +841,9 @@ castedIdentPrimaryBase ; aggregate - : ( SUM^ | AVG^ | MAX^ | MIN^ ) OPEN! ( concatenation | subQuery ) CLOSE! { #aggregate.setType(AGGREGATE); } + : ( SUM^ | AVG^ | MAX^ | MIN^ ) OPEN! ( concatenation ) CLOSE! { #aggregate.setType(AGGREGATE); } // Special case for count - It's 'parameters' can be keywords. - | COUNT^ OPEN! ( STAR { #STAR.setType(ROW_STAR); } | ( ( DISTINCT | ALL )? ( concatenation | subQuery ) ) ) CLOSE! + | COUNT^ OPEN! ( STAR { #STAR.setType(ROW_STAR); } | ( ( DISTINCT | ALL )? ( concatenation ) ) ) CLOSE! | collectionExpr ; From 9952c0984354a45e293213ae3257071dd5eca3fd Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Wed, 10 Mar 2021 16:23:42 -0600 Subject: [PATCH 057/644] HHH-14491 - Apply default allocation/increment size for @GeneratedValue(AUTO) HHH-14492 - Prefer sequence-per-entity (hierarchy) for @GeneratedValue(AUTO) by default - added test as @FailureExpected to track this into 6.0 --- .../enhanced/auto/NewGeneratorsTests.java | 88 +++++++++++++++++++ 1 file changed, 88 insertions(+) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/idgen/enhanced/auto/NewGeneratorsTests.java diff --git a/hibernate-core/src/test/java/org/hibernate/test/idgen/enhanced/auto/NewGeneratorsTests.java b/hibernate-core/src/test/java/org/hibernate/test/idgen/enhanced/auto/NewGeneratorsTests.java new file mode 100644 index 000000000000..5d73e16074e3 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/idgen/enhanced/auto/NewGeneratorsTests.java @@ -0,0 +1,88 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.idgen.enhanced.auto; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; + +import org.hibernate.boot.Metadata; +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistry; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.dialect.H2Dialect; +import org.hibernate.id.enhanced.DatabaseStructure; +import org.hibernate.id.enhanced.SequenceStyleGenerator; +import org.hibernate.id.factory.internal.DefaultIdentifierGeneratorFactory; +import org.hibernate.mapping.PersistentClass; +import org.hibernate.service.spi.ServiceRegistryImplementor; +import org.hibernate.tool.schema.Action; + +import org.hibernate.testing.FailureExpected; +import org.hibernate.testing.junit4.BaseUnitTestCase; +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; + +/** + * @author Steve Ebersole + */ +public class NewGeneratorsTests extends BaseUnitTestCase { + @Test + @FailureExpected( + jiraKey = "HHH-14491", + message = "To be implemented for 6; see https://github.com/hibernate/hibernate-orm/discussions/3809" + ) + public void testAutoDefaults() { + // check that `@GeneratedValue(AUTO)` with no explicit generator applies + // various defaults: + // - allocation/increment size = 50 + // - sequence-per-entity with a suffix + + final StandardServiceRegistryBuilder ssrb = new StandardServiceRegistryBuilder(); + ssrb.applySetting( AvailableSettings.HBM2DDL_AUTO, Action.CREATE_DROP ); + + final StandardServiceRegistry ssr = ssrb.build(); + final Metadata metadata = new MetadataSources( ssr ) + .addAnnotatedClass( Entity1.class ) + .buildMetadata(); + + final DefaultIdentifierGeneratorFactory generatorFactory = new DefaultIdentifierGeneratorFactory(); + generatorFactory.injectServices( (ServiceRegistryImplementor) ssr ); + + final PersistentClass entityBinding = metadata.getEntityBinding( Entity1.class.getName() ); + final SequenceStyleGenerator generator = (SequenceStyleGenerator) entityBinding.getRootClass().getIdentifier().createIdentifierGenerator( + generatorFactory, + new H2Dialect(), + "", + "", + entityBinding.getRootClass() + ); + + final DatabaseStructure databaseStructure = generator.getDatabaseStructure(); + + // HHH-14491 - what we want to happen + assertThat( databaseStructure.getName(), is( "Entity1_SEQ" ) ); + // or this depending on the discussion (Jira) about using entity name v. table name as the base + assertThat( databaseStructure.getName(), is( "tbl_1_SEQ" ) ); + + // HHH-14491 - this is what we want to have happen + assertThat( databaseStructure.getIncrementSize(), is( 50 ) ); + } + + @Entity( name = "Entity1" ) + @Table( name = "tbl_1" ) + public static class Entity1 { + @Id + @GeneratedValue( strategy = GenerationType.AUTO ) + private Integer id; + } +} From 8101e3e47d65497dd30e2d7a9338ae5375c5b279 Mon Sep 17 00:00:00 2001 From: Jaanus Hansen Date: Tue, 10 Apr 2018 00:57:47 +0300 Subject: [PATCH 058/644] HHH-9663 added failing test case for Embeddable orphanRemoval --- ...LazyOrphanRemovalInEmbeddedEntityTest.java | 184 ++++++++++++++++++ 1 file changed, 184 insertions(+) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/jpa/orphan/one2one/embedded/OneToOneLazyOrphanRemovalInEmbeddedEntityTest.java diff --git a/hibernate-core/src/test/java/org/hibernate/test/jpa/orphan/one2one/embedded/OneToOneLazyOrphanRemovalInEmbeddedEntityTest.java b/hibernate-core/src/test/java/org/hibernate/test/jpa/orphan/one2one/embedded/OneToOneLazyOrphanRemovalInEmbeddedEntityTest.java new file mode 100644 index 000000000000..f72f71024e5f --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/jpa/orphan/one2one/embedded/OneToOneLazyOrphanRemovalInEmbeddedEntityTest.java @@ -0,0 +1,184 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.jpa.orphan.one2one.embedded; + +import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; +import org.junit.Assert; +import org.junit.Test; + +import javax.persistence.*; + +import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; +import static org.junit.Assert.assertNull; + +/** + * Similar test as ../OneToOneLazyOrphanRemovalTest, + * shows that orphanRemoval = true is not removing the orphan of OneToOne relations in Embedded objects + * for unidirectional relationship. + * + * @TestForIssue( jiraKey = "HHH-9663" ) + */ +public class OneToOneLazyOrphanRemovalInEmbeddedEntityTest extends BaseEntityManagerFunctionalTestCase { + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { RaceDriver.class, Car.class, Engine.class}; + } + + @Test + public void testOneToOneLazyOrphanRemoval() { + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Initialize the data + doInJPA( this::entityManagerFactory, entityManager -> { + final Engine engine = new Engine( 1, 275 ); + final Car car = new Car(1, engine, "red"); + final RaceDriver raceDriver = new RaceDriver(1, car); + entityManager.persist( engine ); + entityManager.persist( raceDriver ); + } ); + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + //set car engine to null, orphanRemoval = true should trigger deletion for engine entity + doInJPA( this::entityManagerFactory, entityManager -> { + final RaceDriver raceDriver = entityManager.find( RaceDriver.class, 1 ); + final Car car = raceDriver.getCar(); + + //check, that at the moment the engine is orphan + Assert.assertNotNull(car.getEngine()); + + car.setEngine( null ); + entityManager.merge( raceDriver ); + + final RaceDriver raceDriver2 = entityManager.find( RaceDriver.class, 1 ); + Assert.assertNotNull(raceDriver2.car); + } ); + + //check, that the engine is deleted: + doInJPA( this::entityManagerFactory, entityManager -> { + final RaceDriver raceDriver = entityManager.find( RaceDriver.class, 1 ); + final Car car = raceDriver.getCar(); + Assert.assertNull(car.getEngine()); + + final Engine engine = entityManager.find( Engine.class, 1 ); + assertNull( engine); + } ); + } + + @Entity(name = "RaceDriver") + public static class RaceDriver { + + @Id + private Integer id; + + @Embedded + private Car car; + + RaceDriver() { + // Required by JPA + } + + RaceDriver(Integer id, Car car) { + this.id = id; + this.car = car; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Car getCar() { + return car; + } + + public void setCar(Car car) { + this.car = car; + } + } + + @Embeddable + public static class Car { + + @Id + private Integer id; + + // represents a unidirectional one-to-one + @OneToOne(orphanRemoval = true, fetch = FetchType.LAZY) + private Engine engine; + + @Column + private String color; + + Car() { + // Required by JPA + } + + Car(Integer id, Engine engine, String color) { + this.id = id; + this.engine = engine; + this.color = color; + } + + public Engine getEngine() { + return engine; + } + + public void setEngine(Engine engine) { + this.engine = engine; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getColor() { + return color; + } + + public void setColor(String color) { + this.color = color; + } + } + + @Entity(name = "Engine") + public static class Engine { + @Id + private Integer id; + private Integer horsePower; + + Engine() { + // Required by JPA + } + + Engine(Integer id, int horsePower) { + this.id = id; + this.horsePower = horsePower; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public Integer getHorsePower() { + return horsePower; + } + + public void setHorsePower(Integer horsePower) { + this.horsePower = horsePower; + } + } +} From d1445efd828b67c299981d78306bf299fa3ca142 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Thu, 11 Mar 2021 12:58:03 +0100 Subject: [PATCH 059/644] HHH-9663 Implement support for orphan removal of assocations within embeddables --- .../hibernate/engine/internal/Cascade.java | 71 ++++++++++--------- 1 file changed, 39 insertions(+), 32 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/Cascade.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/Cascade.java index f8788c0af476..107a3eff8f87 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/internal/Cascade.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/Cascade.java @@ -7,9 +7,11 @@ package org.hibernate.engine.internal; import java.io.Serializable; +import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; import java.util.Iterator; +import java.util.List; import org.hibernate.HibernateException; import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor; @@ -29,6 +31,7 @@ import org.hibernate.proxy.HibernateProxy; import org.hibernate.type.AssociationType; import org.hibernate.type.CollectionType; +import org.hibernate.type.ComponentType; import org.hibernate.type.CompositeType; import org.hibernate.type.EntityType; import org.hibernate.type.ForeignKeyDirection; @@ -90,7 +93,6 @@ public static void cascade( final String[] propertyNames = persister.getPropertyNames(); final CascadeStyle[] cascadeStyles = persister.getPropertyCascadeStyles(); final boolean hasUninitializedLazyProperties = persister.hasUninitializedLazyProperties( parent ); - final int componentPathStackDepth = 0; for ( int i = 0; i < types.length; i++) { final CascadeStyle style = cascadeStyles[ i ]; final String propertyName = propertyNames[ i ]; @@ -152,7 +154,7 @@ else if ( action.performOnLazyProperty() && types[ i ].isEntityType() ) { action, cascadePoint, eventSource, - componentPathStackDepth, + null, parent, child, types[ i ], @@ -177,7 +179,7 @@ else if ( action.performOnLazyProperty() && types[ i ].isEntityType() ) { cascadeLogicalOneToOneOrphanRemoval( action, eventSource, - componentPathStackDepth, + null, parent, persister.getPropertyValue( parent, i ), types[ i ], @@ -202,7 +204,7 @@ private static void cascadeProperty( final CascadingAction action, final CascadePoint cascadePoint, final EventSource eventSource, - final int componentPathStackDepth, + List componentPath, final Object parent, final Object child, final Type type, @@ -219,7 +221,7 @@ private static void cascadeProperty( action, cascadePoint, eventSource, - componentPathStackDepth, + componentPath, parent, child, type, @@ -230,23 +232,28 @@ private static void cascadeProperty( } } else if ( type.isComponentType() ) { + if ( componentPath == null ) { + componentPath = new ArrayList<>(); + } + componentPath.add( propertyName ); cascadeComponent( action, cascadePoint, eventSource, - componentPathStackDepth, + componentPath, parent, child, (CompositeType) type, anything ); + componentPath.remove( componentPath.size() - 1 ); } } cascadeLogicalOneToOneOrphanRemoval( action, eventSource, - componentPathStackDepth, + componentPath, parent, child, type, @@ -258,7 +265,7 @@ else if ( type.isComponentType() ) { private static void cascadeLogicalOneToOneOrphanRemoval( final CascadingAction action, final EventSource eventSource, - final int componentPathStackDepth, + final List componentPath, final Object parent, final Object child, final Type type, @@ -277,26 +284,26 @@ private static void cascadeLogicalOneToOneOrphanRemoval( final EntityEntry entry = persistenceContext.getEntry( parent ); if ( entry != null && entry.getStatus() != Status.SAVING ) { Object loadedValue; - if ( componentPathStackDepth == 0 ) { + if ( componentPath == null ) { // association defined on entity loadedValue = entry.getLoadedValue( propertyName ); } else { // association defined on component - // todo : this is currently unsupported because of the fact that - // we do not know the loaded state of this value properly - // and doing so would be very difficult given how components and - // entities are loaded (and how 'loaded state' is put into the - // EntityEntry). Solutions here are to either: - // 1) properly account for components as a 2-phase load construct - // 2) just assume the association was just now orphaned and - // issue the orphan delete. This would require a special - // set of SQL statements though since we do not know the - // orphaned value, something a delete with a subquery to - // match the owner. -// final EntityType entityType = (EntityType) type; -// final String getPropertyPath = composePropertyPath( entityType.getPropertyName() ); - loadedValue = null; + // Since the loadedState in the EntityEntry is a flat domain type array + // We first have to extract the component object and then ask the component type + // recursively to give us the value of the sub-property of that object + loadedValue = entry.getLoadedValue( componentPath.get( 0 ) ); + ComponentType componentType = (ComponentType) entry.getPersister().getPropertyType( componentPath.get( 0 ) ); + if ( componentPath.size() != 1 ) { + for ( int i = 1; i < componentPath.size(); i++ ) { + final int subPropertyIndex = componentType.getPropertyIndex( componentPath.get( i ) ); + loadedValue = componentType.getPropertyValue( loadedValue, subPropertyIndex ); + componentType = (ComponentType) componentType.getSubtypes()[subPropertyIndex]; + } + } + + loadedValue = componentType.getPropertyValue( loadedValue, componentType.getPropertyIndex( propertyName ) ); } // orphaned if the association was nulled (child == null) or receives a new value while the @@ -367,7 +374,7 @@ private static void cascadeComponent( final CascadingAction action, final CascadePoint cascadePoint, final EventSource eventSource, - final int componentPathStackDepth, + final List componentPath, final Object parent, final Object child, final CompositeType componentType, @@ -379,7 +386,7 @@ private static void cascadeComponent( for ( int i = 0; i < types.length; i++ ) { final CascadeStyle componentPropertyStyle = componentType.getCascadeStyle( i ); final String subPropertyName = propertyNames[i]; - if ( componentPropertyStyle.doCascade( action ) ) { + if ( componentPropertyStyle.doCascade( action ) || componentPropertyStyle.hasOrphanDelete() && action.deleteOrphans() ) { if (children == null) { // Get children on demand. children = componentType.getPropertyValues( child, eventSource ); @@ -388,7 +395,7 @@ private static void cascadeComponent( action, cascadePoint, eventSource, - componentPathStackDepth + 1, + componentPath, parent, children[i], types[i], @@ -405,7 +412,7 @@ private static void cascadeAssociation( final CascadingAction action, final CascadePoint cascadePoint, final EventSource eventSource, - final int componentPathStackDepth, + final List componentPath, final Object parent, final Object child, final Type type, @@ -420,7 +427,7 @@ else if ( type.isCollectionType() ) { action, cascadePoint, eventSource, - componentPathStackDepth, + componentPath, parent, child, style, @@ -437,7 +444,7 @@ private static void cascadeCollection( final CascadingAction action, final CascadePoint cascadePoint, final EventSource eventSource, - final int componentPathStackDepth, + final List componentPath, final Object parent, final Object child, final CascadeStyle style, @@ -457,7 +464,7 @@ private static void cascadeCollection( action, elementsCascadePoint, eventSource, - componentPathStackDepth, + componentPath, parent, child, type, @@ -504,7 +511,7 @@ private static void cascadeCollectionElements( final CascadingAction action, final CascadePoint cascadePoint, final EventSource eventSource, - final int componentPathStackDepth, + final List componentPath, final Object parent, final Object child, final CollectionType collectionType, @@ -526,7 +533,7 @@ private static void cascadeCollectionElements( action, cascadePoint, eventSource, - componentPathStackDepth, + componentPath, parent, itr.next(), elemType, From 52684bba265199696eca48f62cbfcd32212d1bc7 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Thu, 11 Mar 2021 16:48:15 +0100 Subject: [PATCH 060/644] Fix concurrency issue in QueryCacheTest --- .../test/java/org/hibernate/test/querycache/QueryCacheTest.java | 2 -- 1 file changed, 2 deletions(-) diff --git a/hibernate-core/src/test/java/org/hibernate/test/querycache/QueryCacheTest.java b/hibernate-core/src/test/java/org/hibernate/test/querycache/QueryCacheTest.java index 7855edda7a70..8e23e2cd2f58 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/querycache/QueryCacheTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/querycache/QueryCacheTest.java @@ -744,11 +744,9 @@ public boolean onLoad(Object entity, Serializable id, Object[] state, String[] p try { if (waitLatch != null) { waitLatch.countDown(); - waitLatch = null; } if (blockLatch != null) { blockLatch.await(); - blockLatch = null; } } catch (InterruptedException e) { Thread.currentThread().interrupt(); From fe1e098ba18ab0bbc64f833e58a3a42a18ec4226 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Mon, 8 Mar 2021 14:11:32 +0000 Subject: [PATCH 061/644] HHH-14485 Upgrade integration tests to use Oracle JDBC driver version 21.1 --- databases/oracle/matrix.gradle | 2 +- gradle/libraries.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/databases/oracle/matrix.gradle b/databases/oracle/matrix.gradle index 1805b136d7bc..b72fb8807176 100644 --- a/databases/oracle/matrix.gradle +++ b/databases/oracle/matrix.gradle @@ -4,4 +4,4 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -jdbcDependency 'com.oracle.database.jdbc:ojdbc8:19.8.0.0' \ No newline at end of file +jdbcDependency 'com.oracle.database.jdbc:ojdbc8:21.1.0.0' \ No newline at end of file diff --git a/gradle/libraries.gradle b/gradle/libraries.gradle index f10acd124cb7..eee7e07204ca 100644 --- a/gradle/libraries.gradle +++ b/gradle/libraries.gradle @@ -118,7 +118,7 @@ ext { mariadb: 'org.mariadb.jdbc:mariadb-java-client:2.2.3', cockroachdb: 'org.postgresql:postgresql:42.2.8', - oracle: 'com.oracle.database.jdbc:ojdbc8:19.8.0.0', + oracle: 'com.oracle.database.jdbc:ojdbc8:21.1.0.0', mssql: 'com.microsoft.sqlserver:mssql-jdbc:7.2.1.jre8', db2: 'com.ibm.db2:jcc:11.5.4.0', hana: 'com.sap.cloud.db.jdbc:ngdbc:2.4.59', From 7f814107a88da0b138fdf8ad55c815d00a16275d Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Wed, 11 Mar 2020 16:42:12 +0000 Subject: [PATCH 062/644] HHH-14494 Upgrade the PostgreSQL JDBC driver used for testing to v. 42.2.19 --- databases/pgsql/matrix.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/databases/pgsql/matrix.gradle b/databases/pgsql/matrix.gradle index 9536407774ea..b8ac50d60726 100644 --- a/databases/pgsql/matrix.gradle +++ b/databases/pgsql/matrix.gradle @@ -4,4 +4,4 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -jdbcDependency 'org.postgresql:postgresql:42.2.2' +jdbcDependency 'org.postgresql:postgresql:42.2.19' From 44d78d9b854d3f1562a806d831db5342949a9bcd Mon Sep 17 00:00:00 2001 From: randymay Date: Fri, 3 Nov 2017 16:22:22 -0400 Subject: [PATCH 063/644] HHH-12076 Fix index out of bounds exception and allow table group joins for collection joins as well --- .../hibernate/engine/internal/JoinSequence.java | 14 +++++++++++--- .../hibernate/hql/internal/ast/HqlSqlWalker.java | 4 +++- .../query/hhh12076/HbmMappingJoinClassTest.java | 1 - 3 files changed, 14 insertions(+), 5 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/JoinSequence.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/JoinSequence.java index f9ca7acfb685..713c5b430ba7 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/internal/JoinSequence.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/JoinSequence.java @@ -14,6 +14,7 @@ import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.hql.internal.ast.tree.ImpliedFromElement; import org.hibernate.internal.util.StringHelper; +import org.hibernate.persister.collection.AbstractCollectionPersister; import org.hibernate.persister.collection.QueryableCollection; import org.hibernate.persister.entity.AbstractEntityPersister; import org.hibernate.persister.entity.Joinable; @@ -422,9 +423,16 @@ private boolean needsTableGroupJoin(List joins, String withClauseFragment) } private boolean isSubclassAliasDereferenced(Join join, String withClauseFragment) { - if ( join.getJoinable() instanceof AbstractEntityPersister ) { - AbstractEntityPersister persister = (AbstractEntityPersister) join.getJoinable(); - int subclassTableSpan = persister.getSubclassTableSpan(); + Object joinable = join.getJoinable(); + if ( joinable instanceof AbstractCollectionPersister ) { + final AbstractCollectionPersister collectionPersister = (AbstractCollectionPersister) joinable; + if ( collectionPersister.getElementType().isEntityType() ) { + joinable = ( collectionPersister ).getElementPersister(); + } + } + if ( joinable instanceof AbstractEntityPersister ) { + final AbstractEntityPersister persister = (AbstractEntityPersister) joinable; + final int subclassTableSpan = persister.getSubclassTableSpan(); for ( int j = 1; j < subclassTableSpan; j++ ) { String subclassAlias = AbstractEntityPersister.generateTableAlias( join.getAlias(), j ); if ( isAliasDereferenced( withClauseFragment, subclassAlias ) ) { diff --git a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/HqlSqlWalker.java b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/HqlSqlWalker.java index 5943b7ffb13d..73b7d6afecba 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/HqlSqlWalker.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/HqlSqlWalker.java @@ -557,7 +557,9 @@ public void visit(AST node) { } else { referencedFromElement = fromElement; - joinAlias = extractAppliedAlias( dotNode ); + if ( fromElement != null ) { + joinAlias = extractAppliedAlias( dotNode ); + } // TODO : temporary // needed because currently persister is the one that // creates and renders the join fragments for inheritance diff --git a/hibernate-core/src/test/java/org/hibernate/query/hhh12076/HbmMappingJoinClassTest.java b/hibernate-core/src/test/java/org/hibernate/query/hhh12076/HbmMappingJoinClassTest.java index be9fb29624ce..57feab4e0ff4 100644 --- a/hibernate-core/src/test/java/org/hibernate/query/hhh12076/HbmMappingJoinClassTest.java +++ b/hibernate-core/src/test/java/org/hibernate/query/hhh12076/HbmMappingJoinClassTest.java @@ -80,7 +80,6 @@ protected void prepareTest() { } @Test - @FailureExpected( jiraKey = "HHH-12076") public void testClassExpressionInOnClause() { doInHibernate( this::sessionFactory, session -> { List results = session.createQuery( From b6ba93c786e569ad4b318244b446b68525779517 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Fri, 12 Mar 2021 12:51:38 +0100 Subject: [PATCH 064/644] Increase maximum open cursors --- docker_db.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/docker_db.sh b/docker_db.sh index a496ea5ca6a3..940ac409d96b 100755 --- a/docker_db.sh +++ b/docker_db.sh @@ -148,6 +148,7 @@ alter system checkpoint; alter database drop logfile group 1; alter database drop logfile group 2; alter database drop logfile group 3; +alter system set open_cursors=1000 sid='*' scope=both; EOF\"" } From c9c5a4172e587c2d12b6012d4ddb016f15c87b57 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Mon, 15 Mar 2021 15:35:37 +0100 Subject: [PATCH 065/644] Add Hibernate Github Bot configuration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Yoann Rodière --- .github/workflows/hibernate-github-bot.yml | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .github/workflows/hibernate-github-bot.yml diff --git a/.github/workflows/hibernate-github-bot.yml b/.github/workflows/hibernate-github-bot.yml new file mode 100644 index 000000000000..9d9ad649deb6 --- /dev/null +++ b/.github/workflows/hibernate-github-bot.yml @@ -0,0 +1,3 @@ +--- +jira: + projectKey: "HHH" From 1e3207dbe96fd8c6e3256c34ef4bae1892fb20b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Mon, 15 Mar 2021 15:41:13 +0100 Subject: [PATCH 066/644] Move Hibernate Github Bot configuration to the right directory MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Yoann Rodière --- .github/{workflows => }/hibernate-github-bot.yml | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/{workflows => }/hibernate-github-bot.yml (100%) diff --git a/.github/workflows/hibernate-github-bot.yml b/.github/hibernate-github-bot.yml similarity index 100% rename from .github/workflows/hibernate-github-bot.yml rename to .github/hibernate-github-bot.yml From 394d6ab2d4c207c3a259e11aa423bf2563bf86ba Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Thu, 11 Mar 2021 20:53:55 +0100 Subject: [PATCH 067/644] HHH-14499 Add test for issue --- .../MappedSuperclassWithGenericsTest.java | 90 +++++++++++++++++++ 1 file changed, 90 insertions(+) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/mapping/MappedSuperclassWithGenericsTest.java diff --git a/hibernate-core/src/test/java/org/hibernate/test/mapping/MappedSuperclassWithGenericsTest.java b/hibernate-core/src/test/java/org/hibernate/test/mapping/MappedSuperclassWithGenericsTest.java new file mode 100644 index 000000000000..fe49221bce27 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/mapping/MappedSuperclassWithGenericsTest.java @@ -0,0 +1,90 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.mapping; + +import java.io.Serializable; +import java.util.Objects; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.IdClass; +import javax.persistence.MappedSuperclass; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.Test; + +@TestForIssue(jiraKey = "HHH-14499") +public class MappedSuperclassWithGenericsTest extends BaseCoreFunctionalTestCase { + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + IntermediateAbstractMapped.class, + BaseEntity.class, + AbstractGenericMappedSuperType.class, + }; + } + + @Test + public void testIt() { + + } + + @MappedSuperclass + public static abstract class AbstractGenericMappedSuperType { + + private T whateverType; + + } + + @MappedSuperclass + @IdClass(PK.class) + public static abstract class IntermediateAbstractMapped extends AbstractGenericMappedSuperType { + + @Id + private String keyOne; + @Id + private String keyTwo; + @Id + private String keyThree; + } + + @SuppressWarnings("UnusedDeclaration") + public static class PK implements Serializable { + + private String keyOne; + private String keyTwo; + private String keyThree; + + @Override + public boolean equals(Object o) { + if ( this == o ) { + return true; + } + if ( o == null || getClass() != o.getClass() ) { + return false; + } + PK pk = (PK) o; + return Objects.equals( keyOne, pk.keyOne ) && + Objects.equals( keyTwo, pk.keyTwo ) && + Objects.equals( keyThree, pk.keyThree ); + } + + @Override + public int hashCode() { + return Objects.hash( keyOne, keyTwo, keyThree ); + } + } + + @Entity(name = "BaseEntity") + public static class BaseEntity extends IntermediateAbstractMapped { + + String aString; + + } + +} From 9f22dafe1784d5dc258d0ec587ff26e05d0e0f90 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Thu, 11 Mar 2021 20:52:35 +0100 Subject: [PATCH 068/644] HHH-14499 Explicitly listing mapped classes which are @MappedSuperClass might break narrowing down of generics --- ...AnnotationMetadataSourceProcessorImpl.java | 30 +++++++++++++------ 1 file changed, 21 insertions(+), 9 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/annotations/AnnotationMetadataSourceProcessorImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/annotations/AnnotationMetadataSourceProcessorImpl.java index 4e543f5448ad..e7b4e609463c 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/annotations/AnnotationMetadataSourceProcessorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/annotations/AnnotationMetadataSourceProcessorImpl.java @@ -252,7 +252,7 @@ public void processEntityHierarchies(Set processedEntityNames) { } private List orderAndFillHierarchy(List original) { - List copy = new ArrayList( original ); + List copy = new ArrayList<>( original.size() ); insertMappedSuperclasses( original, copy ); // order the hierarchy @@ -266,16 +266,28 @@ private List orderAndFillHierarchy(List original) { } private void insertMappedSuperclasses(List original, List copy) { + final boolean debug = log.isDebugEnabled(); for ( XClass clazz : original ) { - XClass superClass = clazz.getSuperclass(); - while ( superClass != null - && !reflectionManager.equals( superClass, Object.class ) - && !copy.contains( superClass ) ) { - if ( superClass.isAnnotationPresent( Entity.class ) - || superClass.isAnnotationPresent( javax.persistence.MappedSuperclass.class ) ) { - copy.add( superClass ); + if ( clazz.isAnnotationPresent( javax.persistence.MappedSuperclass.class ) ) { + if ( debug ) { + log.debugf( + "Skipping explicit MappedSuperclass %s, the class will be discovered analyzing the implementing class", + clazz + ); + } + } + else { + copy.add( clazz ); + XClass superClass = clazz.getSuperclass(); + while ( superClass != null + && !reflectionManager.equals( superClass, Object.class ) + && !copy.contains( superClass ) ) { + if ( superClass.isAnnotationPresent( Entity.class ) + || superClass.isAnnotationPresent( javax.persistence.MappedSuperclass.class ) ) { + copy.add( superClass ); + } + superClass = superClass.getSuperclass(); } - superClass = superClass.getSuperclass(); } } } From 2c39bc0ac620ac642360a8ec205a5d15612bec87 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Mon, 15 Mar 2021 16:42:21 +0000 Subject: [PATCH 069/644] HHH-14502 Iterations and memory retention improvements for processing of PropertyContainer metadata --- .../org/hibernate/cfg/AnnotationBinder.java | 3 +- .../org/hibernate/cfg/PropertyContainer.java | 39 ++++++++++++++----- 2 files changed, 30 insertions(+), 12 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java b/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java index 46df157133c8..a1e0f7c7799f 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java @@ -1500,8 +1500,7 @@ static int addElementsOfClass( MetadataBuildingContext context) { int idPropertyCounter = 0; - Collection properties = propertyContainer.getProperties(); - for ( XProperty p : properties ) { + for ( XProperty p : propertyContainer.propertyIterator() ) { final int currentIdPropertyCounter = addProperty( propertyContainer, p, diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/PropertyContainer.java b/hibernate-core/src/main/java/org/hibernate/cfg/PropertyContainer.java index 31004e0dd227..02e3e50b34ea 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/PropertyContainer.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/PropertyContainer.java @@ -9,6 +9,7 @@ package org.hibernate.cfg; +import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashMap; @@ -35,6 +36,7 @@ import org.hibernate.cfg.annotations.HCANNHelper; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.StringHelper; +import org.hibernate.internal.util.collections.CollectionHelper; import org.jboss.logging.Logger; @@ -63,7 +65,7 @@ class PropertyContainer { */ private final AccessType classLevelAccessType; - private final TreeMap persistentAttributeMap; + private final List persistentAttributes; PropertyContainer(XClass clazz, XClass entityAtStake, AccessType defaultClassLevelAccessType) { this.xClass = clazz; @@ -83,7 +85,6 @@ class PropertyContainer { : defaultClassLevelAccessType; assert classLevelAccessType == AccessType.FIELD || classLevelAccessType == AccessType.PROPERTY; - this.persistentAttributeMap = new TreeMap(); final List fields = xClass.getDeclaredProperties( AccessType.FIELD.getType() ); final List getters = xClass.getDeclaredProperties( AccessType.PROPERTY.getType() ); @@ -92,18 +93,23 @@ class PropertyContainer { final Map persistentAttributesFromGetters = new HashMap(); + final TreeMap localAttributeMap = new TreeMap<>(); collectPersistentAttributesUsingLocalAccessType( - persistentAttributeMap, + xClass, + localAttributeMap, persistentAttributesFromGetters, fields, getters ); collectPersistentAttributesUsingClassLevelAccessType( - persistentAttributeMap, + xClass, + classLevelAccessType, + localAttributeMap, persistentAttributesFromGetters, fields, getters ); + this.persistentAttributes = verifyAndInitializePersistentAttributes( xClass, localAttributeMap ); } private void preFilter(List fields, List getters) { @@ -124,7 +130,8 @@ private void preFilter(List fields, List getters) { } } - private void collectPersistentAttributesUsingLocalAccessType( + private static void collectPersistentAttributesUsingLocalAccessType( + XClass xClass, TreeMap persistentAttributeMap, Map persistentAttributesFromGetters, List fields, @@ -176,7 +183,9 @@ private void collectPersistentAttributesUsingLocalAccessType( } } - private void collectPersistentAttributesUsingClassLevelAccessType( + private static void collectPersistentAttributesUsingClassLevelAccessType( + XClass xClass, + AccessType classLevelAccessType, TreeMap persistentAttributeMap, Map persistentAttributesFromGetters, List fields, @@ -229,20 +238,30 @@ public AccessType getClassLevelAccessType() { return classLevelAccessType; } + /** + * @deprecated Use the {@link #propertyIterator()} method instead. + */ + @Deprecated public Collection getProperties() { - assertTypesAreResolvable(); - return Collections.unmodifiableCollection( persistentAttributeMap.values() ); + return Collections.unmodifiableCollection( this.persistentAttributes ); + } + + public Iterable propertyIterator() { + return persistentAttributes; } - private void assertTypesAreResolvable() { - for ( XProperty xProperty : persistentAttributeMap.values() ) { + private static List verifyAndInitializePersistentAttributes(XClass xClass, Map localAttributeMap) { + ArrayList output = new ArrayList( localAttributeMap.size() ); + for ( XProperty xProperty : localAttributeMap.values() ) { if ( !xProperty.isTypeResolved() && !discoverTypeWithoutReflection( xProperty ) ) { String msg = "Property " + StringHelper.qualify( xClass.getName(), xProperty.getName() ) + " has an unbound type and no explicit target entity. Resolve this Generic usage issue" + " or set an explicit target attribute (eg @OneToMany(target=) or use an explicit @Type"; throw new AnnotationException( msg ); } + output.add( xProperty ); } + return CollectionHelper.toSmallList( output ); } // // private void considerExplicitFieldAndPropertyAccess() { From aba49ced1f8115c4458716ab300f74a3f6101633 Mon Sep 17 00:00:00 2001 From: Karel Maesen Date: Tue, 16 Mar 2021 23:18:08 +0100 Subject: [PATCH 070/644] HHH-14454 Add SpatialDialect for CockroachDB --- .../chapters/query/spatial/Spatial.adoc | 78 ++++--- gradle/databases.gradle | 9 + gradle/libraries.gradle | 2 +- .../CockroachDB202SpatialDialect.java | 45 ++++ .../CockroachDBSpatialSupport.java | 46 ++++ .../CockroachSpatialDialectTrait.java | 77 +++++++ .../dialect/cockroachdb/package-info.java | 13 ++ .../postgis/PGGeometryTypeDescriptor.java | 19 +- .../dialect/postgis/PostgisFunctions.java | 4 +- .../dialect/postgis/PostgisNoSQLMM.java | 2 +- .../dialect/postgis/PostgisPG82Dialect.java | 2 +- .../dialect/postgis/PostgisPG91Dialect.java | 2 +- .../dialect/postgis/PostgisPG92Dialect.java | 2 +- .../dialect/postgis/PostgisPG93Dialect.java | 2 +- .../dialect/postgis/PostgisPG94Dialect.java | 2 +- .../dialect/postgis/PostgisPG95Dialect.java | 2 +- .../dialect/postgis/PostgisPG9Dialect.java | 2 +- .../dialect/postgis/PostgisSupport.java | 18 +- .../dialect/postgis/PostgisUnmarshalTest.java | 2 +- .../integration/TestSpatialFunctions.java | 2 +- .../spatial/testing/TestSupportFactories.java | 7 + .../CockroachDBExpectationsFactory.java | 28 +++ .../cockroachdb/CockroachDBTestSupport.java | 45 ++++ .../postgis/PostgisExpectationsFactory.java | 3 +- .../resources/cockroachdb/functions-test.xml | 64 ++++++ .../resources/cockroachdb/test-data-set.xml | 213 ++++++++++++++++++ 26 files changed, 629 insertions(+), 62 deletions(-) create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/cockroachdb/CockroachDB202SpatialDialect.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/cockroachdb/CockroachDBSpatialSupport.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/cockroachdb/CockroachSpatialDialectTrait.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/cockroachdb/package-info.java create mode 100644 hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/cockroachdb/CockroachDBExpectationsFactory.java create mode 100644 hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/cockroachdb/CockroachDBTestSupport.java create mode 100644 hibernate-spatial/src/test/resources/cockroachdb/functions-test.xml create mode 100644 hibernate-spatial/src/test/resources/cockroachdb/test-data-set.xml diff --git a/documentation/src/main/asciidoc/userguide/chapters/query/spatial/Spatial.adoc b/documentation/src/main/asciidoc/userguide/chapters/query/spatial/Spatial.adoc index e348fec902ba..578048ac4d01 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/query/spatial/Spatial.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/query/spatial/Spatial.adoc @@ -86,42 +86,42 @@ relevant section. :no: icon:times[role="red"] [[spatial-configuration-dialect-features]] .Hibernate Spatial dialect function support -[cols=",,,,,,," |options="header",] +[cols=",,,,,,,," |options="header",] |================================ -|Function | Description | PostgresSQL | Oracle 10g/11g | MySQL | SQLServer | GeoDB (H2) | DB2 -|Basic functions on Geometry | | | | | | | -|`int dimension(Geometry)` | SFS §2.1.1.1 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} -|`String geometrytype(Geometry)` | SFS §2.1.1.1 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} -|`int srid(Geometry)` | SFS §2.1.1.1 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} -|`Geometry envelope(Geometry)` | SFS §2.1.1.1 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} -|`String astext(Geometry)` | SFS §2.1.1.1 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} -|`byte[] asbinary(Geometry)` | SFS §2.1.1.1 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} -|`boolean isempty(Geometry)` | SFS §2.1.1.1 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} -|`boolean issimple(Geometry)` | SFS §2.1.1.1 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} -|`Geometry boundary(Geometry)` | SFS §2.1.1.1 | {yes} | {yes} | {no} | {yes} | {yes} | {yes} -|Functions for testing Spatial Relations between geometric objects | | | | | | | -|`boolean equals(Geometry, Geometry)` | SFS §2.1.1.2 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} -|`boolean disjoint(Geometry, Geometry)` | SFS §2.1.1.2 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} -|`boolean intersects(Geometry, Geometry)` | SFS §2.1.1.2 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} -|`boolean touches(Geometry, Geometry)` | SFS §2.1.1.2 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} -|`boolean crosses(Geometry, Geometry)` | SFS §2.1.1.2 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} -|`boolean within(Geometry, Geometry)` | SFS §2.1.1.2 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} -|`boolean contains(Geometry, Geometry)` | SFS §2.1.1.2 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} -|`boolean overlaps(Geometry, Geometry)` | SFS §2.1.1.2 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} -|`boolean relate(Geometry, Geometry, String)` | SFS §2.1.1.2 | {yes} | {yes} | {no} | {yes} | {yes} | {yes} -|Functions that support Spatial Analysis | | | | | | | -|`double distance(Geometry, Geometry)` | SFS §2.1.1.3 | {yes} | {yes} | {no} | {yes} | {yes} | {yes} -|`Geometry buffer(Geometry, double)` | SFS §2.1.1.3 | {yes} | {yes} | {no} | {yes} | {yes} | {yes} -|`Geometry convexhull(Geometry)` | SFS §2.1.1.3 | {yes} | {yes} | {no} | {yes} | {yes} | {yes}^(1)^ -|`Geometry intersection(Geometry, Geometry)` | SFS §2.1.1.3 | {yes} | {yes} | {no} | {yes} | {yes} | {yes}^(1)^ -|`Geometry geomunion(Geometry, Geometry)` | SFS §2.1.1.3 (renamed from union) | {yes} | {yes} | {no} | {yes} | {yes} | {yes}^(1)^ -|`Geometry difference(Geometry, Geometry)` | SFS §2.1.1.3 | {yes} | {yes} | {no} | {yes} | {yes} | {yes}^(1)^ -|`Geometry symdifference(Geometry, Geometry)` | SFS §2.1.1.3 | {yes} | {yes} | {no} | {yes} | {yes} | {yes}^(1)^ -|Common non-SFS functions | | | | | | | -|`boolean dwithin(Geometry, Geometry, double)` | Returns true if the geometries are within the specified distance of one another | {yes} | {yes} | {no} | {no} | {yes} | {yes} -|`Geometry transform(Geometry, int)` | Returns a new geometry with its coordinates transformed to the SRID referenced by the integer parameter | {yes} | {yes} | {no} | {no} | {no} | {no} -|Spatial aggregate Functions | | | | | | | -|`Geometry extent(Geometry)` | Returns a bounding box that bounds the set of returned geometries | {yes} | {yes} | {no} | {no} | {no} | {no} +|Function | Description | PostgresSQL | Oracle 10g/11g | MySQL | SQLServer | GeoDB (H2) | DB2 | CockroachDB +|Basic functions on Geometry | | | | | | | | +|`int dimension(Geometry)` | SFS §2.1.1.1 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} +|`String geometrytype(Geometry)` | SFS §2.1.1.1 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} +|`int srid(Geometry)` | SFS §2.1.1.1 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} +|`Geometry envelope(Geometry)` | SFS §2.1.1.1 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} +|`String astext(Geometry)` | SFS §2.1.1.1 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} +|`byte[] asbinary(Geometry)` | SFS §2.1.1.1 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} +|`boolean isempty(Geometry)` | SFS §2.1.1.1 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} +|`boolean issimple(Geometry)` | SFS §2.1.1.1 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} +|`Geometry boundary(Geometry)` | SFS §2.1.1.1 | {yes} | {yes} | {no} | {yes} | {yes} | {yes} | {yes} +|Functions for testing Spatial Relations between geometric objects | | | | | | | | +|`boolean equals(Geometry, Geometry)` | SFS §2.1.1.2 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} +|`boolean disjoint(Geometry, Geometry)` | SFS §2.1.1.2 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} +|`boolean intersects(Geometry, Geometry)` | SFS §2.1.1.2 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} +|`boolean touches(Geometry, Geometry)` | SFS §2.1.1.2 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} +|`boolean crosses(Geometry, Geometry)` | SFS §2.1.1.2 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} +|`boolean within(Geometry, Geometry)` | SFS §2.1.1.2 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} +|`boolean contains(Geometry, Geometry)` | SFS §2.1.1.2 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} +|`boolean overlaps(Geometry, Geometry)` | SFS §2.1.1.2 | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} | {yes} +|`boolean relate(Geometry, Geometry, String)` | SFS §2.1.1.2 | {yes} | {yes} | {no} | {yes} | {yes} | {yes} | {yes} +|Functions that support Spatial Analysis | | | | | | | | +|`double distance(Geometry, Geometry)` | SFS §2.1.1.3 | {yes} | {yes} | {no} | {yes} | {yes} | {yes} | {yes} +|`Geometry buffer(Geometry, double)` | SFS §2.1.1.3 | {yes} | {yes} | {no} | {yes} | {yes} | {yes} | {yes} +|`Geometry convexhull(Geometry)` | SFS §2.1.1.3 | {yes} | {yes} | {no} | {yes} | {yes} | {yes}^(1)^ | {no} +|`Geometry intersection(Geometry, Geometry)` | SFS §2.1.1.3 | {yes} | {yes} | {no} | {yes} | {yes} | {yes}^(1)^ | {yes} +|`Geometry geomunion(Geometry, Geometry)` | SFS §2.1.1.3 (renamed from union) | {yes} | {yes} | {no} | {yes} | {yes} | {yes}^(1)^ | {yes} +|`Geometry difference(Geometry, Geometry)` | SFS §2.1.1.3 | {yes} | {yes} | {no} | {yes} | {yes} | {yes}^(1)^ | {yes} +|`Geometry symdifference(Geometry, Geometry)` | SFS §2.1.1.3 | {yes} | {yes} | {no} | {yes} | {yes} | {yes}^(1)^ | {yes} +|Common non-SFS functions | | | | | | | | +|`boolean dwithin(Geometry, Geometry, double)` | Returns true if the geometries are within the specified distance of one another | {yes} | {yes} | {no} | {no} | {yes} | {yes} | {yes} +|`Geometry transform(Geometry, int)` | Returns a new geometry with its coordinates transformed to the SRID referenced by the integer parameter | {yes} | {yes} | {no} | {no} | {no} | {no} | {yes} +|Spatial aggregate Functions | | | | | | | | +|`Geometry extent(Geometry)` | Returns a bounding box that bounds the set of returned geometries | {yes} | {yes} | {no} | {no} | {no} | {no} | {yes} |================================ ^(1)^ Argument Geometries need to have the same dimensionality. @@ -191,6 +191,14 @@ The dialect `SqlServer2008Dialect` supports the `GEOMETRY` type in SQL Server 20 The `GEOGRAPHY` type is not currently supported. ==== +CockroachDB:: +The dialect `CockroachDB202SpatialDialect` support the `GEOMETRY` type in CockroachDB v20.2 and later. + +[NOTE] +==== +The `GEOGRAPHY` type is not currently supported. +==== + GeoDB (H2):: The `GeoDBDialect` supports the GeoDB a spatial extension of the H2 in-memory database. [NOTE] diff --git a/gradle/databases.gradle b/gradle/databases.gradle index f570b1e8f06a..8f0795dae05d 100644 --- a/gradle/databases.gradle +++ b/gradle/databases.gradle @@ -226,5 +226,14 @@ ext { // Disable prepared statement caching due to https://www.postgresql.org/message-id/CAEcMXhmmRd4-%2BNQbnjDT26XNdUoXdmntV9zdr8%3DTu8PL9aVCYg%40mail.gmail.com 'jdbc.url' : 'jdbc:postgresql://localhost:26257/defaultdb?sslmode=disable&preparedStatementCacheQueries=0' ], + cockroachdb_spatial : [ + 'db.dialect' : 'org.hibernate.spatial.dialect.cockroachdb.CockroachDB202SpatialDialect', + // CockroachDB uses the same pgwire protocol as PostgreSQL, so the driver is the same. + 'jdbc.driver': 'org.postgresql.Driver', + 'jdbc.user' : 'root', + 'jdbc.pass' : '', + // Disable prepared statement caching due to https://www.postgresql.org/message-id/CAEcMXhmmRd4-%2BNQbnjDT26XNdUoXdmntV9zdr8%3DTu8PL9aVCYg%40mail.gmail.com + 'jdbc.url' : 'jdbc:postgresql://localhost:26257/defaultdb?sslmode=disable&preparedStatementCacheQueries=0' + ] ] } diff --git a/gradle/libraries.gradle b/gradle/libraries.gradle index eee7e07204ca..c97a65f5b4ca 100644 --- a/gradle/libraries.gradle +++ b/gradle/libraries.gradle @@ -29,7 +29,7 @@ ext { assertjVersion = '3.14.0' - geolatteVersion = '1.6.1' + geolatteVersion = '1.8.0' shrinkwrapVersion = '1.2.6' shrinkwrapDescriptorsVersion = '2.0.0' diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/cockroachdb/CockroachDB202SpatialDialect.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/cockroachdb/CockroachDB202SpatialDialect.java new file mode 100644 index 000000000000..d5ba27617a3b --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/cockroachdb/CockroachDB202SpatialDialect.java @@ -0,0 +1,45 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ + +package org.hibernate.spatial.dialect.cockroachdb; + +import java.util.Map; + +import org.hibernate.boot.model.TypeContributions; +import org.hibernate.dialect.CockroachDB201Dialect; +import org.hibernate.dialect.function.SQLFunction; +import org.hibernate.service.ServiceRegistry; +import org.hibernate.spatial.dialect.postgis.PGGeometryTypeDescriptor; + +/** + * An @{code SpatialDialect} for CockroachDB 20.2 and later. CockroachDB's spatial features where introduced in + * that version. + */ +public class CockroachDB202SpatialDialect extends CockroachDB201Dialect implements CockroachSpatialDialectTrait { + + + public CockroachDB202SpatialDialect() { + super(); + registerColumnType( + PGGeometryTypeDescriptor.INSTANCE_WKB_2.getSqlType(), + "GEOMETRY" + ); + for ( Map.Entry entry : functionsToRegister() ) { + registerFunction( entry.getKey(), entry.getValue() ); + } + } + + @Override + public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) { + super.contributeTypes( + typeContributions, + serviceRegistry + ); + delegateContributeTypes( typeContributions, serviceRegistry ); + } + +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/cockroachdb/CockroachDBSpatialSupport.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/cockroachdb/CockroachDBSpatialSupport.java new file mode 100644 index 000000000000..7389598d5e6f --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/cockroachdb/CockroachDBSpatialSupport.java @@ -0,0 +1,46 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ + +package org.hibernate.spatial.dialect.cockroachdb; + +import org.hibernate.boot.model.TypeContributions; +import org.hibernate.service.ServiceRegistry; +import org.hibernate.spatial.GeolatteGeometryJavaTypeDescriptor; +import org.hibernate.spatial.GeolatteGeometryType; +import org.hibernate.spatial.JTSGeometryJavaTypeDescriptor; +import org.hibernate.spatial.JTSGeometryType; +import org.hibernate.spatial.SpatialDialect; +import org.hibernate.spatial.dialect.postgis.PGGeometryTypeDescriptor; +import org.hibernate.spatial.dialect.postgis.PostgisFunctions; +import org.hibernate.spatial.dialect.postgis.PostgisSupport; + +public class CockroachDBSpatialSupport extends PostgisSupport implements SpatialDialect { + + CockroachDBSpatialSupport() { + super( new CockroachDBSpatialFunctions() ); + } + + @Override + public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) { + typeContributions.contributeType( new GeolatteGeometryType( PGGeometryTypeDescriptor.INSTANCE_WKB_2 ) ); + typeContributions.contributeType( new JTSGeometryType( PGGeometryTypeDescriptor.INSTANCE_WKB_2 ) ); + + typeContributions.contributeJavaTypeDescriptor( GeolatteGeometryJavaTypeDescriptor.INSTANCE ); + typeContributions.contributeJavaTypeDescriptor( JTSGeometryJavaTypeDescriptor.INSTANCE ); + } + +} + +class CockroachDBSpatialFunctions extends PostgisFunctions { + + CockroachDBSpatialFunctions() { + super(); + this.functionMap.remove( "geomunion" ); + } + +} + diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/cockroachdb/CockroachSpatialDialectTrait.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/cockroachdb/CockroachSpatialDialectTrait.java new file mode 100644 index 000000000000..17ffb69b7e8e --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/cockroachdb/CockroachSpatialDialectTrait.java @@ -0,0 +1,77 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ + +package org.hibernate.spatial.dialect.cockroachdb; + +import org.hibernate.boot.model.TypeContributions; +import org.hibernate.service.ServiceRegistry; +import org.hibernate.spatial.SpatialDialect; +import org.hibernate.spatial.SpatialFunction; +import org.hibernate.spatial.dialect.SpatialFunctionsRegistry; + +public interface CockroachSpatialDialectTrait extends SpatialDialect { + + CockroachDBSpatialSupport DELEGATE = new CockroachDBSpatialSupport(); + + default SpatialFunctionsRegistry functionsToRegister() { + return DELEGATE.functionsToRegister(); + + } + + default String getSpatialRelateSQL(String columnName, int spatialRelation) { + return DELEGATE.getSpatialRelateSQL( columnName, spatialRelation ); + } + + default void delegateContributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) { + DELEGATE.contributeTypes( typeContributions, serviceRegistry ); + } + + /** + * Returns the SQL fragment for the SQL WHERE-expression when parsing + * org.hibernate.spatial.criterion.SpatialFilterExpressions + * into prepared statements. + * + * @param columnName The name of the geometry-typed column to which the filter is + * be applied + * + * @return Rhe SQL fragment for the {@code SpatialFilterExpression} + */ + default String getSpatialFilterExpression(String columnName) { + return DELEGATE.getSpatialFilterExpression( columnName ); + } + + @Override + default String getSpatialAggregateSQL(String columnName, int aggregation) { + return DELEGATE.getSpatialAggregateSQL( columnName, aggregation ); + } + + @Override + default String getDWithinSQL(String columnName) { + return DELEGATE.getDWithinSQL( columnName ); + } + + @Override + default String getHavingSridSQL(String columnName) { + return DELEGATE.getHavingSridSQL( columnName ); + } + + @Override + default String getIsEmptySQL(String columnName, boolean isEmpty) { + return DELEGATE.getIsEmptySQL( columnName, isEmpty ); + } + + @Override + default boolean supportsFiltering() { + return DELEGATE.supportsFiltering(); + } + + @Override + default boolean supports(SpatialFunction function) { + return DELEGATE.supports( function ); + } + +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/cockroachdb/package-info.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/cockroachdb/package-info.java new file mode 100644 index 000000000000..94f58799a86a --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/cockroachdb/package-info.java @@ -0,0 +1,13 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ + +/** + * {@code SpatialDialect}s for CockroachDB + */ +package org.hibernate.spatial.dialect.cockroachdb; + + diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PGGeometryTypeDescriptor.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PGGeometryTypeDescriptor.java index b221c5c31452..af4ebc86b3c2 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PGGeometryTypeDescriptor.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PGGeometryTypeDescriptor.java @@ -39,12 +39,18 @@ public class PGGeometryTypeDescriptor implements SqlTypeDescriptor { - /** - * An instance of this class - */ - public static final PGGeometryTypeDescriptor INSTANCE = new PGGeometryTypeDescriptor(); + final private Wkb.Dialect wkbDialect; - public static Geometry toGeometry(Object object) { + // Type descriptor instance using EWKB v1 (postgis versions < 2.2.2) + public static final PGGeometryTypeDescriptor INSTANCE_WKB_1 = new PGGeometryTypeDescriptor( Wkb.Dialect.POSTGIS_EWKB_1); + // Type descriptor instance using EWKB v2 (postgis versions >= 2.2.2, see: https://trac.osgeo.org/postgis/ticket/3181) + public static final PGGeometryTypeDescriptor INSTANCE_WKB_2 = new PGGeometryTypeDescriptor(Wkb.Dialect.POSTGIS_EWKB_2); + + private PGGeometryTypeDescriptor(Wkb.Dialect dialect) { + wkbDialect = dialect; + } + + public Geometry toGeometry(Object object) { if ( object == null ) { return null; } @@ -55,9 +61,8 @@ public static Geometry toGeometry(Object object) { if ( pgValue.startsWith( "00" ) || pgValue.startsWith( "01" ) ) { //we have a WKB because this pgValue starts with the bit-order byte buffer = ByteBuffer.from( pgValue ); - final WkbDecoder decoder = Wkb.newDecoder( Wkb.Dialect.POSTGIS_EWKB_1 ); + final WkbDecoder decoder = Wkb.newDecoder( wkbDialect ); return decoder.decode( buffer ); - } else { return parseWkt( pgValue ); diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisFunctions.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisFunctions.java index 77d3c79f8649..baec7a21f9ed 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisFunctions.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisFunctions.java @@ -24,9 +24,9 @@ *

* Created by Karel Maesen, Geovise BVBA on 29/10/16. */ -class PostgisFunctions extends SpatialFunctionsRegistry { +public class PostgisFunctions extends SpatialFunctionsRegistry { - PostgisFunctions() { + public PostgisFunctions() { put( "dimension", new StandardSQLFunction( diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisNoSQLMM.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisNoSQLMM.java index 339177756b51..ab3cf5ce60d6 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisNoSQLMM.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisNoSQLMM.java @@ -23,7 +23,7 @@ public class PostgisNoSQLMM extends PostgisDialect { public PostgisNoSQLMM() { registerColumnType( - PGGeometryTypeDescriptor.INSTANCE.getSqlType(), + PGGeometryTypeDescriptor.INSTANCE_WKB_1.getSqlType(), "GEOMETRY" ); diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG82Dialect.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG82Dialect.java index 2189f5301772..f1fa67c919c3 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG82Dialect.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG82Dialect.java @@ -31,7 +31,7 @@ public class PostgisPG82Dialect extends PostgreSQL82Dialect implements SpatialDi public PostgisPG82Dialect() { super(); registerColumnType( - PGGeometryTypeDescriptor.INSTANCE.getSqlType(), + PGGeometryTypeDescriptor.INSTANCE_WKB_1.getSqlType(), "GEOMETRY" ); for ( Map.Entry entry : support.functionsToRegister() ) { diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG91Dialect.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG91Dialect.java index 25eccc44e976..ca871af1df12 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG91Dialect.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG91Dialect.java @@ -31,7 +31,7 @@ public class PostgisPG91Dialect extends PostgreSQL91Dialect implements SpatialDi public PostgisPG91Dialect() { super(); registerColumnType( - PGGeometryTypeDescriptor.INSTANCE.getSqlType(), + PGGeometryTypeDescriptor.INSTANCE_WKB_1.getSqlType(), "GEOMETRY" ); for ( Map.Entry entry : support.functionsToRegister() ) { diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG92Dialect.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG92Dialect.java index 0006fc28763a..c94d2e902109 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG92Dialect.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG92Dialect.java @@ -31,7 +31,7 @@ public class PostgisPG92Dialect extends PostgreSQL92Dialect implements SpatialDi public PostgisPG92Dialect() { super(); registerColumnType( - PGGeometryTypeDescriptor.INSTANCE.getSqlType(), + PGGeometryTypeDescriptor.INSTANCE_WKB_1.getSqlType(), "GEOMETRY" ); for ( Map.Entry entry : support.functionsToRegister() ) { diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG93Dialect.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG93Dialect.java index 30a8c2b8ee46..f8ac29a1a00e 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG93Dialect.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG93Dialect.java @@ -31,7 +31,7 @@ public class PostgisPG93Dialect extends PostgreSQL93Dialect implements SpatialDi public PostgisPG93Dialect() { super(); registerColumnType( - PGGeometryTypeDescriptor.INSTANCE.getSqlType(), + PGGeometryTypeDescriptor.INSTANCE_WKB_1.getSqlType(), "GEOMETRY" ); for ( Map.Entry entry : support.functionsToRegister() ) { diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG94Dialect.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG94Dialect.java index 2fe8ff00cf6c..c267cf6d8c46 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG94Dialect.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG94Dialect.java @@ -31,7 +31,7 @@ public class PostgisPG94Dialect extends PostgreSQL94Dialect implements SpatialDi public PostgisPG94Dialect() { super(); registerColumnType( - PGGeometryTypeDescriptor.INSTANCE.getSqlType(), + PGGeometryTypeDescriptor.INSTANCE_WKB_1.getSqlType(), "GEOMETRY" ); for ( Map.Entry entry : support.functionsToRegister() ) { diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG95Dialect.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG95Dialect.java index 84f3c04fb091..a99bd40d8327 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG95Dialect.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG95Dialect.java @@ -30,7 +30,7 @@ public class PostgisPG95Dialect extends PostgreSQL95Dialect implements SpatialDi public PostgisPG95Dialect() { super(); registerColumnType( - PGGeometryTypeDescriptor.INSTANCE.getSqlType(), + PGGeometryTypeDescriptor.INSTANCE_WKB_1.getSqlType(), "GEOMETRY" ); for ( Map.Entry entry : support.functionsToRegister() ) { diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG9Dialect.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG9Dialect.java index daceb78ecf10..9182f947f0b5 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG9Dialect.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG9Dialect.java @@ -31,7 +31,7 @@ public class PostgisPG9Dialect extends PostgreSQL9Dialect implements SpatialDial public PostgisPG9Dialect() { super(); registerColumnType( - PGGeometryTypeDescriptor.INSTANCE.getSqlType(), + PGGeometryTypeDescriptor.INSTANCE_WKB_1.getSqlType(), "GEOMETRY" ); for ( Map.Entry entry : support.functionsToRegister() ) { diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisSupport.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisSupport.java index 1b34d0346ae5..126a86e0728e 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisSupport.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisSupport.java @@ -18,24 +18,32 @@ import org.hibernate.spatial.SpatialDialect; import org.hibernate.spatial.SpatialFunction; import org.hibernate.spatial.SpatialRelation; +import org.hibernate.spatial.dialect.SpatialFunctionsRegistry; /** * Created by Karel Maesen, Geovise BVBA on 29/10/16. */ public class PostgisSupport implements SpatialDialect, Serializable { + private final SpatialFunctionsRegistry postgisFunctions; - private PostgisFunctions postgisFunctions = new PostgisFunctions(); + public PostgisSupport(SpatialFunctionsRegistry functions) { + postgisFunctions = functions; + } + + public PostgisSupport() { + postgisFunctions = new PostgisFunctions(); + } - void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) { - typeContributions.contributeType( new GeolatteGeometryType( PGGeometryTypeDescriptor.INSTANCE ) ); - typeContributions.contributeType( new JTSGeometryType( PGGeometryTypeDescriptor.INSTANCE ) ); + public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) { + typeContributions.contributeType( new GeolatteGeometryType( PGGeometryTypeDescriptor.INSTANCE_WKB_1 ) ); + typeContributions.contributeType( new JTSGeometryType( PGGeometryTypeDescriptor.INSTANCE_WKB_1 ) ); typeContributions.contributeJavaTypeDescriptor( GeolatteGeometryJavaTypeDescriptor.INSTANCE ); typeContributions.contributeJavaTypeDescriptor( JTSGeometryJavaTypeDescriptor.INSTANCE ); } - public PostgisFunctions functionsToRegister() { + public SpatialFunctionsRegistry functionsToRegister() { return postgisFunctions; } diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/postgis/PostgisUnmarshalTest.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/postgis/PostgisUnmarshalTest.java index 811ef756d912..06536eaf3eb4 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/postgis/PostgisUnmarshalTest.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/dialect/postgis/PostgisUnmarshalTest.java @@ -69,7 +69,7 @@ public void testWkbNDR() throws SQLException { public void testCase(String pgValue, Geometry expected) throws SQLException { PGobject pgo = new PGobject(); pgo.setValue( pgValue ); - Geometry received = PGGeometryTypeDescriptor.toGeometry( pgo ); + Geometry received = PGGeometryTypeDescriptor.INSTANCE_WKB_1.toGeometry( pgo ); assertEquals( String.format( "Failure on %s", pgValue ), expected, received ); } diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/TestSpatialFunctions.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/TestSpatialFunctions.java index cccabd0419bc..aea9561b4870 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/TestSpatialFunctions.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/TestSpatialFunctions.java @@ -522,7 +522,7 @@ public void test_convexhull_on_geolatte() throws SQLException { } public void convexhull(String pckg) throws SQLException { - if ( !isSupportedByDialect( SpatialFunction.convexhull ) ) { + if ( !isSupportedByDialect( SpatialFunction.convexhull ) || !isSupportedByDialect( SpatialFunction.geomunion )) { return; } Map dbexpected = expectationsFactory.getConvexHull( expectationsFactory.getTestPolygon() ); diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/TestSupportFactories.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/TestSupportFactories.java index 7ed693440b47..d71e78b4f2ec 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/TestSupportFactories.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/TestSupportFactories.java @@ -7,9 +7,11 @@ package org.hibernate.spatial.testing; +import org.hibernate.dialect.CockroachDB192Dialect; import org.hibernate.dialect.Dialect; import org.hibernate.dialect.PostgreSQL82Dialect; import org.hibernate.spatial.SpatialDialect; +import org.hibernate.spatial.testing.dialects.cockroachdb.CockroachDBTestSupport; import org.hibernate.spatial.testing.dialects.db2.DB2TestSupport; import org.hibernate.spatial.testing.dialects.h2geodb.GeoDBTestSupport; import org.hibernate.spatial.testing.dialects.hana.HANATestSupport; @@ -42,6 +44,11 @@ private static Class getSupportFactoryClass(Dialect diale //this test works because all postgis dialects ultimately derive of the Postgresql82Dialect return PostgisTestSupport.class; } + + if ( ( dialect instanceof SpatialDialect ) && CockroachDB192Dialect.class.isAssignableFrom( dialect.getClass() ) ){ + return CockroachDBTestSupport.class; + } + if ( "org.hibernate.spatial.dialect.h2geodb.GeoDBDialect".equals( canonicalName ) ) { return GeoDBTestSupport.class; } diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/cockroachdb/CockroachDBExpectationsFactory.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/cockroachdb/CockroachDBExpectationsFactory.java new file mode 100644 index 000000000000..c09f31dc044b --- /dev/null +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/cockroachdb/CockroachDBExpectationsFactory.java @@ -0,0 +1,28 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ + +package org.hibernate.spatial.testing.dialects.cockroachdb; + +import org.hibernate.spatial.dialect.postgis.PGGeometryTypeDescriptor; +import org.hibernate.spatial.testing.DataSourceUtils; +import org.hibernate.spatial.testing.dialects.postgis.PostgisExpectationsFactory; + +import org.geolatte.geom.jts.JTS; +import org.locationtech.jts.geom.Geometry; + +public class CockroachDBExpectationsFactory extends PostgisExpectationsFactory { + + public CockroachDBExpectationsFactory(DataSourceUtils utils) { + super( utils ); + } + + @Override + protected Geometry decode(Object object) { + org.geolatte.geom.Geometry geometry = PGGeometryTypeDescriptor.INSTANCE_WKB_2.toGeometry( object ); + return JTS.to( geometry ); + } +} diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/cockroachdb/CockroachDBTestSupport.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/cockroachdb/CockroachDBTestSupport.java new file mode 100644 index 000000000000..629b668efbb2 --- /dev/null +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/cockroachdb/CockroachDBTestSupport.java @@ -0,0 +1,45 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ + +package org.hibernate.spatial.testing.dialects.cockroachdb; + +import org.hibernate.spatial.integration.TestGeolatteSpatialPredicates; +import org.hibernate.spatial.integration.TestJTSSpatialPredicates; +import org.hibernate.spatial.integration.TestSpatialFunctions; +import org.hibernate.spatial.integration.TestSpatialRestrictions; +import org.hibernate.spatial.testing.AbstractExpectationsFactory; +import org.hibernate.spatial.testing.DataSourceUtils; +import org.hibernate.spatial.testing.SQLExpressionTemplate; +import org.hibernate.spatial.testing.TestData; +import org.hibernate.spatial.testing.TestSupport; +import org.hibernate.spatial.testing.dialects.postgis.PostgisExpressionTemplate; + +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; + +public class CockroachDBTestSupport extends TestSupport { + @Override + public TestData createTestData(BaseCoreFunctionalTestCase testcase) { + Class testcaseClass = testcase.getClass(); + if ( ( testcaseClass == TestSpatialFunctions.class ) || + ( testcaseClass == TestSpatialRestrictions.class ) || + ( testcaseClass == TestJTSSpatialPredicates.class ) || + ( testcaseClass == TestGeolatteSpatialPredicates.class ) ) { + return TestData.fromFile( "cockroachdb/functions-test.xml" ); + } + return TestData.fromFile( "cockroachdb/test-data-set.xml" ); + } + + @Override + public AbstractExpectationsFactory createExpectationsFactory(DataSourceUtils dataSourceUtils) { + return new CockroachDBExpectationsFactory( dataSourceUtils ); + } + + @Override + public SQLExpressionTemplate getSQLExpressionTemplate() { + return new PostgisExpressionTemplate(); + } +} diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/postgis/PostgisExpectationsFactory.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/postgis/PostgisExpectationsFactory.java index 21b4b9b8d049..1df480fb9901 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/postgis/PostgisExpectationsFactory.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/postgis/PostgisExpectationsFactory.java @@ -238,10 +238,9 @@ protected NativeSQLStatement createNativeDisjointStatement(Geometry geom) { ); } - //remove redundancy with toGeometry function in PGGeometryTypeDescriptor @Override protected Geometry decode(Object object) { - org.geolatte.geom.Geometry geometry = PGGeometryTypeDescriptor.toGeometry( object ); + org.geolatte.geom.Geometry geometry = PGGeometryTypeDescriptor.INSTANCE_WKB_1.toGeometry( object ); return JTS.to( geometry ); } diff --git a/hibernate-spatial/src/test/resources/cockroachdb/functions-test.xml b/hibernate-spatial/src/test/resources/cockroachdb/functions-test.xml new file mode 100644 index 000000000000..407cd75b8b59 --- /dev/null +++ b/hibernate-spatial/src/test/resources/cockroachdb/functions-test.xml @@ -0,0 +1,64 @@ + + + + + 1 + POINT + SRID=4326;POINT(10 5) + + + 2 + POINT + SRID=4326;POINT(79 79) + + + 3 + POINT + SRID=4326;POINT(50 50) + + + 4 + POINT + SRID=4326;POINT(10 20) + + + 5 + POINT + SRID=4326;POINT(-4 -5) + + + + 6 + LINESTRING + SRID=4326;LINESTRING(10.0 5.0, 20.0 15.0) + + + + + + 9 + MULTILINESTRING + SRID=4326;MULTILINESTRING((10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0), (40.0 20.0, 42.0 18.0, 43.0 16.0, 40 + 14.0)) + + + + + 10 + POLYGON + SRID=4326;POLYGON( (0 0, 0 10, 10 10, 10 0, 0 0) ) + + + + 11 + MULTIPOLYGON + SRID=4326;MULTIPOLYGON( ((10 20, 30 40, 44 50, 10 20)), ((15 10, 12 14, 13 13, 15 10)) ) + + + + diff --git a/hibernate-spatial/src/test/resources/cockroachdb/test-data-set.xml b/hibernate-spatial/src/test/resources/cockroachdb/test-data-set.xml new file mode 100644 index 000000000000..7f928daf9efc --- /dev/null +++ b/hibernate-spatial/src/test/resources/cockroachdb/test-data-set.xml @@ -0,0 +1,213 @@ + + + + 1 + POINT + POINT(10 5) + + + 2 + POINT + SRID=4326;POINT(52.25 2.53) + + + + 3 + POINT + SRID=31370;POINT(150000 200000) + + + + 4 + LINESTRING + SRID=4326;LINESTRING(10.0 5.0, 20.0 15.0) + + + + 5 + LINESTRING + SRID=4326;LINESTRING(10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0) + + + + + 6 + MULTILINESTRING + SRID=4326;MULTILINESTRING((10.0 5.0, 20.0 15.0),( 25.0 30.0, 30.0 20.0)) + + + + 7 + MULTILINESTRING + SRID=4326;MULTILINESTRING((10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0), (40.0 20.0, 42.0 18.0, 43.0 16.0, 40 + 14.0)) + + + + + 8 + POLYGON + SRID=4326;POLYGON( (0 0, 0 10, 10 10, 10 0, 0 0) ) + + + + 9 + POLYGON + SRID=4326;POLYGON( (0 0, 0 10, 10 10, 10 0, 0 0), (2 2, 2 5, 5 5,5 2, 2 2)) + + + + 10 + POLYGON + SRID=4326;POLYGON( (110 110, 110 120, 120 120, 120 110, 110 110) ) + + + + 11 + MULTIPOLYGON + SRID=4326;MULTIPOLYGON( ((10 20, 30 40, 44 50, 10 20)), ((105 100, 120 140, 130 134, 105 100)) ) + + + + + 12 + MULTIPOLYGON + SRID=4326;MULTIPOLYGON(( (0 0, 0 50, 50 50, 50 0, 0 0), (10 10, 10 20, 20 20, 20 10, 10 10) ),((105 100, + 120 140, 130 + 134, 105 100)) ) + + + + + + 13 + MULTIPOINT + SRID=4326;MULTIPOINT(21 2, 25 5, 30 3) + + + + 14 + MULTIPOINT + SRID=4326;MULTIPOINT(21 2) + + + + 15 + GEOMETRYCOLLECTION + SRID=4326;GEOMETRYCOLLECTION(POINT(4 0), LINESTRING(4 2, 5 3)) + + + + 16 + GEOMETRYCOLLECTION + SRID=4326;GEOMETRYCOLLECTION(POINT(4 0), LINESTRING(4 2, 5 3), POLYGON((0 0, 3 0, 3 3,0 3, 0 0))) + + + + 17 + GEOMETRYCOLLECTION + SRID=4326;GEOMETRYCOLLECTION(POINT(4 0), LINESTRING(4 2, 5 3), POLYGON((0 0, 3 0, 3 3,0 3, 0 0),(1 1, 2 1, + 2 2, 1 2, + 1 1))) + + + + + 18 + GEOMETRYCOLLECTION + SRID=4326;GEOMETRYCOLLECTION( MULTIPOINT(21 2, 25 5, 30 3), MULTIPOLYGON( ((10 20, 30 40, 44 50, 10 20)), + ((105 100, + 120 140, 130 134, 105 100)) ), MULTILINESTRING((10.0 5.0, 20.0 15.0),( 25.0 30.0, 30.0 20.0))) + + + + + 19 + GEOMETRYCOLLECTION + SRID=4326;GEOMETRYCOLLECTION(POINT(4 0), POINT EMPTY, LINESTRING(4 2, 5 3)) + + + + 20 + GEOMETRYCOLLECTION + SRID=4326;GEOMETRYCOLLECTION(POINT(4 0), LINESTRING EMPTY, LINESTRING(4 2, 5 3)) + + + + 21 + GEOMETRYCOLLECTION + SRID=4326;GEOMETRYCOLLECTION(POINT(4 0), GEOMETRYCOLLECTION EMPTY, LINESTRING(4 2, 5 3)) + + + + 22 + GEOMETRYCOLLECTION + SRID=4326;GEOMETRYCOLLECTION(POINT(4 0), POLYGON EMPTY, LINESTRING(4 2, 5 3)) + + + + 23 + GEOMETRYCOLLECTION + SRID=4326;GEOMETRYCOLLECTION(POINT(4 0), MULTILINESTRING EMPTY, LINESTRING(4 2, 5 3)) + + + + 24 + GEOMETRYCOLLECTION + SRID=4326;GEOMETRYCOLLECTION(POINT(4 0), MULTIPOINT EMPTY, LINESTRING(4 2, 5 3)) + + + + 25 + GEOMETRYCOLLECTION + SRID=4326;GEOMETRYCOLLECTION(POINT(4 0), MULTIPOLYGON EMPTY, LINESTRING(4 2, 5 3)) + + + + 26 + POINT + POINT EMPTY + + + + 27 + LINESTRING + LINESTRING EMPTY + + + + 28 + POLYGON + POLYGON EMPTY + + + + 29 + MULTIPOINT + MULTIPOINT EMPTY + + + + 30 + MULTILINESTRING + MULTILINESTRING EMPTY + + + + 31 + MULTIPOLYGON + MULTIPOLYGON EMPTY + + + + 32 + GEOMETRYCOLLECTION + GEOMETRYCOLLECTION EMPTY + + + From 8eb3354ed9ba7f16fb45dace0b4079b8d49542c5 Mon Sep 17 00:00:00 2001 From: Karel Maesen Date: Wed, 17 Mar 2021 20:29:13 +0100 Subject: [PATCH 071/644] HHH-14037 Add PostgisPG10Dialect --- .../postgis/PGSpatialDialectTrait.java | 128 ++++++++++++++++++ .../dialect/postgis/PostgisPG10Dialect.java | 39 ++++++ .../dialect/postgis/PostgisPG95Dialect.java | 115 +--------------- 3 files changed, 169 insertions(+), 113 deletions(-) create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PGSpatialDialectTrait.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG10Dialect.java diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PGSpatialDialectTrait.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PGSpatialDialectTrait.java new file mode 100644 index 000000000000..2c6dd2edf10c --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PGSpatialDialectTrait.java @@ -0,0 +1,128 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ + +package org.hibernate.spatial.dialect.postgis; + +import org.hibernate.spatial.SpatialDialect; +import org.hibernate.spatial.SpatialFunction; +import org.hibernate.spatial.dialect.SpatialFunctionsRegistry; + +interface PGSpatialDialectTrait extends SpatialDialect { + + PostgisSupport support = new PostgisSupport(); + + + default SpatialFunctionsRegistry functionsToRegister() { + return support.functionsToRegister(); + } + /** + * Returns the SQL fragment for the SQL WHERE-clause when parsing + * org.hibernatespatial.criterion.SpatialRelateExpressions + * into prepared statements. + *

+ * + * @param columnName The name of the geometry-typed column to which the relation is + * applied + * @param spatialRelation The type of spatial relation (as defined in + * SpatialRelation). + * + * @return SQL fragment {@code SpatialRelateExpression} + */ + @Override + default String getSpatialRelateSQL(String columnName, int spatialRelation) { + return support.getSpatialRelateSQL( columnName, spatialRelation ); + } + + /** + * Returns the SQL fragment for the SQL WHERE-expression when parsing + * org.hibernate.spatial.criterion.SpatialFilterExpressions + * into prepared statements. + * + * @param columnName The name of the geometry-typed column to which the filter is + * be applied + * + * @return Rhe SQL fragment for the {@code SpatialFilterExpression} + */ + @Override + default String getSpatialFilterExpression(String columnName) { + return support.getSpatialFilterExpression( columnName ); + } + + /** + * Returns the SQL fragment for the specfied Spatial aggregate expression. + * + * @param columnName The name of the Geometry property + * @param aggregation The type of SpatialAggregate + * + * @return The SQL fragment for the projection + */ + @Override + default String getSpatialAggregateSQL(String columnName, int aggregation) { + return support.getSpatialAggregateSQL( columnName, aggregation ); + } + + /** + * Returns The SQL fragment when parsing a DWithinExpression. + * + * @param columnName The geometry column to test against + * + * @return The SQL fragment when parsing a DWithinExpression. + */ + @Override + default String getDWithinSQL(String columnName) { + return support.getDWithinSQL( columnName ); + } + + /** + * Returns the SQL fragment when parsing a HavingSridExpression. + * + * @param columnName The geometry column to test against + * + * @return The SQL fragment for a HavingSridExpression. + */ + @Override + default String getHavingSridSQL(String columnName) { + return support.getHavingSridSQL( columnName ); + } + + /** + * Returns the SQL fragment when parsing a IsEmptyExpression or + * IsNotEmpty expression. + * + * @param columnName The geometry column + * @param isEmpty Whether the geometry is tested for empty or non-empty + * + * @return The SQL fragment for the isempty function + */ + @Override + default String getIsEmptySQL(String columnName, boolean isEmpty) { + return support.getIsEmptySQL( columnName, isEmpty ); + } + + /** + * Returns true if this SpatialDialect supports a specific filtering function. + *

This is intended to signal DB-support for fast window queries, or MBR-overlap queries.

+ * + * @return True if filtering is supported + */ + @Override + default boolean supportsFiltering() { + return support.supportsFiltering(); + } + + /** + * Does this dialect supports the specified SpatialFunction. + * + * @param function SpatialFunction + * + * @return True if this SpatialDialect supports the spatial function specified by the function parameter. + */ + @Override + default boolean supports(SpatialFunction function) { + return support.supports( function ); + } +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG10Dialect.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG10Dialect.java new file mode 100644 index 000000000000..e7c9412b635a --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG10Dialect.java @@ -0,0 +1,39 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ + +package org.hibernate.spatial.dialect.postgis; + +import java.util.Map; + +import org.hibernate.boot.model.TypeContributions; +import org.hibernate.dialect.PostgreSQL10Dialect; +import org.hibernate.dialect.function.SQLFunction; +import org.hibernate.service.ServiceRegistry; + +public class PostgisPG10Dialect extends PostgreSQL10Dialect implements PGSpatialDialectTrait { + + public PostgisPG10Dialect() { + super(); + registerColumnType( + PGGeometryTypeDescriptor.INSTANCE_WKB_1.getSqlType(), + "GEOMETRY" + ); + for ( Map.Entry entry : functionsToRegister() ) { + registerFunction( entry.getKey(), entry.getValue() ); + } + } + + @Override + public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) { + super.contributeTypes( + typeContributions, + serviceRegistry + ); + support.contributeTypes( typeContributions, serviceRegistry ); + } + +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG95Dialect.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG95Dialect.java index a99bd40d8327..118584fac265 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG95Dialect.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG95Dialect.java @@ -12,17 +12,12 @@ import org.hibernate.dialect.PostgreSQL95Dialect; import org.hibernate.dialect.function.SQLFunction; import org.hibernate.service.ServiceRegistry; -import org.hibernate.spatial.SpatialDialect; -import org.hibernate.spatial.SpatialFunction; /** * Extends the {@code PostgreSQL95Dialect} to add support for the Postgis spatial types, functions and operators . * Created by Karel Maesen, Geovise BVBA on 01/11/16. */ -public class PostgisPG95Dialect extends PostgreSQL95Dialect implements SpatialDialect { - - - transient private PostgisSupport support = new PostgisSupport(); +public class PostgisPG95Dialect extends PostgreSQL95Dialect implements PGSpatialDialectTrait { /** * Creates an instance @@ -33,7 +28,7 @@ public PostgisPG95Dialect() { PGGeometryTypeDescriptor.INSTANCE_WKB_1.getSqlType(), "GEOMETRY" ); - for ( Map.Entry entry : support.functionsToRegister() ) { + for ( Map.Entry entry : functionsToRegister() ) { registerFunction( entry.getKey(), entry.getValue() ); } } @@ -47,110 +42,4 @@ public void contributeTypes(TypeContributions typeContributions, ServiceRegistry support.contributeTypes( typeContributions, serviceRegistry ); } - /** - * Returns the SQL fragment for the SQL WHERE-clause when parsing - * org.hibernatespatial.criterion.SpatialRelateExpressions - * into prepared statements. - *

- * - * @param columnName The name of the geometry-typed column to which the relation is - * applied - * @param spatialRelation The type of spatial relation (as defined in - * SpatialRelation). - * - * @return SQL fragment {@code SpatialRelateExpression} - */ - @Override - public String getSpatialRelateSQL(String columnName, int spatialRelation) { - return support.getSpatialRelateSQL( columnName, spatialRelation ); - } - - /** - * Returns the SQL fragment for the SQL WHERE-expression when parsing - * org.hibernate.spatial.criterion.SpatialFilterExpressions - * into prepared statements. - * - * @param columnName The name of the geometry-typed column to which the filter is - * be applied - * - * @return Rhe SQL fragment for the {@code SpatialFilterExpression} - */ - @Override - public String getSpatialFilterExpression(String columnName) { - return support.getSpatialFilterExpression( columnName ); - } - - /** - * Returns the SQL fragment for the specfied Spatial aggregate expression. - * - * @param columnName The name of the Geometry property - * @param aggregation The type of SpatialAggregate - * - * @return The SQL fragment for the projection - */ - @Override - public String getSpatialAggregateSQL(String columnName, int aggregation) { - return support.getSpatialAggregateSQL( columnName, aggregation ); - } - - /** - * Returns The SQL fragment when parsing a DWithinExpression. - * - * @param columnName The geometry column to test against - * - * @return The SQL fragment when parsing a DWithinExpression. - */ - @Override - public String getDWithinSQL(String columnName) { - return support.getDWithinSQL( columnName ); - } - - /** - * Returns the SQL fragment when parsing a HavingSridExpression. - * - * @param columnName The geometry column to test against - * - * @return The SQL fragment for a HavingSridExpression. - */ - @Override - public String getHavingSridSQL(String columnName) { - return support.getHavingSridSQL( columnName ); - } - - /** - * Returns the SQL fragment when parsing a IsEmptyExpression or - * IsNotEmpty expression. - * - * @param columnName The geometry column - * @param isEmpty Whether the geometry is tested for empty or non-empty - * - * @return The SQL fragment for the isempty function - */ - @Override - public String getIsEmptySQL(String columnName, boolean isEmpty) { - return support.getIsEmptySQL( columnName, isEmpty ); - } - - /** - * Returns true if this SpatialDialect supports a specific filtering function. - *

This is intended to signal DB-support for fast window queries, or MBR-overlap queries.

- * - * @return True if filtering is supported - */ - @Override - public boolean supportsFiltering() { - return support.supportsFiltering(); - } - - /** - * Does this dialect supports the specified SpatialFunction. - * - * @param function SpatialFunction - * - * @return True if this SpatialDialect supports the spatial function specified by the function parameter. - */ - @Override - public boolean supports(SpatialFunction function) { - return support.supports( function ); - } } From 5324db9f259c51b20b7467585000d17e097e8c7b Mon Sep 17 00:00:00 2001 From: Karel Maesen Date: Wed, 17 Mar 2021 20:03:13 +0100 Subject: [PATCH 072/644] Docker_db improvements - enable experimental settings for cockroachdb - reduce shmni setting for Hana --- docker_db.sh | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/docker_db.sh b/docker_db.sh index 940ac409d96b..eee8c47bd58d 100755 --- a/docker_db.sh +++ b/docker_db.sh @@ -200,7 +200,7 @@ hana() { --ulimit nofile=1048576:1048576 \ --sysctl kernel.shmmax=1073741824 \ --sysctl net.ipv4.ip_local_port_range='40000 60999' \ - --sysctl kernel.shmmni=524288 \ + --sysctl kernel.shmmni=4096 \ --sysctl kernel.shmall=8388608 \ -v $temp_dir:/config \ store/saplabs/hanaexpress:2.00.045.00.20200121.1 \ @@ -225,6 +225,12 @@ cockroachdb() { sleep 10 OUTPUT=$(docker logs cockroach) done + echo "Enabling experimental box2d operators" + docker exec -it cockroach bash -c "cat < Date: Wed, 17 Mar 2021 18:25:56 +0530 Subject: [PATCH 073/644] HHH-14449 : ResultStream closing is not properly handled --- .../query/internal/AbstractProducedQuery.java | 6 +- .../query/spi/DoubleStreamDecorator.java | 8 +- .../query/spi/IntStreamDecorator.java | 8 +- .../query/spi/LongStreamDecorator.java | 14 +- .../hibernate/query/spi/StreamDecorator.java | 8 +- .../test/stream/basic/BasicStreamTest.java | 49 +++ .../test/stream/basic/JpaStreamTest.java | 294 ++++++++++++++++-- 7 files changed, 338 insertions(+), 49 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/AbstractProducedQuery.java b/hibernate-core/src/main/java/org/hibernate/query/internal/AbstractProducedQuery.java index 1ca1739101ef..170a7288a2cc 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/internal/AbstractProducedQuery.java +++ b/hibernate-core/src/main/java/org/hibernate/query/internal/AbstractProducedQuery.java @@ -1584,12 +1584,10 @@ public Stream stream() { final ScrollableResultsIterator iterator = new ScrollableResultsIterator<>( scrollableResults ); final Spliterator spliterator = Spliterators.spliteratorUnknownSize( iterator, Spliterator.NONNULL ); - final Stream stream = new StreamDecorator( + return new StreamDecorator<>( StreamSupport.stream( spliterator, false ), - scrollableResults::close + iterator::close ); - - return stream; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/query/spi/DoubleStreamDecorator.java b/hibernate-core/src/main/java/org/hibernate/query/spi/DoubleStreamDecorator.java index 9035a682898b..00a02d069977 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/spi/DoubleStreamDecorator.java +++ b/hibernate-core/src/main/java/org/hibernate/query/spi/DoubleStreamDecorator.java @@ -41,15 +41,13 @@ public class DoubleStreamDecorator implements DoubleStream { private final DoubleStream delegate; - - private Runnable closeHandler; + private final Runnable closeHandler; public DoubleStreamDecorator( DoubleStream delegate, Runnable closeHandler) { - this.delegate = delegate; this.closeHandler = closeHandler; - this.delegate.onClose( closeHandler ); + this.delegate = delegate.onClose( closeHandler ); } @Override @@ -292,7 +290,7 @@ public DoubleStream unordered() { @Override public DoubleStream onClose(Runnable closeHandler) { - this.closeHandler = closeHandler; + this.delegate.onClose( closeHandler ); return this; } diff --git a/hibernate-core/src/main/java/org/hibernate/query/spi/IntStreamDecorator.java b/hibernate-core/src/main/java/org/hibernate/query/spi/IntStreamDecorator.java index d8050af65812..470128b2c97e 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/spi/IntStreamDecorator.java +++ b/hibernate-core/src/main/java/org/hibernate/query/spi/IntStreamDecorator.java @@ -42,15 +42,13 @@ public class IntStreamDecorator implements IntStream { private final IntStream delegate; - - private Runnable closeHandler; + private final Runnable closeHandler; public IntStreamDecorator( IntStream delegate, Runnable closeHandler) { - this.delegate = delegate; this.closeHandler = closeHandler; - this.delegate.onClose( closeHandler ); + this.delegate = delegate.onClose( closeHandler ); } @Override @@ -307,7 +305,7 @@ public IntStream unordered() { @Override public IntStream onClose(Runnable closeHandler) { - this.closeHandler = closeHandler; + this.delegate.onClose( closeHandler ); return this; } diff --git a/hibernate-core/src/main/java/org/hibernate/query/spi/LongStreamDecorator.java b/hibernate-core/src/main/java/org/hibernate/query/spi/LongStreamDecorator.java index b34c0203169a..befd5a16f29d 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/spi/LongStreamDecorator.java +++ b/hibernate-core/src/main/java/org/hibernate/query/spi/LongStreamDecorator.java @@ -42,15 +42,13 @@ public class LongStreamDecorator implements LongStream { private final LongStream delegate; - - private Runnable closeHandler; + private final Runnable closeHandler; public LongStreamDecorator( LongStream delegate, Runnable closeHandler) { - this.delegate = delegate; this.closeHandler = closeHandler; - this.delegate.onClose( closeHandler ); + this.delegate = delegate.onClose( closeHandler ); } @Override @@ -226,21 +224,21 @@ public LongSummaryStatistics summaryStatistics() { @Override public boolean anyMatch(LongPredicate predicate) { - boolean result = delegate.anyMatch(predicate); + boolean result = delegate.anyMatch( predicate ); close(); return result; } @Override public boolean allMatch(LongPredicate predicate) { - boolean result = delegate.allMatch(predicate); + boolean result = delegate.allMatch( predicate ); close(); return result; } @Override public boolean noneMatch(LongPredicate predicate) { - boolean result = delegate.noneMatch(predicate); + boolean result = delegate.noneMatch( predicate ); close(); return result; } @@ -300,7 +298,7 @@ public LongStream unordered() { @Override public LongStream onClose(Runnable closeHandler) { - this.closeHandler = closeHandler; + this.delegate.onClose( closeHandler ); return this; } diff --git a/hibernate-core/src/main/java/org/hibernate/query/spi/StreamDecorator.java b/hibernate-core/src/main/java/org/hibernate/query/spi/StreamDecorator.java index 526b4ee9b936..9d862396b7f4 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/spi/StreamDecorator.java +++ b/hibernate-core/src/main/java/org/hibernate/query/spi/StreamDecorator.java @@ -46,15 +46,13 @@ public class StreamDecorator implements Stream { private final Stream delegate; - - private Runnable closeHandler; + private final Runnable closeHandler; public StreamDecorator( Stream delegate, Runnable closeHandler) { - this.delegate = delegate; this.closeHandler = closeHandler; - this.delegate.onClose( closeHandler ); + this.delegate = delegate.onClose( closeHandler ); } @Override @@ -301,7 +299,7 @@ public Stream unordered() { @Override public Stream onClose(Runnable closeHandler) { - this.closeHandler = closeHandler; + this.delegate.onClose( closeHandler ); return this; } diff --git a/hibernate-core/src/test/java/org/hibernate/test/stream/basic/BasicStreamTest.java b/hibernate-core/src/test/java/org/hibernate/test/stream/basic/BasicStreamTest.java index 471a193899c1..79adf7b4218e 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/stream/basic/BasicStreamTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/stream/basic/BasicStreamTest.java @@ -6,6 +6,7 @@ */ package org.hibernate.test.stream.basic; +import java.util.concurrent.atomic.AtomicInteger; import java.util.stream.Stream; import javax.persistence.Entity; import javax.persistence.Id; @@ -25,6 +26,7 @@ import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.core.Is.is; +import static org.hamcrest.core.IsEqual.equalTo; import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping; import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; @@ -123,6 +125,53 @@ public void testTupleStream() { } ); } + @Test + public void basicStreamTestWithExplicitOnClose() { + Session session = openSession(); + session.getTransaction().begin(); + + AtomicInteger onCloseCount = new AtomicInteger(); + + // mainly we want to make sure that closing the Stream releases the ScrollableResults too + assertThat( ( (SessionImplementor) session ).getJdbcCoordinator() + .getLogicalConnection() + .getResourceRegistry() + .hasRegisteredResources(), is( false ) ); + + assertThat( onCloseCount.get(), equalTo( 0 ) ); + + final Stream stream = session.createQuery( "from MyEntity", MyEntity.class ).stream().onClose( + onCloseCount::incrementAndGet ); + + assertThat( ( (SessionImplementor) session ).getJdbcCoordinator() + .getLogicalConnection() + .getResourceRegistry() + .hasRegisteredResources(), is( true ) ); + + assertThat( onCloseCount.get(), equalTo( 0 ) ); + + stream.forEach( System.out::println ); + + assertThat( ( (SessionImplementor) session ).getJdbcCoordinator() + .getLogicalConnection() + .getResourceRegistry() + .hasRegisteredResources(), is( false ) ); + + assertThat( onCloseCount.get(), equalTo( 1 ) ); + + stream.close(); + + assertThat( ( (SessionImplementor) session ).getJdbcCoordinator() + .getLogicalConnection() + .getResourceRegistry() + .hasRegisteredResources(), is( false ) ); + + assertThat( onCloseCount.get(), equalTo( 1 ) ); + + session.getTransaction().commit(); + session.close(); + } + @Entity(name = "MyEntity") @Table(name="MyEntity") public static class MyEntity { diff --git a/hibernate-core/src/test/java/org/hibernate/test/stream/basic/JpaStreamTest.java b/hibernate-core/src/test/java/org/hibernate/test/stream/basic/JpaStreamTest.java index 14fefac44617..dc7f72e1765e 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/stream/basic/JpaStreamTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/stream/basic/JpaStreamTest.java @@ -8,7 +8,12 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import java.util.Arrays; +import java.util.Collections; import java.util.List; +import java.util.Objects; +import java.util.Optional; +import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Predicate; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -28,6 +33,7 @@ import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; import org.junit.Test; +import static org.assertj.core.api.Assertions.assertThat; import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping; import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; import static org.junit.Assert.assertEquals; @@ -78,8 +84,8 @@ public void testQueryStream() { } @Test - @TestForIssue( jiraKey = "HHH-13872") @RequiresDialect(H2Dialect.class) + @TestForIssue( jiraKey = {"HHH-13872", "HHH-14449"}) public void testStreamCloseOnTerminalOperation() { doInHibernate( this::sessionFactory, session -> { session.createQuery( "delete from MyEntity" ).executeUpdate(); @@ -92,10 +98,116 @@ public void testStreamCloseOnTerminalOperation() { } } ); + Runnable noOp = () -> { + // do nothing + }; + + // run without onClose callbacks + + this.runTerminalOperationTests(noOp, Collections.emptyList(), noOp, false, false); + + AtomicInteger onClose1Count = new AtomicInteger(); + AtomicInteger onClose2Count = new AtomicInteger(); + AtomicInteger onClose3Count = new AtomicInteger(); + + // run with chained onClose callbacks + + this.runTerminalOperationTests( + () -> { + // prepare + onClose1Count.set( 0 ); + onClose2Count.set( 0 ); + onClose3Count.set( 0 ); + }, + Arrays.asList( + onClose1Count::incrementAndGet, // onClose1 logic + onClose2Count::incrementAndGet, // onClose2 logic + onClose3Count::incrementAndGet // onClose3 logic + ), + () -> { + // assertion + assertThat( onClose1Count ).hasValue( 1 ); + assertThat( onClose2Count ).hasValue( 1 ); + assertThat( onClose3Count ).hasValue( 1 ); + }, + false, // no flatMap before onClose + false // no flatMap after onClose + ); + + this.runTerminalOperationTests( + () -> { + // prepare + onClose1Count.set( 0 ); + onClose2Count.set( 0 ); + onClose3Count.set( 0 ); + }, + Arrays.asList( + onClose1Count::incrementAndGet, // onClose1 logic + onClose2Count::incrementAndGet, // onClose2 logic + onClose3Count::incrementAndGet // onClose3 logic + ), + () -> { + // assertion + assertThat( onClose1Count ).hasValue( 1 ); + assertThat( onClose2Count ).hasValue( 1 ); + assertThat( onClose3Count ).hasValue( 1 ); + }, + true, // run a flatMap operation before onClose + false // no flatMap after onClose + ); + + this.runTerminalOperationTests( + () -> { + // prepare + onClose1Count.set( 0 ); + onClose2Count.set( 0 ); + onClose3Count.set( 0 ); + }, + Arrays.asList( + onClose1Count::incrementAndGet, // onClose1 logic + onClose2Count::incrementAndGet, // onClose2 logic + onClose3Count::incrementAndGet // onClose3 logic + ), + () -> { + // assertion + assertThat( onClose1Count ).hasValue( 1 ); + assertThat( onClose2Count ).hasValue( 1 ); + assertThat( onClose3Count ).hasValue( 1 ); + }, + false, // no flatMap before onClose + true // run a flatMap operation after onClose + ); + + this.runTerminalOperationTests( + () -> { + // prepare + onClose1Count.set( 0 ); + onClose2Count.set( 0 ); + onClose3Count.set( 0 ); + }, + Arrays.asList( + onClose1Count::incrementAndGet, // onClose1 logic + onClose2Count::incrementAndGet, // onClose2 logic + onClose3Count::incrementAndGet // onClose3 logic + ), + () -> { + // assertion + assertThat( onClose1Count ).hasValue( 1 ); + assertThat( onClose2Count ).hasValue( 1 ); + assertThat( onClose3Count ).hasValue( 1 ); + }, + true, // run a flatMap operation before onClose + true // run a flatMap operation after onClose + ); + } + + private void runTerminalOperationTests( + Runnable prepare, List onCloseCallbacks, Runnable onCloseAssertion, + boolean flatMapBefore, boolean flatMapAfter) { + + // collect as list doInHibernate( this::sessionFactory, session -> { - Stream stream = session - .createQuery( "SELECT me FROM MyEntity me" ) - .getResultStream(); + Stream stream = getMyEntityStream(prepare, session, onCloseCallbacks, flatMapBefore, flatMapAfter); ResourceRegistry resourceRegistry = resourceRegistry(session); assertTrue( resourceRegistry.hasRegisteredResources() ); @@ -104,12 +216,90 @@ public void testStreamCloseOnTerminalOperation() { assertEquals(10, entities.size()); assertFalse( resourceRegistry.hasRegisteredResources() ); + + onCloseAssertion.run(); } ); + // forEach (TestCase based on attachment EntityManagerIllustrationTest.java in HHH-14449) doInHibernate( this::sessionFactory, session -> { - Stream stream = session - .createQuery( "SELECT me FROM MyEntity me" ) - .getResultStream(); + Stream stream = getMyEntityStream(prepare, session, onCloseCallbacks, flatMapBefore, flatMapAfter); + + ResourceRegistry resourceRegistry = resourceRegistry(session); + assertTrue( resourceRegistry.hasRegisteredResources() ); + + AtomicInteger count = new AtomicInteger(); + + stream.forEach(myEntity -> count.incrementAndGet()); + + assertEquals(10, count.get()); + + assertFalse( resourceRegistry.hasRegisteredResources() ); + + onCloseAssertion.run(); + } ); + + // filter (always true) + forEach (TestCase based on attachment EntityManagerIllustrationTest.java in HHH-14449) + doInHibernate( this::sessionFactory, session -> { + Stream stream = getMyEntityStream(prepare, session, onCloseCallbacks, flatMapBefore, flatMapAfter); + + ResourceRegistry resourceRegistry = resourceRegistry(session); + assertTrue( resourceRegistry.hasRegisteredResources() ); + + AtomicInteger count = new AtomicInteger(); + + stream.filter(Objects::nonNull).forEach(myEntity -> count.incrementAndGet()); + + assertEquals(10, count.get()); + + assertFalse( resourceRegistry.hasRegisteredResources() ); + + onCloseAssertion.run(); + } ); + + // filter (partially true) + forEach (TestCase based on attachment EntityManagerIllustrationTest.java in HHH-14449) + doInHibernate( this::sessionFactory, session -> { + Stream stream = getMyEntityStream(prepare, session, onCloseCallbacks, flatMapBefore, flatMapAfter); + + ResourceRegistry resourceRegistry = resourceRegistry(session); + assertTrue( resourceRegistry.hasRegisteredResources() ); + + AtomicInteger count = new AtomicInteger(); + + stream.filter(entity -> entity.getId() % 2 == 0).forEach(myEntity -> count.incrementAndGet()); + + assertEquals(5, count.get()); + + assertFalse( resourceRegistry.hasRegisteredResources() ); + + onCloseAssertion.run(); + } ); + + // multiple chained operations (TestCase based on attachment EntityManagerIllustrationTest.java in HHH-14449) + doInHibernate( this::sessionFactory, session -> { + Stream stream = getMyEntityStream(prepare, session, onCloseCallbacks, flatMapBefore, flatMapAfter); + + ResourceRegistry resourceRegistry = resourceRegistry(session); + assertTrue( resourceRegistry.hasRegisteredResources() ); + + AtomicInteger count = new AtomicInteger(); + + stream + .filter(Objects::nonNull) + .map(Optional::of) + .filter(Optional::isPresent) + .map(Optional::get) + .forEach(myEntity -> count.incrementAndGet()); + + assertEquals(10, count.get()); + + assertFalse( resourceRegistry.hasRegisteredResources() ); + + onCloseAssertion.run(); + } ); + + // mapToInt + doInHibernate( this::sessionFactory, session -> { + Stream stream = getMyEntityStream(prepare, session, onCloseCallbacks, flatMapBefore, flatMapAfter); ResourceRegistry resourceRegistry = resourceRegistry(session); assertTrue( resourceRegistry.hasRegisteredResources() ); @@ -118,12 +308,13 @@ public void testStreamCloseOnTerminalOperation() { assertEquals(55, sum); assertFalse( resourceRegistry.hasRegisteredResources() ); + + onCloseAssertion.run(); } ); + // mapToLong doInHibernate( this::sessionFactory, session -> { - Stream stream = session - .createQuery( "SELECT me FROM MyEntity me" ) - .getResultStream(); + Stream stream = getMyEntityStream(prepare, session, onCloseCallbacks, flatMapBefore, flatMapAfter); ResourceRegistry resourceRegistry = resourceRegistry(session); assertTrue( resourceRegistry.hasRegisteredResources() ); @@ -132,12 +323,13 @@ public void testStreamCloseOnTerminalOperation() { assertEquals(10, result); assertFalse( resourceRegistry.hasRegisteredResources() ); + + onCloseAssertion.run(); } ); + // mapToDouble doInHibernate( this::sessionFactory, session -> { - Stream stream = session - .createQuery( "SELECT me FROM MyEntity me" ) - .getResultStream(); + Stream stream = getMyEntityStream(prepare, session, onCloseCallbacks, flatMapBefore, flatMapAfter); ResourceRegistry resourceRegistry = resourceRegistry(session); assertTrue( resourceRegistry.hasRegisteredResources() ); @@ -146,14 +338,14 @@ public void testStreamCloseOnTerminalOperation() { assertEquals(1, result, 0.1); assertFalse( resourceRegistry.hasRegisteredResources() ); + + onCloseAssertion.run(); } ); //Test call close explicitly doInHibernate( this::sessionFactory, session -> { - try (Stream stream = session - .createQuery( "SELECT me.id FROM MyEntity me" ) - .getResultStream()) { + try (Stream stream = getLongStream(prepare, session, onCloseCallbacks, flatMapBefore, flatMapAfter)) { ResourceRegistry resourceRegistry = resourceRegistry( session ); assertTrue( resourceRegistry.hasRegisteredResources() ); @@ -164,6 +356,8 @@ public void testStreamCloseOnTerminalOperation() { assertEquals( 10, result[4] ); assertFalse( resourceRegistry.hasRegisteredResources() ); + + onCloseAssertion.run(); } } ); @@ -172,9 +366,7 @@ public void testStreamCloseOnTerminalOperation() { Method takeWhileMethod = ReflectHelper.getMethod( Stream.class, "takeWhile", Predicate.class ); if ( takeWhileMethod != null ) { - try (Stream stream = session - .createQuery( "SELECT me.id FROM MyEntity me" ) - .getResultStream()) { + try (Stream stream = getLongStream(prepare, session, onCloseCallbacks, flatMapBefore, flatMapAfter)) { ResourceRegistry resourceRegistry = resourceRegistry( session ); assertTrue( resourceRegistry.hasRegisteredResources() ); @@ -191,6 +383,8 @@ public void testStreamCloseOnTerminalOperation() { assertTrue( result.contains( 5 ) ); assertFalse( resourceRegistry.hasRegisteredResources() ); + + onCloseAssertion.run(); } catch (IllegalAccessException | InvocationTargetException e) { fail( "Could not execute takeWhile because of " + e.getMessage() ); @@ -202,9 +396,7 @@ public void testStreamCloseOnTerminalOperation() { Method dropWhileMethod = ReflectHelper.getMethod( Stream.class, "dropWhile", Predicate.class ); if ( dropWhileMethod != null ) { - try (Stream stream = session - .createQuery( "SELECT me.id FROM MyEntity me" ) - .getResultStream()) { + try (Stream stream = getLongStream(prepare, session, onCloseCallbacks, flatMapBefore, flatMapAfter)) { ResourceRegistry resourceRegistry = resourceRegistry( session ); assertTrue( resourceRegistry.hasRegisteredResources() ); @@ -221,6 +413,8 @@ public void testStreamCloseOnTerminalOperation() { assertTrue( result.contains( 10 ) ); assertFalse( resourceRegistry.hasRegisteredResources() ); + + onCloseAssertion.run(); } catch (IllegalAccessException | InvocationTargetException e) { fail( "Could not execute takeWhile because of " + e.getMessage() ); @@ -229,6 +423,62 @@ public void testStreamCloseOnTerminalOperation() { } ); } + private static Stream getMyEntityStream( + Runnable prepare, + Session session, + List onCloseCallbacks, + boolean flatMapBefore, + boolean flatMapAfter) { + return getStream( + prepare, + session, + "SELECT me FROM MyEntity me", + onCloseCallbacks, + flatMapBefore, + flatMapAfter + ); + } + + private static Stream getLongStream( + Runnable prepare, + Session session, + List onCloseCallbacks, + boolean flatMapBefore, + boolean flatMapAfter) { + return getStream( + prepare, + session, + "SELECT me.id FROM MyEntity me", + onCloseCallbacks, + flatMapBefore, + flatMapAfter + ); + } + + @SuppressWarnings("unchecked") + private static Stream getStream( + Runnable prepare, Session session, String queryString, + List onCloseCallbacks, boolean flatMapBefore, boolean flatMapAfter) { + + prepare.run(); + + Stream stream = session.createQuery( queryString ).getResultStream(); + + if ( flatMapBefore ) { + stream = stream.flatMap( Stream::of ); + } + + for ( Runnable callback : onCloseCallbacks ) { + stream = stream.onClose( callback ); + } + + if ( flatMapAfter ) { + stream = stream.flatMap( Stream::of ); + } + + return stream; + } + private ResourceRegistry resourceRegistry(Session session) { SharedSessionContractImplementor sharedSessionContractImplementor = (SharedSessionContractImplementor) session; JdbcCoordinator jdbcCoordinator = sharedSessionContractImplementor.getJdbcCoordinator(); From 725faa258fe01429c5a2f2da5996323daed6b5e2 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Fri, 19 Mar 2021 10:59:03 -0500 Subject: [PATCH 074/644] HHH-14509 : Git master -> main branch renaming --- .github/workflows/contributor-build.yml | 4 +- CONTRIBUTING.md | 4 +- README.md | 2 +- etc/hibernate.properties | 2 +- etc/hibernate.properties.template | 2 +- .../hibernate/internal/CoreMessageLogger.java | 2 +- .../annotations/entity/FormalLastName.java | 2 +- .../org/hibernate/test/fileimport/Dog.java | 10 +- ...atedFormWithBeanValidationNotNullTest.java | 2 +- ...nnotatedMaster.java => AnnotatedRoot.java} | 2 +- .../hibernate/test/formulajoin/Detail.java | 10 +- .../test/formulajoin/FormulaJoinTest.java | 36 +-- .../{Master.hbm.xml => Root.hbm.xml} | 14 +- .../formulajoin/{Master.java => Root.java} | 5 +- ...SubqueryReferencingTargetPropertyTest.java | 30 +-- .../java/org/hibernate/test/hql/HQLTest.java | 6 +- .../org/hibernate/test/hql/HqlParserTest.java | 32 +-- .../test/hql/QueryTranslatorTestCase.java | 2 +- .../UpdateJoinedSubclassCorrelationTest.java | 40 +-- ...r.hbm.xml => ComponentNotNullRoot.hbm.xml} | 12 +- ...lMaster.java => ComponentNotNullRoot.java} | 5 +- .../test/legacy/ComponentNotNullTest.java | 78 +++--- .../org/hibernate/test/legacy/Detail.java | 10 +- .../org/hibernate/test/legacy/FumTest.java | 36 +-- .../org/hibernate/test/legacy/Middle.hbm.xml | 2 +- .../org/hibernate/test/legacy/Middle.java | 4 +- .../org/hibernate/test/legacy/MiddleKey.java | 8 +- .../org/hibernate/test/legacy/OuterKey.java | 14 +- .../test/legacy/QueryByExampleTest.java | 42 ++-- .../test/legacy/{Master.java => Root.java} | 29 ++- ...asterDetail.hbm.xml => RootDetail.hbm.xml} | 18 +- ...terDetailTest.java => RootDetailTest.java} | 230 +++++++++--------- .../org/hibernate/test/fileimport/Dog.hbm.xml | 2 +- .../org/hibernate/test/fileimport/dogs.sql | 6 +- .../inverseToSuperclass/DetailSuperclass.java | 10 +- .../ManyToManyInverseToSuperclassTest.java | 58 +---- .../{Master.java => Root.java} | 4 +- .../manytoone/ManyToOneNotInsertable.java | 8 +- .../inverseToSuperclass/DetailSuperclass.java | 6 +- .../OneToManyInverseToSuperclassTest.java | 20 +- .../{Master.java => Root.java} | 4 +- .../inverseToSuperclass/mappings.hbm.xml | 14 +- .../inverseToSuperclass/mappings.hbm.xml | 10 +- shared/config/checkstyle/checkstyle.xml | 6 + test-case-guide.adoc | 2 +- .../test/accesstype/AccessTypeTest.java | 2 +- .../jpamodelgen/test/accesstype/Hotel.java | 10 +- 47 files changed, 403 insertions(+), 454 deletions(-) rename hibernate-core/src/test/java/org/hibernate/test/formulajoin/{AnnotatedMaster.java => AnnotatedRoot.java} (97%) rename hibernate-core/src/test/java/org/hibernate/test/formulajoin/{Master.hbm.xml => Root.hbm.xml} (84%) rename hibernate-core/src/test/java/org/hibernate/test/formulajoin/{Master.java => Root.java} (87%) rename hibernate-core/src/test/java/org/hibernate/test/legacy/{ComponentNotNullMaster.hbm.xml => ComponentNotNullRoot.hbm.xml} (87%) rename hibernate-core/src/test/java/org/hibernate/test/legacy/{ComponentNotNullMaster.java => ComponentNotNullRoot.java} (95%) rename hibernate-core/src/test/java/org/hibernate/test/legacy/{Master.java => Root.java} (82%) rename hibernate-core/src/test/java/org/hibernate/test/legacy/{MasterDetail.hbm.xml => RootDetail.hbm.xml} (82%) rename hibernate-core/src/test/java/org/hibernate/test/legacy/{MasterDetailTest.java => RootDetailTest.java} (80%) rename hibernate-envers/src/test/java/org/hibernate/envers/test/integration/manytomany/inverseToSuperclass/{Master.java => Root.java} (95%) rename hibernate-envers/src/test/java/org/hibernate/envers/test/integration/onetomany/inverseToSuperclass/{Master.java => Root.java} (95%) diff --git a/.github/workflows/contributor-build.yml b/.github/workflows/contributor-build.yml index 3414218fd8a7..9a549710f3a1 100644 --- a/.github/workflows/contributor-build.yml +++ b/.github/workflows/contributor-build.yml @@ -9,11 +9,11 @@ name: Hibernate ORM build on: push: branches: - - 'master' + - 'main' - 'wip/6.0' pull_request: branches: - - 'master' + - 'main' - 'wip/6.0' jobs: build: diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6b0c2242415f..81c00899efbc 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -62,8 +62,8 @@ although this is more of a mnemonic strategy than a hard-and-fast rule - but doi _If there is not already a JIRA issue covering the work you want to do, create one._ -Assuming you will be working from the master branch and working -on the JIRA HHH-123 : `git checkout -b HHH-123 master` +Assuming you will be working from the `main` branch and working +on the JIRA HHH-123 : `git checkout -b HHH-123 main` ## Code diff --git a/README.md b/README.md index 9376ca205005..005d039071ff 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ It also provides an implementation of the JPA specification, which is the standa This is the repository of its source code: see [Hibernate.org](http://hibernate.org/orm/) for additional information. -[![Build Status](http://ci.hibernate.org/job/hibernate-orm-master-h2-main/badge/icon)](http://ci.hibernate.org/job/hibernate-orm-master-h2-main/) +[![Build Status](http://ci.hibernate.org/job/hibernate-orm-main-h2-main/badge/icon)](http://ci.hibernate.org/job/hibernate-orm-main-h2-main/) [![Language grade: Java](https://img.shields.io/lgtm/grade/java/g/hibernate/hibernate-orm.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/hibernate/hibernate-orm/context:java) Building from sources diff --git a/etc/hibernate.properties b/etc/hibernate.properties index cb78aabf2cdf..35ac7c0466ba 100644 --- a/etc/hibernate.properties +++ b/etc/hibernate.properties @@ -190,7 +190,7 @@ hibernate.connection.url jdbc:hsqldb:./build/db/hsqldb/hibernate #hibernate.dialect org.hibernate.dialect.InterbaseDialect #hibernate.connection.username sysdba -#hibernate.connection.password masterkey +#hibernate.connection.password thekey ## DO NOT specify hibernate.connection.sqlDialect diff --git a/etc/hibernate.properties.template b/etc/hibernate.properties.template index 3b9c7681d91f..b4088e0e64db 100644 --- a/etc/hibernate.properties.template +++ b/etc/hibernate.properties.template @@ -169,7 +169,7 @@ hibernate.connection.url @DB_URL@ #hibernate.dialect org.hibernate.dialect.InterbaseDialect #hibernate.connection.username sysdba -#hibernate.connection.password masterkey +#hibernate.connection.password thepass ## DO NOT specify hibernate.connection.sqlDialect diff --git a/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java b/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java index 04083199e97a..3028bbb1805e 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java @@ -1669,7 +1669,7 @@ void cannotResolveNonNullableTransientDependencies( ) void applyingExplicitDiscriminatorColumnForJoined(String className, String overrideSetting); - // 458-466 reserved for use by master (ORM 5.0.0) + // 458-466 reserved for use by main branch (ORM 5.0.0) @LogMessage(level = DEBUG) @Message(value = "Creating pooled optimizer (lo) with [incrementSize=%s; returnClass=%s]", id = 467) diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/entity/FormalLastName.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/entity/FormalLastName.java index 7b283f58937d..f6a8bf5c4cb1 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/entity/FormalLastName.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/entity/FormalLastName.java @@ -26,7 +26,7 @@ public class FormalLastName { @Embedded private LastName lastName; - private String designation; /* Mr/Mrs/Master */ + private String designation; /* Mr/Mrs */ public Integer getId() { return id; diff --git a/hibernate-core/src/test/java/org/hibernate/test/fileimport/Dog.java b/hibernate-core/src/test/java/org/hibernate/test/fileimport/Dog.java index 2aae9d98d6f9..e35e6b004d58 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/fileimport/Dog.java +++ b/hibernate-core/src/test/java/org/hibernate/test/fileimport/Dog.java @@ -12,7 +12,7 @@ */ public class Dog { private Integer id; - private Human master; + private Human owner; public Integer getId() { return id; @@ -22,11 +22,11 @@ public void setId(Integer id) { this.id = id; } - public Human getMaster() { - return master; + public Human getOwner() { + return owner; } - public void setMaster(Human master) { - this.master = master; + public void setOwner(Human owner) { + this.owner = owner; } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/formulajoin/AnnotatedFormWithBeanValidationNotNullTest.java b/hibernate-core/src/test/java/org/hibernate/test/formulajoin/AnnotatedFormWithBeanValidationNotNullTest.java index 799ee3eb38a2..fdd052786a37 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/formulajoin/AnnotatedFormWithBeanValidationNotNullTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/formulajoin/AnnotatedFormWithBeanValidationNotNullTest.java @@ -21,7 +21,7 @@ public class AnnotatedFormWithBeanValidationNotNullTest extends BaseUnitTestCase @TestForIssue( jiraKey = "HHH-8167" ) public void testAnnotatedFormWithBeanValidationNotNull() { Configuration cfg = new Configuration(); - cfg.addAnnotatedClass( AnnotatedMaster.class ).addAnnotatedClass( AnnotatedDetail.class ); + cfg.addAnnotatedClass( AnnotatedRoot.class ).addAnnotatedClass( AnnotatedDetail.class ); cfg.buildSessionFactory().close(); } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/formulajoin/AnnotatedMaster.java b/hibernate-core/src/test/java/org/hibernate/test/formulajoin/AnnotatedRoot.java similarity index 97% rename from hibernate-core/src/test/java/org/hibernate/test/formulajoin/AnnotatedMaster.java rename to hibernate-core/src/test/java/org/hibernate/test/formulajoin/AnnotatedRoot.java index 0c0696ee9691..fdbaa8fe9714 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/formulajoin/AnnotatedMaster.java +++ b/hibernate-core/src/test/java/org/hibernate/test/formulajoin/AnnotatedRoot.java @@ -22,7 +22,7 @@ * @author Steve Ebersole */ @Entity -public class AnnotatedMaster { +public class AnnotatedRoot { @Id private Integer id; private String name; diff --git a/hibernate-core/src/test/java/org/hibernate/test/formulajoin/Detail.java b/hibernate-core/src/test/java/org/hibernate/test/formulajoin/Detail.java index c7b77e0502c0..029a9d2d6458 100755 --- a/hibernate-core/src/test/java/org/hibernate/test/formulajoin/Detail.java +++ b/hibernate-core/src/test/java/org/hibernate/test/formulajoin/Detail.java @@ -14,7 +14,7 @@ */ public class Detail implements Serializable { private Long id; - private Master master; + private Root root; private int version; private String details; private boolean currentVersion; @@ -37,11 +37,11 @@ public Long getId() { public void setId(Long id) { this.id = id; } - public Master getMaster() { - return master; + public Root getRoot() { + return root; } - public void setMaster(Master master) { - this.master = master; + public void setRoot(Root root) { + this.root = root; } public int getVersion() { return version; diff --git a/hibernate-core/src/test/java/org/hibernate/test/formulajoin/FormulaJoinTest.java b/hibernate-core/src/test/java/org/hibernate/test/formulajoin/FormulaJoinTest.java index fd423fab7a19..1279980adc2d 100755 --- a/hibernate-core/src/test/java/org/hibernate/test/formulajoin/FormulaJoinTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/formulajoin/FormulaJoinTest.java @@ -24,27 +24,27 @@ */ public class FormulaJoinTest extends BaseCoreFunctionalTestCase { public String[] getMappings() { - return new String[] { "formulajoin/Master.hbm.xml" }; + return new String[] { "formulajoin/Root.hbm.xml" }; } @Test public void testFormulaJoin() { Session s = openSession(); Transaction tx = s.beginTransaction(); - Master master = new Master(); - master.setName("master 1"); + Root root = new Root(); + root.setName("root 1"); Detail current = new Detail(); current.setCurrentVersion(true); current.setVersion(2); - current.setDetails("details of master 1 blah blah"); - current.setMaster(master); - master.setDetail(current); + current.setDetails("details of root 1 blah blah"); + current.setRoot( root ); + root.setDetail(current); Detail past = new Detail(); past.setCurrentVersion(false); past.setVersion(1); - past.setDetails("old details of master 1 yada yada"); - past.setMaster(master); - s.persist(master); + past.setDetails("old details of root 1 yada yada"); + past.setRoot( root ); + s.persist( root ); s.persist(past); s.persist(current); tx.commit(); @@ -54,42 +54,42 @@ public void testFormulaJoin() { s = openSession(); tx = s.beginTransaction(); - List l = s.createQuery("from Master m left join m.detail d").list(); + List l = s.createQuery("from Root m left join m.detail d").list(); assertEquals( l.size(), 1 ); tx.commit(); s.close(); s = openSession(); tx = s.beginTransaction(); - l = s.createQuery("from Master m left join fetch m.detail").list(); + l = s.createQuery("from Root m left join fetch m.detail").list(); assertEquals( l.size(), 1 ); - Master m = (Master) l.get(0); - assertEquals( "master 1", m.getDetail().getMaster().getName() ); - assertTrue( m==m.getDetail().getMaster() ); + Root m = (Root) l.get(0); + assertEquals( "root 1", m.getDetail().getRoot().getName() ); + assertTrue( m==m.getDetail().getRoot() ); tx.commit(); s.close(); s = openSession(); tx = s.beginTransaction(); - l = s.createQuery("from Master m join fetch m.detail").list(); + l = s.createQuery("from Root m join fetch m.detail").list(); assertEquals( l.size(), 1 ); tx.commit(); s.close(); s = openSession(); tx = s.beginTransaction(); - l = s.createQuery("from Detail d join fetch d.currentMaster.master").list(); + l = s.createQuery("from Detail d join fetch d.currentRoot.root").list(); assertEquals( l.size(), 2 ); tx.commit(); s.close(); s = openSession(); tx = s.beginTransaction(); - l = s.createQuery("from Detail d join fetch d.currentMaster.master m join fetch m.detail").list(); + l = s.createQuery("from Detail d join fetch d.currentRoot.root m join fetch m.detail").list(); assertEquals( l.size(), 2 ); s.createQuery("delete from Detail").executeUpdate(); - s.createQuery("delete from Master").executeUpdate(); + s.createQuery("delete from Root").executeUpdate(); tx.commit(); s.close(); diff --git a/hibernate-core/src/test/java/org/hibernate/test/formulajoin/Master.hbm.xml b/hibernate-core/src/test/java/org/hibernate/test/formulajoin/Root.hbm.xml similarity index 84% rename from hibernate-core/src/test/java/org/hibernate/test/formulajoin/Master.hbm.xml rename to hibernate-core/src/test/java/org/hibernate/test/formulajoin/Root.hbm.xml index 64217e528fca..022b2dfcc830 100755 --- a/hibernate-core/src/test/java/org/hibernate/test/formulajoin/Master.hbm.xml +++ b/hibernate-core/src/test/java/org/hibernate/test/formulajoin/Root.hbm.xml @@ -18,7 +18,7 @@ - + @@ -30,7 +30,7 @@ update="false"/> @@ -53,13 +53,13 @@ + unique-key="rootVersion"/> - - - + + . */ - -//$Id: Master.java 4602 2004-09-26 11:42:47Z oneovthafew $ package org.hibernate.test.formulajoin; + import java.io.Serializable; /** * @author Gavin King */ -public class Master implements Serializable { +public class Root implements Serializable { private Long id; private String name; private Detail detail; diff --git a/hibernate-core/src/test/java/org/hibernate/test/hql/DeleteQuerySubqueryReferencingTargetPropertyTest.java b/hibernate-core/src/test/java/org/hibernate/test/hql/DeleteQuerySubqueryReferencingTargetPropertyTest.java index 9e2be86721ae..a795755864e4 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/hql/DeleteQuerySubqueryReferencingTargetPropertyTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/hql/DeleteQuerySubqueryReferencingTargetPropertyTest.java @@ -21,45 +21,45 @@ public class DeleteQuerySubqueryReferencingTargetPropertyTest extends BaseEntity @Override protected Class[] getAnnotatedClasses() { - return new Class[] { Master.class, Detail.class }; + return new Class[] { Root.class, Detail.class }; } @Test public void testSubQueryReferencingTargetProperty() { // prepare doInJPA( this::entityManagerFactory, entityManager -> { - Master m1 = new Master(); + Root m1 = new Root(); entityManager.persist( m1 ); Detail d11 = new Detail( m1 ); entityManager.persist( d11 ); Detail d12 = new Detail( m1 ); entityManager.persist( d12 ); - Master m2 = new Master(); + Root m2 = new Root(); entityManager.persist( m2 ); } ); doInJPA( this::entityManagerFactory, entityManager -> { - // depending on the generated ids above this delete removes all masters or nothing - // removal of all masters results in foreign key constraint violation - // removal of nothing is incorrect since 2nd master does not have any details + // depending on the generated ids above this delete removes all Roots or nothing + // removal of all Roots results in foreign key constraint violation + // removal of nothing is incorrect since 2nd Root does not have any details // DO NOT CHANGE this query: it used to trigger a very specific bug caused // by the alias not being added to the generated query - String d = "delete from Master m where not exists (select d from Detail d where d.master=m)"; + String d = "delete from Root m where not exists (select d from Detail d where d.root=m)"; Query del = entityManager.createQuery( d ); del.executeUpdate(); - // so check for exactly one master after deletion + // so check for exactly one Root after deletion CriteriaBuilder builder = entityManager.getCriteriaBuilder(); - CriteriaQuery query = builder.createQuery( Master.class ); - query.select( query.from( Master.class ) ); + CriteriaQuery query = builder.createQuery( Root.class ); + query.select( query.from( Root.class ) ); Assert.assertEquals( 1, entityManager.createQuery( query ).getResultList().size() ); } ); } - @Entity(name = "Master") - public static class Master { + @Entity(name = "Root") + public static class Root { @Id @GeneratedValue private Integer id; @@ -72,10 +72,10 @@ public static class Detail { private Integer id; @ManyToOne(optional = false) - private Master master; + private Root root; - public Detail(Master master) { - this.master = master; + public Detail(Root root) { + this.root = root; } } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/hql/HQLTest.java b/hibernate-core/src/test/java/org/hibernate/test/hql/HQLTest.java index 1108a31b0399..beb71222b4bd 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/hql/HQLTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/hql/HQLTest.java @@ -445,8 +445,8 @@ public void testMultipleElementAccessorOperators() throws Exception { public void testKeyManyToOneJoin() { //TODO: new parser generates unnecessary joins (though the query results are correct) assertTranslation( "from Order o left join fetch o.lineItems li left join fetch li.product p" ); - assertTranslation( "from Outer o where o.id.master.id.sup.dudu is not null" ); - assertTranslation( "from Outer o where o.id.master.id.sup.dudu is not null" ); + assertTranslation( "from Outer o where o.id.root.id.sup.dudu is not null" ); + assertTranslation( "from Outer o where o.id.root.id.sup.dudu is not null" ); } @Test @@ -670,7 +670,7 @@ public void testFetchList() throws Exception { @Test public void testCollectionFetchWithExplicitThetaJoin() { - assertTranslation( "select m from Master m1, Master m left join fetch m.details where m.name=m1.name" ); + assertTranslation( "select m from Root m1, Root m left join fetch m.details where m.name=m1.name" ); } @Test diff --git a/hibernate-core/src/test/java/org/hibernate/test/hql/HqlParserTest.java b/hibernate-core/src/test/java/org/hibernate/test/hql/HqlParserTest.java index abf18473f272..ff92dc0f9e66 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/hql/HqlParserTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/hql/HqlParserTest.java @@ -676,16 +676,16 @@ public class HqlParserTest { parse( "from fo in class org.hibernate.test.Fo where fo.id.string like 'an instance of fo'" ); parse( "from org.hibernate.test.Inner" ); parse( "from org.hibernate.test.Outer o where o.id.detailId = ?" ); - parse( "from org.hibernate.test.Outer o where o.id.master.id.sup.dudu is not null" ); - parse( "from org.hibernate.test.Outer o where o.id.master.id.sup.id.akey is not null" ); - parse( "select o.id.master.id.sup.dudu from org.hibernate.test.Outer o where o.id.master.id.sup.dudu is not null" ); - parse( "select o.id.master.id.sup.id.akey from org.hibernate.test.Outer o where o.id.master.id.sup.id.akey is not null" ); - parse( "from org.hibernate.test.Outer o where o.id.master.bla = ''" ); - parse( "from org.hibernate.test.Outer o where o.id.master.id.one = ''" ); - parse( "from org.hibernate.test.Inner inn where inn.id.bkey is not null and inn.backOut.id.master.id.sup.id.akey > 'a'" ); - parse( "from org.hibernate.test.Outer as o left join o.id.master m left join m.id.sup where o.bubu is not null" ); - parse( "from org.hibernate.test.Outer as o left join o.id.master.id.sup s where o.bubu is not null" ); - parse( "from org.hibernate.test.Outer as o left join o.id.master m left join o.id.master.id.sup s where o.bubu is not null" ); + parse( "from org.hibernate.test.Outer o where o.id.main.id.sup.dudu is not null" ); + parse( "from org.hibernate.test.Outer o where o.id.main.id.sup.id.akey is not null" ); + parse( "select o.id.main.id.sup.dudu from org.hibernate.test.Outer o where o.id.main.id.sup.dudu is not null" ); + parse( "select o.id.main.id.sup.id.akey from org.hibernate.test.Outer o where o.id.main.id.sup.id.akey is not null" ); + parse( "from org.hibernate.test.Outer o where o.id.main.bla = ''" ); + parse( "from org.hibernate.test.Outer o where o.id.main.id.one = ''" ); + parse( "from org.hibernate.test.Inner inn where inn.id.bkey is not null and inn.backOut.id.main.id.sup.id.akey > 'a'" ); + parse( "from org.hibernate.test.Outer as o left join o.id.main m left join m.id.sup where o.bubu is not null" ); + parse( "from org.hibernate.test.Outer as o left join o.id.main.id.sup s where o.bubu is not null" ); + parse( "from org.hibernate.test.Outer as o left join o.id.main m left join o.id.main.id.sup s where o.bubu is not null" ); parse( "select fum1.fo from fum1 in class org.hibernate.test.Fum where fum1.fo.fum is not null" ); parse( "from fum1 in class org.hibernate.test.Fum where fum1.fo.fum is not null order by fum1.fo.fum" ); parse( "select elements(fum1.friends) from fum1 in class org.hibernate.test.Fum" ); @@ -696,7 +696,7 @@ public class HqlParserTest { parse( "from org.hibernate.test.Up up order by up.id2 asc" ); parse( "from org.hibernate.test.Down down" ); parse( "from org.hibernate.test.Up up" ); - parse( "from m in class org.hibernate.test.Master" ); + parse( "from m in class org.hibernate.test.Root" ); parse( "from s in class org.hibernate.test.Several" ); parse( "from s in class org.hibernate.test.Single" ); parse( "\n" + @@ -915,11 +915,11 @@ public class HqlParserTest { parse( "from bar in class org.hibernate.test.Bar, foo in elements(bar.baz.fooSet)" ); parse( "from one in class org.hibernate.test.One, many in elements(one.manies) where one.id = 1 and many.id = 1" ); parse( "from org.hibernate.test.Inner _inner join _inner.middles middle" ); - parse( "FROM m IN CLASS org.hibernate.test.Master WHERE NOT EXISTS ( FROM d IN elements(m.details) WHERE NOT d.i=5 )" ); - parse( "FROM m IN CLASS org.hibernate.test.Master WHERE NOT 5 IN ( SELECT d.i FROM d IN elements(m.details) )" ); - parse( "SELECT m FROM m IN CLASS org.hibernate.test.Master, d IN elements(m.details) WHERE d.i=5" ); - parse( "SELECT m FROM m IN CLASS org.hibernate.test.Master, d IN elements(m.details) WHERE d.i=5" ); - parse( "SELECT m.id FROM m IN CLASS org.hibernate.test.Master, d IN elements(m.details) WHERE d.i=5" ); + parse( "FROM m IN CLASS org.hibernate.test.Root WHERE NOT EXISTS ( FROM d IN elements(m.details) WHERE NOT d.i=5 )" ); + parse( "FROM m IN CLASS org.hibernate.test.Root WHERE NOT 5 IN ( SELECT d.i FROM d IN elements(m.details) )" ); + parse( "SELECT m FROM m IN CLASS org.hibernate.test.Root, d IN elements(m.details) WHERE d.i=5" ); + parse( "SELECT m FROM m IN CLASS org.hibernate.test.Root, d IN elements(m.details) WHERE d.i=5" ); + parse( "SELECT m.id FROM m IN CLASS org.hibernate.test.Root, d IN elements(m.details) WHERE d.i=5" ); // I'm not sure about these... [jsd] // parse("select bar.string, foo.string from bar in class org.hibernate.test.Bar inner join bar.baz as baz inner join elements(baz.fooSet) as foo where baz.name = 'name'"); // parse("select bar.string, foo.string from bar in class org.hibernate.test.Bar, bar.baz as baz, elements(baz.fooSet) as foo where baz.name = 'name'"); diff --git a/hibernate-core/src/test/java/org/hibernate/test/hql/QueryTranslatorTestCase.java b/hibernate-core/src/test/java/org/hibernate/test/hql/QueryTranslatorTestCase.java index 007c05b8a14b..5e921f21b0fa 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/hql/QueryTranslatorTestCase.java +++ b/hibernate-core/src/test/java/org/hibernate/test/hql/QueryTranslatorTestCase.java @@ -61,7 +61,7 @@ public String[] getMappings() { "legacy/Holder.hbm.xml", "legacy/Many.hbm.xml", "legacy/Marelo.hbm.xml", - "legacy/MasterDetail.hbm.xml", + "legacy/RootDetail.hbm.xml", "legacy/Middle.hbm.xml", "legacy/Multi.hbm.xml", "legacy/Nameable.hbm.xml", diff --git a/hibernate-core/src/test/java/org/hibernate/test/hql/UpdateJoinedSubclassCorrelationTest.java b/hibernate-core/src/test/java/org/hibernate/test/hql/UpdateJoinedSubclassCorrelationTest.java index 1939a48f5931..170085795706 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/hql/UpdateJoinedSubclassCorrelationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/hql/UpdateJoinedSubclassCorrelationTest.java @@ -19,14 +19,14 @@ public class UpdateJoinedSubclassCorrelationTest extends BaseEntityManagerFuncti @Override protected Class[] getAnnotatedClasses() { - return new Class[] { Master.class, SubMaster.class, Detail.class }; + return new Class[] { Root.class, SubRoot.class, Detail.class }; } @Test public void testJoinedSubclassUpdateWithCorrelation() { // prepare doInJPA( this::entityManagerFactory, entityManager -> { - Master m1 = new SubMaster( 1, null ); + Root m1 = new SubRoot( 1, null ); entityManager.persist( m1 ); Detail d11 = new Detail( 10, m1 ); entityManager.persist( d11 ); @@ -35,40 +35,40 @@ public void testJoinedSubclassUpdateWithCorrelation() { doInJPA( this::entityManagerFactory, entityManager -> { // DO NOT CHANGE this query: it used to trigger a very specific bug caused // by the root table alias being added to the generated subquery instead of the table name - String u = "update SubMaster m set name = (select 'test' from Detail d where d.master = m)"; + String u = "update SubRoot m set name = (select 'test' from Detail d where d.root = m)"; Query updateQuery = entityManager.createQuery( u ); updateQuery.executeUpdate(); - // so check if the name of the SubMaster has been correctly updated + // so check if the name of the SubRoot has been correctly updated CriteriaBuilder builder = entityManager.getCriteriaBuilder(); - CriteriaQuery query = builder.createQuery( Master.class ); - query.select( query.from( Master.class ) ); - List masters = entityManager.createQuery( query ).getResultList(); - Assert.assertEquals( 1, masters.size() ); - Assert.assertEquals( "test", ((SubMaster) masters.get(0)).name ); + CriteriaQuery query = builder.createQuery( Root.class ); + query.select( query.from( Root.class ) ); + List roots = entityManager.createQuery( query ).getResultList(); + Assert.assertEquals( 1, roots.size() ); + Assert.assertEquals( "test", ((SubRoot) roots.get(0)).name ); } ); } @Inheritance(strategy = JOINED) - @Entity(name = "Master") - public static abstract class Master { + @Entity(name = "Root") + public static abstract class Root { @Id private Integer id; - public Master() { } + public Root() { } - public Master( Integer id ) { + public Root(Integer id ) { this.id = id; } } - @Entity(name = "SubMaster") - public static class SubMaster extends Master { + @Entity(name = "SubRoot") + public static class SubRoot extends Root { private String name; - public SubMaster() { } + public SubRoot() { } - public SubMaster( Integer id, String name ) { + public SubRoot(Integer id, String name ) { super(id); this.name = name; } @@ -80,11 +80,11 @@ public static class Detail { private Integer id; @ManyToOne(optional = false) - private Master master; + private Root root; - public Detail( Integer id, Master master ) { + public Detail( Integer id, Root root) { this.id = id; - this.master = master; + this.root = root; } } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/legacy/ComponentNotNullMaster.hbm.xml b/hibernate-core/src/test/java/org/hibernate/test/legacy/ComponentNotNullRoot.hbm.xml similarity index 87% rename from hibernate-core/src/test/java/org/hibernate/test/legacy/ComponentNotNullMaster.hbm.xml rename to hibernate-core/src/test/java/org/hibernate/test/legacy/ComponentNotNullRoot.hbm.xml index cd5bd4dc4c70..6a1fe999e378 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/legacy/ComponentNotNullMaster.hbm.xml +++ b/hibernate-core/src/test/java/org/hibernate/test/legacy/ComponentNotNullRoot.hbm.xml @@ -11,7 +11,7 @@ - + @@ -28,10 +28,10 @@ - + - + @@ -40,15 +40,15 @@ - + - + - + diff --git a/hibernate-core/src/test/java/org/hibernate/test/legacy/ComponentNotNullMaster.java b/hibernate-core/src/test/java/org/hibernate/test/legacy/ComponentNotNullRoot.java similarity index 95% rename from hibernate-core/src/test/java/org/hibernate/test/legacy/ComponentNotNullMaster.java rename to hibernate-core/src/test/java/org/hibernate/test/legacy/ComponentNotNullRoot.java index 03ead8f2c1ed..caa3ff0d4e42 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/legacy/ComponentNotNullMaster.java +++ b/hibernate-core/src/test/java/org/hibernate/test/legacy/ComponentNotNullRoot.java @@ -4,9 +4,8 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ - -//$Id: ComponentNotNullMaster.java 4599 2004-09-26 05:18:27Z oneovthafew $ package org.hibernate.test.legacy; + import java.util.List; /** @@ -14,7 +13,7 @@ * * @author Emmanuel Bernard */ -public class ComponentNotNullMaster { +public class ComponentNotNullRoot { private int id; private String test; diff --git a/hibernate-core/src/test/java/org/hibernate/test/legacy/ComponentNotNullTest.java b/hibernate-core/src/test/java/org/hibernate/test/legacy/ComponentNotNullTest.java index 213371129f34..f10171321c7d 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/legacy/ComponentNotNullTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/legacy/ComponentNotNullTest.java @@ -26,7 +26,7 @@ public class ComponentNotNullTest extends LegacyTestCase { @Override public String[] getMappings() { return new String[] { - "legacy/ComponentNotNullMaster.hbm.xml", + "legacy/ComponentNotNullRoot.hbm.xml", "legacy/One.hbm.xml", "legacy/Many.hbm.xml", "legacy/Simple.hbm.xml" }; @@ -45,16 +45,16 @@ public void testComponentNotNull() throws Exception { // Session s = openSession(); Transaction t = s.beginTransaction(); - ComponentNotNullMaster master = new ComponentNotNullMaster(); + ComponentNotNullRoot root = new ComponentNotNullRoot(); ComponentNotNull nullable = new ComponentNotNull(); ComponentNotNull supercomp = new ComponentNotNull(); ComponentNotNull subcomp = new ComponentNotNull(); - master.setNullable(nullable); + root.setNullable(nullable); subcomp.setProp1Subcomp("test"); supercomp.setSubcomp(subcomp); - master.setSupercomp(supercomp); - s.save(master); + root.setSupercomp(supercomp); + s.save(root); t.commit(); s.close(); @@ -63,20 +63,20 @@ public void testComponentNotNull() throws Exception { s = openSession(); t = s.beginTransaction(); - master = new ComponentNotNullMaster(); + root = new ComponentNotNullRoot(); nullable = new ComponentNotNull(); supercomp = new ComponentNotNull(); subcomp = new ComponentNotNull(); - master.setNullable(nullable); + root.setNullable(nullable); // do not set property //subcomp.setProp1Subcomp("test"); supercomp.setSubcomp(subcomp); - master.setSupercomp(supercomp); + root.setSupercomp(supercomp); try { - s.save(master); + s.save(root); t.commit(); fail("Inserting not-null null property should fail"); } catch (PropertyValueException e) { @@ -90,20 +90,20 @@ public void testComponentNotNull() throws Exception { s = openSession(); t = s.beginTransaction(); - master = new ComponentNotNullMaster(); + root = new ComponentNotNullRoot(); nullable = new ComponentNotNull(); supercomp = new ComponentNotNull(); subcomp = new ComponentNotNull(); - master.setNullable(nullable); - // do not set supercomp for master + root.setNullable(nullable); + // do not set supercomp for root //subcomp.setProp1Subcomp("test"); //supercomp.setSubcomp(subcomp); - //master.setSupercomp(supercomp); + //root.setSupercomp(supercomp); try { - s.save(master); + s.save(root); t.commit(); fail("Inserting not-null null property should fail"); } catch (PropertyValueException e) { @@ -118,23 +118,23 @@ public void testCompositeElement() throws Exception { //composite-element nullable Session s = openSession(); Transaction t = s.beginTransaction(); - ComponentNotNullMaster master = new ComponentNotNullMaster(); + ComponentNotNullRoot root = new ComponentNotNullRoot(); ComponentNotNull nullable = new ComponentNotNull(); ComponentNotNull supercomp = new ComponentNotNull(); ComponentNotNull subcomp = new ComponentNotNull(); - master.setNullable(nullable); + root.setNullable(nullable); subcomp.setProp1Subcomp("test"); supercomp.setSubcomp(subcomp); - master.setSupercomp(supercomp); + root.setSupercomp(supercomp); - master.setComponents(new ArrayList()); - ComponentNotNullMaster.ContainerInnerClass cc = - new ComponentNotNullMaster.ContainerInnerClass(); - master.getComponents().add(cc); + root.setComponents(new ArrayList()); + ComponentNotNullRoot.ContainerInnerClass cc = + new ComponentNotNullRoot.ContainerInnerClass(); + root.getComponents().add(cc); try { - s.save(master); + s.save(root); t.commit(); fail("Inserting not-null many-to-one should fail"); } catch (PropertyValueException e) { @@ -148,26 +148,26 @@ public void testCompositeElement() throws Exception { s = openSession(); t = s.beginTransaction(); - master = new ComponentNotNullMaster(); + root = new ComponentNotNullRoot(); nullable = new ComponentNotNull(); supercomp = new ComponentNotNull(); subcomp = new ComponentNotNull(); - master.setNullable(nullable); + root.setNullable(nullable); subcomp.setProp1Subcomp("test"); supercomp.setSubcomp(subcomp); - master.setSupercomp(supercomp); + root.setSupercomp(supercomp); - master.setComponentsImplicit(new ArrayList()); - ComponentNotNullMaster.ContainerInnerClass nestedCc = - new ComponentNotNullMaster.ContainerInnerClass(); + root.setComponentsImplicit(new ArrayList()); + ComponentNotNullRoot.ContainerInnerClass nestedCc = + new ComponentNotNullRoot.ContainerInnerClass(); cc = - new ComponentNotNullMaster.ContainerInnerClass(); + new ComponentNotNullRoot.ContainerInnerClass(); cc.setNested(nestedCc); - master.getComponentsImplicit().add(cc); + root.getComponentsImplicit().add(cc); try { - s.save(master); + s.save(root); t.commit(); fail("Inserting not-null null property should fail"); } catch (PropertyValueException e) { @@ -181,26 +181,26 @@ public void testCompositeElement() throws Exception { s = openSession(); t = s.beginTransaction(); - master = new ComponentNotNullMaster(); + root = new ComponentNotNullRoot(); nullable = new ComponentNotNull(); supercomp = new ComponentNotNull(); subcomp = new ComponentNotNull(); - master.setNullable(nullable); + root.setNullable(nullable); subcomp.setProp1Subcomp("test"); supercomp.setSubcomp(subcomp); - master.setSupercomp(supercomp); + root.setSupercomp(supercomp); - master.setComponentsImplicit(new ArrayList()); + root.setComponentsImplicit(new ArrayList()); nestedCc = - new ComponentNotNullMaster.ContainerInnerClass(); + new ComponentNotNullRoot.ContainerInnerClass(); cc = - new ComponentNotNullMaster.ContainerInnerClass(); + new ComponentNotNullRoot.ContainerInnerClass(); cc.setNested(nestedCc); nestedCc.setNestedproperty("test"); - master.getComponentsImplicit().add(cc); + root.getComponentsImplicit().add(cc); - s.save(master); + s.save(root); t.commit(); s.close(); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/legacy/Detail.java b/hibernate-core/src/test/java/org/hibernate/test/legacy/Detail.java index a7f29fa9f8a0..441fc7e25670 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/legacy/Detail.java +++ b/hibernate-core/src/test/java/org/hibernate/test/legacy/Detail.java @@ -13,7 +13,7 @@ public class Detail implements Serializable { - private Master master; + private Root root; private int i; private Set details = new HashSet(); private int x; @@ -25,12 +25,12 @@ public void setX(int x) { this.x = x; } - public Master getMaster() { - return master; + public Root getRoot() { + return root; } - public void setMaster(Master master) { - this.master = master; + public void setRoot(Root root) { + this.root = root; } public int getI() { diff --git a/hibernate-core/src/test/java/org/hibernate/test/legacy/FumTest.java b/hibernate-core/src/test/java/org/hibernate/test/legacy/FumTest.java index 7fffc1a26757..8f6032765cab 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/legacy/FumTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/legacy/FumTest.java @@ -663,7 +663,7 @@ public void testKeyManyToOne() throws Exception { m.setBla("bla"); Outer d = new Outer(); OuterKey did = new OuterKey(); - did.setMaster(m); + did.setRoot(m); did.setDetailId("detail"); d.setId(did); d.setBubu("bubu"); @@ -689,10 +689,10 @@ public void testKeyManyToOne() throws Exception { s = openSession(); s.beginTransaction(); d = (Outer) s.load(Outer.class, did); - assertTrue( d.getId().getMaster().getId().getSup().getDudu().equals("dudu") ); + assertTrue( d.getId().getRoot().getId().getSup().getDudu().equals("dudu") ); s.delete(d); - s.delete( d.getId().getMaster() ); - s.save( d.getId().getMaster() ); + s.delete( d.getId().getRoot() ); + s.save( d.getId().getRoot() ); s.save(d); s.getTransaction().commit(); s.close(); @@ -703,29 +703,29 @@ public void testKeyManyToOne() throws Exception { .setParameter( 0, d.getId().getDetailId(), StandardBasicTypes.STRING ) .list() .get(0); - s.createQuery( "from Outer o where o.id.master.id.sup.dudu is not null" ).list(); - s.createQuery( "from Outer o where o.id.master.id.sup.id.akey is not null" ).list(); - s.createQuery( "from Inner i where i.backOut.id.master.id.sup.id.akey = i.id.bkey" ).list(); - List l = s.createQuery( "select o.id.master.id.sup.dudu from Outer o where o.id.master.id.sup.dudu is not null" ) + s.createQuery( "from Outer o where o.id.root.id.sup.dudu is not null" ).list(); + s.createQuery( "from Outer o where o.id.root.id.sup.id.akey is not null" ).list(); + s.createQuery( "from Inner i where i.backOut.id.root.id.sup.id.akey = i.id.bkey" ).list(); + List l = s.createQuery( "select o.id.root.id.sup.dudu from Outer o where o.id.root.id.sup.dudu is not null" ) .list(); assertTrue(l.size()==1); - l = s.createQuery( "select o.id.master.id.sup.id.akey from Outer o where o.id.master.id.sup.id.akey is not null" ) + l = s.createQuery( "select o.id.root.id.sup.id.akey from Outer o where o.id.root.id.sup.id.akey is not null" ) .list(); assertTrue(l.size()==1); s.createQuery( - "select i.backOut.id.master.id.sup.id.akey from Inner i where i.backOut.id.master.id.sup.id.akey = i.id.bkey" + "select i.backOut.id.root.id.sup.id.akey from Inner i where i.backOut.id.root.id.sup.id.akey = i.id.bkey" ).list(); - s.createQuery( "from Outer o where o.id.master.bla = ''" ).list(); - s.createQuery( "from Outer o where o.id.master.id.one = ''" ).list(); - s.createQuery( "from Inner inn where inn.id.bkey is not null and inn.backOut.id.master.id.sup.id.akey > 'a'" ) + s.createQuery( "from Outer o where o.id.root.bla = ''" ).list(); + s.createQuery( "from Outer o where o.id.root.id.one = ''" ).list(); + s.createQuery( "from Inner inn where inn.id.bkey is not null and inn.backOut.id.root.id.sup.id.akey > 'a'" ) .list(); - s.createQuery( "from Outer as o left join o.id.master m left join m.id.sup where o.bubu is not null" ).list(); - s.createQuery( "from Outer as o left join o.id.master.id.sup s where o.bubu is not null" ).list(); - s.createQuery( "from Outer as o left join o.id.master m left join o.id.master.id.sup s where o.bubu is not null" ) + s.createQuery( "from Outer as o left join o.id.root m left join m.id.sup where o.bubu is not null" ).list(); + s.createQuery( "from Outer as o left join o.id.root.id.sup s where o.bubu is not null" ).list(); + s.createQuery( "from Outer as o left join o.id.root m left join o.id.root.id.sup s where o.bubu is not null" ) .list(); s.delete(d); - s.delete( d.getId().getMaster() ); - s.delete( d.getId().getMaster().getId().getSup() ); + s.delete( d.getId().getRoot() ); + s.delete( d.getId().getRoot().getId().getSup() ); s.getTransaction().commit(); s.close(); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/legacy/Middle.hbm.xml b/hibernate-core/src/test/java/org/hibernate/test/legacy/Middle.hbm.xml index ccd2cc55d338..40fa3ef6767e 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/legacy/Middle.hbm.xml +++ b/hibernate-core/src/test/java/org/hibernate/test/legacy/Middle.hbm.xml @@ -47,7 +47,7 @@ - + diff --git a/hibernate-core/src/test/java/org/hibernate/test/legacy/Middle.java b/hibernate-core/src/test/java/org/hibernate/test/legacy/Middle.java index e0efcc371143..813b65b909d3 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/legacy/Middle.java +++ b/hibernate-core/src/test/java/org/hibernate/test/legacy/Middle.java @@ -34,9 +34,9 @@ public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof Middle)) return false; - final Middle cidMaster = (Middle) o; + final Middle cidMiddle = (Middle) o; - if (id != null ? !id.equals(cidMaster.id) : cidMaster.id != null) return false; + if (id != null ? !id.equals(cidMiddle.id) : cidMiddle.id != null) return false; return true; } diff --git a/hibernate-core/src/test/java/org/hibernate/test/legacy/MiddleKey.java b/hibernate-core/src/test/java/org/hibernate/test/legacy/MiddleKey.java index 210ecde164f4..c39ed22383e1 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/legacy/MiddleKey.java +++ b/hibernate-core/src/test/java/org/hibernate/test/legacy/MiddleKey.java @@ -43,11 +43,11 @@ public boolean equals(Object o) { if (this == o) return true; if (!(o instanceof MiddleKey)) return false; - final MiddleKey cidMasterID = (MiddleKey) o; + final MiddleKey cidMiddleKey = (MiddleKey) o; - if (one != null ? !one.equals(cidMasterID.one) : cidMasterID.one != null) return false; - if (sup != null ? !sup.equals(cidMasterID.sup) : cidMasterID.sup != null) return false; - if (two != null ? !two.equals(cidMasterID.two) : cidMasterID.two != null) return false; + if (one != null ? !one.equals(cidMiddleKey.one) : cidMiddleKey.one != null) return false; + if (sup != null ? !sup.equals(cidMiddleKey.sup) : cidMiddleKey.sup != null) return false; + if (two != null ? !two.equals(cidMiddleKey.two) : cidMiddleKey.two != null) return false; return true; } diff --git a/hibernate-core/src/test/java/org/hibernate/test/legacy/OuterKey.java b/hibernate-core/src/test/java/org/hibernate/test/legacy/OuterKey.java index 267c64714944..52934eb06343 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/legacy/OuterKey.java +++ b/hibernate-core/src/test/java/org/hibernate/test/legacy/OuterKey.java @@ -11,15 +11,15 @@ * @author Stefano Travelli */ public class OuterKey implements Serializable { - private Middle master; + private Middle root; private String detailId; - public Middle getMaster() { - return master; + public Middle getRoot() { + return root; } - public void setMaster(Middle master) { - this.master = master; + public void setRoot(Middle root) { + this.root = root; } public String getDetailId() { @@ -37,14 +37,14 @@ public boolean equals(Object o) { final OuterKey cidDetailID = (OuterKey) o; if (detailId != null ? !detailId.equals(cidDetailID.detailId) : cidDetailID.detailId != null) return false; - if (master != null ? !master.equals(cidDetailID.master) : cidDetailID.master != null) return false; + if ( root != null ? !root.equals(cidDetailID.root ) : cidDetailID.root != null) return false; return true; } public int hashCode() { int result; - result = (master != null ? master.hashCode() : 0); + result = ( root != null ? root.hashCode() : 0); result = 29 * result + (detailId != null ? detailId.hashCode() : 0); return result; } diff --git a/hibernate-core/src/test/java/org/hibernate/test/legacy/QueryByExampleTest.java b/hibernate-core/src/test/java/org/hibernate/test/legacy/QueryByExampleTest.java index 8b985f16ad54..1655227bab42 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/legacy/QueryByExampleTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/legacy/QueryByExampleTest.java @@ -39,9 +39,9 @@ public void testSimpleQBE() throws Exception { Session s = openSession(); Transaction t = s.beginTransaction(); - Componentizable master = getMaster("hibernate", "open sourc%", "open source1"); + Componentizable componentizable = getComponentizeable("hibernate", "open sourc%", "open source1"); Criteria crit = s.createCriteria(Componentizable.class); - Example ex = Example.create(master).enableLike(); + Example ex = Example.create(componentizable).enableLike(); crit.add(ex); List result = crit.list(); assertNotNull(result); @@ -58,9 +58,9 @@ public void testJunctionNotExpressionQBE() throws Exception { initData(); Session s = openSession(); Transaction t = s.beginTransaction(); - Componentizable master = getMaster("hibernate", null, "ope%"); + Componentizable componentizeable = getComponentizeable("hibernate", null, "ope%"); Criteria crit = s.createCriteria(Componentizable.class); - Example ex = Example.create(master).enableLike(); + Example ex = Example.create(componentizeable).enableLike(); crit.add(Restrictions.or(Restrictions.not(ex), ex)); @@ -78,18 +78,18 @@ public void testExcludingQBE() throws Exception { initData(); Session s = openSession(); Transaction t = s.beginTransaction(); - Componentizable master = getMaster("hibernate", null, "ope%"); + Componentizable componentizeable = getComponentizeable("hibernate", null, "ope%"); Criteria crit = s.createCriteria(Componentizable.class); - Example ex = Example.create(master).enableLike() + Example ex = Example.create(componentizeable).enableLike() .excludeProperty("component.subComponent"); crit.add(ex); List result = crit.list(); assertNotNull(result); assertEquals(3, result.size()); - master = getMaster("hibernate", "ORM tool", "fake stuff"); + componentizeable = getComponentizeable("hibernate", "ORM tool", "fake stuff"); crit = s.createCriteria(Componentizable.class); - ex = Example.create(master).enableLike() + ex = Example.create(componentizeable).enableLike() .excludeProperty("component.subComponent.subName1"); crit.add(ex); result = crit.list(); @@ -104,12 +104,12 @@ public void testExcludingQBE() throws Exception { private void initData() throws Exception { Session s = openSession(); Transaction t = s.beginTransaction(); - Componentizable master = getMaster("hibernate", "ORM tool", "ORM tool1"); - s.saveOrUpdate(master); - master = getMaster("hibernate", "open source", "open source1"); - s.saveOrUpdate(master); - master = getMaster("hibernate", null, null); - s.saveOrUpdate(master); + Componentizable componentizeable = getComponentizeable("hibernate", "ORM tool", "ORM tool1"); + s.saveOrUpdate(componentizeable); + componentizeable = getComponentizeable("hibernate", "open source", "open source1"); + s.saveOrUpdate(componentizeable); + componentizeable = getComponentizeable("hibernate", null, null); + s.saveOrUpdate(componentizeable); t.commit(); s.close(); } @@ -124,19 +124,19 @@ private void deleteData() throws Exception { s.close(); } - private Componentizable getMaster(String name, String subname, String subname1) { - Componentizable master = new Componentizable(); + private Componentizable getComponentizeable(String name, String subname, String subname1) { + Componentizable componentizable = new Componentizable(); if (name != null) { - Component masterComp = new Component(); - masterComp.setName(name); + Component component = new Component(); + component.setName(name); if (subname != null || subname1 != null) { SubComponent subComponent = new SubComponent(); subComponent.setSubName(subname); subComponent.setSubName1(subname1); - masterComp.setSubComponent(subComponent); + component.setSubComponent(subComponent); } - master.setComponent(masterComp); + componentizable.setComponent(component); } - return master; + return componentizable; } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/legacy/Master.java b/hibernate-core/src/test/java/org/hibernate/test/legacy/Root.java similarity index 82% rename from hibernate-core/src/test/java/org/hibernate/test/legacy/Master.java rename to hibernate-core/src/test/java/org/hibernate/test/legacy/Root.java index 7abca78fc936..60147f72b119 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/legacy/Master.java +++ b/hibernate-core/src/test/java/org/hibernate/test/legacy/Root.java @@ -4,9 +4,8 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ - -//$Id: Master.java 4599 2004-09-26 05:18:27Z oneovthafew $ package org.hibernate.test.legacy; + import java.io.Serializable; import java.math.BigDecimal; import java.util.Collection; @@ -14,21 +13,21 @@ import java.util.HashSet; import java.util.Set; -public class Master implements Serializable, Named { +public class Root implements Serializable, Named { private Long id; - private Master otherMaster; + private Root otherRoot; private Set details = new HashSet(); private Set moreDetails = new HashSet(); private Set incoming = new HashSet(); private Set outgoing = new HashSet(); - private String name="master"; + private String name="root"; private Date stamp; private int version; private BigDecimal bigDecimal = new BigDecimal("1234.123"); private int x; private Collection allDetails; - public Master() { + public Root() { } public Long getId() { @@ -63,19 +62,19 @@ public void removeDetail(Detail d) { details.remove(d); } - public void addIncoming(Master m) { + public void addIncoming(Root m) { incoming.add(m); } - public void removeIncoming(Master m) { + public void removeIncoming(Root m) { incoming.remove(m); } - public void addOutgoing(Master m) { + public void addOutgoing(Root m) { outgoing.add(m); } - public void removeOutgoing(Master m) { + public void removeOutgoing(Root m) { outgoing.remove(m); } @@ -130,15 +129,15 @@ public void setBigDecimal(BigDecimal bigDecimal) { /** * @return */ - public Master getOtherMaster() { - return otherMaster; + public Root getOtherRoot() { + return otherRoot; } /** - * @param master + * @param root */ - public void setOtherMaster(Master master) { - otherMaster = master; + public void setOtherRoot(Root root) { + otherRoot = root; } /** diff --git a/hibernate-core/src/test/java/org/hibernate/test/legacy/MasterDetail.hbm.xml b/hibernate-core/src/test/java/org/hibernate/test/legacy/RootDetail.hbm.xml similarity index 82% rename from hibernate-core/src/test/java/org/hibernate/test/legacy/MasterDetail.hbm.xml rename to hibernate-core/src/test/java/org/hibernate/test/legacy/RootDetail.hbm.xml index 207bb348dd2f..ce91ed1cea03 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/legacy/MasterDetail.hbm.xml +++ b/hibernate-core/src/test/java/org/hibernate/test/legacy/RootDetail.hbm.xml @@ -11,9 +11,9 @@ - + foo - + @@ -26,24 +26,24 @@ - + - + - + - + - + @@ -57,8 +57,8 @@ - - + + diff --git a/hibernate-core/src/test/java/org/hibernate/test/legacy/MasterDetailTest.java b/hibernate-core/src/test/java/org/hibernate/test/legacy/RootDetailTest.java similarity index 80% rename from hibernate-core/src/test/java/org/hibernate/test/legacy/MasterDetailTest.java rename to hibernate-core/src/test/java/org/hibernate/test/legacy/RootDetailTest.java index f5e4409cbfc5..e48eea4bfdf9 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/legacy/MasterDetailTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/legacy/RootDetailTest.java @@ -34,11 +34,11 @@ import static org.junit.Assert.assertTrue; -public class MasterDetailTest extends LegacyTestCase { +public class RootDetailTest extends LegacyTestCase { @Override public String[] getMappings() { return new String[] { - "legacy/MasterDetail.hbm.xml", + "legacy/RootDetail.hbm.xml", "legacy/Custom.hbm.xml", "legacy/Category.hbm.xml", "legacy/Nameable.hbm.xml", @@ -87,15 +87,6 @@ public void testOuterJoin() throws Exception { s.close(); } -// @Test -// public void testMeta() throws Exception { -// PersistentClass clazz = configuration().getClassMapping( Master.class.getName() ); -// MetaAttribute meta = clazz.getMetaAttribute("foo"); -// assertTrue( "foo".equals( meta.getValue() ) ); -// meta = clazz.getProperty("name").getMetaAttribute("bar"); -// assertTrue( meta.isMultiValued() ); -// } - @Test @SuppressWarnings( {"unchecked"}) public void testCopy() throws Exception { @@ -196,19 +187,19 @@ public void testNotNullDiscriminator() throws Exception { public void testSelfManyToOne() throws Exception { Session s = openSession(); Transaction t = s.beginTransaction(); - Master m = new Master(); - m.setOtherMaster(m); + Root m = new Root(); + m.setOtherRoot(m); s.save(m); t.commit(); s.close(); s = openSession(); t = s.beginTransaction(); - Iterator i = s.createQuery( "from Master" ).iterate(); - m = (Master) i.next(); - assertTrue( m.getOtherMaster()==m ); + Iterator i = s.createQuery( "from Root" ).iterate(); + m = (Root) i.next(); + assertTrue( m.getOtherRoot()==m ); if ( getDialect() instanceof HSQLDialect || getDialect() instanceof MySQLDialect ) { - m.setOtherMaster(null); + m.setOtherRoot(null); s.flush(); } s.delete(m); @@ -221,41 +212,41 @@ public void testSelfManyToOne() throws Exception { public void testExample() throws Exception { Session s = openSession(); Transaction t = s.beginTransaction(); - Master m = new Master(); + Root m = new Root(); m.setName("name"); m.setX(5); - m.setOtherMaster(m); + m.setOtherRoot(m); s.save(m); t.commit(); s.close(); s = openSession(); t = s.beginTransaction(); - Master m1 = (Master) s.createCriteria(Master.class) + Root m1 = (Root) s.createCriteria( Root.class) .add( Example.create(m).enableLike().ignoreCase().excludeProperty("bigDecimal") ) .uniqueResult(); - assertTrue( m1.getOtherMaster()==m1 ); - m1 = (Master) s.createCriteria(Master.class) + assertTrue( m1.getOtherRoot()==m1 ); + m1 = (Root) s.createCriteria( Root.class) .add( Restrictions.eq("name", "foobar") ) .uniqueResult(); assertTrue( m1==null ); - m1 = (Master) s.createCriteria(Master.class) + m1 = (Root) s.createCriteria( Root.class) .add( Example.create(m).excludeProperty("bigDecimal") ) - .createCriteria("otherMaster") + .createCriteria("otherRoot") .add( Example.create(m).excludeZeroes().excludeProperty("bigDecimal") ) .uniqueResult(); - assertTrue( m1.getOtherMaster()==m1 ); - Master m2 = (Master) s.createCriteria(Master.class) + assertTrue( m1.getOtherRoot()==m1 ); + Root m2 = (Root) s.createCriteria( Root.class) .add( Example.create(m).excludeNone().excludeProperty("bigDecimal") ) .uniqueResult(); assertTrue( m2==m1 ); m.setName(null); - m2 = (Master) s.createCriteria(Master.class) + m2 = (Root) s.createCriteria( Root.class) .add( Example.create(m).excludeNone().excludeProperty("bigDecimal") ) .uniqueResult(); assertTrue( null == m2 ); if (getDialect() instanceof HSQLDialect || getDialect() instanceof MySQLDialect) { - m1.setOtherMaster(null); + m1.setOtherRoot(null); s.flush(); } s.delete(m1); @@ -307,39 +298,39 @@ public void testCollectionQuery() throws Exception { Session s = openSession(); Transaction t = s.beginTransaction(); if ( !(getDialect() instanceof MySQLDialect) && !(getDialect() instanceof SAPDBDialect) && !(getDialect() instanceof MckoiDialect) ) { - s.createQuery( "FROM Master m WHERE NOT EXISTS ( FROM m.details d WHERE NOT d.i=5 )" ).iterate(); - s.createQuery( "FROM Master m WHERE NOT 5 IN ( SELECT d.i FROM m.details AS d )" ).iterate(); + s.createQuery( "FROM Root m WHERE NOT EXISTS ( FROM m.details d WHERE NOT d.i=5 )" ).iterate(); + s.createQuery( "FROM Root m WHERE NOT 5 IN ( SELECT d.i FROM m.details AS d )" ).iterate(); } - s.createQuery( "SELECT m FROM Master m JOIN m.details d WHERE d.i=5" ).iterate(); - s.createQuery( "SELECT m FROM Master m JOIN m.details d WHERE d.i=5" ).list(); - s.createQuery( "SELECT m.id FROM Master AS m JOIN m.details AS d WHERE d.i=5" ).list(); + s.createQuery( "SELECT m FROM Root m JOIN m.details d WHERE d.i=5" ).iterate(); + s.createQuery( "SELECT m FROM Root m JOIN m.details d WHERE d.i=5" ).list(); + s.createQuery( "SELECT m.id FROM Root AS m JOIN m.details AS d WHERE d.i=5" ).list(); t.commit(); s.close(); } @Test - public void testMasterDetail() throws Exception { + public void tesRootDetail() throws Exception { if (getDialect() instanceof HSQLDialect) return; Session s = openSession(); Transaction t = s.beginTransaction(); - Master master = new Master(); - assertTrue( "save returned native id", s.save(master)!=null ); - Serializable mid = s.getIdentifier(master); + Root root = new Root(); + assertTrue( "save returned native id", s.save( root )!=null ); + Serializable mid = s.getIdentifier( root ); Detail d1 = new Detail(); - d1.setMaster(master); + d1.setRoot( root ); Serializable did = s.save(d1); Detail d2 = new Detail(); d2.setI(12); - d2.setMaster(master); + d2.setRoot( root ); assertTrue( "generated id returned", s.save(d2)!=null); - master.addDetail(d1); - master.addDetail(d2); + root.addDetail(d1); + root.addDetail(d2); if ( !(getDialect() instanceof MySQLDialect) && !(getDialect() instanceof SAPDBDialect) && !(getDialect() instanceof MckoiDialect) && !(getDialect() instanceof org.hibernate.dialect.TimesTenDialect)) { assertTrue( "query", s.createQuery( - "from Detail d, Master m where m = d.master and size(m.outgoing) = 0 and size(m.incoming) = 0" + "from Detail d, Root m where m = d.root and size(m.outgoing) = 0 and size(m.incoming) = 0" ).list().size()==2 ); } @@ -348,42 +339,42 @@ public void testMasterDetail() throws Exception { s = openSession(); t = s.beginTransaction(); - master = new Master(); - s.load(master, mid); - assertTrue( master.getDetails().size()==2 ); + root = new Root(); + s.load( root, mid); + assertTrue( root.getDetails().size()==2 ); t.commit(); s.close(); s = openSession(); t = s.beginTransaction(); - master = (Master) s.load(Master.class, mid); - Iterator iter = master.getDetails().iterator(); + root = (Root) s.load( Root.class, mid); + Iterator iter = root.getDetails().iterator(); int i=0; while ( iter.hasNext() ) { Detail d = (Detail) iter.next(); - assertTrue( "master-detail", d.getMaster()==master ); + assertTrue( "root-detail", d.getRoot()== root ); i++; } - assertTrue( "master-detail", i==2 ); + assertTrue( "root-detail", i==2 ); t.commit(); s.close(); s = openSession(); t = s.beginTransaction(); - assertTrue( s.createQuery( "select elements(master.details) from Master master" ).list().size()==2 ); + assertTrue( s.createQuery( "select elements(root.details) from Root root" ).list().size()==2 ); t.commit(); s.close(); s = openSession(); t = s.beginTransaction(); - List list = s.createQuery( "from Master m left join fetch m.details" ).list(); - Master m = (Master) list.get(0); + List list = s.createQuery( "from Root m left join fetch m.details" ).list(); + Root m = (Root) list.get(0); assertTrue( Hibernate.isInitialized( m.getDetails() ) ); assertTrue( m.getDetails().size()==2 ); - list = s.createQuery( "from Detail d inner join fetch d.master" ).list(); + list = s.createQuery( "from Detail d inner join fetch d.root" ).list(); Detail dt = (Detail) list.get(0); Serializable dtid = s.getIdentifier(dt); - assertTrue( dt.getMaster()==m ); + assertTrue( dt.getRoot()==m ); //assertTrue(m.getAllDetails().size()==2); @@ -392,25 +383,22 @@ public void testMasterDetail() throws Exception { s = openSession(); t = s.beginTransaction(); - list = s.createQuery( "select m from Master m1, Master m left join fetch m.details where m.name=m1.name" ) + list = s.createQuery( "select m from Root m1, Root m left join fetch m.details where m.name=m1.name" ) .list(); - assertTrue( Hibernate.isInitialized( ( (Master) list.get(0) ).getDetails() ) ); + assertTrue( Hibernate.isInitialized( ( (Root) list.get(0) ).getDetails() ) ); dt = (Detail) s.load(Detail.class, dtid); - assertTrue( ( (Master) list.get(0) ).getDetails().contains(dt) ); + assertTrue( ( (Root) list.get(0) ).getDetails().contains(dt) ); t.commit(); s.close(); s = openSession(); t = s.beginTransaction(); list = s.createQuery( - "select m, m1.name from Master m1, Master m left join fetch m.details where m.name=m1.name" + "select m, m1.name from Root m1, Root m left join fetch m.details where m.name=m1.name" ).list(); - assertTrue( Hibernate.isInitialized( ( (Master) ( (Object[]) list.get(0) )[0] ).getDetails() ) ); + assertTrue( Hibernate.isInitialized( ( (Root) ( (Object[]) list.get(0) )[0] ).getDetails() ) ); dt = (Detail) s.load(Detail.class, dtid); - assertTrue( ( (Master) ( (Object[]) list.get(0) )[0] ).getDetails().contains(dt) ); - //list = s.find("select m from Master m, Master m2 left join fetch m.details"); -// depracted syntax -// list = s.find("select m.id from Master m inner join fetch m.details"); + assertTrue( ( (Root) ( (Object[]) list.get(0) )[0] ).getDetails().contains(dt) ); t.commit(); s.close(); @@ -418,14 +406,14 @@ public void testMasterDetail() throws Exception { s = openSession(); t = s.beginTransaction(); Detail dd = (Detail) s.load(Detail.class, did); - master = dd.getMaster(); - assertTrue( "detail-master", master.getDetails().contains(dd) ); - assertTrue( s.createFilter( master.getDetails(), "order by this.i desc" ).list().size()==2 ); - assertTrue( s.createFilter( master.getDetails(), "select this where this.id > -1" ).list().size()==2 ); - Query q = s.createFilter( master.getDetails(), "where this.id > :id" ); + root = dd.getRoot(); + assertTrue( "detail-root", root.getDetails().contains(dd) ); + assertTrue( s.createFilter( root.getDetails(), "order by this.i desc" ).list().size()==2 ); + assertTrue( s.createFilter( root.getDetails(), "select this where this.id > -1" ).list().size()==2 ); + Query q = s.createFilter( root.getDetails(), "where this.id > :id" ); q.setInteger("id", -1); assertTrue( q.list().size()==2 ); - q = s.createFilter( master.getDetails(), "where this.id > :id1 and this.id < :id2" ); + q = s.createFilter( root.getDetails(), "where this.id > :id1 and this.id < :id2" ); q.setInteger("id1", -1); q.setInteger("id2", 99999999); assertTrue( q.list().size()==2 ); @@ -436,38 +424,38 @@ public void testMasterDetail() throws Exception { list.add(did); list.add( new Long(-1) ); - q = s.createFilter( master.getDetails(), "where this.id in (:ids)" ); + q = s.createFilter( root.getDetails(), "where this.id in (:ids)" ); q.setParameterList("ids", list); assertTrue( q.list().size()==1 ); - q = s.createFilter( master.getDetails(), "where this.id in (:ids)" ); + q = s.createFilter( root.getDetails(), "where this.id in (:ids)" ); q.setParameterList("ids", list); assertTrue( q.iterate().hasNext() ); - assertTrue( s.createFilter( master.getDetails(), "where this.id > -1" ).list().size()==2 ); - assertTrue( s.createFilter( master.getDetails(), "select this.master where this.id > -1" ).list().size()==2 ); + assertTrue( s.createFilter( root.getDetails(), "where this.id > -1" ).list().size()==2 ); + assertTrue( s.createFilter( root.getDetails(), "select this.root where this.id > -1" ).list().size()==2 ); assertTrue( - s.createFilter( master.getDetails(), "select m from Master m where this.id > -1 and this.master=m" ) + s.createFilter( root.getDetails(), "select m from Root m where this.id > -1 and this.root=m" ) .list() .size()==2 ); - assertTrue( s.createFilter( master.getIncoming(), "where this.id > -1 and this.name is not null" ).list().size()==0 ); + assertTrue( s.createFilter( root.getIncoming(), "where this.id > -1 and this.name is not null" ).list().size()==0 ); - assertTrue( s.createFilter( master.getDetails(), "select max(this.i)" ).iterate().next() instanceof Integer ); - assertTrue( s.createFilter( master.getDetails(), "select max(this.i) group by this.id" ).iterate().next() instanceof Integer ); - assertTrue( s.createFilter( master.getDetails(), "select count(*)" ).iterate().next() instanceof Long ); + assertTrue( s.createFilter( root.getDetails(), "select max(this.i)" ).iterate().next() instanceof Integer ); + assertTrue( s.createFilter( root.getDetails(), "select max(this.i) group by this.id" ).iterate().next() instanceof Integer ); + assertTrue( s.createFilter( root.getDetails(), "select count(*)" ).iterate().next() instanceof Long ); - assertTrue( s.createFilter( master.getDetails(), "select this.master" ).list().size()==2 ); - assertTrue( s.createFilter( master.getMoreDetails(), "" ).list().size()==0 ); - assertTrue( s.createFilter( master.getIncoming(), "" ).list().size()==0 ); + assertTrue( s.createFilter( root.getDetails(), "select this.root" ).list().size()==2 ); + assertTrue( s.createFilter( root.getMoreDetails(), "" ).list().size()==0 ); + assertTrue( s.createFilter( root.getIncoming(), "" ).list().size()==0 ); - Query f = s.createFilter( master.getDetails(), "select max(this.i) where this.i < :top and this.i>=:bottom" ); + Query f = s.createFilter( root.getDetails(), "select max(this.i) where this.i < :top and this.i>=:bottom" ); f.setInteger("top", 100); f.setInteger("bottom", 0); assertEquals( f.iterate().next(), new Integer(12) ); f.setInteger("top", 2); assertEquals( f.iterate().next(), new Integer(0) ); - f = s.createFilter( master.getDetails(), "select max(this.i) where this.i not in (:list)" ); + f = s.createFilter( root.getDetails(), "select max(this.i) where this.i not in (:list)" ); Collection coll = new ArrayList(); coll.add( new Integer(-666) ); coll.add( new Integer(22) ); @@ -475,21 +463,21 @@ public void testMasterDetail() throws Exception { f.setParameterList("list", coll); assertEquals( f.iterate().next(), new Integer(12) ); - f = s.createFilter( master.getDetails(), "select max(this.i) where this.i not in (:list) and this.master.name = :listy2" ); + f = s.createFilter( root.getDetails(), "select max(this.i) where this.i not in (:list) and this.root.name = :listy2" ); f.setParameterList("list", coll); - f.setParameter( "listy2", master.getName() ); + f.setParameter( "listy2", root.getName() ); assertEquals( f.iterate().next(), new Integer(12) ); - iter = master.getDetails().iterator(); + iter = root.getDetails().iterator(); i=0; while ( iter.hasNext() ) { Detail d = (Detail) iter.next(); - assertTrue( "master-detail", d.getMaster()==master ); + assertTrue( "root-detail", d.getRoot()== root ); s.delete(d); i++; } - assertTrue( "master-detail", i==2 ); - s.delete(master); + assertTrue( "root-detail", i==2 ); + s.delete( root ); t.commit(); s.close(); } @@ -498,19 +486,19 @@ public void testMasterDetail() throws Exception { public void testIncomingOutgoing() throws Exception { Session s = openSession(); s.beginTransaction(); - Master master1 = new Master(); - Master master2 = new Master(); - Master master3 = new Master(); - s.save(master1); - s.save(master2); - s.save(master3); - master1.addIncoming(master2); - master2.addOutgoing(master1); - master1.addIncoming(master3); - master3.addOutgoing(master1); - Serializable m1id = s.getIdentifier(master1); + Root root1 = new Root(); + Root root2 = new Root(); + Root root3 = new Root(); + s.save( root1 ); + s.save( root2 ); + s.save( root3 ); + root1.addIncoming( root2 ); + root2.addOutgoing( root1 ); + root1.addIncoming( root3 ); + root3.addOutgoing( root1 ); + Serializable m1id = s.getIdentifier( root1 ); assertTrue( - s.createFilter( master1.getIncoming(), "where this.id > 0 and this.name is not null" ) + s.createFilter( root1.getIncoming(), "where this.id > 0 and this.name is not null" ) .list() .size() == 2 ); @@ -519,18 +507,18 @@ public void testIncomingOutgoing() throws Exception { s = openSession(); s.beginTransaction(); - master1 = (Master) s.load(Master.class, m1id); - Iterator iter = master1.getIncoming().iterator(); + root1 = (Root) s.load( Root.class, m1id); + Iterator iter = root1.getIncoming().iterator(); int i=0; while ( iter.hasNext() ) { - Master m = (Master) iter.next(); + Root m = (Root) iter.next(); assertTrue( "outgoing", m.getOutgoing().size()==1 ); - assertTrue( "outgoing", m.getOutgoing().contains(master1) ); + assertTrue( "outgoing", m.getOutgoing().contains( root1 ) ); s.delete(m); i++; } assertTrue( "incoming-outgoing", i == 2 ); - s.delete( master1 ); + s.delete( root1 ); s.getTransaction().commit(); s.close(); } @@ -542,11 +530,11 @@ public void testCascading() throws Exception { Detail d1 = new Detail(); Detail d2 = new Detail(); d2.setI(22); - Master m = new Master(); - Master m0 = new Master(); + Root m = new Root(); + Root m0 = new Root(); Serializable m0id = s.save(m0); m0.addDetail(d1); m0.addDetail(d2); - d1.setMaster(m0); d2.setMaster(m0); + d1.setRoot(m0); d2.setRoot(m0); m.getMoreDetails().add(d1); m.getMoreDetails().add(d2); Serializable mid = s.save(m); @@ -555,11 +543,11 @@ public void testCascading() throws Exception { s = openSession(); s.beginTransaction(); - m = (Master) s.load(Master.class, mid); + m = (Root) s.load( Root.class, mid); assertTrue( "cascade save", m.getMoreDetails().size()==2 ); - assertTrue( "cascade save", ( (Detail) m.getMoreDetails().iterator().next() ).getMaster().getDetails().size()==2 ); + assertTrue( "cascade save", ( (Detail) m.getMoreDetails().iterator().next() ).getRoot().getDetails().size()==2 ); s.delete( m ); - s.delete( s.load( Master.class, m0id ) ); + s.delete( s.load( Root.class, m0id ) ); s.getTransaction().commit(); s.close(); } @@ -578,13 +566,13 @@ public void testNamedQuery() throws Exception { public void testUpdateLazyCollections() throws Exception { Session s = openSession(); s.beginTransaction(); - Master m = new Master(); + Root m = new Root(); s.save( m ); Detail d1 = new Detail(); Detail d2 = new Detail(); d2.setX( 14 ); - d1.setMaster( m ); - d2.setMaster( m ); + d1.setRoot( m ); + d2.setRoot( m ); s.save( d1 ); s.save( d2 ); m.addDetail( d1 ); @@ -594,7 +582,7 @@ public void testUpdateLazyCollections() throws Exception { s = openSession(); s.beginTransaction(); - m = (Master) s.load( Master.class, m.getId() ); + m = (Root) s.load( Root.class, m.getId() ); s.getTransaction().commit(); s.close(); m.setName("New Name"); @@ -622,11 +610,11 @@ public void testMultiLevelCascade() throws Exception { Transaction txn = s.beginTransaction(); Detail detail = new Detail(); SubDetail subdetail = new SubDetail(); - Master m = new Master(); - Master m0 = new Master(); + Root m = new Root(); + Root m0 = new Root(); Serializable m0id = s.save(m0); m0.addDetail(detail); - detail.setMaster(m0); + detail.setRoot(m0); m.getMoreDetails().add(detail); detail.setSubDetails( new HashSet() ); detail.getSubDetails().add(subdetail); @@ -636,12 +624,12 @@ public void testMultiLevelCascade() throws Exception { s = openSession(); txn = s.beginTransaction(); - m = (Master) s.load( Master.class, mid ); + m = (Root) s.load( Root.class, mid ); assertTrue( ( (Detail) m.getMoreDetails().iterator().next() ).getSubDetails().size()!=0 ); s.delete(m); assertTrue( s.createQuery( "from SubDetail" ).list().size()==0 ); assertTrue( s.createQuery( "from Detail d" ).list().size()==0 ); - s.delete( s.load(Master.class, m0id) ); + s.delete( s.load( Root.class, m0id) ); txn.commit(); s.close(); } diff --git a/hibernate-core/src/test/resources/org/hibernate/test/fileimport/Dog.hbm.xml b/hibernate-core/src/test/resources/org/hibernate/test/fileimport/Dog.hbm.xml index cb62abf86ca1..acfe018761fc 100644 --- a/hibernate-core/src/test/resources/org/hibernate/test/fileimport/Dog.hbm.xml +++ b/hibernate-core/src/test/resources/org/hibernate/test/fileimport/Dog.hbm.xml @@ -12,6 +12,6 @@ - + diff --git a/hibernate-core/src/test/resources/org/hibernate/test/fileimport/dogs.sql b/hibernate-core/src/test/resources/org/hibernate/test/fileimport/dogs.sql index 22de471641bb..7e8f566a4502 100644 --- a/hibernate-core/src/test/resources/org/hibernate/test/fileimport/dogs.sql +++ b/hibernate-core/src/test/resources/org/hibernate/test/fileimport/dogs.sql @@ -1,3 +1,3 @@ -INSERT INTO dog (id, master_fk) VALUES (1,1) -INSERT INTO dog (id, master_fk) VALUES (2,2) -INSERT INTO dog (id, master_fk) VALUES (3,3) \ No newline at end of file +INSERT INTO dog (id, owner_fk) VALUES (1,1) +INSERT INTO dog (id, owner_fk) VALUES (2,2) +INSERT INTO dog (id, owner_fk) VALUES (3,3) \ No newline at end of file diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/manytomany/inverseToSuperclass/DetailSuperclass.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/manytomany/inverseToSuperclass/DetailSuperclass.java index 771a97907afd..3a131d221946 100644 --- a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/manytomany/inverseToSuperclass/DetailSuperclass.java +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/manytomany/inverseToSuperclass/DetailSuperclass.java @@ -15,7 +15,7 @@ public class DetailSuperclass { private long id; - private List masters; + private List roots; public DetailSuperclass() { @@ -29,12 +29,12 @@ public void setId(long id) { this.id = id; } - public List getMasters() { - return masters; + public List getRoots() { + return roots; } - public void setMasters(List masters) { - this.masters = masters; + public void setRoots(List roots) { + this.roots = roots; } } diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/manytomany/inverseToSuperclass/ManyToManyInverseToSuperclassTest.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/manytomany/inverseToSuperclass/ManyToManyInverseToSuperclassTest.java index f904cff43bf2..064a39d65be8 100644 --- a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/manytomany/inverseToSuperclass/ManyToManyInverseToSuperclassTest.java +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/manytomany/inverseToSuperclass/ManyToManyInverseToSuperclassTest.java @@ -30,7 +30,7 @@ protected String[] getMappings() { public void initData() { EntityManager em = getEntityManager(); - Master m1 = new Master(); + Root m1 = new Root(); DetailSubclass det1 = new DetailSubclass2(); // Revision 1 @@ -38,66 +38,24 @@ public void initData() { det1.setStr2( "detail 1" ); - m1.setStr( "master" ); + m1.setStr( "root" ); m1.setItems( new ArrayList() ); m1.getItems().add( det1 ); - det1.setMasters( new ArrayList() ); - det1.getMasters().add( m1 ); + det1.setRoots( new ArrayList() ); + det1.getRoots().add( m1 ); em.persist( m1 ); em.getTransaction().commit(); m1_id = m1.getId(); - - // Revision 2 -// em.getTransaction().begin(); -// -// m1 = em.find(Master.class, m1_id); -// -// det2.setStr2("detail 2"); -// det2.setParent(m1); -// m1.getItems().add(det2); -// em.getTransaction().commit(); -// -// // Revision 3 -// em.getTransaction().begin(); -// -// m1 = em.find(Master.class, m1_id); -// m1.setStr("new master"); -// -// det1 = m1.getItems().get(0); -// det1.setStr2("new detail"); -// DetailSubclass det3 = new DetailSubclass2(); -// det3.setStr2("detail 3"); -// det3.setParent(m1); -// -// m1.getItems().get(1).setParent(null); -// // m1.getItems().remove(1); -// m1.getItems().add(det3); -// -// em.persist(m1); -// em.getTransaction().commit(); -// -// // Revision 4 -// em.getTransaction().begin(); -// -// m1 = em.find(Master.class, m1_id); -// -// det1 = m1.getItems().get(0); -// det1.setParent(null); -// // m1.getItems().remove(det1); -// -// em.persist(m1); -// em.getTransaction().commit(); - } @Test public void testHistoryExists() { - Master rev1_1 = getAuditReader().find( Master.class, m1_id, 1 ); - Master rev1_2 = getAuditReader().find( Master.class, m1_id, 2 ); - Master rev1_3 = getAuditReader().find( Master.class, m1_id, 3 ); - Master rev1_4 = getAuditReader().find( Master.class, m1_id, 4 ); + Root rev1_1 = getAuditReader().find( Root.class, m1_id, 1 ); + Root rev1_2 = getAuditReader().find( Root.class, m1_id, 2 ); + Root rev1_3 = getAuditReader().find( Root.class, m1_id, 3 ); + Root rev1_4 = getAuditReader().find( Root.class, m1_id, 4 ); assert (rev1_1 != null); assert (rev1_2 != null); diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/manytomany/inverseToSuperclass/Master.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/manytomany/inverseToSuperclass/Root.java similarity index 95% rename from hibernate-envers/src/test/java/org/hibernate/envers/test/integration/manytomany/inverseToSuperclass/Master.java rename to hibernate-envers/src/test/java/org/hibernate/envers/test/integration/manytomany/inverseToSuperclass/Root.java index 4cc5a3c3589a..2d4a0b65918c 100644 --- a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/manytomany/inverseToSuperclass/Master.java +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/manytomany/inverseToSuperclass/Root.java @@ -11,7 +11,7 @@ import org.hibernate.envers.Audited; @Audited -public class Master { +public class Root { private long id; @@ -19,7 +19,7 @@ public class Master { private List items; - public Master() { + public Root() { } diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/notinsertable/manytoone/ManyToOneNotInsertable.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/notinsertable/manytoone/ManyToOneNotInsertable.java index 3d832688b775..e11798543d93 100644 --- a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/notinsertable/manytoone/ManyToOneNotInsertable.java +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/notinsertable/manytoone/ManyToOneNotInsertable.java @@ -48,16 +48,16 @@ public void initData() { // Rev 2 em.getTransaction().begin(); - ManyToOneNotInsertableEntity master = new ManyToOneNotInsertableEntity( mto_id1, type_id1, type1 ); - em.persist( master ); + ManyToOneNotInsertableEntity entity = new ManyToOneNotInsertableEntity( mto_id1, type_id1, type1 ); + em.persist( entity ); em.getTransaction().commit(); // Rev 2 em.getTransaction().begin(); - master = em.find( ManyToOneNotInsertableEntity.class, mto_id1 ); - master.setNumber( type_id2 ); + entity = em.find( ManyToOneNotInsertableEntity.class, mto_id1 ); + entity.setNumber( type_id2 ); em.getTransaction().commit(); } diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/onetomany/inverseToSuperclass/DetailSuperclass.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/onetomany/inverseToSuperclass/DetailSuperclass.java index ffba2d909b16..a233389f5ebd 100644 --- a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/onetomany/inverseToSuperclass/DetailSuperclass.java +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/onetomany/inverseToSuperclass/DetailSuperclass.java @@ -13,7 +13,7 @@ public class DetailSuperclass { private long id; - private Master parent; + private Root parent; public DetailSuperclass() { @@ -27,11 +27,11 @@ public void setId(long id) { this.id = id; } - public Master getParent() { + public Root getParent() { return parent; } - public void setParent(Master parent) { + public void setParent(Root parent) { this.parent = parent; } diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/onetomany/inverseToSuperclass/OneToManyInverseToSuperclassTest.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/onetomany/inverseToSuperclass/OneToManyInverseToSuperclassTest.java index bff200867847..84c3b4ca6ad1 100644 --- a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/onetomany/inverseToSuperclass/OneToManyInverseToSuperclassTest.java +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/onetomany/inverseToSuperclass/OneToManyInverseToSuperclassTest.java @@ -32,7 +32,7 @@ protected String[] getMappings() { public void initData() { EntityManager em = getEntityManager(); - Master m1 = new Master(); + Root m1 = new Root(); DetailSubclass det1 = new DetailSubclass2(); DetailSubclass det2 = new DetailSubclass2(); @@ -41,7 +41,7 @@ public void initData() { det1.setStr2( "detail 1" ); - m1.setStr( "master" ); + m1.setStr( "root" ); m1.setItems( new ArrayList() ); m1.getItems().add( det1 ); det1.setParent( m1 ); @@ -53,7 +53,7 @@ public void initData() { // Revision 2 em.getTransaction().begin(); - m1 = em.find( Master.class, m1_id ); + m1 = em.find( Root.class, m1_id ); det2.setStr2( "detail 2" ); det2.setParent( m1 ); @@ -63,8 +63,8 @@ public void initData() { // Revision 3 em.getTransaction().begin(); - m1 = em.find( Master.class, m1_id ); - m1.setStr( "new master" ); + m1 = em.find( Root.class, m1_id ); + m1.setStr( "new root" ); det1 = m1.getItems().get( 0 ); det1.setStr2( "new detail" ); @@ -82,7 +82,7 @@ public void initData() { // Revision 4 em.getTransaction().begin(); - m1 = em.find( Master.class, m1_id ); + m1 = em.find( Root.class, m1_id ); det1 = m1.getItems().get( 0 ); det1.setParent( null ); @@ -95,10 +95,10 @@ public void initData() { @Test public void testHistoryExists() { - Master rev1_1 = getAuditReader().find( Master.class, m1_id, 1 ); - Master rev1_2 = getAuditReader().find( Master.class, m1_id, 2 ); - Master rev1_3 = getAuditReader().find( Master.class, m1_id, 3 ); - Master rev1_4 = getAuditReader().find( Master.class, m1_id, 4 ); + Root rev1_1 = getAuditReader().find( Root.class, m1_id, 1 ); + Root rev1_2 = getAuditReader().find( Root.class, m1_id, 2 ); + Root rev1_3 = getAuditReader().find( Root.class, m1_id, 3 ); + Root rev1_4 = getAuditReader().find( Root.class, m1_id, 4 ); assert (rev1_1 != null); assert (rev1_2 != null); diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/onetomany/inverseToSuperclass/Master.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/onetomany/inverseToSuperclass/Root.java similarity index 95% rename from hibernate-envers/src/test/java/org/hibernate/envers/test/integration/onetomany/inverseToSuperclass/Master.java rename to hibernate-envers/src/test/java/org/hibernate/envers/test/integration/onetomany/inverseToSuperclass/Root.java index 4a2b196947a2..b99f27532bf8 100644 --- a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/onetomany/inverseToSuperclass/Master.java +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/onetomany/inverseToSuperclass/Root.java @@ -11,7 +11,7 @@ import org.hibernate.envers.Audited; @Audited -public class Master { +public class Root { private long id; @@ -19,7 +19,7 @@ public class Master { private List items; - public Master() { + public Root() { } diff --git a/hibernate-envers/src/test/resources/mappings/manyToMany/inverseToSuperclass/mappings.hbm.xml b/hibernate-envers/src/test/resources/mappings/manyToMany/inverseToSuperclass/mappings.hbm.xml index d4a75eb59d81..d6099c6d4767 100644 --- a/hibernate-envers/src/test/resources/mappings/manyToMany/inverseToSuperclass/mappings.hbm.xml +++ b/hibernate-envers/src/test/resources/mappings/manyToMany/inverseToSuperclass/mappings.hbm.xml @@ -9,8 +9,8 @@ + name="org.hibernate.envers.test.integration.manytomany.inverseToSuperclass.Root" + table="HIB_ROOT_ENTITY"> @@ -19,8 +19,8 @@ - + table="HIB_ROOT_DETAIL"> + @@ -36,11 +36,11 @@ - + + class="org.hibernate.envers.test.integration.manytomany.inverseToSuperclass.Root" + column="ID_ROOT" /> + name="org.hibernate.envers.test.integration.onetomany.inverseToSuperclass.Root" + table="HIB_ROOT_ENTITY"> @@ -20,7 +20,7 @@ - + @@ -35,8 +35,8 @@ - + + + + + + + diff --git a/test-case-guide.adoc b/test-case-guide.adoc index 4e23f321b06b..1f4a8b61851b 100644 --- a/test-case-guide.adoc +++ b/test-case-guide.adoc @@ -15,7 +15,7 @@ There are a number of tenants that make up a good test case as opposed to a poor == Test templates -The Hibernate team maintains a set of "test templates" intended to help developers write tests. These test templates are maintained in GitHub @ https://github.com/hibernate/hibernate-test-case-templates/tree/master/orm[hibernate-test-case-templates] +The Hibernate team maintains a set of "test templates" intended to help developers write tests. These test templates are maintained in GitHub @ https://github.com/hibernate/hibernate-test-case-templates/tree/main/orm[hibernate-test-case-templates] * If you want to use the Hibernate native API, you should follow the instructions from http://in.relation.to/2015/06/26/hibernate-test-case-templates/[this article]. * If you want to use JPA, you should use the JPA templates that were detailed in http://in.relation.to/2016/01/14/hibernate-jpa-test-case-template/[this article]. diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/accesstype/AccessTypeTest.java b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/accesstype/AccessTypeTest.java index 1e2588d50082..adff0698ff4f 100644 --- a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/accesstype/AccessTypeTest.java +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/accesstype/AccessTypeTest.java @@ -86,7 +86,7 @@ public void testInheritedAccessTypeForEmbeddable() { @TestForIssue(jiraKey = " METAGEN-81") public void testAccessTypeForEmbeddableDeterminedByIdAnnotationInRootEntity() { assertPresenceOfFieldInMetamodelFor( - Hotel.class, "webmaster", + Hotel.class, "webDomainExpert", "Access type should be inherited position of the @Id field annotation in the root entity" ); } diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/accesstype/Hotel.java b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/accesstype/Hotel.java index fab3111c2a7a..0f996610c15b 100644 --- a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/accesstype/Hotel.java +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/accesstype/Hotel.java @@ -16,13 +16,13 @@ public class Hotel { @OneToOne - private User webmaster; + private User webDomainExpert; - public User getWebmaster() { - return webmaster; + public User getWebDomainExpert() { + return webDomainExpert; } - public void setWebmaster(User webmaster) { - this.webmaster = webmaster; + public void setWebDomainExpert(User webDomainExpert) { + this.webDomainExpert = webDomainExpert; } } From e9dd160d7f7254cd519c06cf59b8409c5a7b4ddb Mon Sep 17 00:00:00 2001 From: Karel Maesen Date: Wed, 17 Mar 2021 21:53:53 +0100 Subject: [PATCH 075/644] HHH-14090 Add MariaDB103SpatialDialect --- gradle/databases.gradle | 7 + .../mariadb/MariaDB103SpatialDialect.java | 42 ++++ .../mariadb/MariaDB103SpatialFunctions.java | 179 ++++++++++++++++++ .../MariaDBGeometryTypeDescriptor.java | 102 ++++++++++ .../mariadb/MariaDBSpatialDialectTrait.java | 102 ++++++++++ .../spatial/testing/TestSupportFactories.java | 8 +- .../mariadb/MariaDBExpectationsFactory.java | 18 ++ .../mariadb/MariaDBExpressionTemplate.java | 16 ++ .../dialects/mariadb/MariaDBTestSupport.java | 35 ++++ .../mysql/MySQL8ExpectationsFactory.java | 7 +- .../test-mariadb-functions-data-set.xml | 135 +++++++++++++ 11 files changed, 647 insertions(+), 4 deletions(-) create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/mariadb/MariaDB103SpatialDialect.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/mariadb/MariaDB103SpatialFunctions.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/mariadb/MariaDBGeometryTypeDescriptor.java create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/mariadb/MariaDBSpatialDialectTrait.java create mode 100644 hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/mariadb/MariaDBExpectationsFactory.java create mode 100644 hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/mariadb/MariaDBExpressionTemplate.java create mode 100644 hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/mariadb/MariaDBTestSupport.java create mode 100644 hibernate-spatial/src/test/resources/mariadb/test-mariadb-functions-data-set.xml diff --git a/gradle/databases.gradle b/gradle/databases.gradle index 8f0795dae05d..8e62ba2feec8 100644 --- a/gradle/databases.gradle +++ b/gradle/databases.gradle @@ -91,6 +91,13 @@ ext { 'jdbc.pass' : 'hibernate_orm_test', 'jdbc.url' : 'jdbc:mariadb://' + dbHost + '/hibernate_orm_test' ], + mariadb_spatial_ci : [ + 'db.dialect' : 'org.hibernate.spatial.dialect.mariadb.MariaDB103SpatialDialect', + 'jdbc.driver': 'org.mariadb.jdbc.Driver', + 'jdbc.user' : 'root', + 'jdbc.pass' : 'hibernate_orm_test', + 'jdbc.url' : 'jdbc:mariadb://' + dbHost + '/hibernate_orm_test' + ], postgis : [ 'db.dialect' : 'org.hibernate.spatial.dialect.postgis.PostgisPG95Dialect', 'jdbc.driver': 'org.postgresql.Driver', diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/mariadb/MariaDB103SpatialDialect.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/mariadb/MariaDB103SpatialDialect.java new file mode 100644 index 000000000000..48a98d0c93c0 --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/mariadb/MariaDB103SpatialDialect.java @@ -0,0 +1,42 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ + +package org.hibernate.spatial.dialect.mariadb; + +import java.util.Map; + +import org.hibernate.boot.model.TypeContributions; +import org.hibernate.dialect.MariaDB103Dialect; +import org.hibernate.dialect.function.SQLFunction; +import org.hibernate.service.ServiceRegistry; +import org.hibernate.spatial.dialect.SpatialFunctionsRegistry; + +public class MariaDB103SpatialDialect extends MariaDB103Dialect implements MariaDBSpatialDialectTrait { + + final private SpatialFunctionsRegistry spatialFunctions = new MariaDB103SpatialFunctions(); + + public MariaDB103SpatialDialect() { + super(); + registerColumnType( + MariaDBGeometryTypeDescriptor.INSTANCE.getSqlType(), + "GEOMETRY" + ); + for ( Map.Entry entry : spatialFunctions ) { + registerFunction( entry.getKey(), entry.getValue() ); + } + } + + @Override + public void contributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) { + delegateContributeTypes( typeContributions, serviceRegistry ); + } + + @Override + public SpatialFunctionsRegistry spatialFunctions() { + return spatialFunctions; + } +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/mariadb/MariaDB103SpatialFunctions.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/mariadb/MariaDB103SpatialFunctions.java new file mode 100644 index 000000000000..944678fe5743 --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/mariadb/MariaDB103SpatialFunctions.java @@ -0,0 +1,179 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ + +package org.hibernate.spatial.dialect.mariadb; + +import org.hibernate.dialect.function.StandardSQLFunction; +import org.hibernate.spatial.SpatialFunction; +import org.hibernate.spatial.dialect.SpatialFunctionsRegistry; +import org.hibernate.type.StandardBasicTypes; + +class MariaDB103SpatialFunctions extends SpatialFunctionsRegistry { + + public MariaDB103SpatialFunctions() { + functionMap.put( + "dimension", new StandardSQLFunction( + "ST_Dimension", + StandardBasicTypes.INTEGER + ) + ); + functionMap.put( + "geometrytype", new StandardSQLFunction( + "ST_GeometryType", StandardBasicTypes.STRING + ) + ); + functionMap.put( + "srid", new StandardSQLFunction( + "ST_SRID", + StandardBasicTypes.INTEGER + ) + ); + functionMap.put( + "envelope", new StandardSQLFunction( + "ST_Envelope" + ) + ); + functionMap.put( + "astext", new StandardSQLFunction( + "ST_Astext", + StandardBasicTypes.STRING + ) + ); + functionMap.put( + "asbinary", new StandardSQLFunction( + "ST_Asbinary", + StandardBasicTypes.BINARY + ) + ); + functionMap.put( + "isempty", new StandardSQLFunction( + "ST_IsEmpty", + StandardBasicTypes.BOOLEAN + ) + ); + functionMap.put( + "issimple", new StandardSQLFunction( + "ST_IsSimple", + StandardBasicTypes.BOOLEAN + ) + ); + functionMap.put( + "boundary", new StandardSQLFunction( + "ST_Boundary" + ) + ); + + // Register functions for spatial relation constructs + functionMap.put( + "overlaps", new StandardSQLFunction( + "ST_Overlaps", + StandardBasicTypes.BOOLEAN + ) + ); + functionMap.put( + "intersects", new StandardSQLFunction( + "ST_Intersects", + StandardBasicTypes.BOOLEAN + ) + ); + functionMap.put( + "equals", new StandardSQLFunction( + "ST_Equals", + StandardBasicTypes.BOOLEAN + ) + ); + functionMap.put( + "contains", new StandardSQLFunction( + "ST_Contains", + StandardBasicTypes.BOOLEAN + ) + ); + functionMap.put( + "crosses", new StandardSQLFunction( + "ST_Crosses", + StandardBasicTypes.BOOLEAN + ) + ); + functionMap.put( + "disjoint", new StandardSQLFunction( + "ST_Disjoint", + StandardBasicTypes.BOOLEAN + ) + ); + functionMap.put( + "touches", new StandardSQLFunction( + "ST_Touches", + StandardBasicTypes.BOOLEAN + ) + ); + functionMap.put( + "within", new StandardSQLFunction( + "ST_Within", + StandardBasicTypes.BOOLEAN + ) + ); + functionMap.put( + "relate", new StandardSQLFunction( + "ST_Relate", + StandardBasicTypes.BOOLEAN + ) + ); + + // register the spatial analysis functions + functionMap.put( + "distance", new StandardSQLFunction( + "ST_Distance", + StandardBasicTypes.DOUBLE + ) + ); + + functionMap.put( + "buffer", new StandardSQLFunction( + "ST_Buffer" + ) + ); + + functionMap.put( + "convexhull", new StandardSQLFunction( + "ST_ConvexHull" + ) + ); + + functionMap.put( + "difference", new StandardSQLFunction( + "ST_Difference" + ) + ); + + functionMap.put( + "intersection", new StandardSQLFunction( + "ST_Intersection" + ) + ); + + functionMap.put( + "symdifference", new StandardSQLFunction( + "ST_SymDifference" + ) + ); + + functionMap.put( + "geomunion", new StandardSQLFunction( + "ST_Union" + ) + ); + + functionMap.put( + SpatialFunction.filter.name(), new StandardSQLFunction( + "MBRIntersects", + StandardBasicTypes.BOOLEAN + ) + ); + } + +} + diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/mariadb/MariaDBGeometryTypeDescriptor.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/mariadb/MariaDBGeometryTypeDescriptor.java new file mode 100644 index 000000000000..929b0286816e --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/mariadb/MariaDBGeometryTypeDescriptor.java @@ -0,0 +1,102 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ + +package org.hibernate.spatial.dialect.mariadb; + +import java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; + +import org.hibernate.type.descriptor.ValueBinder; +import org.hibernate.type.descriptor.ValueExtractor; +import org.hibernate.type.descriptor.WrapperOptions; +import org.hibernate.type.descriptor.java.JavaTypeDescriptor; +import org.hibernate.type.descriptor.sql.BasicBinder; +import org.hibernate.type.descriptor.sql.BasicExtractor; +import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; + +import org.geolatte.geom.ByteBuffer; +import org.geolatte.geom.ByteOrder; +import org.geolatte.geom.Geometry; +import org.geolatte.geom.codec.Wkb; +import org.geolatte.geom.codec.WkbDecoder; +import org.geolatte.geom.codec.WkbEncoder; + +public class MariaDBGeometryTypeDescriptor implements SqlTypeDescriptor { + + public static final MariaDBGeometryTypeDescriptor INSTANCE = new MariaDBGeometryTypeDescriptor(); + final WkbEncoder encoder = Wkb.newEncoder( Wkb.Dialect.MYSQL_WKB ); + final WkbDecoder decoder = Wkb.newDecoder( Wkb.Dialect.MYSQL_WKB ); + + @Override + public int getSqlType() { + return Types.ARRAY; + } + + @Override + public boolean canBeRemapped() { + return false; + } + + @Override + public ValueBinder getBinder(JavaTypeDescriptor javaTypeDescriptor) { + + return new BasicBinder( javaTypeDescriptor, this ) { + @Override + protected void doBind( + PreparedStatement st, X value, int index, WrapperOptions options) throws SQLException { + final byte[] bytes = valueToByteArray( value, options ); + st.setBytes( index, bytes ); + } + + @Override + protected void doBind( + CallableStatement st, X value, String name, WrapperOptions options) throws SQLException { + final byte[] bytes = valueToByteArray( value, options ); + st.setBytes( name, bytes ); + } + + private byte[] valueToByteArray(X value, WrapperOptions options) { + final Geometry geometry = getJavaDescriptor().unwrap( value, Geometry.class, options ); + final ByteBuffer buffer = encoder.encode( geometry, ByteOrder.NDR ); + return buffer == null ? null : buffer.toByteArray(); + } + }; + } + + @Override + public ValueExtractor getExtractor(JavaTypeDescriptor javaTypeDescriptor) { + return new BasicExtractor( javaTypeDescriptor, this ) { + + @Override + protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException { + return getJavaDescriptor().wrap( toGeometry( rs.getBytes( name ) ), options ); + } + + @Override + protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException { + return getJavaDescriptor().wrap( toGeometry( statement.getBytes( index ) ), options ); + } + + @Override + protected X doExtract(CallableStatement statement, String name, WrapperOptions options) + throws SQLException { + return getJavaDescriptor().wrap( toGeometry( statement.getBytes( name ) ), options ); + } + }; + } + + private Geometry toGeometry(byte[] bytes) { + if ( bytes == null ) { + return null; + } + final ByteBuffer buffer = ByteBuffer.from( bytes ); + return decoder.decode( buffer ); + } +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/mariadb/MariaDBSpatialDialectTrait.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/mariadb/MariaDBSpatialDialectTrait.java new file mode 100644 index 000000000000..b3b853ae1282 --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/mariadb/MariaDBSpatialDialectTrait.java @@ -0,0 +1,102 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ + +package org.hibernate.spatial.dialect.mariadb; + +import java.util.Locale; + +import org.hibernate.boot.model.TypeContributions; +import org.hibernate.service.ServiceRegistry; +import org.hibernate.spatial.GeolatteGeometryJavaTypeDescriptor; +import org.hibernate.spatial.GeolatteGeometryType; +import org.hibernate.spatial.JTSGeometryJavaTypeDescriptor; +import org.hibernate.spatial.JTSGeometryType; +import org.hibernate.spatial.SpatialDialect; +import org.hibernate.spatial.SpatialFunction; +import org.hibernate.spatial.SpatialRelation; +import org.hibernate.spatial.dialect.SpatialFunctionsRegistry; + +public interface MariaDBSpatialDialectTrait extends SpatialDialect { + + + default void delegateContributeTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) { + typeContributions.contributeType( new GeolatteGeometryType( MariaDBGeometryTypeDescriptor.INSTANCE ) ); + typeContributions.contributeType( new JTSGeometryType( MariaDBGeometryTypeDescriptor.INSTANCE ) ); + + typeContributions.contributeJavaTypeDescriptor( GeolatteGeometryJavaTypeDescriptor.INSTANCE ); + typeContributions.contributeJavaTypeDescriptor( JTSGeometryJavaTypeDescriptor.INSTANCE ); + } + + + SpatialFunctionsRegistry spatialFunctions(); + + @Override + default String getSpatialRelateSQL(String columnName, int spatialRelation) { + switch ( spatialRelation ) { + case SpatialRelation.WITHIN: + return " ST_within(" + columnName + ",?)"; + case SpatialRelation.CONTAINS: + return " ST_contains(" + columnName + ", ?)"; + case SpatialRelation.CROSSES: + return " ST_crosses(" + columnName + ", ?)"; + case SpatialRelation.OVERLAPS: + return " ST_overlaps(" + columnName + ", ?)"; + case SpatialRelation.DISJOINT: + return " ST_disjoint(" + columnName + ", ?)"; + case SpatialRelation.INTERSECTS: + return " ST_intersects(" + columnName + + ", ?)"; + case SpatialRelation.TOUCHES: + return " ST_touches(" + columnName + ", ?)"; + case SpatialRelation.EQUALS: + return " ST_equals(" + columnName + ", ?)"; + default: + throw new IllegalArgumentException( + "Spatial relation is not known by this dialect" + ); + } + } + + @Override + default String getSpatialFilterExpression(String columnName) { + return String.format( Locale.ENGLISH, "MBRIntersects(%s,?)", columnName + ); + } + + @Override + default String getSpatialAggregateSQL(String columnName, int aggregation) { + throw new UnsupportedOperationException( "MariaDB has no spatial aggregate functions." ); + } + + @Override + default String getDWithinSQL(String columnName) { + throw new UnsupportedOperationException( "MariaDB doesn't support the DWithin function." ); + } + + @Override + default String getHavingSridSQL(String columnName) { + return " (ST_SRID(" + columnName + ") = ?) "; + } + + @Override + default String getIsEmptySQL(String columnName, boolean isEmpty) { + final String emptyExpr = " ST_IsEmpty(" + columnName + ") "; + return isEmpty ? emptyExpr : "( NOT " + emptyExpr + ")"; + } + + @Override + default boolean supportsFiltering() { + return true; + } + + @Override + default boolean supports(SpatialFunction function) { + return spatialFunctions().get( function.toString() ) != null; + } + +} + diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/TestSupportFactories.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/TestSupportFactories.java index d71e78b4f2ec..e296c6454004 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/TestSupportFactories.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/TestSupportFactories.java @@ -9,12 +9,14 @@ import org.hibernate.dialect.CockroachDB192Dialect; import org.hibernate.dialect.Dialect; +import org.hibernate.dialect.MariaDBDialect; import org.hibernate.dialect.PostgreSQL82Dialect; import org.hibernate.spatial.SpatialDialect; import org.hibernate.spatial.testing.dialects.cockroachdb.CockroachDBTestSupport; import org.hibernate.spatial.testing.dialects.db2.DB2TestSupport; import org.hibernate.spatial.testing.dialects.h2geodb.GeoDBTestSupport; import org.hibernate.spatial.testing.dialects.hana.HANATestSupport; +import org.hibernate.spatial.testing.dialects.mariadb.MariaDBTestSupport; import org.hibernate.spatial.testing.dialects.mysql.MySQL56TestSupport; import org.hibernate.spatial.testing.dialects.mysql.MySQL8TestSupport; import org.hibernate.spatial.testing.dialects.mysql.MySQLTestSupport; @@ -45,7 +47,11 @@ private static Class getSupportFactoryClass(Dialect diale return PostgisTestSupport.class; } - if ( ( dialect instanceof SpatialDialect ) && CockroachDB192Dialect.class.isAssignableFrom( dialect.getClass() ) ){ + if ( ( dialect instanceof SpatialDialect ) && MariaDBDialect.class.isAssignableFrom( dialect.getClass() ) ) { + return MariaDBTestSupport.class; + } + + if ( ( dialect instanceof SpatialDialect ) && CockroachDB192Dialect.class.isAssignableFrom( dialect.getClass() ) ) { return CockroachDBTestSupport.class; } diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/mariadb/MariaDBExpectationsFactory.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/mariadb/MariaDBExpectationsFactory.java new file mode 100644 index 000000000000..094216ce3c96 --- /dev/null +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/mariadb/MariaDBExpectationsFactory.java @@ -0,0 +1,18 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ + +package org.hibernate.spatial.testing.dialects.mariadb; + +import org.hibernate.spatial.testing.DataSourceUtils; +import org.hibernate.spatial.testing.dialects.mysql.MySQL8ExpectationsFactory; + +//for now, create the same expectations as for MySQL8 +public class MariaDBExpectationsFactory extends MySQL8ExpectationsFactory { + public MariaDBExpectationsFactory(DataSourceUtils dataSourceUtils) { + super( dataSourceUtils ); + } +} diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/mariadb/MariaDBExpressionTemplate.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/mariadb/MariaDBExpressionTemplate.java new file mode 100644 index 000000000000..1ff5f4da15bb --- /dev/null +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/mariadb/MariaDBExpressionTemplate.java @@ -0,0 +1,16 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ + +package org.hibernate.spatial.testing.dialects.mariadb; + + +import org.hibernate.spatial.testing.dialects.mysql.MySQL8ExpressionTemplate; + +//for now, just extends the MySQL8 template +public class MariaDBExpressionTemplate extends MySQL8ExpressionTemplate { + +} diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/mariadb/MariaDBTestSupport.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/mariadb/MariaDBTestSupport.java new file mode 100644 index 000000000000..132d3f59e137 --- /dev/null +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/mariadb/MariaDBTestSupport.java @@ -0,0 +1,35 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ + +package org.hibernate.spatial.testing.dialects.mariadb; + +import org.hibernate.spatial.testing.AbstractExpectationsFactory; +import org.hibernate.spatial.testing.DataSourceUtils; +import org.hibernate.spatial.testing.SQLExpressionTemplate; +import org.hibernate.spatial.testing.TestData; +import org.hibernate.spatial.testing.TestSupport; + +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.Test; + +public class MariaDBTestSupport extends TestSupport { + @Override + public TestData createTestData(BaseCoreFunctionalTestCase testcase) { + return TestData.fromFile( "mariadb/test-mariadb-functions-data-set.xml" ); + + } + + @Override + public AbstractExpectationsFactory createExpectationsFactory(DataSourceUtils dataSourceUtils) { + return new MariaDBExpectationsFactory( dataSourceUtils ); + } + + @Override + public SQLExpressionTemplate getSQLExpressionTemplate() { + return new MariaDBExpressionTemplate(); + } +} diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/mysql/MySQL8ExpectationsFactory.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/mysql/MySQL8ExpectationsFactory.java index def100dcdac3..2fe2b796d201 100644 --- a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/mysql/MySQL8ExpectationsFactory.java +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/dialects/mysql/MySQL8ExpectationsFactory.java @@ -24,7 +24,7 @@ public class MySQL8ExpectationsFactory extends AbstractExpectationsFactory { - MySQL8ExpectationsFactory(DataSourceUtils dataSourceUtils) { + public MySQL8ExpectationsFactory(DataSourceUtils dataSourceUtils) { super( dataSourceUtils ); } @@ -95,7 +95,8 @@ protected NativeSQLStatement createNativeDisjointStatement(Geometry geom) { @Override protected NativeSQLStatement createNativeRelateStatement(Geometry geom, String matrix) { - throw new UnsupportedOperationException(); + String sql = "select t.id, ST_Relate(t.geom, ST_GeomFromText(?, 31370), '" + matrix + "' ) from geomtest t where ST_Relate(t.geom, ST_GeomFromText(?, 31370), '" + matrix + "') = 1 "; + return createNativeSQLStatementAllWKTParams( sql, geom.toText() ); } @Override @@ -200,7 +201,7 @@ protected NativeSQLStatement createNativeIsNotEmptyStatement() { @Override protected NativeSQLStatement createNativeBoundaryStatement() { - throw new UnsupportedOperationException(); + return createNativeSQLStatement( "select id, st_boundary(geom) from geomtest" ); } @Override diff --git a/hibernate-spatial/src/test/resources/mariadb/test-mariadb-functions-data-set.xml b/hibernate-spatial/src/test/resources/mariadb/test-mariadb-functions-data-set.xml new file mode 100644 index 000000000000..22baa09bac64 --- /dev/null +++ b/hibernate-spatial/src/test/resources/mariadb/test-mariadb-functions-data-set.xml @@ -0,0 +1,135 @@ + + + + + + + 1 + POINT + SRID=31370;POINT(10 5) + + + 2 + POINT + SRID=31370;POINT(52.25 2.53) + + + + 3 + POINT + SRID=31370;POINT(51 12) + + + 4 + POINT + SRID=31370;POINT(10.0 2.0) + + + + 5 + LINESTRING + SRID=31370;LINESTRING(10.0 5.0, 20.0 15.0) + + + + 6 + LINESTRING + SRID=31370;LINESTRING(10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0) + + + + + 11 + MULTILINESTRING + SRID=31370;MULTILINESTRING((10.0 5.0, 20.0 15.0),( 25.0 30.0, 30.0 20.0)) + + + + 12 + MULTILINESTRING + SRID=31370;MULTILINESTRING((10.0 5.0, 20.0 15.0, 30.3 22.4, 10 30.0), (40.0 20.0, 42.0 18.0, 43.0 16.0, 40 + 14.0)) + + + + + + 16 + POLYGON + SRID=31370;POLYGON( (0 0, 0 10, 10 10, 10 0, 0 0) ) + + + 18 + POLYGON + SRID=31370;POLYGON( (0 0, 0 10, 10 10, 10 0, 0 0), (2 2, 2 5, 5 5,5 2, 2 2)) + + + 19 + POLYGON + SRID=31370;POLYGON( (50 50, 50 70, 70 70, 70 50, 50 50) ) + + + + 20 + MULTIPOLYGON + SRID=31370;MULTIPOLYGON( ((10 20, 30 40, 44 50, 10 20)), ((55 50, 60 70, 70 78, 55 50)) ) + + + 22 + MULTIPOLYGON + SRID=31370;MULTIPOLYGON(( (0 0, 0 50, 50 50, 50 0, 0 0), (10 10, 10 20, 20 20, 20 10, 10 10) ),((15 10, 12 + 14, 13 + 14, 15 10)) ) + + + + + + 25 + MULTIPOINT + SRID=31370;MULTIPOINT(21 2, 25 5, 30 3) + + + 26 + MULTIPOINT + SRID=31370;MULTIPOINT(21 2) + + + + 30 + GEOMETRYCOLLECTION + SRID=31370;GEOMETRYCOLLECTION(POINT(4 0), LINESTRING(4 2, 5 3)) + + + 31 + GEOMETRYCOLLECTION + SRID=31370;GEOMETRYCOLLECTION(POINT(4 0), LINESTRING(4 2, 5 3), POLYGON((0 0, 3 0, 3 3,0 3, 0 0))) + + + 32 + GEOMETRYCOLLECTION + SRID=31370;GEOMETRYCOLLECTION(POINT(4 0), LINESTRING(4 2, 5 3), POLYGON((0 0, 3 0, 3 3,0 3, 0 0),(1 1, 2 1, + 2 2, 1 2, + 1 1))) + + + + 33 + GEOMETRYCOLLECTION + SRID=31370;GEOMETRYCOLLECTION( MULTIPOINT(21 2, 25 5, 30 3), MULTIPOLYGON( ((10 20, 30 40, 44 50, 10 20)), + ((15 10, + 12 14, 13 14, 15 10)) ), MULTILINESTRING((10.0 5.0, 20.0 15.0),( 25.0 30.0, 30.0 20.0))) + + + + + From 2c1aedd176e81221ff3e07f047a0798059fc1ffc Mon Sep 17 00:00:00 2001 From: Guillaume Smet Date: Tue, 31 Jul 2018 14:50:20 +0200 Subject: [PATCH 076/644] HHH-12867 Add test case --- .../cascade/RefreshLazyOneToManyTest.java | 152 ++++++++++++++++++ 1 file changed, 152 insertions(+) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/cascade/RefreshLazyOneToManyTest.java diff --git a/hibernate-core/src/test/java/org/hibernate/test/cascade/RefreshLazyOneToManyTest.java b/hibernate-core/src/test/java/org/hibernate/test/cascade/RefreshLazyOneToManyTest.java new file mode 100644 index 000000000000..bb7ff42c3473 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/cascade/RefreshLazyOneToManyTest.java @@ -0,0 +1,152 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.cascade; + +import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; +import static org.junit.Assert.assertFalse; + +import java.util.List; + +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import javax.persistence.Table; + +import org.hibernate.Hibernate; + +import org.hibernate.testing.FailureExpected; +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.Test; + +@TestForIssue(jiraKey = "HHH-12867") +public class RefreshLazyOneToManyTest extends BaseCoreFunctionalTestCase { + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[]{ Invoice.class, Tax.class, Line.class }; + } + + @Test + @FailureExpected( jiraKey = "HHH-12867") + public void testRefreshCascade() { + doInHibernate( this::sessionFactory, session -> { + Invoice invoice = new Invoice( "An invoice for John Smith" ); + session.save( invoice ); + + session.save( new Line( "1 pen - 5€", invoice ) ); + session.save( new Tax( "21%", invoice ) ); + } ); + + doInHibernate( this::sessionFactory, session -> { + Invoice invoice = session.get( Invoice.class, 1 ); + + assertFalse( "Taxes should not be initialized before refresh", + Hibernate.isInitialized( invoice.getTaxes() ) ); + assertFalse( "Lines should not be initialized before refresh", + Hibernate.isInitialized( invoice.getLines() ) ); + + session.refresh( invoice ); + + assertFalse( "Taxes should not be initialized after refresh", + Hibernate.isInitialized( invoice.getTaxes() ) ); + assertFalse( "Lines should not be initialized after refresh", + Hibernate.isInitialized( invoice.getLines() ) ); + } ); + } + + @Entity + @Table(name = "invoice") + public static class Invoice { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(name = "id") + private Integer id; + + @Column(name = "description") + private String description; + + @OneToMany(mappedBy = "invoice", cascade = CascadeType.ALL) + private List lines; + + @OneToMany(mappedBy = "invoice", cascade = CascadeType.ALL) + private List taxes; + + public Invoice() { + } + + public Invoice(String description) { + this.description = description; + } + + public List getLines() { + return lines; + } + + public List getTaxes() { + return taxes; + } + } + + @Entity + @Table(name = "invoice_line") + public static class Line { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(name = "id") + private Integer id; + + @Column(name = "description") + private String description; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "invoice_id") + private Invoice invoice; + + public Line() { + } + + public Line(String description, Invoice invoice) { + this.description = description; + this.invoice = invoice; + } + } + + @Entity + @Table(name = "invoice_tax") + public static class Tax { + + @Id + @GeneratedValue(strategy = GenerationType.AUTO) + @Column(name = "id") + private Integer id; + + @Column(name = "description") + private String description; + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn(name = "invoice_id") + private Invoice invoice; + + public Tax() { + } + + public Tax(String description, Invoice invoice) { + this.description = description; + this.invoice = invoice; + } + } +} From 2b06123635dd723d9e3b38c6c22cae901d12055c Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Wed, 24 Mar 2021 19:21:13 +0100 Subject: [PATCH 077/644] Try dropping local tables in same connection --- .../hql/spi/id/local/LocalTemporaryTableBulkIdStrategy.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/local/LocalTemporaryTableBulkIdStrategy.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/local/LocalTemporaryTableBulkIdStrategy.java index 17df6167d914..68c2088932ba 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/local/LocalTemporaryTableBulkIdStrategy.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/local/LocalTemporaryTableBulkIdStrategy.java @@ -163,7 +163,7 @@ protected void prepareForUse(Queryable persister, SharedSessionContractImplement protected void releaseFromUse(Queryable persister, SharedSessionContractImplementor session) { Helper.INSTANCE.releaseTempTable( tableInfo, - afterUseAction, + dropIdTables ? AfterUseAction.DROP : afterUseAction, ddlTransactionHandling, session ); @@ -194,7 +194,7 @@ protected void prepareForUse(Queryable persister, SharedSessionContractImplement protected void releaseFromUse(Queryable persister, SharedSessionContractImplementor session) { Helper.INSTANCE.releaseTempTable( tableInfo, - afterUseAction, + dropIdTables ? AfterUseAction.DROP : afterUseAction, ddlTransactionHandling, session ); From 9cb9137fb8a7189a8041c714ade0214ebaf6a0b8 Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Sun, 28 Mar 2021 15:11:40 -0700 Subject: [PATCH 078/644] HHH-14537 : Added test for issue --- .../test/notfound/EagerProxyNotFoundTest.java | 162 ++++++++++++++++++ 1 file changed, 162 insertions(+) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/notfound/EagerProxyNotFoundTest.java diff --git a/hibernate-core/src/test/java/org/hibernate/test/notfound/EagerProxyNotFoundTest.java b/hibernate-core/src/test/java/org/hibernate/test/notfound/EagerProxyNotFoundTest.java new file mode 100644 index 000000000000..996559263d4f --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/notfound/EagerProxyNotFoundTest.java @@ -0,0 +1,162 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.notfound; + +import javax.persistence.Column; +import javax.persistence.ConstraintMode; +import javax.persistence.Entity; +import javax.persistence.EntityNotFoundException; +import javax.persistence.FetchType; +import javax.persistence.ForeignKey; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; + +import org.hibernate.annotations.NotFound; +import org.hibernate.annotations.NotFoundAction; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; +import org.junit.After; +import org.junit.Test; + +import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.fail; + +/** + * @author Gail Badner + */ +@TestForIssue(jiraKey = "HHH-14537") +public class EagerProxyNotFoundTest extends BaseNonConfigCoreFunctionalTestCase { + + @Test + public void testNoProxyInSession() { + doInHibernate( this::sessionFactory, session -> { + final Task task = new Task(); + task.id = 1; + task.employeeId = 2; + session.persist( task ); + }); + + doInHibernate( this::sessionFactory, session -> { + final Task task = session.createQuery( "from Task", Task.class ).getSingleResult(); + assertNotNull( task ); + assertEquals( 2, task.employeeId ); + assertNull( task.employee ); + }); + } + + @Test + public void testNonExistingProxyInSession() { + doInHibernate( this::sessionFactory, session -> { + final Task task = new Task(); + task.id = 1; + task.employeeId = 2; + session.persist( task ); + }); + + doInHibernate( this::sessionFactory, session -> { + session.load( Employee.class, 2 ); + final Task task = session.createQuery( "from Task", Task.class ).getSingleResult(); + assertNotNull( task ); + assertEquals( 2, task.employeeId ); + assertNull( task.employee ); + }); + } + + @Test + public void testExistingProxyWithNonExistingAssociation() { + doInHibernate( this::sessionFactory, session -> { + final Employee employee = new Employee(); + employee.id = 1; + session.persist( employee ); + + final Task task = new Task(); + task.id = 2; + task.employee = employee; + task.employeeId = 1; + session.persist( task ); + + session.flush(); + + session.createNativeQuery( "update Employee set locationId = 3 where id = 1" ) + .executeUpdate(); + }); + + try { + doInHibernate( this::sessionFactory, session -> { + session.load( Employee.class, 1 ); + session.createQuery( "from Task", Task.class ).getSingleResult(); + }); + fail( "EntityNotFoundException should have been thrown because Task.employee.location is not found " + + "and is not mapped with @NotFound(IGNORE)" ); + } + catch (EntityNotFoundException expected) { + } + } + + @After + public void deleteData() { + doInHibernate( this::sessionFactory, session -> { + session.createQuery( "delete from Task" ).executeUpdate(); + session.createQuery( "delete from Employee" ).executeUpdate(); + session.createQuery( "delete from Location" ).executeUpdate(); + }); + } + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + Task.class, + Employee.class, + Location.class + }; + } + + @Entity(name = "Task") + public static class Task { + + @Id + private int id; + + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn( + name = "employeeId", + insertable = false, + updatable = false, + foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT) + ) + @NotFound(action = NotFoundAction.IGNORE) + private Employee employee; + + @Column(name = "employeeId") + private int employeeId; + } + + @Entity(name = "Employee") + public static class Employee { + @Id + private int id; + + private String name; + + @ManyToOne(fetch = FetchType.EAGER) + @JoinColumn(name = "locationId", foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT)) + private Location location; + } + + @Entity(name = "Location") + public static class Location { + @Id + private int id; + + private String description; + } +} From 3c1e16e06ce7232fbe69bf1a3322d3f251a8bfbb Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Sun, 28 Mar 2021 15:13:00 -0700 Subject: [PATCH 079/644] HHH-14537 EntityNotFoundException thrown when non-existing association with @NotFound(IGNORE) mapped has proxy in PersistenceContext --- .../event/internal/DefaultLoadEventListener.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultLoadEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultLoadEventListener.java index 5888f4acf9ad..3b7c10fe87b7 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultLoadEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultLoadEventListener.java @@ -362,10 +362,17 @@ private Object returnNarrowedProxy( if ( !options.isAllowProxyCreation() ) { impl = load( event, persister, keyToLoad, options ); if ( impl == null ) { - event.getSession() - .getFactory() - .getEntityNotFoundDelegate() - .handleEntityNotFound( persister.getEntityName(), keyToLoad.getIdentifier() ); + if ( options == LoadEventListener.INTERNAL_LOAD_NULLABLE ) { + // The proxy is for a non-existing association mapped as @NotFound. + // Don't throw an exeption; just return null. + return null; + } + else { + event.getSession() + .getFactory() + .getEntityNotFoundDelegate() + .handleEntityNotFound( persister.getEntityName(), keyToLoad.getIdentifier() ); + } } } From ad84aaf0bcb161b272731c82742018ad3445742b Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Mon, 29 Mar 2021 14:58:37 -0700 Subject: [PATCH 080/644] HHH-14537 : Updated test as requested; added tests that lazy associations with non-existing entity is unaffected. --- .../test/notfound/EagerProxyNotFoundTest.java | 78 +++++++++++++++---- 1 file changed, 64 insertions(+), 14 deletions(-) diff --git a/hibernate-core/src/test/java/org/hibernate/test/notfound/EagerProxyNotFoundTest.java b/hibernate-core/src/test/java/org/hibernate/test/notfound/EagerProxyNotFoundTest.java index 996559263d4f..d7b77a29d31f 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/notfound/EagerProxyNotFoundTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/notfound/EagerProxyNotFoundTest.java @@ -6,7 +6,6 @@ */ package org.hibernate.test.notfound; -import javax.persistence.Column; import javax.persistence.ConstraintMode; import javax.persistence.Entity; import javax.persistence.EntityNotFoundException; @@ -18,6 +17,7 @@ import org.hibernate.annotations.NotFound; import org.hibernate.annotations.NotFoundAction; +import org.hibernate.proxy.HibernateProxy; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; @@ -28,6 +28,8 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertSame; +import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; /** @@ -41,15 +43,14 @@ public void testNoProxyInSession() { doInHibernate( this::sessionFactory, session -> { final Task task = new Task(); task.id = 1; - task.employeeId = 2; + task.employeeEagerNotFoundIgnore = session.load( Employee.class, 2 ); session.persist( task ); }); doInHibernate( this::sessionFactory, session -> { final Task task = session.createQuery( "from Task", Task.class ).getSingleResult(); assertNotNull( task ); - assertEquals( 2, task.employeeId ); - assertNull( task.employee ); + assertNull( task.employeeEagerNotFoundIgnore ); }); } @@ -58,7 +59,7 @@ public void testNonExistingProxyInSession() { doInHibernate( this::sessionFactory, session -> { final Task task = new Task(); task.id = 1; - task.employeeId = 2; + task.employeeEagerNotFoundIgnore = session.load( Employee.class, 2 ); session.persist( task ); }); @@ -66,8 +67,49 @@ public void testNonExistingProxyInSession() { session.load( Employee.class, 2 ); final Task task = session.createQuery( "from Task", Task.class ).getSingleResult(); assertNotNull( task ); - assertEquals( 2, task.employeeId ); - assertNull( task.employee ); + assertNull( task.employeeEagerNotFoundIgnore ); + }); + } + + @Test + public void testEagerIgnoreLazyProxy() { + doInHibernate( this::sessionFactory, session -> { + final Task task = new Task(); + task.id = 1; + task.employeeLazy = session.load( Employee.class, 2 ); + task.employeeEagerNotFoundIgnore = task.employeeLazy; + session.persist( task ); + }); + + doInHibernate( this::sessionFactory, session -> { + final Task task = session.createQuery( "from Task", Task.class ).getSingleResult(); + assertNotNull( task ); + assertNull( task.employeeEagerNotFoundIgnore ); + assertNotNull( task.employeeLazy ); + assertTrue( HibernateProxy.class.isInstance( task.employeeLazy ) ); + assertEquals( 2, task.employeeLazy.getId() ); + }); + } + + @Test + public void testProxyInSessionEagerIgnoreLazyProxy() { + doInHibernate( this::sessionFactory, session -> { + final Task task = new Task(); + task.id = 1; + task.employeeLazy = session.load( Employee.class, 2 ); + task.employeeEagerNotFoundIgnore = task.employeeLazy; + session.persist( task ); + }); + + doInHibernate( this::sessionFactory, session -> { + final Employee employeeProxy = session.load( Employee.class, 2 ); + final Task task = session.createQuery( "from Task", Task.class ).getSingleResult(); + assertNotNull( task ); + assertNull( task.employeeEagerNotFoundIgnore ); + assertNotNull( task.employeeLazy ); + assertTrue( HibernateProxy.class.isInstance( task.employeeLazy ) ); + assertEquals( 2, task.employeeLazy.getId() ); + assertSame( employeeProxy, task.employeeLazy ); }); } @@ -80,8 +122,7 @@ public void testExistingProxyWithNonExistingAssociation() { final Task task = new Task(); task.id = 2; - task.employee = employee; - task.employeeId = 1; + task.employeeEagerNotFoundIgnore = employee; session.persist( task ); session.flush(); @@ -129,15 +170,17 @@ public static class Task { @ManyToOne(fetch = FetchType.EAGER) @JoinColumn( name = "employeeId", - insertable = false, - updatable = false, foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT) ) @NotFound(action = NotFoundAction.IGNORE) - private Employee employee; + private Employee employeeEagerNotFoundIgnore; - @Column(name = "employeeId") - private int employeeId; + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn( + name = "lazyEmployeeId", + foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT) + ) + private Employee employeeLazy; } @Entity(name = "Employee") @@ -150,6 +193,13 @@ public static class Employee { @ManyToOne(fetch = FetchType.EAGER) @JoinColumn(name = "locationId", foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT)) private Location location; + + public int getId() { + return id; + } + public void setId(int id) { + this.id = id; + } } @Entity(name = "Location") From 298b1f87b7c2a476e3aa44df55dc829f0062714c Mon Sep 17 00:00:00 2001 From: sajad Date: Sun, 4 Apr 2021 16:19:42 +0430 Subject: [PATCH 081/644] HHH-14545 Fix typo "Generator" -> "GeneratorType" --- .../main/asciidoc/userguide/chapters/domain/basic_types.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/src/main/asciidoc/userguide/chapters/domain/basic_types.adoc b/documentation/src/main/asciidoc/userguide/chapters/domain/basic_types.adoc index e867553c2644..fe4816863849 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/domain/basic_types.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/domain/basic_types.adoc @@ -1448,7 +1448,7 @@ include::{sourcedir}/generated/GeneratorTypeTest.java[tags=mapping-generated-Gen When the `Person` entity is persisted, Hibernate is going to populate the `createdBy` column with the currently logged user. [[mapping-generated-GeneratorType-persist-example]] -.`@Generated` persist example +.`@GeneratorType` persist example ==== [source, JAVA, indent=0] ---- @@ -1465,7 +1465,7 @@ The same goes when the `Person` entity is updated. Hibernate is going to populate the `updatedBy` column with the currently logged user. [[mapping-generated-GeneratorType-update-example]] -.`@Generated` update example +.`@GeneratorType` update example ==== [source, JAVA, indent=0] ---- From b166e684e1e5a7c8062d63e938a2a2deb0e9729b Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Tue, 6 Apr 2021 14:24:13 +0200 Subject: [PATCH 082/644] Skip certain LockTests for Oracle on GH Actions which don't work there --- .github/workflows/contributor-build.yml | 13 +++++- .travis.yml | 56 ----------------------- README.md | 19 ++++++++ ci/build-github.sh | 16 ------- ci/build.sh | 7 ++- ci/{build-travis.sh => database-start.sh} | 12 ++--- docker_db.sh | 3 +- gradle/databases.gradle | 34 ++++++++------ hibernate-core/hibernate-core.gradle | 6 +++ 9 files changed, 68 insertions(+), 98 deletions(-) delete mode 100644 .travis.yml rename ci/{build-travis.sh => database-start.sh} (79%) diff --git a/.github/workflows/contributor-build.yml b/.github/workflows/contributor-build.yml index 9a549710f3a1..dbdb5d6e2d9e 100644 --- a/.github/workflows/contributor-build.yml +++ b/.github/workflows/contributor-build.yml @@ -41,10 +41,19 @@ jobs: experimental: true - rdbms: mssql experimental: true +# Running with HANA requires at least 8GB memory just for the database, which we don't have on GH Actions runners +# - rdbms: hana +# experimental: true steps: - uses: actions/checkout@v2 + with: + persist-credentials: false - name: Reclaim Disk Space run: .github/ci-prerequisites.sh + - name: Start database + env: + RDBMS: ${{ matrix.rdbms }} + run: ci/database-start.sh - name: Set up Java 8 uses: actions/setup-java@v1 with: @@ -86,6 +95,8 @@ jobs: continue-on-error: true steps: - uses: actions/checkout@v2 + with: + persist-credentials: false - name: Set up Java 11 uses: actions/setup-java@v1 with: @@ -117,4 +128,4 @@ jobs: ./**/target/reports/tests/ ./**/target/reports/checkstyle/ - name: Omit produced artifacts from build cache - run: ./ci/before-cache.sh \ No newline at end of file + run: ./ci/before-cache.sh diff --git a/.travis.yml b/.travis.yml deleted file mode 100644 index 0418e1966c23..000000000000 --- a/.travis.yml +++ /dev/null @@ -1,56 +0,0 @@ -dist: trusty -language: java -script: - - ./ci/build-travis.sh -before_cache: - - ./ci/before-cache.sh -cache: - directories: - - $HOME/.gradle/caches/ - - $HOME/.gradle/wrapper/ -matrix: - fast_finish: true - include: - - env: RDBMS=h2 - jdk: oraclejdk8 - sudo: required -# - env: RDBMS=derby -# jdk: oraclejdk8 -# sudo: required -# - env: RDBMS=mariadb -# jdk: oraclejdk8 -# sudo: true -# services: -# - docker -# - env: RDBMS=postgresql -# jdk: oraclejdk8 -# sudo: true -# services: -# - docker -# - env: RDBMS=oracle -# jdk: oraclejdk8 -# sudo: true -# services: -# - docker -# - env: RDBMS=db2 -# jdk: oraclejdk8 -# sudo: true -# services: -# - docker -# - env: RDBMS=mssql -# jdk: oraclejdk8 -# sudo: true -# services: -# - docker - - env: JDK=11 - install: - - curl -L -o install-jdk.sh https://github.com/sormuras/bach/raw/master/install-jdk.sh - - source ./install-jdk.sh --target ./openjdk11 --url https://github.com/AdoptOpenJDK/openjdk11-binaries/releases/download/jdk-11.0.9%2B11.1/OpenJDK11U-jdk_x64_linux_hotspot_11.0.9_11.tar.gz - allow_failures: -# - env: RDBMS=derby -# - env: RDBMS=mariadb -# - env: RDBMS=postgresql -# - env: RDBMS=oracle -# - env: RDBMS=db2 -# - env: RDBMS=mssql - - env: JDK=11 \ No newline at end of file diff --git a/README.md b/README.md index 005d039071ff..8f5a40840b4d 100644 --- a/README.md +++ b/README.md @@ -146,3 +146,22 @@ You can do this from the module which you are interested in testing or from the Afterward, just pick any test from the IDE and run it as usual. Hibernate will pick the database configuration from the `hibernate.properties` file that was set up by the `setDataBase` Gradle task. + +Starting test databases locally as docker containers +------------------------------------------------------------- + +You don't have to install all databases locally to be able to test against them in case you have docker available. +The script `docker_db.sh` allows you to start a pre-configured database which can be used for testing. + +All you have to do is run the following command: + + ./docker_db.sh postgresql_9_5 + +omitting the argument will print a list of possible options. + +When the database is properly started, you can run tests with special profiles that are suffixed with `_ci` +e.g. `pgsql_ci` for PostgreSQL. By using the system property `dbHost` you can configure the IP address of your docker host. + +The command for running tests could look like the following: + + gradlew test -Pdb=pgsql_ci "-DdbHost=192.168.99.100" \ No newline at end of file diff --git a/ci/build-github.sh b/ci/build-github.sh index 281feed19cb1..74c0ae24de7d 100755 --- a/ci/build-github.sh +++ b/ci/build-github.sh @@ -4,20 +4,4 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" java -version -if [ "$RDBMS" == 'mysql' ]; then - bash $DIR/../docker_db.sh mysql_5_7 -elif [ "$RDBMS" == 'mysql8' ]; then - bash $DIR/../docker_db.sh mysql_8_0 -elif [ "$RDBMS" == 'mariadb' ]; then - bash $DIR/../docker_db.sh mariadb -elif [ "$RDBMS" == 'postgresql' ]; then - bash $DIR/../docker_db.sh postgresql_9_5 -elif [ "$RDBMS" == 'db2' ]; then - bash $DIR/../docker_db.sh db2 -elif [ "$RDBMS" == 'oracle' ]; then - bash $DIR/../docker_db.sh oracle -elif [ "$RDBMS" == 'mssql' ]; then - bash $DIR/../docker_db.sh mssql -fi - exec bash $DIR/build.sh \ No newline at end of file diff --git a/ci/build.sh b/ci/build.sh index 5a72ba2a4505..30176554d921 100755 --- a/ci/build.sh +++ b/ci/build.sh @@ -8,11 +8,14 @@ elif [ "$RDBMS" == "mariadb" ]; then elif [ "$RDBMS" == "postgresql" ]; then goal="-Pdb=pgsql_ci" elif [ "$RDBMS" == "oracle" ]; then - goal="-Pdb=oracle_ci" + # I have no idea why, but these tests don't work on GH Actions + goal="-Pdb=oracle_ci -PexcludeTests=**.LockTest.testQueryTimeout*" elif [ "$RDBMS" == "db2" ]; then goal="-Pdb=db2_ci" elif [ "$RDBMS" == "mssql" ]; then goal="-Pdb=mssql_ci" +elif [ "$RDBMS" == "hana" ]; then + goal="-Pdb=hana_ci" fi -exec ./gradlew check ${goal} -Plog-test-progress=true --stacktrace \ No newline at end of file +exec ./gradlew check ${goal} -Plog-test-progress=true --stacktrace diff --git a/ci/build-travis.sh b/ci/database-start.sh similarity index 79% rename from ci/build-travis.sh rename to ci/database-start.sh index 603396112b72..e603a9631bfe 100755 --- a/ci/build-travis.sh +++ b/ci/database-start.sh @@ -2,19 +2,13 @@ DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" -java -version - if [ "$RDBMS" == 'mysql' ]; then - sudo service mysql stop bash $DIR/../docker_db.sh mysql_5_7 elif [ "$RDBMS" == 'mysql8' ]; then - sudo service mysql stop bash $DIR/../docker_db.sh mysql_8_0 elif [ "$RDBMS" == 'mariadb' ]; then - sudo service mysql stop bash $DIR/../docker_db.sh mariadb elif [ "$RDBMS" == 'postgresql' ]; then - sudo service postgres stop bash $DIR/../docker_db.sh postgresql_9_5 elif [ "$RDBMS" == 'db2' ]; then bash $DIR/../docker_db.sh db2 @@ -22,6 +16,6 @@ elif [ "$RDBMS" == 'oracle' ]; then bash $DIR/../docker_db.sh oracle elif [ "$RDBMS" == 'mssql' ]; then bash $DIR/../docker_db.sh mssql -fi - -exec bash $DIR/build.sh \ No newline at end of file +elif [ "$RDBMS" == 'hana' ]; then + bash $DIR/../docker_db.sh hana +fi \ No newline at end of file diff --git a/docker_db.sh b/docker_db.sh index eee8c47bd58d..4f0cd16494df 100755 --- a/docker_db.sh +++ b/docker_db.sh @@ -197,6 +197,7 @@ hana() { chmod 777 -R $temp_dir docker rm -f hana || true docker run -d --name hana -p 39013:39013 -p 39017:39017 -p 39041-39045:39041-39045 -p 1128-1129:1128-1129 -p 59013-59014:59013-59014 \ + --memory=8g \ --ulimit nofile=1048576:1048576 \ --sysctl kernel.shmmax=1073741824 \ --sysctl net.ipv4.ip_local_port_range='40000 60999' \ @@ -251,4 +252,4 @@ if [ -z ${1} ]; then echo -e "\tcockroachdb" else ${1} -fi \ No newline at end of file +fi diff --git a/gradle/databases.gradle b/gradle/databases.gradle index 8e62ba2feec8..cf54fda5dd4d 100644 --- a/gradle/databases.gradle +++ b/gradle/databases.gradle @@ -45,7 +45,7 @@ ext { 'jdbc.user' : 'hibernate_orm_test', 'jdbc.pass' : 'hibernate_orm_test', // Disable prepared statement caching due to https://www.postgresql.org/message-id/CAEcMXhmmRd4-%2BNQbnjDT26XNdUoXdmntV9zdr8%3DTu8PL9aVCYg%40mail.gmail.com - 'jdbc.url' : 'jdbc:postgresql://127.0.0.1/hibernate_orm_test?preparedStatementCacheQueries=0' + 'jdbc.url' : 'jdbc:postgresql://' + dbHost + '/hibernate_orm_test?preparedStatementCacheQueries=0' ], pgsql_ci : [ 'db.dialect' : 'org.hibernate.dialect.PostgreSQL95Dialect', @@ -60,14 +60,14 @@ ext { 'jdbc.driver': 'com.mysql.jdbc.Driver', 'jdbc.user' : 'hibernateormtest', 'jdbc.pass' : 'hibernateormtest', - 'jdbc.url' : 'jdbc:mysql://localhost/hibernate_orm_test' + 'jdbc.url' : 'jdbc:mysql://' + dbHost + '/hibernate_orm_test' ], mysql_docker : [ 'db.dialect' : 'org.hibernate.dialect.MySQL57Dialect', 'jdbc.driver': 'com.mysql.jdbc.Driver', 'jdbc.user' : 'hibernate_orm_test', 'jdbc.pass' : 'hibernate_orm_test', - 'jdbc.url' : 'jdbc:mysql://127.0.0.1/hibernate_orm_test?useSSL=false' + 'jdbc.url' : 'jdbc:mysql://' + dbHost + '/hibernate_orm_test?useSSL=false' ], // uses docker mysql_8_0 mysql8_spatial_ci: [ @@ -82,7 +82,7 @@ ext { 'jdbc.driver': 'org.mariadb.jdbc.Driver', 'jdbc.user' : 'hibernate_orm_test', 'jdbc.pass' : 'hibernate_orm_test', - 'jdbc.url' : 'jdbc:mariadb://127.0.0.1/hibernate_orm_test' + 'jdbc.url' : 'jdbc:mariadb://' + dbHost + '/hibernate_orm_test' ], mariadb_ci : [ 'db.dialect' : 'org.hibernate.dialect.MariaDB103Dialect', @@ -111,7 +111,7 @@ ext { 'jdbc.driver': 'oracle.jdbc.OracleDriver', 'jdbc.user' : 'hibernate_orm_test', 'jdbc.pass' : 'hibernate_orm_test', - 'jdbc.url' : 'jdbc:oracle:thin:@localhost:1521/xe' + 'jdbc.url' : 'jdbc:oracle:thin:@' + dbHost + ':1521/xe' ], // Use ./docker_db.sh oracle_ee to start the database oracle_docker : [ @@ -140,7 +140,7 @@ ext { 'jdbc.driver': 'com.microsoft.sqlserver.jdbc.SQLServerDriver', 'jdbc.user' : 'hibernate_orm_test', 'jdbc.pass' : 'hibernate_orm_test', - 'jdbc.url' : 'jdbc:sqlserver://localhost;instance=SQLEXPRESS;databaseName=hibernate_orm_test' + 'jdbc.url' : 'jdbc:sqlserver://' + dbHost + ';instance=SQLEXPRESS;databaseName=hibernate_orm_test' ], mssql_ci : [ 'db.dialect' : 'org.hibernate.dialect.SQLServer2012Dialect', @@ -161,14 +161,14 @@ ext { 'jdbc.driver': 'com.informix.jdbc.IfxDriver', 'jdbc.user' : 'informix', 'jdbc.pass' : 'in4mix', - 'jdbc.url' : 'jdbc:informix-sqli://127.0.0.1:9088/sysuser:INFORMIXSERVER=dev;user=informix;password=in4mix' + 'jdbc.url' : 'jdbc:informix-sqli://' + dbHost + ':9088/sysuser:INFORMIXSERVER=dev;user=informix;password=in4mix' ], db2 : [ 'db.dialect' : 'org.hibernate.dialect.DB2Dialect', 'jdbc.driver': 'com.ibm.db2.jcc.DB2Driver', 'jdbc.user' : 'db2inst1', 'jdbc.pass' : 'db2inst1-pwd', - 'jdbc.url' : 'jdbc:db2://127.0.0.1:50000/hibern8' + 'jdbc.url' : 'jdbc:db2://' + dbHost + ':50000/hibern8' ], db2_ci : [ 'db.dialect' : 'org.hibernate.dialect.DB2Dialect', @@ -190,7 +190,7 @@ ext { 'jdbc.user' : 'HIBERNATE_TEST', 'jdbc.pass' : 'H1bernate_test', // Disable prepared statement caching due to https://help.sap.com/viewer/0eec0d68141541d1b07893a39944924e/2.0.04/en-US/78f2163887814223858e4369d18e2847.html - 'jdbc.url' : 'jdbc:sap://localhost:30015/?statementCacheSize=0' + 'jdbc.url' : 'jdbc:sap://' + dbHost + ':30015/?statementCacheSize=0' ], hana_cloud : [ 'db.dialect' : 'org.hibernate.dialect.HANACloudColumnStoreDialect', @@ -198,7 +198,7 @@ ext { 'jdbc.user' : 'HIBERNATE_TEST', 'jdbc.pass' : 'H1bernate_test', // Disable prepared statement caching due to https://help.sap.com/viewer/0eec0d68141541d1b07893a39944924e/2.0.04/en-US/78f2163887814223858e4369d18e2847.html - 'jdbc.url' : 'jdbc:sap://localhost:443/?encrypt=true&validateCertificate=false&statementCacheSize=0' + 'jdbc.url' : 'jdbc:sap://' + dbHost + ':443/?encrypt=true&validateCertificate=false&statementCacheSize=0' ], hana_vlad : [ 'db.dialect' : 'org.hibernate.dialect.HANAColumnStoreDialect', @@ -206,7 +206,7 @@ ext { 'jdbc.user' : 'VLAD', 'jdbc.pass' : 'V1ad_test', // Disable prepared statement caching due to https://help.sap.com/viewer/0eec0d68141541d1b07893a39944924e/2.0.04/en-US/78f2163887814223858e4369d18e2847.html - 'jdbc.url' : 'jdbc:sap://localhost:39015/?statementCacheSize=0' + 'jdbc.url' : 'jdbc:sap://' + dbHost + ':39015/?statementCacheSize=0' ], hana_docker : [ 'db.dialect' : 'org.hibernate.dialect.HANAColumnStoreDialect', @@ -216,6 +216,14 @@ ext { // Disable prepared statement caching due to https://help.sap.com/viewer/0eec0d68141541d1b07893a39944924e/2.0.04/en-US/78f2163887814223858e4369d18e2847.html 'jdbc.url' : 'jdbc:sap://' + dbHost + ':39017/?statementCacheSize=0' ], + hana_ci : [ + 'db.dialect' : 'org.hibernate.dialect.HANAColumnStoreDialect', + 'jdbc.driver': 'com.sap.db.jdbc.Driver', + 'jdbc.user' : 'SYSTEM', + 'jdbc.pass' : 'H1bernate_test', + // Disable prepared statement caching due to https://help.sap.com/viewer/0eec0d68141541d1b07893a39944924e/2.0.04/en-US/78f2163887814223858e4369d18e2847.html + 'jdbc.url' : 'jdbc:sap://' + dbHost + ':39017/?statementCacheSize=0' + ], hana_spatial_ci : [ 'db.dialect' : 'org.hibernate.spatial.dialect.hana.HANASpatialDialect', 'jdbc.driver': 'com.sap.db.jdbc.Driver', @@ -231,7 +239,7 @@ ext { 'jdbc.user' : 'root', 'jdbc.pass' : '', // Disable prepared statement caching due to https://www.postgresql.org/message-id/CAEcMXhmmRd4-%2BNQbnjDT26XNdUoXdmntV9zdr8%3DTu8PL9aVCYg%40mail.gmail.com - 'jdbc.url' : 'jdbc:postgresql://localhost:26257/defaultdb?sslmode=disable&preparedStatementCacheQueries=0' + 'jdbc.url' : 'jdbc:postgresql://' + dbHost + ':26257/defaultdb?sslmode=disable&preparedStatementCacheQueries=0' ], cockroachdb_spatial : [ 'db.dialect' : 'org.hibernate.spatial.dialect.cockroachdb.CockroachDB202SpatialDialect', @@ -240,7 +248,7 @@ ext { 'jdbc.user' : 'root', 'jdbc.pass' : '', // Disable prepared statement caching due to https://www.postgresql.org/message-id/CAEcMXhmmRd4-%2BNQbnjDT26XNdUoXdmntV9zdr8%3DTu8PL9aVCYg%40mail.gmail.com - 'jdbc.url' : 'jdbc:postgresql://localhost:26257/defaultdb?sslmode=disable&preparedStatementCacheQueries=0' + 'jdbc.url' : 'jdbc:postgresql://' + dbHost + ':26257/defaultdb?sslmode=disable&preparedStatementCacheQueries=0' ] ] } diff --git a/hibernate-core/hibernate-core.gradle b/hibernate-core/hibernate-core.gradle index bfedf123cd72..f4ae9c527003 100644 --- a/hibernate-core/hibernate-core.gradle +++ b/hibernate-core/hibernate-core.gradle @@ -251,6 +251,12 @@ test { beforeTest { descriptor -> //println "Starting test: " + descriptor } + // Allow to exclude specific tests + if (project.hasProperty('excludeTests')) { + filter { + excludeTestsMatching project.property('excludeTests').toString() + } + } } //Create the task that runs the integration tests found from the From e76241a3091078713dd4b57de085f5fadce5e0db Mon Sep 17 00:00:00 2001 From: Karel Maesen Date: Wed, 31 Mar 2021 21:30:35 +0200 Subject: [PATCH 083/644] HHH-14523 Fix for dirty-checking bug --- hibernate-spatial/hibernate-spatial.gradle | 1 + .../JTSGeometryJavaTypeDescriptor.java | 6 + .../hibernate/spatial/JTSGeometryType.java | 1 + .../org/hibernate/spatial/jts/JTSUtils.java | 132 +++++++++++++++++ .../jts/hhh14523/DirtyCheckingTest.java | 140 ++++++++++++++++++ .../jts/hhh14523/package-info.java | 9 ++ 6 files changed, 289 insertions(+) create mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/jts/JTSUtils.java create mode 100644 hibernate-spatial/src/test/java/org/hibernate/spatial/integration/jts/hhh14523/DirtyCheckingTest.java create mode 100644 hibernate-spatial/src/test/java/org/hibernate/spatial/integration/jts/hhh14523/package-info.java diff --git a/hibernate-spatial/hibernate-spatial.gradle b/hibernate-spatial/hibernate-spatial.gradle index 4915d432968a..ab0edc0fc4e8 100644 --- a/hibernate-spatial/hibernate-spatial.gradle +++ b/hibernate-spatial/hibernate-spatial.gradle @@ -25,6 +25,7 @@ dependencies { testCompile(libraries.junit) testCompile(project(':hibernate-testing')) + testCompile( project( path: ':hibernate-core', configuration: 'tests' ) ) testCompile([group: 'org.apache.commons', name: 'commons-dbcp2', version: '2.8.0']) testCompile(libraries.validation) testCompile(libraries.jandex) diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/JTSGeometryJavaTypeDescriptor.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/JTSGeometryJavaTypeDescriptor.java index 0ffcde4699e6..535c6fc8e2d4 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/JTSGeometryJavaTypeDescriptor.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/JTSGeometryJavaTypeDescriptor.java @@ -9,6 +9,7 @@ import java.util.Locale; +import org.hibernate.spatial.jts.JTSUtils; import org.hibernate.type.descriptor.WrapperOptions; import org.hibernate.type.descriptor.java.AbstractTypeDescriptor; import org.hibernate.type.descriptor.java.JavaTypeDescriptor; @@ -54,6 +55,11 @@ public Geometry fromString(String string) { } } + @Override + public boolean areEqual(Geometry one, Geometry another) { + return JTSUtils.equalsExact3D( one, another ); + } + @Override public X unwrap(Geometry value, Class type, WrapperOptions options) { if ( value == null ) { diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/JTSGeometryType.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/JTSGeometryType.java index 8136c455b123..4eaedf43e027 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/JTSGeometryType.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/JTSGeometryType.java @@ -48,4 +48,5 @@ public String getName() { return "jts_geometry"; } + } diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/jts/JTSUtils.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/jts/JTSUtils.java new file mode 100644 index 000000000000..8a4507b456e7 --- /dev/null +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/jts/JTSUtils.java @@ -0,0 +1,132 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ + +package org.hibernate.spatial.jts; + + +//Note that this Utility class will be available directly from +// geolatte-geom 1.9 + + +import org.locationtech.jts.geom.Coordinate; +import org.locationtech.jts.geom.Geometry; +import org.locationtech.jts.geom.LineString; +import org.locationtech.jts.geom.Point; +import org.locationtech.jts.geom.Polygon; + +/** + * Some utility functions for working with JTS geometries + */ +public class JTSUtils { + + private JTSUtils() { + } + + /** + * Determines equality between geometries taking into + * account all coordinates, and the SRID. + *

+ * This is used e.g. for Dirty-checking of geometry values + * in Hibernate + * + * @param g1 + * @param g2 + * + * @return + */ + public static boolean equalsExact3D(Geometry g1, Geometry g2) { + if ( g1 == g2 ) { + return true; + } + if ( g1 == null || g2 == null ) { + return false; + } + if ( !g1.getGeometryType().equals( g2.getGeometryType() ) ) { + return false; + } + if ( g1.getSRID() != g2.getSRID() ) { + return false; + } + + //empty geometries of the same type are the same + if ( g1.isEmpty() && g2.isEmpty() ) { + return true; + } + + int ng1 = g1.getNumGeometries(); + int ng2 = g2.getNumGeometries(); + if ( ng1 != ng2 ) { + return false; + } + + if ( ng1 == 1 ) { + return equals3DPrimitiveGeometries( g1, g2 ); + } + + return equalComponentGeometries( g1, g2, ng1 ); + } + + private static boolean equalComponentGeometries(Geometry g1, Geometry g2, int ng1) { + for ( int gIdx = 0; gIdx < ng1; gIdx++ ) { + if ( !equalsExact3D( g1.getGeometryN( gIdx ), g2.getGeometryN( gIdx ) ) ) { + return false; + } + } + return true; + } + + public static boolean equals3D(Coordinate c1, Coordinate c2) { + return c1.x == c2.x && c1.y == c2.y && + ( ( Double.isNaN( c1.z ) && Double.isNaN( c2.z ) ) || c1.z == c2.z ) && + ( ( Double.isNaN( c1.getM() ) && Double.isNaN( c2.getM() ) ) || c1.getM() == c2.getM() ); + } + + private static boolean equalLineStringCoordinates(LineString g1, LineString g2) { + int np1 = g1.getNumPoints(); + int np2 = g2.getNumPoints(); + if ( np1 != np2 ) { + return false; + } + for ( int i = 0; i < np1; i++ ) { + if ( !equalsExact3D( g1.getPointN( i ), g2.getPointN( i ) ) ) { + return false; + } + } + return true; + } + + private static boolean equalPolygonCoordinates(Polygon g1, Polygon g2) { + int nr1 = g1.getNumInteriorRing(); + int nr2 = g2.getNumInteriorRing(); + if ( nr1 != nr2 ) { + return false; + } + for ( int i = 0; i < nr1; i++ ) { + if ( !equalLineStringCoordinates( g1.getInteriorRingN( i ), g2.getInteriorRingN( i ) ) ) { + return false; + } + } + return equalLineStringCoordinates( g1.getExteriorRing(), g2.getExteriorRing() ); + } + + private static boolean equals3DPrimitiveGeometries(Geometry g1, Geometry g2) { + //this method assumes that g1 and g2 are of the same type + assert ( g1.getClass().equals( g2.getClass() ) ); + if ( g1 instanceof Point ) { + return equals3D( g1.getCoordinate(), g2.getCoordinate() ); + } + + if ( g1 instanceof LineString ) { + return equalLineStringCoordinates( (LineString) g1, (LineString) g2 ); + } + + if ( g1 instanceof Polygon ) { + return equalPolygonCoordinates( (Polygon) g1, (Polygon) g2 ); + } + throw new IllegalStateException( "Only simple geometries should be used" ); + } +} diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/jts/hhh14523/DirtyCheckingTest.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/jts/hhh14523/DirtyCheckingTest.java new file mode 100644 index 000000000000..0516ecb73863 --- /dev/null +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/jts/hhh14523/DirtyCheckingTest.java @@ -0,0 +1,140 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ + +package org.hibernate.spatial.integration.jts.hhh14523; + +import java.io.Serializable; +import java.util.List; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.EntityManager; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Query; +import javax.persistence.SequenceGenerator; +import javax.persistence.Table; + +import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; +import org.hibernate.spatial.dialect.postgis.PostgisPG95Dialect; + +import org.hibernate.testing.RequiresDialect; +import org.hibernate.testing.TestForIssue; +import org.junit.Test; + +import org.geolatte.geom.codec.Wkt; +import org.geolatte.geom.jts.JTS; +import org.locationtech.jts.geom.GeometryFactory; +import org.locationtech.jts.geom.Point; + +import static org.junit.Assert.assertEquals; + +@TestForIssue(jiraKey = "HHH-14523") +@RequiresDialect(PostgisPG95Dialect.class) +public class DirtyCheckingTest extends BaseEntityManagerFunctionalTestCase { + + private GeometryFactory gfact = new GeometryFactory(); + + @Override + public Class[] getAnnotatedClasses() { + return new Class[] { + TestEntity.class + }; + } + + public void createtestEntity() { + Point pnt = (Point) JTS.to( Wkt.fromWkt( "POINT Z( 3.41127795 8.11062269 2.611)", Wkt.Dialect.SFA_1_2_1 ) ); + EntityManager entityManager = createEntityManager(); + TestEntity test1 = new TestEntity( "radar 5", pnt ); + + entityManager.getTransaction().begin(); + entityManager.persist( test1 ); + entityManager.getTransaction().commit(); + + entityManager.close(); + } + + // Entities are auto-discovered, so just add them anywhere on class-path + // Add your tests, using standard JUnit. + @Test + public void hhh14523() throws Exception { + + createtestEntity(); + + EntityManager entityManager = createEntityManager(); + entityManager.getTransaction().begin(); + Query query = entityManager.createQuery( "select t from TestEntity t" ); + TestEntity ent = (TestEntity) query.getResultList().get( 0 ); + Point newPnt = (Point) JTS.to( Wkt.fromWkt( "POINT Z( 3.41127795 8.11062269 8.611)", Wkt.Dialect.SFA_1_2_1 ) ); + ent.setGeom( newPnt ); + entityManager.getTransaction().commit(); + entityManager.close(); + + + entityManager = createEntityManager(); + entityManager.getTransaction().begin(); + List entities = entityManager.createQuery( "select t from TestEntity t" ).getResultList(); + TestEntity ent2 = entities.get( 0 ); + try { + assertEquals( 8.611, ent2.getGeom().getCoordinate().getZ(), 0.00001 ); + } + finally { + entityManager.getTransaction().commit(); + } + entityManager.close(); + } +} + +@Entity +@Table(name = "test") +@SequenceGenerator(name = "test_id_seq", sequenceName = "test_id_seq", allocationSize = 1) +class TestEntity implements Serializable { + private static final long serialVersionUID = 1L; + + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "test_id_seq") + @Column(name = "id") + private Long id; + + @Column(name = "uid", unique = true) + private String uid; + + @Column(name = "geom") + private Point geom; + + public TestEntity() { + } + + public TestEntity(String uid, Point geom) { + this.uid = uid; + this.geom = geom; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getUid() { + return uid; + } + + public void setUid(String uid) { + this.uid = uid; + } + + public Point getGeom() { + return geom; + } + + public void setGeom(Point geom) { + this.geom = geom; + } +} diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/jts/hhh14523/package-info.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/jts/hhh14523/package-info.java new file mode 100644 index 000000000000..939f83ef7f02 --- /dev/null +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/integration/jts/hhh14523/package-info.java @@ -0,0 +1,9 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ + +//test case for bug HHH-14523 +package org.hibernate.spatial.integration.jts.hhh14523; \ No newline at end of file From 3825a671a70fc67e0773019c0c4f2f80278a24a6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Tue, 13 Apr 2021 14:24:10 +0200 Subject: [PATCH 084/644] HHH-14557 Always release JDBC connection and resources on rollback --- .../hibernate/engine/jdbc/internal/JdbcCoordinatorImpl.java | 3 ++- .../jdbc/internal/LogicalConnectionManagedImpl.java | 6 ++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/JdbcCoordinatorImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/JdbcCoordinatorImpl.java index 5e018dc63ee4..2d0dae12e242 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/JdbcCoordinatorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/JdbcCoordinatorImpl.java @@ -270,7 +270,8 @@ public void afterStatementExecution() { public void afterTransaction() { transactionTimeOutInstant = -1; if ( getConnectionReleaseMode() == ConnectionReleaseMode.AFTER_STATEMENT || - getConnectionReleaseMode() == ConnectionReleaseMode.AFTER_TRANSACTION ) { + getConnectionReleaseMode() == ConnectionReleaseMode.AFTER_TRANSACTION || + getConnectionReleaseMode() == ConnectionReleaseMode.BEFORE_TRANSACTION_COMPLETION ) { this.logicalConnection.afterTransaction(); } } diff --git a/hibernate-core/src/main/java/org/hibernate/resource/jdbc/internal/LogicalConnectionManagedImpl.java b/hibernate-core/src/main/java/org/hibernate/resource/jdbc/internal/LogicalConnectionManagedImpl.java index 1d13e5d28408..6ac9a878a55b 100644 --- a/hibernate-core/src/main/java/org/hibernate/resource/jdbc/internal/LogicalConnectionManagedImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/resource/jdbc/internal/LogicalConnectionManagedImpl.java @@ -167,8 +167,10 @@ public void afterTransaction() { super.afterTransaction(); if ( connectionHandlingMode.getReleaseMode() != ConnectionReleaseMode.ON_CLOSE ) { - // NOTE : we check for !ON_CLOSE here (rather than AFTER_TRANSACTION) to also catch AFTER_STATEMENT cases - // that were circumvented due to held resources + // NOTE : we check for !ON_CLOSE here (rather than AFTER_TRANSACTION) to also catch: + // - AFTER_STATEMENT cases that were circumvented due to held resources + // - BEFORE_TRANSACTION_COMPLETION cases that were circumvented because a rollback occurred + // (we don't get a beforeTransactionCompletion event on rollback). log.debug( "Initiating JDBC connection release from afterTransaction" ); releaseConnection(); } From e03beca97f9d117f7d651b66f5241322f7769e41 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Tue, 13 Apr 2021 14:09:43 +0200 Subject: [PATCH 085/644] HHH-14557 Test JDBC resources are released on each commit Not just on session closing. --- .../BeforeCompletionReleaseTest.java | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/hibernate-core/src/test/java/org/hibernate/test/connections/BeforeCompletionReleaseTest.java b/hibernate-core/src/test/java/org/hibernate/test/connections/BeforeCompletionReleaseTest.java index 365dd3cdc437..e60735d23021 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/connections/BeforeCompletionReleaseTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/connections/BeforeCompletionReleaseTest.java @@ -110,11 +110,11 @@ protected Class[] getAnnotatedClasses() { @Test @TestForIssue(jiraKey = {"HHH-13976", "HHH-14326"}) public void testResourcesReleasedThenConnectionClosedThenCommit() throws SQLException, XAException { - XAResource transactionSpy = mock( XAResource.class ); - Connection[] connectionSpies = new Connection[1]; - Statement statementMock = Mockito.mock( Statement.class ); - try (SessionImplementor s = (SessionImplementor) openSession()) { + XAResource transactionSpy = mock( XAResource.class ); + Connection[] connectionSpies = new Connection[1]; + Statement statementMock = Mockito.mock( Statement.class ); + TransactionUtil2.inTransaction( s, session -> { spyOnTransaction( transactionSpy ); @@ -126,16 +126,18 @@ public void testResourcesReleasedThenConnectionClosedThenCommit() throws SQLExce logicalConnection.getResourceRegistry().register( statementMock, true ); connectionSpies[0] = logicalConnection.getPhysicalConnection(); } ); - } - Connection connectionSpy = connectionSpies[0]; + // Note: all this must happen BEFORE the session is closed; + // it's particularly important when reusing the session. - // Must close the resources, then the connection, then commit - InOrder inOrder = inOrder( statementMock, connectionSpy, transactionSpy ); - inOrder.verify( statementMock ).close(); - inOrder.verify( connectionSpy ).close(); - inOrder.verify( transactionSpy ).commit( any(), anyBoolean() ); - Mockito.reset( connectionSpy ); + Connection connectionSpy = connectionSpies[0]; + + // Must close the resources, then the connection, then commit + InOrder inOrder = inOrder( statementMock, connectionSpy, transactionSpy ); + inOrder.verify( statementMock ).close(); + inOrder.verify( connectionSpy ).close(); + inOrder.verify( transactionSpy ).commit( any(), anyBoolean() ); + } } private void spyOnTransaction(XAResource xaResource) { From 571af7bc9ee6b926abf70e219d862ad48dcc25e0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Tue, 13 Apr 2021 14:32:14 +0200 Subject: [PATCH 086/644] HHH-14557 Test JDBC resources are released on each rollback --- .../BeforeCompletionReleaseTest.java | 44 +++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/hibernate-core/src/test/java/org/hibernate/test/connections/BeforeCompletionReleaseTest.java b/hibernate-core/src/test/java/org/hibernate/test/connections/BeforeCompletionReleaseTest.java index e60735d23021..69305549d83a 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/connections/BeforeCompletionReleaseTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/connections/BeforeCompletionReleaseTest.java @@ -140,6 +140,50 @@ public void testResourcesReleasedThenConnectionClosedThenCommit() throws SQLExce } } + @Test + @TestForIssue(jiraKey = {"HHH-14557"}) + public void testResourcesReleasedThenConnectionClosedOnEachRollback() throws SQLException { + try (SessionImplementor s = (SessionImplementor) openSession()) { + Connection[] connectionSpies = new Connection[1]; + Statement statementMock = Mockito.mock( Statement.class ); + RuntimeException rollbackException = new RuntimeException("Rollback"); + + try { + TransactionUtil2.inTransaction( s, session -> { + Thing thing = new Thing(); + thing.setId( 1 ); + session.persist( thing ); + + LogicalConnectionImplementor logicalConnection = session.getJdbcCoordinator().getLogicalConnection(); + logicalConnection.getResourceRegistry().register( statementMock, true ); + connectionSpies[0] = logicalConnection.getPhysicalConnection(); + + throw rollbackException; + } ); + } + catch (RuntimeException e) { + if ( e != rollbackException ) { + throw e; + } + // Else: ignore, that was expected. + } + + // Note: all this must happen BEFORE the session is closed; + // it's particularly important when reusing the session. + + Connection connectionSpy = connectionSpies[0]; + + // Must close the resources, then the connection + InOrder inOrder = inOrder( statementMock, connectionSpy ); + inOrder.verify( statementMock ).close(); + inOrder.verify( connectionSpy ).close(); + // We don't check the relative ordering of the rollback here, + // because unfortunately we know it's wrong: + // we don't get a "before transaction completion" event for rollbacks, + // so in the case of rollbacks the closing always happen after transaction completion. + } + } + private void spyOnTransaction(XAResource xaResource) { try { TestingJtaPlatformImpl.transactionManager().getTransaction().enlistResource( xaResource ); From ebb30aa178a36af567ddd8bf4e0a6481b44ec82f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Mon, 22 Mar 2021 16:36:46 +0100 Subject: [PATCH 087/644] HHH-14530 Allow adding pre-parsed XML mappings to MetadataSources MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Yoann Rodière --- .../org/hibernate/boot/MetadataSources.java | 12 +++ .../java/org/hibernate/cfg/Configuration.java | 20 +++++ .../xml/ejb3/PreParsedOrmXmlTest.java | 78 +++++++++++++++++++ .../xml/hbm/PreParsedHbmXmlTest.java | 78 +++++++++++++++++++ .../annotations/xml/ejb3/pre-parsed-orm.xml | 22 ++++++ .../annotations/xml/hbm/pre-parsed-hbm.xml | 18 +++++ 6 files changed, 228 insertions(+) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/PreParsedOrmXmlTest.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/xml/hbm/PreParsedHbmXmlTest.java create mode 100644 hibernate-core/src/test/resources/org/hibernate/test/annotations/xml/ejb3/pre-parsed-orm.xml create mode 100644 hibernate-core/src/test/resources/org/hibernate/test/annotations/xml/hbm/pre-parsed-hbm.xml diff --git a/hibernate-core/src/main/java/org/hibernate/boot/MetadataSources.java b/hibernate-core/src/main/java/org/hibernate/boot/MetadataSources.java index 5e86f504ad46..932ac5c16cf1 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/MetadataSources.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/MetadataSources.java @@ -338,6 +338,18 @@ public MetadataSources addFile(File file) { return this; } + /** + * Add XML mapping bindings created from an arbitrary source by the {@link #getXmlMappingBinderAccess() binder}. + * + * @param binding The binding. + * + * @return this (for method chaining purposes) + */ + public MetadataSources addXmlBinding(Binding binding) { + getXmlBindingsForWrite().add( binding ); + return this; + } + /** * See {@link #addCacheableFile(java.io.File)} for description * diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/Configuration.java b/hibernate-core/src/main/java/org/hibernate/cfg/Configuration.java index 85b63d24a4fe..d6c4715f1ab0 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/Configuration.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/Configuration.java @@ -29,6 +29,7 @@ import org.hibernate.boot.MetadataBuilder; import org.hibernate.boot.MetadataSources; import org.hibernate.boot.SessionFactoryBuilder; +import org.hibernate.boot.jaxb.spi.Binding; import org.hibernate.boot.model.TypeContributor; import org.hibernate.boot.model.naming.ImplicitNamingStrategy; import org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl; @@ -39,6 +40,7 @@ import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.boot.spi.XmlMappingBinderAccess; import org.hibernate.cfg.annotations.NamedEntityGraphDefinition; import org.hibernate.cfg.annotations.NamedProcedureCallDefinition; import org.hibernate.context.spi.CurrentTenantIdentifierResolver; @@ -364,6 +366,13 @@ public Configuration addFile(File xmlFile) throws MappingException { return this; } + /** + * @return An object capable of parsing XML mapping files that can then be passed to {@link #addXmlMapping(Binding)}. + */ + public XmlMappingBinderAccess getXmlMappingBinderAccess() { + return metadataSources.getXmlMappingBinderAccess(); + } + /** * @deprecated No longer supported. */ @@ -371,6 +380,17 @@ public Configuration addFile(File xmlFile) throws MappingException { public void add(XmlDocument metadataXml) { } + /** + * Read mappings that were parsed using {@link #getXmlMappingBinderAccess()}. + * + * @param binding the parsed mapping + * @return this (for method chaining purposes) + */ + public Configuration addXmlMapping(Binding binding) { + metadataSources.addXmlBinding( binding ); + return this; + } + /** * Add a cached mapping file. A cached file is a serialized representation * of the DOM structure of a particular mapping. It is saved from a previous diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/PreParsedOrmXmlTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/PreParsedOrmXmlTest.java new file mode 100644 index 000000000000..04640901d860 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/PreParsedOrmXmlTest.java @@ -0,0 +1,78 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.annotations.xml.ejb3; + +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; + +import org.hibernate.boot.jaxb.spi.Binding; +import org.hibernate.cfg.Configuration; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +@TestForIssue(jiraKey = "HHH-14530") +public class PreParsedOrmXmlTest extends BaseCoreFunctionalTestCase { + + @Override + protected void addMappings(Configuration configuration) { + super.addMappings( configuration ); + try (InputStream xmlStream = Thread.currentThread().getContextClassLoader() + .getResourceAsStream( "org/hibernate/test/annotations/xml/ejb3/pre-parsed-orm.xml" )) { + Binding parsed = configuration.getXmlMappingBinderAccess().bind( xmlStream ); + configuration.addXmlMapping( parsed ); + } + catch (IOException e) { + throw new UncheckedIOException( e ); + } + } + + @Test + public void testPreParsedOrmXml() { + // Just check that the entity can be persisted, which means the mapping file was taken into account + NonAnnotatedEntity persistedEntity = new NonAnnotatedEntity( "someName" ); + inTransaction( s -> s.persist( persistedEntity ) ); + inTransaction( s -> { + NonAnnotatedEntity retrievedEntity = s.find( NonAnnotatedEntity.class, persistedEntity.getId() ); + assertThat( retrievedEntity ).extracting( NonAnnotatedEntity::getName ) + .isEqualTo( persistedEntity.getName() ); + } ); + } + + public static class NonAnnotatedEntity { + private long id; + + private String name; + + public NonAnnotatedEntity() { + } + + public NonAnnotatedEntity(String name) { + this.name = name; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/hbm/PreParsedHbmXmlTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/hbm/PreParsedHbmXmlTest.java new file mode 100644 index 000000000000..441751aa61b0 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/hbm/PreParsedHbmXmlTest.java @@ -0,0 +1,78 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.annotations.xml.hbm; + +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; + +import org.hibernate.boot.jaxb.spi.Binding; +import org.hibernate.cfg.Configuration; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +@TestForIssue(jiraKey = "HHH-14530") +public class PreParsedHbmXmlTest extends BaseCoreFunctionalTestCase { + + @Override + protected void addMappings(Configuration configuration) { + super.addMappings( configuration ); + try (InputStream xmlStream = Thread.currentThread().getContextClassLoader() + .getResourceAsStream( "org/hibernate/test/annotations/xml/hbm/pre-parsed-hbm.xml" )) { + Binding parsed = configuration.getXmlMappingBinderAccess().bind( xmlStream ); + configuration.addXmlMapping( parsed ); + } + catch (IOException e) { + throw new UncheckedIOException( e ); + } + } + + @Test + public void testPreParsedHbmXml() { + // Just check that the entity can be persisted, which means the mapping file was taken into account + NonAnnotatedEntity persistedEntity = new NonAnnotatedEntity( "someName" ); + inTransaction( s -> s.persist( persistedEntity ) ); + inTransaction( s -> { + NonAnnotatedEntity retrievedEntity = s.find( NonAnnotatedEntity.class, persistedEntity.getId() ); + assertThat( retrievedEntity ).extracting( NonAnnotatedEntity::getName ) + .isEqualTo( persistedEntity.getName() ); + } ); + } + + public static class NonAnnotatedEntity { + private long id; + + private String name; + + public NonAnnotatedEntity() { + } + + public NonAnnotatedEntity(String name) { + this.name = name; + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } +} diff --git a/hibernate-core/src/test/resources/org/hibernate/test/annotations/xml/ejb3/pre-parsed-orm.xml b/hibernate-core/src/test/resources/org/hibernate/test/annotations/xml/ejb3/pre-parsed-orm.xml new file mode 100644 index 000000000000..bc06432f182a --- /dev/null +++ b/hibernate-core/src/test/resources/org/hibernate/test/annotations/xml/ejb3/pre-parsed-orm.xml @@ -0,0 +1,22 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/hibernate-core/src/test/resources/org/hibernate/test/annotations/xml/hbm/pre-parsed-hbm.xml b/hibernate-core/src/test/resources/org/hibernate/test/annotations/xml/hbm/pre-parsed-hbm.xml new file mode 100644 index 000000000000..8aca88a94f5f --- /dev/null +++ b/hibernate-core/src/test/resources/org/hibernate/test/annotations/xml/hbm/pre-parsed-hbm.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + From fcc63d9ab0d4e2206d1d1d92ca2b24f1e38e5f3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Wed, 31 Mar 2021 16:51:42 +0200 Subject: [PATCH 088/644] HHH-14529 Stop using two separate BootstrapServiceRegistries for the same SessionFactory in BaseCoreFunctionalTestCase --- .../collections/BasicTypeCollectionTest.java | 5 ++--- .../mapping/basic/BitSetTypeTest.java | 5 ++--- .../mapping/basic/BitSetUserTypeTest.java | 5 ++--- .../bulkid/AbstractBulkCompositeIdTest.java | 5 ++--- .../test/bulkid/AbstractBulkIdTest.java | 5 ++--- .../SQLServerDialectCollationTest.java | 9 +++++---- ...SQLServerDialectTempTableCollationTest.java | 10 +++++----- .../functional/SQLServerDialectTest.java | 5 ++--- .../TenantResolverConfigurationTest.java | 5 ++--- .../junit4/BaseCoreFunctionalTestCase.java | 18 ++++++------------ 10 files changed, 30 insertions(+), 42 deletions(-) diff --git a/documentation/src/test/java/org/hibernate/userguide/collections/BasicTypeCollectionTest.java b/documentation/src/test/java/org/hibernate/userguide/collections/BasicTypeCollectionTest.java index 8def4aedf7c1..edf53fcb330a 100644 --- a/documentation/src/test/java/org/hibernate/userguide/collections/BasicTypeCollectionTest.java +++ b/documentation/src/test/java/org/hibernate/userguide/collections/BasicTypeCollectionTest.java @@ -51,12 +51,11 @@ public void testLifecycle() { } @Override - protected Configuration constructAndConfigureConfiguration() { - Configuration configuration = super.constructAndConfigureConfiguration(); + protected void configure(Configuration configuration) { + super.configure( configuration ); configuration.registerTypeContributor( (typeContributions, serviceRegistry) -> { typeContributions.contributeType( new CommaDelimitedStringsType() ); } ); - return configuration; } //tag::collections-comma-delimited-collection-example[] diff --git a/documentation/src/test/java/org/hibernate/userguide/mapping/basic/BitSetTypeTest.java b/documentation/src/test/java/org/hibernate/userguide/mapping/basic/BitSetTypeTest.java index d7e426463351..baa87e38aad5 100644 --- a/documentation/src/test/java/org/hibernate/userguide/mapping/basic/BitSetTypeTest.java +++ b/documentation/src/test/java/org/hibernate/userguide/mapping/basic/BitSetTypeTest.java @@ -32,14 +32,13 @@ protected Class[] getAnnotatedClasses() { } @Override - protected Configuration constructAndConfigureConfiguration() { - Configuration configuration = super.constructAndConfigureConfiguration(); + protected void configure(Configuration configuration) { + super.configure( configuration ); //tag::basic-custom-type-register-BasicType-example[] configuration.registerTypeContributor( (typeContributions, serviceRegistry) -> { typeContributions.contributeType( BitSetType.INSTANCE ); } ); //end::basic-custom-type-register-BasicType-example[] - return configuration; } @Test diff --git a/documentation/src/test/java/org/hibernate/userguide/mapping/basic/BitSetUserTypeTest.java b/documentation/src/test/java/org/hibernate/userguide/mapping/basic/BitSetUserTypeTest.java index a0c7fd7293fe..6a7a7ffb52f7 100644 --- a/documentation/src/test/java/org/hibernate/userguide/mapping/basic/BitSetUserTypeTest.java +++ b/documentation/src/test/java/org/hibernate/userguide/mapping/basic/BitSetUserTypeTest.java @@ -36,14 +36,13 @@ protected Class[] getAnnotatedClasses() { } @Override - protected Configuration constructAndConfigureConfiguration() { - Configuration configuration = super.constructAndConfigureConfiguration(); + protected void configure(Configuration configuration) { + super.configure( configuration ); //tag::basic-custom-type-register-UserType-example[] configuration.registerTypeContributor( (typeContributions, serviceRegistry) -> { typeContributions.contributeType( BitSetUserType.INSTANCE, "bitset"); } ); //end::basic-custom-type-register-UserType-example[] - return configuration; } @Test diff --git a/hibernate-core/src/test/java/org/hibernate/test/bulkid/AbstractBulkCompositeIdTest.java b/hibernate-core/src/test/java/org/hibernate/test/bulkid/AbstractBulkCompositeIdTest.java index 4b468ccd1365..a3c4d5138f39 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bulkid/AbstractBulkCompositeIdTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bulkid/AbstractBulkCompositeIdTest.java @@ -33,13 +33,12 @@ protected Class[] getAnnotatedClasses() { } @Override - protected Configuration constructConfiguration() { - Configuration configuration = super.constructConfiguration(); + protected void configure(Configuration configuration) { + super.configure( configuration ); Class strategyClass = getMultiTableBulkIdStrategyClass(); if ( strategyClass != null ) { configuration.setProperty( AvailableSettings.HQL_BULK_ID_STRATEGY, strategyClass.getName() ); } - return configuration; } protected abstract Class getMultiTableBulkIdStrategyClass(); diff --git a/hibernate-core/src/test/java/org/hibernate/test/bulkid/AbstractBulkIdTest.java b/hibernate-core/src/test/java/org/hibernate/test/bulkid/AbstractBulkIdTest.java index eeef7b9a676b..fddbd710eeff 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bulkid/AbstractBulkIdTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bulkid/AbstractBulkIdTest.java @@ -32,10 +32,9 @@ protected Class[] getAnnotatedClasses() { } @Override - protected Configuration constructConfiguration() { - Configuration configuration = super.constructConfiguration(); + protected void configure(Configuration configuration) { + super.configure( configuration ); configuration.setProperty( AvailableSettings.HQL_BULK_ID_STRATEGY, getMultiTableBulkIdStrategyClass().getName() ); - return configuration; } protected abstract Class getMultiTableBulkIdStrategyClass(); diff --git a/hibernate-core/src/test/java/org/hibernate/test/dialect/functional/SQLServerDialectCollationTest.java b/hibernate-core/src/test/java/org/hibernate/test/dialect/functional/SQLServerDialectCollationTest.java index 02eeb5602d39..0de04ac8540f 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/dialect/functional/SQLServerDialectCollationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/dialect/functional/SQLServerDialectCollationTest.java @@ -47,15 +47,16 @@ public class SQLServerDialectCollationTest extends BaseCoreFunctionalTestCase { @Override - protected Configuration constructConfiguration() { - Configuration configuration = super.constructConfiguration(); + protected void configure(Configuration configuration) { + super.configure( configuration ); configuration.setProperty( AvailableSettings.KEYWORD_AUTO_QUOTING_ENABLED, Boolean.TRUE.toString() ); - return configuration; } + @Override protected void buildSessionFactory() { BootstrapServiceRegistry bootRegistry = buildBootstrapServiceRegistry(); - StandardServiceRegistryImpl _serviceRegistry = buildServiceRegistry( bootRegistry, constructConfiguration() ); + StandardServiceRegistryImpl _serviceRegistry = + buildServiceRegistry( bootRegistry, constructAndConfigureConfiguration( bootRegistry ) ); try { try { diff --git a/hibernate-core/src/test/java/org/hibernate/test/dialect/functional/SQLServerDialectTempTableCollationTest.java b/hibernate-core/src/test/java/org/hibernate/test/dialect/functional/SQLServerDialectTempTableCollationTest.java index 0322f9284f1b..de4241181601 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/dialect/functional/SQLServerDialectTempTableCollationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/dialect/functional/SQLServerDialectTempTableCollationTest.java @@ -43,10 +43,9 @@ public class SQLServerDialectTempTableCollationTest extends BaseCoreFunctionalTe private boolean collationChanged; @Override - protected Configuration constructConfiguration() { - Configuration configuration = super.constructConfiguration(); + protected void configure(Configuration configuration) { + super.configure( configuration ); configuration.setProperty( AvailableSettings.KEYWORD_AUTO_QUOTING_ENABLED, Boolean.TRUE.toString() ); - return configuration; } @Override @@ -56,7 +55,7 @@ protected void releaseSessionFactory() { BootstrapServiceRegistry bootRegistry = buildBootstrapServiceRegistry(); StandardServiceRegistryImpl serviceRegistry = buildServiceRegistry( bootRegistry, - constructConfiguration() + constructAndConfigureConfiguration( bootRegistry ) ); try { TransactionUtil.doWithJDBC( @@ -92,7 +91,8 @@ protected void releaseSessionFactory() { @Override protected void buildSessionFactory() { BootstrapServiceRegistry bootRegistry = buildBootstrapServiceRegistry(); - StandardServiceRegistryImpl serviceRegistry = buildServiceRegistry( bootRegistry, constructConfiguration() ); + StandardServiceRegistryImpl serviceRegistry = + buildServiceRegistry( bootRegistry, constructAndConfigureConfiguration( bootRegistry ) ); try { try { diff --git a/hibernate-core/src/test/java/org/hibernate/test/dialect/functional/SQLServerDialectTest.java b/hibernate-core/src/test/java/org/hibernate/test/dialect/functional/SQLServerDialectTest.java index c1ba41ed72f4..98643877b7da 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/dialect/functional/SQLServerDialectTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/dialect/functional/SQLServerDialectTest.java @@ -44,10 +44,9 @@ public class SQLServerDialectTest extends BaseCoreFunctionalTestCase { @Override - protected Configuration constructConfiguration() { - Configuration configuration = super.constructConfiguration(); + protected void configure(Configuration configuration) { + super.configure( configuration ); configuration.setProperty( AvailableSettings.KEYWORD_AUTO_QUOTING_ENABLED, Boolean.TRUE.toString() ); - return configuration; } @Test diff --git a/hibernate-core/src/test/java/org/hibernate/test/multitenancy/schema/TenantResolverConfigurationTest.java b/hibernate-core/src/test/java/org/hibernate/test/multitenancy/schema/TenantResolverConfigurationTest.java index e8423e6a4ad6..18aacf542814 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/multitenancy/schema/TenantResolverConfigurationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/multitenancy/schema/TenantResolverConfigurationTest.java @@ -24,10 +24,9 @@ public class TenantResolverConfigurationTest extends BaseCoreFunctionalTestCase private TestCurrentTenantIdentifierResolver currentTenantResolver = new TestCurrentTenantIdentifierResolver(); @Override - protected Configuration constructAndConfigureConfiguration() { - Configuration configuration = super.constructAndConfigureConfiguration(); + protected void configure(Configuration configuration) { + super.configure( configuration ); configuration.setCurrentTenantIdentifierResolver( currentTenantResolver ); - return configuration; } @Test diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseCoreFunctionalTestCase.java b/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseCoreFunctionalTestCase.java index ebd52c8ee21f..d3dee0e2c494 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseCoreFunctionalTestCase.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseCoreFunctionalTestCase.java @@ -112,11 +112,11 @@ protected void buildSessionFactory() { protected void buildSessionFactory(Consumer configurationAdapter) { // for now, build the configuration to get all the property settings - configuration = constructAndConfigureConfiguration(); + BootstrapServiceRegistry bootRegistry = buildBootstrapServiceRegistry(); + configuration = constructAndConfigureConfiguration( bootRegistry ); if ( configurationAdapter != null ) { configurationAdapter.accept(configuration); } - BootstrapServiceRegistry bootRegistry = buildBootstrapServiceRegistry(); serviceRegistry = buildServiceRegistry( bootRegistry, configuration ); // this is done here because Configuration does not currently support 4.0 xsd afterConstructAndConfigureConfiguration( configuration ); @@ -145,14 +145,8 @@ protected void rebuildSessionFactory(Consumer configurationAdapte buildSessionFactory( configurationAdapter ); } - protected Configuration buildConfiguration() { - Configuration cfg = constructAndConfigureConfiguration(); - afterConstructAndConfigureConfiguration( cfg ); - return cfg; - } - - protected Configuration constructAndConfigureConfiguration() { - Configuration cfg = constructConfiguration(); + protected Configuration constructAndConfigureConfiguration(BootstrapServiceRegistry bootstrapServiceRegistry) { + Configuration cfg = constructConfiguration( bootstrapServiceRegistry ); configure( cfg ); return cfg; } @@ -163,8 +157,8 @@ private void afterConstructAndConfigureConfiguration(Configuration cfg) { afterConfigurationBuilt( cfg ); } - protected Configuration constructConfiguration() { - Configuration configuration = new Configuration(); + protected Configuration constructConfiguration(BootstrapServiceRegistry bootstrapServiceRegistry) { + Configuration configuration = new Configuration( bootstrapServiceRegistry ); configuration.setProperty( AvailableSettings.CACHE_REGION_FACTORY, CachingRegionFactory.class.getName() ); configuration.setProperty( AvailableSettings.USE_NEW_ID_GENERATOR_MAPPINGS, "true" ); if ( createSchema() ) { From 18f23ee7015096a5a1d03288f4bcab2873c6f727 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Wed, 31 Mar 2021 14:37:03 +0200 Subject: [PATCH 089/644] HHH-14529 Fix invalid namespace URIs in MappingXsdSupport Probably copy/pasted from ConfigXsdSupport, and we forgot to add the "/orm" suffix. --- .../main/java/org/hibernate/boot/xsd/MappingXsdSupport.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/boot/xsd/MappingXsdSupport.java b/hibernate-core/src/main/java/org/hibernate/boot/xsd/MappingXsdSupport.java index 33a371927088..0ba5ee2ab8b2 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/xsd/MappingXsdSupport.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/xsd/MappingXsdSupport.java @@ -35,13 +35,13 @@ public class MappingXsdSupport { private final XsdDescriptor jpa21 = LocalXsdResolver.buildXsdDescriptor( "org/hibernate/jpa/orm_2_1.xsd", "2.1", - "http://xmlns.jcp.org/xml/ns/persistence" + "http://xmlns.jcp.org/xml/ns/persistence/orm" ); private final XsdDescriptor jpa22 = LocalXsdResolver.buildXsdDescriptor( "org/hibernate/jpa/orm_2_2.xsd", "2.2", - "http://xmlns.jcp.org/xml/ns/persistence" + "http://xmlns.jcp.org/xml/ns/persistence/orm" ); private final XsdDescriptor jpa30 = LocalXsdResolver.buildXsdDescriptor( From 252fb65f95f8984eea6b44dc268cf57e00a68eb3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Wed, 24 Mar 2021 15:28:09 +0100 Subject: [PATCH 090/644] HHH-14529 Remove an unused xjb file --- hibernate-core/src/main/xjb/orm-bindings.xjb | 18 ------------------ 1 file changed, 18 deletions(-) delete mode 100644 hibernate-core/src/main/xjb/orm-bindings.xjb diff --git a/hibernate-core/src/main/xjb/orm-bindings.xjb b/hibernate-core/src/main/xjb/orm-bindings.xjb deleted file mode 100644 index 940eb3a86a24..000000000000 --- a/hibernate-core/src/main/xjb/orm-bindings.xjb +++ /dev/null @@ -1,18 +0,0 @@ - - - - - - - - - - - - - - - - \ No newline at end of file From 2907c95cbd92f382a83252723b944cfdbcdf25b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Wed, 24 Mar 2021 15:40:12 +0100 Subject: [PATCH 091/644] HHH-14529 Introduce JAXB bindings for JPA's orm.xml Adapted from Steve's work on the unified JPA/ORM XML mapping. See: https://github.com/sebersole/hibernate-orm/commit/4ff3795e60ef33bc893d4174b6c998027e64be10#diff-b407928c3aa7ee1f231e0119ff70345caa5f6a83ed6348128c5159afbe3c6df2 https://github.com/sebersole/hibernate-orm/compare/jandex-binding Co-authored-by: Steve Ebersole --- hibernate-core/hibernate-core.gradle | 5 + .../internal/AccessTypeMarshalling.java | 24 + .../DiscriminatorTypeMarshalling.java | 24 + .../mapping/internal/EnumTypeMarshalling.java | 24 + .../internal/FetchTypeMarshalling.java | 24 + .../internal/LockModeTypeMarshalling.java | 24 + .../internal/ParameterModeMarshalling.java | 24 + .../internal/TemporalTypeMarshalling.java | 24 + .../boot/jaxb/mapping/package-info.java | 11 + .../jaxb/mapping/spi/AttributesContainer.java | 35 + .../jaxb/mapping/spi/CollectionAttribute.java | 57 + .../jaxb/mapping/spi/FetchableAttribute.java | 22 + .../jaxb/mapping/spi/LifecycleCallback.java | 17 + .../boot/jaxb/mapping/spi/ManagedType.java | 28 + .../jaxb/mapping/spi/PersistentAttribute.java | 23 + .../boot/jaxb/mapping/spi/SchemaAware.java | 23 + .../hibernate/mapping/PersistentClass.java | 31 + .../org/hibernate/mapping/SimpleValue.java | 21 + .../hibernate/xsd/mapping/mapping-2.1.0.xsd | 2543 +++++++++++++++++ .../src/main/xjb/mapping-bindings.xjb | 164 ++ 20 files changed, 3148 insertions(+) create mode 100644 hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/AccessTypeMarshalling.java create mode 100644 hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/DiscriminatorTypeMarshalling.java create mode 100644 hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/EnumTypeMarshalling.java create mode 100644 hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/FetchTypeMarshalling.java create mode 100644 hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/LockModeTypeMarshalling.java create mode 100644 hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/ParameterModeMarshalling.java create mode 100644 hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/TemporalTypeMarshalling.java create mode 100644 hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/package-info.java create mode 100644 hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/AttributesContainer.java create mode 100644 hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/CollectionAttribute.java create mode 100644 hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/FetchableAttribute.java create mode 100644 hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/LifecycleCallback.java create mode 100644 hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/ManagedType.java create mode 100644 hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/PersistentAttribute.java create mode 100644 hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/SchemaAware.java create mode 100644 hibernate-core/src/main/resources/org/hibernate/xsd/mapping/mapping-2.1.0.xsd create mode 100644 hibernate-core/src/main/xjb/mapping-bindings.xjb diff --git a/hibernate-core/hibernate-core.gradle b/hibernate-core/hibernate-core.gradle index f4ae9c527003..8008fa1c4fd2 100644 --- a/hibernate-core/hibernate-core.gradle +++ b/hibernate-core/hibernate-core.gradle @@ -200,6 +200,11 @@ xjc { xjcBinding = file( 'src/main/xjb/hbm-mapping-bindings.xjb' ) xjcExtensions = ['inheritance', 'simplify'] } + mapping { + xsd = file( 'src/main/resources/org/hibernate/jpa/orm_2_2.xsd' ) + xjcBinding = file( 'src/main/xjb/mapping-bindings.xjb' ) + xjcExtensions = ['inheritance'] + } } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/AccessTypeMarshalling.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/AccessTypeMarshalling.java new file mode 100644 index 000000000000..6d413c8024ed --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/AccessTypeMarshalling.java @@ -0,0 +1,24 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.boot.jaxb.mapping.internal; + +import javax.persistence.AccessType; + +/** + * Marshalling support for dealing with JPA AccessType enums. Plugged into JAXB for binding + * + * @author Steve Ebersole + */ +public class AccessTypeMarshalling { + public static AccessType fromXml(String name) { + return AccessType.valueOf( name ); + } + + public static String toXml(AccessType accessType) { + return accessType.name(); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/DiscriminatorTypeMarshalling.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/DiscriminatorTypeMarshalling.java new file mode 100644 index 000000000000..06ece7dff167 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/DiscriminatorTypeMarshalling.java @@ -0,0 +1,24 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.boot.jaxb.mapping.internal; + +import javax.persistence.DiscriminatorType; + +/** + * Marshalling support for dealing with JPA DiscriminatorType enums. Plugged into JAXB for binding + * + * @author Steve Ebersole + */ +public class DiscriminatorTypeMarshalling { + public static DiscriminatorType fromXml(String name) { + return DiscriminatorType.valueOf( name ); + } + + public static String toXml(DiscriminatorType discriminatorType) { + return discriminatorType.name(); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/EnumTypeMarshalling.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/EnumTypeMarshalling.java new file mode 100644 index 000000000000..9164ad6e6f4b --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/EnumTypeMarshalling.java @@ -0,0 +1,24 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.boot.jaxb.mapping.internal; + +import javax.persistence.EnumType; + +/** + * Marshalling support for dealing with JPA EnumType enums. Plugged into JAXB for binding + * + * @author Steve Ebersole + */ +public class EnumTypeMarshalling { + public static EnumType fromXml(String name) { + return EnumType.valueOf( name ); + } + + public static String toXml(EnumType enumType) { + return enumType.name(); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/FetchTypeMarshalling.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/FetchTypeMarshalling.java new file mode 100644 index 000000000000..537c76377dce --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/FetchTypeMarshalling.java @@ -0,0 +1,24 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.boot.jaxb.mapping.internal; + +import javax.persistence.FetchType; + +/** + * Marshalling support for dealing with JPA FetchType enums. Plugged into JAXB for binding + * + * @author Steve Ebersole + */ +public class FetchTypeMarshalling { + public static FetchType fromXml(String name) { + return FetchType.valueOf( name ); + } + + public static String toXml(FetchType fetchType) { + return fetchType.name(); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/LockModeTypeMarshalling.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/LockModeTypeMarshalling.java new file mode 100644 index 000000000000..fb975cc7568a --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/LockModeTypeMarshalling.java @@ -0,0 +1,24 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.boot.jaxb.mapping.internal; + +import javax.persistence.LockModeType; + +/** + * Marshalling support for dealing with JPA LockModeType enums. Plugged into JAXB for binding + * + * @author Steve Ebersole + */ +public class LockModeTypeMarshalling { + public static LockModeType fromXml(String name) { + return LockModeType.valueOf( name ); + } + + public static String toXml(LockModeType lockModeType) { + return lockModeType.name(); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/ParameterModeMarshalling.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/ParameterModeMarshalling.java new file mode 100644 index 000000000000..a48193340005 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/ParameterModeMarshalling.java @@ -0,0 +1,24 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.boot.jaxb.mapping.internal; + +import javax.persistence.ParameterMode; + +/** + * Marshalling support for dealing with JPA ParameterMode enums. Plugged into JAXB for binding + * + * @author Steve Ebersole + */ +public class ParameterModeMarshalling { + public static ParameterMode fromXml(String name) { + return ParameterMode.valueOf( name ); + } + + public static String toXml(ParameterMode parameterMode) { + return parameterMode.name(); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/TemporalTypeMarshalling.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/TemporalTypeMarshalling.java new file mode 100644 index 000000000000..09ace499db99 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/TemporalTypeMarshalling.java @@ -0,0 +1,24 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.boot.jaxb.mapping.internal; + +import javax.persistence.TemporalType; + +/** + * Marshalling support for dealing with JPA TemporalType enums. Plugged into JAXB for binding + * + * @author Steve Ebersole + */ +public class TemporalTypeMarshalling { + public static TemporalType fromXml(String name) { + return TemporalType.valueOf( name ); + } + + public static String toXml(TemporalType temporalType) { + return temporalType.name(); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/package-info.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/package-info.java new file mode 100644 index 000000000000..0d61b3224e46 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/package-info.java @@ -0,0 +1,11 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ + +/** + * JAXB for JPA's {@code orm.xml} mapping schema. + */ +package org.hibernate.boot.jaxb.mapping; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/AttributesContainer.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/AttributesContainer.java new file mode 100644 index 000000000000..18b20d6592ab --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/AttributesContainer.java @@ -0,0 +1,35 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.boot.jaxb.mapping.spi; + +import java.util.List; + +/** + * Common interface for JAXB bindings which are containers of attributes. + * + * @author Strong Liu + * @author Steve Ebersole + */ +public interface AttributesContainer { + + List getTransient(); + + List getBasic(); + + List getElementCollection(); + + List getEmbedded(); + + List getManyToMany(); + + List getManyToOne(); + + List getOneToMany(); + + List getOneToOne(); + +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/CollectionAttribute.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/CollectionAttribute.java new file mode 100644 index 000000000000..dc81a6f2245c --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/CollectionAttribute.java @@ -0,0 +1,57 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.boot.jaxb.mapping.spi; + +import java.util.List; +import javax.persistence.EnumType; +import javax.persistence.TemporalType; + +/** + * Common interface for Jaxb bindings that represent persistent collection attributes. + * + * @author Brett Meyer + */ +public interface CollectionAttribute extends FetchableAttribute { + + String getOrderBy(); + + void setOrderBy(String value); + + JaxbOrderColumn getOrderColumn(); + + void setOrderColumn(JaxbOrderColumn value); + + JaxbMapKey getMapKey(); + + void setMapKey(JaxbMapKey value); + + JaxbMapKeyClass getMapKeyClass(); + + void setMapKeyClass(JaxbMapKeyClass value); + + TemporalType getMapKeyTemporal(); + + void setMapKeyTemporal(TemporalType value); + + EnumType getMapKeyEnumerated(); + + void setMapKeyEnumerated(EnumType value); + + List getMapKeyAttributeOverride(); + + List getMapKeyConvert(); + + JaxbMapKeyColumn getMapKeyColumn(); + + void setMapKeyColumn(JaxbMapKeyColumn value); + + List getMapKeyJoinColumn(); + + JaxbForeignKey getMapKeyForeignKey(); + + void setMapKeyForeignKey(JaxbForeignKey value); +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/FetchableAttribute.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/FetchableAttribute.java new file mode 100644 index 000000000000..edce1ae6555a --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/FetchableAttribute.java @@ -0,0 +1,22 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.boot.jaxb.mapping.spi; + +import javax.persistence.FetchType; + +/** + * Common interface for JAXB bindings that represent attributes with laziness and fetch style. + * + * @author Brett Meyer + */ +public interface FetchableAttribute { + + FetchType getFetch(); + + void setFetch(FetchType value); + +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/LifecycleCallback.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/LifecycleCallback.java new file mode 100644 index 000000000000..223207dd81fb --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/LifecycleCallback.java @@ -0,0 +1,17 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.boot.jaxb.mapping.spi; + +/** + * Common interface for all the JAXB bindings representing lifecycle callbacks. + * + * @author Strong Liu + * @author Steve Ebersole + */ +public interface LifecycleCallback { + String getMethodName(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/ManagedType.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/ManagedType.java new file mode 100644 index 000000000000..ab70cbf6d3db --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/ManagedType.java @@ -0,0 +1,28 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.boot.jaxb.mapping.spi; + +import javax.persistence.AccessType; + +/** + * Common interface for JAXB bindings representing entities, mapped-superclasses and embeddables (JPA collective + * calls these "managed types" in terms of its Metamodel api). + * + * @author Strong Liu + * @author Steve Ebersole + */ +public interface ManagedType { + String getClazz(); + + void setClazz(String className); + + Boolean isMetadataComplete(); + + void setMetadataComplete(Boolean isMetadataComplete); + + AccessType getAccess(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/PersistentAttribute.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/PersistentAttribute.java new file mode 100644 index 000000000000..f1ee13b1edfd --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/PersistentAttribute.java @@ -0,0 +1,23 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.boot.jaxb.mapping.spi; + +import javax.persistence.AccessType; + +/** + * Common interface for JAXB bindings that represent persistent attributes. + * + * @author Strong Liu + * @author Steve Ebersole + */ +public interface PersistentAttribute { + String getName(); + + AccessType getAccess(); + + void setAccess(AccessType accessType); +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/SchemaAware.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/SchemaAware.java new file mode 100644 index 000000000000..3f726a4b5159 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/SchemaAware.java @@ -0,0 +1,23 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.boot.jaxb.mapping.spi; + +/** + * Common interface for JAXB bindings that understand database schema (tables, sequences, etc). + * + * @author Strong Liu + * @author Steve Ebersole + */ +public interface SchemaAware { + String getSchema(); + + void setSchema(String schema); + + String getCatalog(); + + void setCatalog(String catalog); +} diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/PersistentClass.java b/hibernate-core/src/main/java/org/hibernate/mapping/PersistentClass.java index 6ab1e7de76b3..7703755e3003 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/PersistentClass.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/PersistentClass.java @@ -17,6 +17,7 @@ import org.hibernate.EntityMode; import org.hibernate.MappingException; +import org.hibernate.boot.model.CustomSql; import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.engine.OptimisticLockStyle; @@ -744,6 +745,16 @@ public Iterator getUnjoinedPropertyIterator() { return properties.iterator(); } + public void setCustomSqlInsert(CustomSql customSql) { + if ( customSql != null ) { + setCustomSQLInsert( + customSql.getSql(), + customSql.isCallable(), + customSql.getCheckStyle() + ); + } + } + public void setCustomSQLInsert(String customSQLInsert, boolean callable, ExecuteUpdateResultCheckStyle checkStyle) { this.customSQLInsert = customSQLInsert; this.customInsertCallable = callable; @@ -762,6 +773,16 @@ public ExecuteUpdateResultCheckStyle getCustomSQLInsertCheckStyle() { return insertCheckStyle; } + public void setCustomSqlUpdate(CustomSql customSql) { + if ( customSql != null ) { + setCustomSQLUpdate( + customSql.getSql(), + customSql.isCallable(), + customSql.getCheckStyle() + ); + } + } + public void setCustomSQLUpdate(String customSQLUpdate, boolean callable, ExecuteUpdateResultCheckStyle checkStyle) { this.customSQLUpdate = customSQLUpdate; this.customUpdateCallable = callable; @@ -780,6 +801,16 @@ public ExecuteUpdateResultCheckStyle getCustomSQLUpdateCheckStyle() { return updateCheckStyle; } + public void setCustomSqlDelete(CustomSql customSql) { + if ( customSql != null ) { + setCustomSQLDelete( + customSql.getSql(), + customSql.isCallable(), + customSql.getCheckStyle() + ); + } + } + public void setCustomSQLDelete(String customSQLDelete, boolean callable, ExecuteUpdateResultCheckStyle checkStyle) { this.customSQLDelete = customSQLDelete; this.customDeleteCallable = callable; diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java b/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java index b1c9790f24b4..da3afbe33ea5 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java @@ -13,6 +13,7 @@ import java.util.Iterator; import java.util.List; import java.util.Locale; +import java.util.Map; import java.util.Properties; import java.util.Objects; import javax.persistence.AttributeConverter; @@ -399,6 +400,18 @@ public void setIdentifierGeneratorProperties(Properties identifierGeneratorPrope this.identifierGeneratorProperties = identifierGeneratorProperties; } + /** + * Sets the identifierGeneratorProperties. + * @param identifierGeneratorProperties The identifierGeneratorProperties to set + */ + public void setIdentifierGeneratorProperties(Map identifierGeneratorProperties) { + if ( identifierGeneratorProperties != null ) { + Properties properties = new Properties(); + properties.putAll( identifierGeneratorProperties ); + setIdentifierGeneratorProperties( properties ); + } + } + /** * Sets the identifierGeneratorStrategy. * @param identifierGeneratorStrategy The identifierGeneratorStrategy to set @@ -679,6 +692,14 @@ public boolean isTypeSpecified() { public void setTypeParameters(Properties parameterMap) { this.typeParameters = parameterMap; } + + public void setTypeParameters(Map parameters) { + if ( parameters != null ) { + Properties properties = new Properties(); + properties.putAll( parameters ); + setTypeParameters( properties ); + } + } public Properties getTypeParameters() { return typeParameters; diff --git a/hibernate-core/src/main/resources/org/hibernate/xsd/mapping/mapping-2.1.0.xsd b/hibernate-core/src/main/resources/org/hibernate/xsd/mapping/mapping-2.1.0.xsd new file mode 100644 index 000000000000..d1b364771bbe --- /dev/null +++ b/hibernate-core/src/main/resources/org/hibernate/xsd/mapping/mapping-2.1.0.xsd @@ -0,0 +1,2543 @@ + + + + + + + ... + + ]]> + + + + + + + + + + The entity-mappings element is the root element of a mapping + file. It contains the following four types of elements: + + 1. The persistence-unit-metadata element contains metadata + for the entire persistence unit. The behavior is undefined if this element + occurs in multiple mapping files within the same persistence unit. + + 2. The package, schema, catalog and access elements apply to all of + the entity, mapped-superclass and embeddable elements defined in + the same file in which they occur. + + 3. The sequence-generator, table-generator, converter, named-query, + named-native-query, named-stored-procedure-query, and + sql-result-set-mapping elements are global to the persistence + unit. + + a. The behavior is undefined when having more than one sequence-generator + or table-generator occur in a persistence unit (whether in the same or + different mapping file). + + b. The behavior is undefined when having more than one named-query, + named-native-query, sql-result-set-mapping, or named-stored-procedure-query + of the same name in a persistence unit (whether in the same or different + mapping file). + + c. The behavior is undefined when having more than one converter for the same + target type in a persistence unit (whether in the same or different mapping file). + + 4. The entity, mapped-superclass and embeddable elements each define + the mapping information for a managed persistent class. The mapping + information contained in these elements may be complete or it may + be partial. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Metadata that applies to the persistence unit and not just to the mapping + file in which it is contained. + + If the xml-mapping-metadata-complete element is specified, + the complete set of mapping metadata for the persistence unit + is contained in the XML mapping files for the persistence unit. + + + + + + + + + + + + + + + These defaults are applied to the persistence unit as a whole unless they + are overridden by local annotation or XML element settings. + + schema - Used as the schema for all tables, secondary tables, join + tables, collection tables, sequence generators, and table + generators that apply to the persistence unit + + catalog - Used as the catalog for all tables, secondary tables, join + tables, collection tables, sequence generators, and table + generators that apply to the persistence unit + + delimited-identifiers - Used to treat database identifiers as + delimited identifiers. + + access - Used as the access type for all managed classes in + the persistence unit + + cascade-persist - Adds cascade-persist to the set of cascade options + in all entity relationships of the persistence unit + + entity-listeners - List of default entity listeners to be invoked + on each entity in the persistence unit. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + javax.persistence.AccessType enum values + + + + + + + + + + + + + + + Hibernate specific "any" mapping, which is a polymorphic association to any different + tables based on a discriminator + + the given identifier type. The first listed column is a VARCHAR column + holding the name of the class (for that row). + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + com.acme.Employee + ]]> + + + + + + + + + + + + + + + This element contains the entity field or property mappings. + It may be sparsely populated to include only a subset of the + fields or properties. If metadata-complete for the entity is true + then the remainder of the attributes will be defaulted according + to the default rules. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @javax.persistence.AssociationOverride + + + + + + + + + + + + + + + + + + + + + + @javax.persistence.AttributeOverride + + + + + + + + + + + + + + + + See javax.persistence.Basic + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Corresponds to the org.hibernate.annotations.Cache annotation. + + Used to specify Hibernate-specific extra control over the caching + of entity and collection state. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.hibernate.CacheMode enum values + + + + + + + + + + + + + + + + + + javax.persistence.CascadeType enum values + + + + + + + + + + + + + + + + + + + org.hibernate.annotations.CascadeType enum values + + + + + + + + + + + + + + + + + + + + + + org.hibernate.annotations.OnDeleteAction enum values + + + + + + + + + + + + + + + @CollectionTable annotation + + + + + + + + + + + + + + + + + + + + + + + See the javax.persistence.Column annotation. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Corresponds to the javax.persistence.Convert annotation + + + + + + + + + + + + + + + + + + Corresponds to the javax.persistence.Converter annotation + + + + + + + + + + + + + + + + @DiscriminatorColumn annotation + + + + + + + + + + + + + + + + + javax.persistence.DiscriminatorType enum values + + + + + + + + + + + + + + + + + @Target({TYPE}) @Retention(RUNTIME) + public @interface DiscriminatorValue { + String value(); + } + + + + + + + + + + + + + Corresponds to the @ElementCollection annotation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + See javax.persistence.Embeddable + + Defines the settings and mappings for embeddable objects. + + Again, with metadata-complete=false the mapping is used in + conjunction with annotations. Alternatively, metadata-complete=true + can be used to indicate that no annotations are to be processed + in the class. If this is the case then the defaulting rules will + be recursively applied. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Corresponds to the javax.persistence.Embedded annotation + + + + + + + + + + + + + + + + + + + + Corresponds to the javax.persistence.EmbeddedId annotation + + + + + + + + + + + + + + + + + See javax.persistence.Entity + + Defines the settings and mappings for an entity. + + May be used in 2 ways: + 1. sparsely populated (metadata-complete=false) and used in + conjunction with the annotations. + 2. as complete self-contained metadata (metadata-complete=true) + indicating that no annotations on the entity class (and its fields + or properties) are to be processed. If this is the case then + the defaulting rules for the entity and its subelements will + be recursively applied. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Corresponds to the JPA javax.persistence.EntityListeners annotation + + + + + + + + + + + + + + Corresponds to the JPA javax.persistence.EntityListener annotation + + Defines an entity listener to be invoked at lifecycle events for + the entities that list this listener. + + + + + + + + + + + + + + + + + + + + + + javax.persistence.EnumType enum values + + + + + + + + + + + + + + + Corresponds to the javax.persistence.Enumerated annotation. + + + + + + + + + + + + javax.persistence.FetchType enum values + + + + + + + + + + + + + + + org.hibernate.annotations.FetchMode enum values + + + + + + + + + + + + + + + + org.hibernate.FlushMode enum values + + + + + + + + + + + + + + + + @ForeignKey annotation + + + + + + + + + + + + + + + + + + See the javax.persistence.GeneratedValue annotation + + + + + + + + + + javax.persistence.GenerationType rnum values + + todo : add custom ones like INCREMENT, UUID, etc + + + + + + + + + + + + + + + + + Hibernate-specific element used declare and short-name custom + org.hibernate.id.IdentifierGenerator implementations + + + + + + + + + + + + + Corresponds to the javax.persistence.Id annotation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Corresponds to the javax.persistence.IdClass annotation + + + + + + + + + + + + Corresponds to @Index annotation + + + + + + + + + + + + + + + + + + + Corresponds to the @Inheritance annotation + + + + + + + + + + + + Corresponds to the JPA InheritanceType enumeration values + Hibernate's UNION_SUBCLASS + + todo : make a singular enum to cover these + + + + + + + + + + + + + + + + + JoinColumn annotation + + + + + + + + + + + + + + + + + + + + @JoinTable annotation + + + + + + + + + + + + + + + + + + + + + + + + + + + + Corresponds to javax.persistence.Lob (marker) annotation + + + + + + + + + + + javax.persistence.LockModeType enum values + + + + + + + + + + + + + + + + + + + + + Hibernate specific "any" mapping (plural form), which is a polymorphic association to any different + tables based on a discriminator. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @ManyToMany annotation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Corresponds to the @ManyToOne annotation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @javax.persistence.MapKey + + + + + + + + + + + + @javax.persistence.MapKeyClass + + + + + + + + + + + + + @javax.persistence.MapKeyColumn + + + + + + + + + + + + + + + + + + + + + + @javax.persistence.MapKeyJoinColumn + + + + + + + + + + + + + + + + + + + + See javax.persistence.MappedSuperclass + + Defines the settings and mappings for a mapped superclass. + + May be used in 2 ways: + 1. sparsely populated (metadata-complete=false) and used in + conjunction with the annotations. + 2. as complete self-contained metadata (metadata-complete=true) + indicating that no annotations are to be processed. If this is + the case then the defaulting rules will be recursively applied. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Hibernate-specific element used to describe the meta-value (discriminator) + mapping for ANY associations. + + + + + + + + + + + + + + @NamedEntityGraph annotation + + + + + + + + + + + + + + + + + @NamedAttributeNode annotation + + + + + + + + + + + + @NamedSubgraph annotation + + + + + + + + + + + + + + + + + + Common Hibernate specific extensions available for named query definitions. + + todo : a lot of these extensions could be handled by JPA QueryHint scheme + + + + + + + + + + + + + + + + + + + + + + + Mix of @javax.persistence.NamedNativeQuery and @org.hibernate.annotations.NamedNativeQuery + + + + + + + + + + + + + + + + + + + + + + Mix of @javax.persistence.NamedQuery and @org.hibernate.annotations.NamedQuery + + + + + + + + + + + + + + + + + + + + Corresponds to the javax.persistence.NamedStoredProcedureQuery annotation + + + + + + + + + + + + + + + + + + + Corresponds to javax.persistence.StoredProcedureParameter annotation + + + + + + + + + + + + + + + + javax.persistence.ParameterMode enum values + + + + + + + + + + + + + + + + + + @OneToMany annotation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Corresponds to the @OneToOne annotation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @javax.persistence.OrderBy annotation + + + + + + + + + + + + + @javax.persistence.OrderColumn annotation + + + + + + + + + + + + + + + + + Corresponds to the javax.persistence.PostLoad annotation + + + + + + + + + + + + + + + + + Corresponds to the javax.persistence.PostPersist annotation + + + + + + + + + + + + + + + + + Corresponds to the javax.persistence.PostRemove annotation + + + + + + + + + + + + + + + + + Corresponds to the javax.persistence.PostUpdate annotation + + + + + + + + + + + + + + + + + Corresponds to the javax.persistence.PrePersist annotation + + + + + + + + + + + + + + + + + Corresponds to the javax.persistence.PreRemove annotation + + + + + + + + + + + + + + + + + Corresponds to the javax.persistence.PreUpdate annotation + + + + + + + + + + + + + + + + + @PrimaryKeyJoinColumn annotation + + + + + + + + + + + + + + + @javax.persistence.QueryHint + + + + + + + + + + + + + + + + + + Used only by tools to generate finder methods for named queries + + + + + + + + + + + + + + @javax.persistence.SecondaryTable + + + + + + + + + + + + + + + + + + + + + + + + + + @javax.persistence.SequenceGenerator + + + + + + + + + + + + + + + + + + + + + + @javax.persistence.SqlResultSetMapping + + + + + + + + + + + + + + + + + + @javax.persistence.ColumnResult + + + + + + + + + + + + @javax.persistence.ConstructorResult + + + + + + + + + + + + + + + @javax.persistence.EntityResult + + + + + + + + + + + + + + + + @javax.persistence.FieldResult + + + + + + + + + + + + + + + + + + + + + @javax.persistence.Table + + + + + + + + + + + + + + + + + + + + + + + + + + + + @javax.persistence.TableGenerator + + + + + + + + + + + + + + + + + + + + + + + + + + + + @javax.persistence.Temporal + + + + + + + + + + + + javax.persistence.TemporalType enum values + + + + + + + + + + + + + + + + @javax.persistence.Transient + + + + + + + + + + + + @javax.persistence.UniqueConstraint + + + + + + + + + + + + + + + + + @javax.persistence.Version + + + + + + + + + + + + + + + + + + + + + + element defines a single path to which the fetch + refers, as well as the style of fetch to apply. The 'root' of the + path is different depending upon the context in which the + containing occurs; within a element, + the entity-name of the containing class mapping is assumed... + ]]> + + + + + + + + + + + + + + + + + + + + + + + + + + Specifies a filter definition. After definition, a filter + can be applied to entity or collection by name. + + + + + + + + + Used to identify all bind parameters in the condition elemement + + + + + + + + + + + + + + + + Applies a filter defined by hbm-filter-def usage + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + Names a org.hibernate.id.IdentifierGenerator implementation (class attribute) + as well as any configuration information need by the implementation (Hibernate + will pass it the parameters after instantiation). + + + + + + + + + + + + + Corresponds to the org.hibernate.annotations.Parameter annotation + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + The loader element allows specification of a named query to be used for fetching + an entity or collection + + + + + + + + + + + + + + + + + + + + + + + + + tags from hbm.xml dtd; renamed here for + self-documentation. This information is intended mainly for tooling. + ]]> + + + + + + + + + + + + + + + + Corresponds to the org.hibernate.annotations.Type annotation, naming + a org.hibernate.type.* or org.hibernate.usertype.* implementation to use. + + name - names the type implementation class + + param - If the type is able to accept parameters (implementation stems from + org.hibernate.type.Type, org.hibernate.type.CollectionType, or + org.hibernate.usertype.ParameterizedType) the specified parameters will be + passed to the type instance after instantiation. + + + + + + + + + + + + + + + + + + + + + + + + + + + + + A natural-id element allows declaration of unique business key + + + + + + + + + + + + + \ No newline at end of file diff --git a/hibernate-core/src/main/xjb/mapping-bindings.xjb b/hibernate-core/src/main/xjb/mapping-bindings.xjb new file mode 100644 index 000000000000..8ee8f838c3fd --- /dev/null +++ b/hibernate-core/src/main/xjb/mapping-bindings.xjb @@ -0,0 +1,164 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + org.hibernate.boot.jaxb.mapping.spi.SchemaAware + + + org.hibernate.boot.jaxb.mapping.spi.SchemaAware + + + org.hibernate.boot.jaxb.mapping.spi.SchemaAware + + + org.hibernate.boot.jaxb.mapping.spi.SchemaAware + + + org.hibernate.boot.jaxb.mapping.spi.SchemaAware + + + org.hibernate.boot.jaxb.mapping.spi.SchemaAware + + + + org.hibernate.boot.jaxb.mapping.spi.ManagedType + + + org.hibernate.boot.jaxb.mapping.spi.ManagedType + + + org.hibernate.boot.jaxb.mapping.spi.ManagedType + + + + org.hibernate.boot.jaxb.mapping.spi.PersistentAttribute + + + org.hibernate.boot.jaxb.mapping.spi.PersistentAttribute + + + org.hibernate.boot.jaxb.mapping.spi.PersistentAttribute + + + org.hibernate.boot.jaxb.mapping.spi.PersistentAttribute + org.hibernate.boot.jaxb.mapping.spi.FetchableAttribute + + + org.hibernate.boot.jaxb.mapping.spi.PersistentAttribute + org.hibernate.boot.jaxb.mapping.spi.CollectionAttribute + + + org.hibernate.boot.jaxb.mapping.spi.PersistentAttribute + org.hibernate.boot.jaxb.mapping.spi.FetchableAttribute + + + org.hibernate.boot.jaxb.mapping.spi.PersistentAttribute + + + org.hibernate.boot.jaxb.mapping.spi.PersistentAttribute + + + org.hibernate.boot.jaxb.mapping.spi.PersistentAttribute + org.hibernate.boot.jaxb.mapping.spi.CollectionAttribute + + + org.hibernate.boot.jaxb.mapping.spi.PersistentAttribute + org.hibernate.boot.jaxb.mapping.spi.CollectionAttribute + + + + org.hibernate.boot.jaxb.mapping.spi.LifecycleCallback + + + org.hibernate.boot.jaxb.mapping.spi.LifecycleCallback + + + org.hibernate.boot.jaxb.mapping.spi.LifecycleCallback + + + org.hibernate.boot.jaxb.mapping.spi.LifecycleCallback + + + org.hibernate.boot.jaxb.mapping.spi.LifecycleCallback + + + org.hibernate.boot.jaxb.mapping.spi.LifecycleCallback + + + org.hibernate.boot.jaxb.mapping.spi.LifecycleCallback + + + + org.hibernate.boot.jaxb.mapping.spi.AttributesContainer + + + org.hibernate.boot.jaxb.mapping.spi.AttributesContainer + + + + + + + + + + \ No newline at end of file From f92275f6c230d89c7bcc0c91a675b5b228a24b34 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Wed, 24 Mar 2021 17:38:30 +0100 Subject: [PATCH 092/644] HHH-14529 Clarify that most fields are final in JPAOverriddenAnnotationReader --- .../JPAOverriddenAnnotationReader.java | 24 +++++++++++-------- 1 file changed, 14 insertions(+), 10 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/JPAOverriddenAnnotationReader.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/JPAOverriddenAnnotationReader.java index b40d2e531c7c..b9adae8b41f2 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/JPAOverriddenAnnotationReader.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/JPAOverriddenAnnotationReader.java @@ -238,12 +238,12 @@ private enum PropertyType { annotationToXml.put( ConstructorResult.class, "constructor-result" ); } - private XMLContext xmlContext; + private final XMLContext xmlContext; private final ClassLoaderAccess classLoaderAccess; private final AnnotatedElement element; - private String className; - private String propertyName; - private PropertyType propertyType; + private final String className; + private final String propertyName; + private final PropertyType propertyType; private transient Annotation[] annotations; private transient Map annotationsMap; private transient List elementsForProperty; @@ -263,6 +263,8 @@ public JPAOverriddenAnnotationReader( if ( el instanceof Class ) { Class clazz = (Class) el; className = clazz.getName(); + propertyName = null; + propertyType = null; } else if ( el instanceof Field ) { Field field = (Field) el; @@ -282,18 +284,18 @@ else if ( el instanceof Field ) { else if ( el instanceof Method ) { Method method = (Method) el; className = method.getDeclaringClass().getName(); - propertyName = method.getName(); + String methodName = method.getName(); // YUCK! The null here is the 'boundType', we'd rather get the TypeEnvironment() if ( ReflectionUtil.isProperty( method, null, PersistentAttributeFilter.INSTANCE ) ) { - if ( propertyName.startsWith( "get" ) ) { - propertyName = Introspector.decapitalize( propertyName.substring( "get".length() ) ); + if ( methodName.startsWith( "get" ) ) { + propertyName = Introspector.decapitalize( methodName.substring( "get".length() ) ); } - else if ( propertyName.startsWith( "is" ) ) { - propertyName = Introspector.decapitalize( propertyName.substring( "is".length() ) ); + else if ( methodName.startsWith( "is" ) ) { + propertyName = Introspector.decapitalize( methodName.substring( "is".length() ) ); } else { - throw new RuntimeException( "Method " + propertyName + " is not a property getter" ); + throw new RuntimeException( "Method " + methodName + " is not a property getter" ); } propertyType = PropertyType.PROPERTY; try { @@ -304,12 +306,14 @@ else if ( propertyName.startsWith( "is" ) ) { } } else { + propertyName = methodName; propertyType = PropertyType.METHOD; } } else { className = null; propertyName = null; + propertyType = null; } } From 55ef4d47f2aa595734fca8632477ff104b002b84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Fri, 26 Mar 2021 08:26:44 +0100 Subject: [PATCH 093/644] HHH-14529 Remove commented-out code related to mapping parsing using dom4j --- ...AnnotationMetadataSourceProcessorImpl.java | 23 ------------------- 1 file changed, 23 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/annotations/AnnotationMetadataSourceProcessorImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/annotations/AnnotationMetadataSourceProcessorImpl.java index e7b4e609463c..9fe1d5ed8342 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/annotations/AnnotationMetadataSourceProcessorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/annotations/AnnotationMetadataSourceProcessorImpl.java @@ -83,13 +83,6 @@ public AnnotationMetadataSourceProcessorImpl( final JPAMetadataProvider jpaMetadataProvider = (JPAMetadataProvider) ( (MetadataProviderInjector) reflectionManager ) .getMetadataProvider(); for ( Binding xmlBinding : managedResources.getXmlMappingBindings() ) { - // if ( !MappingBinder.DelayedOrmXmlData.class.isInstance( xmlBinding.getRoot() ) ) { - // continue; - // } - // - // // convert the StAX representation in delayedOrmXmlData to DOM because that's what commons-annotations needs - // final MappingBinder.DelayedOrmXmlData delayedOrmXmlData = (MappingBinder.DelayedOrmXmlData) xmlBinding.getRoot(); - // org.dom4j.Document dom4jDocument = toDom4jDocument( delayedOrmXmlData ); if ( !org.dom4j.Document.class.isInstance( xmlBinding.getRoot() ) ) { continue; } @@ -138,22 +131,6 @@ private XClass toXClass(String className, ReflectionManager reflectionManager, C return reflectionManager.toXClass( cls.classForName( className ) ); } -// private Document toDom4jDocument(MappingBinder.DelayedOrmXmlData delayedOrmXmlData) { -// // todo : do we need to build a DocumentFactory instance for use here? -// // historically we did that to set TCCL since, iirc, dom4j uses TCCL -// org.dom4j.io.STAXEventReader staxToDom4jReader = new STAXEventReader(); -// try { -// return staxToDom4jReader.readDocument( delayedOrmXmlData.getStaxEventReader() ); -// } -// catch (XMLStreamException e) { -// throw new MappingException( -// "An error occurred transforming orm.xml document from StAX to dom4j representation ", -// e, -// delayedOrmXmlData.getOrigin() -// ); -// } -// } - @Override public void prepare() { // use any persistence-unit-defaults defined in orm.xml From 72910366801831e7ccaea216318a79dd5b3bf204 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Fri, 26 Mar 2021 08:59:56 +0100 Subject: [PATCH 094/644] HHH-14529 Copy orm.xml handling code to prepare for the new JAXB-based implementation We will adapt the code in a later commit; I'm only doing the copy in this commit in order to keep the review manageable. --- .../JPAXMLOverriddenAnnotationReader.java | 3084 +++++++++++++++++ .../JPAXMLOverriddenMetadataProvider.java | 230 ++ .../reflection/internal/XMLContext.java | 359 ++ .../ElementCollectionConverterTest.java | 10 +- .../JPAXMLOverriddenAnnotationReaderTest.java | 432 +++ .../LegacyElementCollectionConverterTest.java | 71 + ...acyJPAOverriddenAnnotationReaderTest.java} | 88 +- .../reflection/LegacyXMLContextTest.java | 73 + .../reflection/XMLContextTest.java | 10 +- .../ejb3/Ejb3XmlElementCollectionTest.java | 2 + .../xml/ejb3/Ejb3XmlManyToManyTest.java | 2 + .../xml/ejb3/Ejb3XmlManyToOneTest.java | 2 + .../xml/ejb3/Ejb3XmlOneToManyTest.java | 2 + .../xml/ejb3/Ejb3XmlOneToOneTest.java | 2 + .../annotations/xml/ejb3/Ejb3XmlTest.java | 10 + .../annotations/xml/ejb3/Ejb3XmlTestCase.java | 12 +- .../LegacyEjb3XmlElementCollectionTest.java | 716 ++++ .../xml/ejb3/LegacyEjb3XmlManyToManyTest.java | 508 +++ .../xml/ejb3/LegacyEjb3XmlManyToOneTest.java | 245 ++ .../xml/ejb3/LegacyEjb3XmlOneToManyTest.java | 561 +++ .../xml/ejb3/LegacyEjb3XmlOneToOneTest.java | 309 ++ .../xml/ejb3/LegacyEjb3XmlTest.java | 148 + .../xml/ejb3/LegacyEjb3XmlTestCase.java | 82 + .../ejb3/LegacyNonExistentOrmVersionTest.java | 42 + .../ejb3/LegacyOrmVersion1SupportedTest.java | 68 + .../xml/ejb3/LegacyPreParsedOrmXmlTest.java | 58 + .../xml/ejb3/NonExistentOrmVersionTest.java | 6 +- .../xml/ejb3/OrmVersion1SupportedTest.java | 9 +- .../xml/ejb3/PreParsedOrmXmlTest.java | 9 +- 29 files changed, 7125 insertions(+), 25 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenAnnotationReader.java create mode 100644 hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenMetadataProvider.java create mode 100644 hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/XMLContext.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/JPAXMLOverriddenAnnotationReaderTest.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/LegacyElementCollectionConverterTest.java rename hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/{JPAOverriddenAnnotationReaderTest.java => LegacyJPAOverriddenAnnotationReaderTest.java} (88%) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/LegacyXMLContextTest.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlElementCollectionTest.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlManyToManyTest.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlManyToOneTest.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlOneToManyTest.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlOneToOneTest.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlTest.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlTestCase.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyNonExistentOrmVersionTest.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyOrmVersion1SupportedTest.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyPreParsedOrmXmlTest.java diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenAnnotationReader.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenAnnotationReader.java new file mode 100644 index 000000000000..4e2a630952ee --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenAnnotationReader.java @@ -0,0 +1,3084 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.cfg.annotations.reflection.internal; + +import java.beans.Introspector; +import java.lang.annotation.Annotation; +import java.lang.reflect.AccessibleObject; +import java.lang.reflect.AnnotatedElement; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Set; +import javax.persistence.Access; +import javax.persistence.AccessType; +import javax.persistence.AssociationOverride; +import javax.persistence.AssociationOverrides; +import javax.persistence.AttributeOverride; +import javax.persistence.AttributeOverrides; +import javax.persistence.Basic; +import javax.persistence.Cacheable; +import javax.persistence.CascadeType; +import javax.persistence.CollectionTable; +import javax.persistence.Column; +import javax.persistence.ColumnResult; +import javax.persistence.ConstructorResult; +import javax.persistence.Convert; +import javax.persistence.Converts; +import javax.persistence.DiscriminatorColumn; +import javax.persistence.DiscriminatorType; +import javax.persistence.DiscriminatorValue; +import javax.persistence.ElementCollection; +import javax.persistence.Embeddable; +import javax.persistence.Embedded; +import javax.persistence.EmbeddedId; +import javax.persistence.Entity; +import javax.persistence.EntityListeners; +import javax.persistence.EntityResult; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.ExcludeDefaultListeners; +import javax.persistence.ExcludeSuperclassListeners; +import javax.persistence.FetchType; +import javax.persistence.FieldResult; +import javax.persistence.ForeignKey; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.IdClass; +import javax.persistence.Index; +import javax.persistence.Inheritance; +import javax.persistence.InheritanceType; +import javax.persistence.JoinColumn; +import javax.persistence.JoinColumns; +import javax.persistence.JoinTable; +import javax.persistence.Lob; +import javax.persistence.ManyToMany; +import javax.persistence.ManyToOne; +import javax.persistence.MapKey; +import javax.persistence.MapKeyClass; +import javax.persistence.MapKeyColumn; +import javax.persistence.MapKeyEnumerated; +import javax.persistence.MapKeyJoinColumn; +import javax.persistence.MapKeyJoinColumns; +import javax.persistence.MapKeyTemporal; +import javax.persistence.MappedSuperclass; +import javax.persistence.MapsId; +import javax.persistence.NamedAttributeNode; +import javax.persistence.NamedEntityGraph; +import javax.persistence.NamedEntityGraphs; +import javax.persistence.NamedNativeQueries; +import javax.persistence.NamedNativeQuery; +import javax.persistence.NamedQueries; +import javax.persistence.NamedQuery; +import javax.persistence.NamedStoredProcedureQueries; +import javax.persistence.NamedStoredProcedureQuery; +import javax.persistence.NamedSubgraph; +import javax.persistence.OneToMany; +import javax.persistence.OneToOne; +import javax.persistence.OrderBy; +import javax.persistence.OrderColumn; +import javax.persistence.ParameterMode; +import javax.persistence.PostLoad; +import javax.persistence.PostPersist; +import javax.persistence.PostRemove; +import javax.persistence.PostUpdate; +import javax.persistence.PrePersist; +import javax.persistence.PreRemove; +import javax.persistence.PreUpdate; +import javax.persistence.PrimaryKeyJoinColumn; +import javax.persistence.PrimaryKeyJoinColumns; +import javax.persistence.QueryHint; +import javax.persistence.SecondaryTable; +import javax.persistence.SecondaryTables; +import javax.persistence.SequenceGenerator; +import javax.persistence.SqlResultSetMapping; +import javax.persistence.SqlResultSetMappings; +import javax.persistence.StoredProcedureParameter; +import javax.persistence.Table; +import javax.persistence.TableGenerator; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import javax.persistence.Transient; +import javax.persistence.UniqueConstraint; +import javax.persistence.Version; + +import org.hibernate.AnnotationException; +import org.hibernate.annotations.Any; +import org.hibernate.annotations.Cascade; +import org.hibernate.annotations.Columns; +import org.hibernate.annotations.ManyToAny; +import org.hibernate.annotations.common.annotationfactory.AnnotationDescriptor; +import org.hibernate.annotations.common.annotationfactory.AnnotationFactory; +import org.hibernate.annotations.common.reflection.AnnotationReader; +import org.hibernate.annotations.common.reflection.ReflectionUtil; +import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; +import org.hibernate.boot.spi.BootstrapContext; +import org.hibernate.boot.spi.ClassLoaderAccess; +import org.hibernate.cfg.annotations.reflection.PersistentAttributeFilter; +import org.hibernate.internal.CoreLogging; +import org.hibernate.internal.CoreMessageLogger; +import org.hibernate.internal.util.StringHelper; + +import org.dom4j.Attribute; +import org.dom4j.Element; + +/** + * Encapsulates the overriding of Java annotations from an EJB 3.0 descriptor (orm.xml, ...). + * + * @author Paolo Perrotta + * @author Davide Marchignoli + * @author Emmanuel Bernard + * @author Hardy Ferentschik + */ +@SuppressWarnings("unchecked") +public class JPAXMLOverriddenAnnotationReader implements AnnotationReader { + private static final CoreMessageLogger LOG = CoreLogging.messageLogger( JPAXMLOverriddenAnnotationReader.class ); + + private static final String SCHEMA_VALIDATION = "Activate schema validation for more information"; + private static final String WORD_SEPARATOR = "-"; + + private enum PropertyType { + PROPERTY, + FIELD, + METHOD + } + + private static final Map annotationToXml; + + static { + annotationToXml = new HashMap<>(); + annotationToXml.put( Entity.class, "entity" ); + annotationToXml.put( MappedSuperclass.class, "mapped-superclass" ); + annotationToXml.put( Embeddable.class, "embeddable" ); + annotationToXml.put( Table.class, "table" ); + annotationToXml.put( SecondaryTable.class, "secondary-table" ); + annotationToXml.put( SecondaryTables.class, "secondary-table" ); + annotationToXml.put( PrimaryKeyJoinColumn.class, "primary-key-join-column" ); + annotationToXml.put( PrimaryKeyJoinColumns.class, "primary-key-join-column" ); + annotationToXml.put( IdClass.class, "id-class" ); + annotationToXml.put( Inheritance.class, "inheritance" ); + annotationToXml.put( DiscriminatorValue.class, "discriminator-value" ); + annotationToXml.put( DiscriminatorColumn.class, "discriminator-column" ); + annotationToXml.put( SequenceGenerator.class, "sequence-generator" ); + annotationToXml.put( TableGenerator.class, "table-generator" ); + annotationToXml.put( NamedEntityGraph.class, "named-entity-graph" ); + annotationToXml.put( NamedEntityGraphs.class, "named-entity-graph" ); + annotationToXml.put( NamedQuery.class, "named-query" ); + annotationToXml.put( NamedQueries.class, "named-query" ); + annotationToXml.put( NamedNativeQuery.class, "named-native-query" ); + annotationToXml.put( NamedNativeQueries.class, "named-native-query" ); + annotationToXml.put( NamedStoredProcedureQuery.class, "named-stored-procedure-query" ); + annotationToXml.put( NamedStoredProcedureQueries.class, "named-stored-procedure-query" ); + annotationToXml.put( SqlResultSetMapping.class, "sql-result-set-mapping" ); + annotationToXml.put( SqlResultSetMappings.class, "sql-result-set-mapping" ); + annotationToXml.put( ExcludeDefaultListeners.class, "exclude-default-listeners" ); + annotationToXml.put( ExcludeSuperclassListeners.class, "exclude-superclass-listeners" ); + annotationToXml.put( AccessType.class, "access" ); + annotationToXml.put( AttributeOverride.class, "attribute-override" ); + annotationToXml.put( AttributeOverrides.class, "attribute-override" ); + annotationToXml.put( AttributeOverride.class, "association-override" ); + annotationToXml.put( AttributeOverrides.class, "association-override" ); + annotationToXml.put( AttributeOverride.class, "map-key-attribute-override" ); + annotationToXml.put( AttributeOverrides.class, "map-key-attribute-override" ); + annotationToXml.put( Id.class, "id" ); + annotationToXml.put( EmbeddedId.class, "embedded-id" ); + annotationToXml.put( GeneratedValue.class, "generated-value" ); + annotationToXml.put( Column.class, "column" ); + annotationToXml.put( Columns.class, "column" ); + annotationToXml.put( Temporal.class, "temporal" ); + annotationToXml.put( Lob.class, "lob" ); + annotationToXml.put( Enumerated.class, "enumerated" ); + annotationToXml.put( Version.class, "version" ); + annotationToXml.put( Transient.class, "transient" ); + annotationToXml.put( Basic.class, "basic" ); + annotationToXml.put( Embedded.class, "embedded" ); + annotationToXml.put( ManyToOne.class, "many-to-one" ); + annotationToXml.put( OneToOne.class, "one-to-one" ); + annotationToXml.put( OneToMany.class, "one-to-many" ); + annotationToXml.put( ManyToMany.class, "many-to-many" ); + annotationToXml.put( Any.class, "any" ); + annotationToXml.put( ManyToAny.class, "many-to-any" ); + annotationToXml.put( JoinTable.class, "join-table" ); + annotationToXml.put( JoinColumn.class, "join-column" ); + annotationToXml.put( JoinColumns.class, "join-column" ); + annotationToXml.put( MapKey.class, "map-key" ); + annotationToXml.put( OrderBy.class, "order-by" ); + annotationToXml.put( EntityListeners.class, "entity-listeners" ); + annotationToXml.put( PrePersist.class, "pre-persist" ); + annotationToXml.put( PreRemove.class, "pre-remove" ); + annotationToXml.put( PreUpdate.class, "pre-update" ); + annotationToXml.put( PostPersist.class, "post-persist" ); + annotationToXml.put( PostRemove.class, "post-remove" ); + annotationToXml.put( PostUpdate.class, "post-update" ); + annotationToXml.put( PostLoad.class, "post-load" ); + annotationToXml.put( CollectionTable.class, "collection-table" ); + annotationToXml.put( MapKeyClass.class, "map-key-class" ); + annotationToXml.put( MapKeyTemporal.class, "map-key-temporal" ); + annotationToXml.put( MapKeyEnumerated.class, "map-key-enumerated" ); + annotationToXml.put( MapKeyColumn.class, "map-key-column" ); + annotationToXml.put( MapKeyJoinColumn.class, "map-key-join-column" ); + annotationToXml.put( MapKeyJoinColumns.class, "map-key-join-column" ); + annotationToXml.put( OrderColumn.class, "order-column" ); + annotationToXml.put( Cacheable.class, "cacheable" ); + annotationToXml.put( Index.class, "index" ); + annotationToXml.put( ForeignKey.class, "foreign-key" ); + annotationToXml.put( Convert.class, "convert" ); + annotationToXml.put( Converts.class, "convert" ); + annotationToXml.put( ConstructorResult.class, "constructor-result" ); + } + + private final XMLContext xmlContext; + private final ClassLoaderAccess classLoaderAccess; + private final AnnotatedElement element; + private final String className; + private final String propertyName; + private final PropertyType propertyType; + private transient Annotation[] annotations; + private transient Map annotationsMap; + private transient List elementsForProperty; + private AccessibleObject mirroredAttribute; + + /** + * @deprecated Use {@link #JPAXMLOverriddenAnnotationReader(AnnotatedElement, XMLContext, BootstrapContext)} instead. + */ + public JPAXMLOverriddenAnnotationReader( + AnnotatedElement el, + XMLContext xmlContext, + ClassLoaderAccess classLoaderAccess) { + this.element = el; + this.xmlContext = xmlContext; + this.classLoaderAccess = classLoaderAccess; + + if ( el instanceof Class ) { + Class clazz = (Class) el; + className = clazz.getName(); + propertyName = null; + propertyType = null; + } + else if ( el instanceof Field ) { + Field field = (Field) el; + className = field.getDeclaringClass().getName(); + propertyName = field.getName(); + propertyType = PropertyType.FIELD; + String expectedGetter = "get" + Character.toUpperCase( propertyName.charAt( 0 ) ) + propertyName.substring( + 1 + ); + try { + mirroredAttribute = field.getDeclaringClass().getDeclaredMethod( expectedGetter ); + } + catch ( NoSuchMethodException e ) { + //no method + } + } + else if ( el instanceof Method ) { + Method method = (Method) el; + className = method.getDeclaringClass().getName(); + String methodName = method.getName(); + + // YUCK! The null here is the 'boundType', we'd rather get the TypeEnvironment() + if ( ReflectionUtil.isProperty( method, null, PersistentAttributeFilter.INSTANCE ) ) { + if ( methodName.startsWith( "get" ) ) { + propertyName = Introspector.decapitalize( methodName.substring( "get".length() ) ); + } + else if ( methodName.startsWith( "is" ) ) { + propertyName = Introspector.decapitalize( methodName.substring( "is".length() ) ); + } + else { + throw new RuntimeException( "Method " + methodName + " is not a property getter" ); + } + propertyType = PropertyType.PROPERTY; + try { + mirroredAttribute = method.getDeclaringClass().getDeclaredField( propertyName ); + } + catch ( NoSuchFieldException e ) { + //no method + } + } + else { + propertyName = methodName; + propertyType = PropertyType.METHOD; + } + } + else { + className = null; + propertyName = null; + propertyType = null; + } + } + + public JPAXMLOverriddenAnnotationReader( + AnnotatedElement el, + XMLContext xmlContext, + BootstrapContext bootstrapContext) { + this( el, xmlContext, bootstrapContext.getClassLoaderAccess() ); + } + + + public T getAnnotation(Class annotationType) { + initAnnotations(); + return (T) annotationsMap.get( annotationType ); + } + + public boolean isAnnotationPresent(Class annotationType) { + initAnnotations(); + return annotationsMap.containsKey( annotationType ); + } + + public Annotation[] getAnnotations() { + initAnnotations(); + return annotations; + } + + /* + * The idea is to create annotation proxies for the xml configuration elements. Using this proxy annotations together + * with the {@link JPAMetadataProvider} allows to handle xml configuration the same way as annotation configuration. + */ + private void initAnnotations() { + if ( annotations == null ) { + XMLContext.Default defaults = xmlContext.getDefault( className ); + if ( className != null && propertyName == null ) { + //is a class + Element tree = xmlContext.getXMLTree( className ); + Annotation[] annotations = getPhysicalAnnotations(); + List annotationList = new ArrayList<>( annotations.length + 5 ); + annotationsMap = new HashMap<>( annotations.length + 5 ); + for ( Annotation annotation : annotations ) { + if ( !annotationToXml.containsKey( annotation.annotationType() ) ) { + //unknown annotations are left over + annotationList.add( annotation ); + } + } + addIfNotNull( annotationList, getEntity( tree, defaults ) ); + addIfNotNull( annotationList, getMappedSuperclass( tree, defaults ) ); + addIfNotNull( annotationList, getEmbeddable( tree, defaults ) ); + addIfNotNull( annotationList, getTable( tree, defaults ) ); + addIfNotNull( annotationList, getSecondaryTables( tree, defaults ) ); + addIfNotNull( annotationList, getPrimaryKeyJoinColumns( tree, defaults, true ) ); + addIfNotNull( annotationList, getIdClass( tree, defaults ) ); + addIfNotNull( annotationList, getCacheable( tree, defaults ) ); + addIfNotNull( annotationList, getInheritance( tree, defaults ) ); + addIfNotNull( annotationList, getDiscriminatorValue( tree, defaults ) ); + addIfNotNull( annotationList, getDiscriminatorColumn( tree, defaults ) ); + addIfNotNull( annotationList, getSequenceGenerator( tree, defaults ) ); + addIfNotNull( annotationList, getTableGenerator( tree, defaults ) ); + addIfNotNull( annotationList, getNamedQueries( tree, defaults ) ); + addIfNotNull( annotationList, getNamedNativeQueries( tree, defaults ) ); + addIfNotNull( annotationList, getNamedStoredProcedureQueries( tree, defaults ) ); + addIfNotNull( annotationList, getNamedEntityGraphs( tree, defaults ) ); + addIfNotNull( annotationList, getSqlResultSetMappings( tree, defaults ) ); + addIfNotNull( annotationList, getExcludeDefaultListeners( tree, defaults ) ); + addIfNotNull( annotationList, getExcludeSuperclassListeners( tree, defaults ) ); + addIfNotNull( annotationList, getAccessType( tree, defaults ) ); + addIfNotNull( annotationList, getAttributeOverrides( tree, defaults, true ) ); + addIfNotNull( annotationList, getAssociationOverrides( tree, defaults, true ) ); + addIfNotNull( annotationList, getEntityListeners( tree, defaults ) ); + addIfNotNull( annotationList, getConverts( tree, defaults ) ); + + this.annotations = annotationList.toArray( new Annotation[annotationList.size()] ); + for ( Annotation ann : this.annotations ) { + annotationsMap.put( ann.annotationType(), ann ); + } + checkForOrphanProperties( tree ); + } + else if ( className != null ) { //&& propertyName != null ) { //always true but less confusing + Element tree = xmlContext.getXMLTree( className ); + Annotation[] annotations = getPhysicalAnnotations(); + List annotationList = new ArrayList<>( annotations.length + 5 ); + annotationsMap = new HashMap<>( annotations.length + 5 ); + for ( Annotation annotation : annotations ) { + if ( !annotationToXml.containsKey( annotation.annotationType() ) ) { + //unknown annotations are left over + annotationList.add( annotation ); + } + } + preCalculateElementsForProperty( tree ); + Transient transientAnn = getTransient( defaults ); + if ( transientAnn != null ) { + annotationList.add( transientAnn ); + } + else { + if ( defaults.canUseJavaAnnotations() ) { + Annotation annotation = getPhysicalAnnotation( Access.class ); + addIfNotNull( annotationList, annotation ); + } + getId( annotationList, defaults ); + getEmbeddedId( annotationList, defaults ); + getEmbedded( annotationList, defaults ); + getBasic( annotationList, defaults ); + getVersion( annotationList, defaults ); + getAssociation( ManyToOne.class, annotationList, defaults ); + getAssociation( OneToOne.class, annotationList, defaults ); + getAssociation( OneToMany.class, annotationList, defaults ); + getAssociation( ManyToMany.class, annotationList, defaults ); + getAssociation( Any.class, annotationList, defaults ); + getAssociation( ManyToAny.class, annotationList, defaults ); + getElementCollection( annotationList, defaults ); + addIfNotNull( annotationList, getSequenceGenerator( elementsForProperty, defaults ) ); + addIfNotNull( annotationList, getTableGenerator( elementsForProperty, defaults ) ); + addIfNotNull( annotationList, getConvertsForAttribute( elementsForProperty, defaults ) ); + } + processEventAnnotations( annotationList, defaults ); + //FIXME use annotationsMap rather than annotationList this will be faster since the annotation type is usually known at put() time + this.annotations = annotationList.toArray( new Annotation[annotationList.size()] ); + for ( Annotation ann : this.annotations ) { + annotationsMap.put( ann.annotationType(), ann ); + } + } + else { + this.annotations = getPhysicalAnnotations(); + annotationsMap = new HashMap<>( annotations.length + 5 ); + for ( Annotation ann : this.annotations ) { + annotationsMap.put( ann.annotationType(), ann ); + } + } + } + } + + private Annotation getConvertsForAttribute(List elementsForProperty, XMLContext.Default defaults) { + // NOTE : we use a map here to make sure that an xml and annotation referring to the same attribute + // properly overrides. Very sparse map, yes, but easy setup. + // todo : revisit this + // although bear in mind that this code is no longer used in 5.0... + + final Map convertAnnotationsMap = new HashMap<>(); + + for ( Element element : elementsForProperty ) { + final boolean isBasic = "basic".equals( element.getName() ); + final boolean isEmbedded = "embedded".equals( element.getName() ); + final boolean isElementCollection = "element-collection".equals(element.getName()); + + final boolean canHaveConverts = isBasic || isEmbedded || isElementCollection; + + if ( !canHaveConverts ) { + continue; + } + + final String attributeNamePrefix = isBasic ? null : propertyName; + applyXmlDefinedConverts( element, defaults, attributeNamePrefix, convertAnnotationsMap ); + } + + // NOTE : per section 12.2.3.16 of the spec is additive, although only if "metadata-complete" is not + // specified in the XML + + if ( defaults.canUseJavaAnnotations() ) { + // todo : note sure how to best handle attributeNamePrefix here + applyPhysicalConvertAnnotations( propertyName, convertAnnotationsMap ); + } + + if ( !convertAnnotationsMap.isEmpty() ) { + final AnnotationDescriptor groupingDescriptor = new AnnotationDescriptor( Converts.class ); + groupingDescriptor.setValue( "value", convertAnnotationsMap.values().toArray( new Convert[convertAnnotationsMap.size()]) ); + return AnnotationFactory.create( groupingDescriptor ); + } + + return null; + } + + private Converts getConverts(Element tree, XMLContext.Default defaults) { + // NOTE : we use a map here to make sure that an xml and annotation referring to the same attribute + // properly overrides. Bit sparse, but easy... + final Map convertAnnotationsMap = new HashMap<>(); + + if ( tree != null ) { + applyXmlDefinedConverts( tree, defaults, null, convertAnnotationsMap ); + } + + // NOTE : per section 12.2.3.16 of the spec is additive, although only if "metadata-complete" is not + // specified in the XML + + if ( defaults.canUseJavaAnnotations() ) { + applyPhysicalConvertAnnotations( null, convertAnnotationsMap ); + } + + if ( !convertAnnotationsMap.isEmpty() ) { + final AnnotationDescriptor groupingDescriptor = new AnnotationDescriptor( Converts.class ); + groupingDescriptor.setValue( "value", convertAnnotationsMap.values().toArray( new Convert[convertAnnotationsMap.size()]) ); + return AnnotationFactory.create( groupingDescriptor ); + } + + return null; + } + + private void applyXmlDefinedConverts( + Element containingElement, + XMLContext.Default defaults, + String attributeNamePrefix, + Map convertAnnotationsMap) { + final List convertElements = containingElement.elements( "convert" ); + for ( Element convertElement : convertElements ) { + final AnnotationDescriptor convertAnnotationDescriptor = new AnnotationDescriptor( Convert.class ); + copyStringAttribute( convertAnnotationDescriptor, convertElement, "attribute-name", false ); + copyBooleanAttribute( convertAnnotationDescriptor, convertElement, "disable-conversion" ); + + final Attribute converterClassAttr = convertElement.attribute( "converter" ); + if ( converterClassAttr != null ) { + final String converterClassName = XMLContext.buildSafeClassName( + converterClassAttr.getValue(), + defaults + ); + try { + final Class converterClass = classLoaderAccess.classForName( converterClassName ); + convertAnnotationDescriptor.setValue( "converter", converterClass ); + } + catch (ClassLoadingException e) { + throw new AnnotationException( "Unable to find specified converter class id-class: " + converterClassName, e ); + } + } + final Convert convertAnnotation = AnnotationFactory.create( convertAnnotationDescriptor ); + final String qualifiedAttributeName = qualifyConverterAttributeName( + attributeNamePrefix, + convertAnnotation.attributeName() + ); + convertAnnotationsMap.put( qualifiedAttributeName, convertAnnotation ); + } + + } + + private String qualifyConverterAttributeName(String attributeNamePrefix, String specifiedAttributeName) { + String qualifiedAttributeName; + if ( StringHelper.isNotEmpty( specifiedAttributeName ) ) { + if ( StringHelper.isNotEmpty( attributeNamePrefix ) ) { + qualifiedAttributeName = attributeNamePrefix + '.' + specifiedAttributeName; + } + else { + qualifiedAttributeName = specifiedAttributeName; + } + } + else { + qualifiedAttributeName = ""; + } + return qualifiedAttributeName; + } + + private void applyPhysicalConvertAnnotations( + String attributeNamePrefix, + Map convertAnnotationsMap) { + final Convert physicalAnnotation = getPhysicalAnnotation( Convert.class ); + if ( physicalAnnotation != null ) { + // only add if no XML element named a converter for this attribute + final String qualifiedAttributeName = qualifyConverterAttributeName( attributeNamePrefix, physicalAnnotation.attributeName() ); + if ( ! convertAnnotationsMap.containsKey( qualifiedAttributeName ) ) { + convertAnnotationsMap.put( qualifiedAttributeName, physicalAnnotation ); + } + } + final Converts physicalGroupingAnnotation = getPhysicalAnnotation( Converts.class ); + if ( physicalGroupingAnnotation != null ) { + for ( Convert convertAnnotation : physicalGroupingAnnotation.value() ) { + // again, only add if no XML element named a converter for this attribute + final String qualifiedAttributeName = qualifyConverterAttributeName( attributeNamePrefix, convertAnnotation.attributeName() ); + if ( ! convertAnnotationsMap.containsKey( qualifiedAttributeName ) ) { + convertAnnotationsMap.put( qualifiedAttributeName, convertAnnotation ); + } + } + } + } + + private void checkForOrphanProperties(Element tree) { + Class clazz; + try { + clazz = classLoaderAccess.classForName( className ); + } + catch ( ClassLoadingException e ) { + return; //a primitive type most likely + } + Element element = tree != null ? tree.element( "attributes" ) : null; + //put entity.attributes elements + if ( element != null ) { + //precompute the list of properties + //TODO is it really useful... + Set properties = new HashSet<>(); + for ( Field field : clazz.getFields() ) { + properties.add( field.getName() ); + } + for ( Method method : clazz.getMethods() ) { + String name = method.getName(); + if ( name.startsWith( "get" ) ) { + properties.add( Introspector.decapitalize( name.substring( "get".length() ) ) ); + } + else if ( name.startsWith( "is" ) ) { + properties.add( Introspector.decapitalize( name.substring( "is".length() ) ) ); + } + } + for ( Element subelement : (List) element.elements() ) { + String propertyName = subelement.attributeValue( "name" ); + if ( !properties.contains( propertyName ) ) { + LOG.propertyNotFound( StringHelper.qualify( className, propertyName ) ); + } + } + } + } + + /** + * Adds {@code annotation} to the list (only if it's not null) and then returns it. + * + * @param annotationList The list of annotations. + * @param annotation The annotation to add to the list. + * + * @return The annotation which was added to the list or {@code null}. + */ + private Annotation addIfNotNull(List annotationList, Annotation annotation) { + if ( annotation != null ) { + annotationList.add( annotation ); + } + return annotation; + } + + //TODO mutualize the next 2 methods + private Annotation getTableGenerator(List elementsForProperty, XMLContext.Default defaults) { + for ( Element element : elementsForProperty ) { + Element subelement = element != null ? element.element( annotationToXml.get( TableGenerator.class ) ) : null; + if ( subelement != null ) { + return buildTableGeneratorAnnotation( subelement, defaults ); + } + } + if ( elementsForProperty.size() == 0 && defaults.canUseJavaAnnotations() ) { + return getPhysicalAnnotation( TableGenerator.class ); + } + else { + return null; + } + } + + private Annotation getSequenceGenerator(List elementsForProperty, XMLContext.Default defaults) { + for ( Element element : elementsForProperty ) { + Element subelement = element != null ? element.element( annotationToXml.get( SequenceGenerator.class ) ) : null; + if ( subelement != null ) { + return buildSequenceGeneratorAnnotation( subelement ); + } + } + if ( elementsForProperty.size() == 0 && defaults.canUseJavaAnnotations() ) { + return getPhysicalAnnotation( SequenceGenerator.class ); + } + else { + return null; + } + } + + private void processEventAnnotations(List annotationList, XMLContext.Default defaults) { + boolean eventElement = false; + for ( Element element : elementsForProperty ) { + String elementName = element.getName(); + if ( "pre-persist".equals( elementName ) ) { + AnnotationDescriptor ad = new AnnotationDescriptor( PrePersist.class ); + annotationList.add( AnnotationFactory.create( ad ) ); + eventElement = true; + } + else if ( "pre-remove".equals( elementName ) ) { + AnnotationDescriptor ad = new AnnotationDescriptor( PreRemove.class ); + annotationList.add( AnnotationFactory.create( ad ) ); + eventElement = true; + } + else if ( "pre-update".equals( elementName ) ) { + AnnotationDescriptor ad = new AnnotationDescriptor( PreUpdate.class ); + annotationList.add( AnnotationFactory.create( ad ) ); + eventElement = true; + } + else if ( "post-persist".equals( elementName ) ) { + AnnotationDescriptor ad = new AnnotationDescriptor( PostPersist.class ); + annotationList.add( AnnotationFactory.create( ad ) ); + eventElement = true; + } + else if ( "post-remove".equals( elementName ) ) { + AnnotationDescriptor ad = new AnnotationDescriptor( PostRemove.class ); + annotationList.add( AnnotationFactory.create( ad ) ); + eventElement = true; + } + else if ( "post-update".equals( elementName ) ) { + AnnotationDescriptor ad = new AnnotationDescriptor( PostUpdate.class ); + annotationList.add( AnnotationFactory.create( ad ) ); + eventElement = true; + } + else if ( "post-load".equals( elementName ) ) { + AnnotationDescriptor ad = new AnnotationDescriptor( PostLoad.class ); + annotationList.add( AnnotationFactory.create( ad ) ); + eventElement = true; + } + } + if ( !eventElement && defaults.canUseJavaAnnotations() ) { + Annotation ann = getPhysicalAnnotation( PrePersist.class ); + addIfNotNull( annotationList, ann ); + ann = getPhysicalAnnotation( PreRemove.class ); + addIfNotNull( annotationList, ann ); + ann = getPhysicalAnnotation( PreUpdate.class ); + addIfNotNull( annotationList, ann ); + ann = getPhysicalAnnotation( PostPersist.class ); + addIfNotNull( annotationList, ann ); + ann = getPhysicalAnnotation( PostRemove.class ); + addIfNotNull( annotationList, ann ); + ann = getPhysicalAnnotation( PostUpdate.class ); + addIfNotNull( annotationList, ann ); + ann = getPhysicalAnnotation( PostLoad.class ); + addIfNotNull( annotationList, ann ); + } + } + + private EntityListeners getEntityListeners(Element tree, XMLContext.Default defaults) { + Element element = tree != null ? tree.element( "entity-listeners" ) : null; + if ( element != null ) { + List entityListenerClasses = new ArrayList<>(); + for ( Element subelement : (List) element.elements( "entity-listener" ) ) { + String className = subelement.attributeValue( "class" ); + try { + entityListenerClasses.add( + classLoaderAccess.classForName( + XMLContext.buildSafeClassName( className, defaults ) + ) + ); + } + catch ( ClassLoadingException e ) { + throw new AnnotationException( + "Unable to find " + element.getPath() + ".class: " + className, e + ); + } + } + AnnotationDescriptor ad = new AnnotationDescriptor( EntityListeners.class ); + ad.setValue( "value", entityListenerClasses.toArray( new Class[entityListenerClasses.size()] ) ); + return AnnotationFactory.create( ad ); + } + else if ( defaults.canUseJavaAnnotations() ) { + return getPhysicalAnnotation( EntityListeners.class ); + } + else { + return null; + } + } + + private JoinTable overridesDefaultsInJoinTable(Annotation annotation, XMLContext.Default defaults) { + //no element but might have some default or some annotation + boolean defaultToJoinTable = !( isPhysicalAnnotationPresent( JoinColumn.class ) + || isPhysicalAnnotationPresent( JoinColumns.class ) ); + final Class annotationClass = annotation.annotationType(); + defaultToJoinTable = defaultToJoinTable && + ( ( annotationClass == ManyToMany.class && StringHelper.isEmpty( ( (ManyToMany) annotation ).mappedBy() ) ) + || ( annotationClass == OneToMany.class && StringHelper.isEmpty( ( (OneToMany) annotation ).mappedBy() ) ) + || ( annotationClass == ElementCollection.class ) + ); + final Class annotationType = JoinTable.class; + if ( defaultToJoinTable + && ( StringHelper.isNotEmpty( defaults.getCatalog() ) + || StringHelper.isNotEmpty( defaults.getSchema() ) ) ) { + AnnotationDescriptor ad = new AnnotationDescriptor( annotationType ); + if ( defaults.canUseJavaAnnotations() ) { + JoinTable table = getPhysicalAnnotation( annotationType ); + if ( table != null ) { + ad.setValue( "name", table.name() ); + ad.setValue( "schema", table.schema() ); + ad.setValue( "catalog", table.catalog() ); + ad.setValue( "uniqueConstraints", table.uniqueConstraints() ); + ad.setValue( "joinColumns", table.joinColumns() ); + ad.setValue( "inverseJoinColumns", table.inverseJoinColumns() ); + } + } + if ( StringHelper.isEmpty( (String) ad.valueOf( "schema" ) ) + && StringHelper.isNotEmpty( defaults.getSchema() ) ) { + ad.setValue( "schema", defaults.getSchema() ); + } + if ( StringHelper.isEmpty( (String) ad.valueOf( "catalog" ) ) + && StringHelper.isNotEmpty( defaults.getCatalog() ) ) { + ad.setValue( "catalog", defaults.getCatalog() ); + } + return AnnotationFactory.create( ad ); + } + else if ( defaults.canUseJavaAnnotations() ) { + return getPhysicalAnnotation( annotationType ); + } + else { + return null; + } + } + + private Annotation overridesDefaultCascadePersist(Annotation annotation, XMLContext.Default defaults) { + if ( Boolean.TRUE.equals( defaults.getCascadePersist() ) ) { + final Class annotationType = annotation.annotationType(); + + if ( annotationType == ManyToOne.class ) { + ManyToOne manyToOne = (ManyToOne) annotation; + List cascades = new ArrayList<>( Arrays.asList( manyToOne.cascade() ) ); + if ( !cascades.contains( CascadeType.ALL ) && !cascades.contains( CascadeType.PERSIST ) ) { + cascades.add( CascadeType.PERSIST ); + } + else { + return annotation; + } + + AnnotationDescriptor ad = new AnnotationDescriptor( annotationType ); + ad.setValue( "cascade", cascades.toArray( new CascadeType[] {} ) ); + ad.setValue( "targetEntity", manyToOne.targetEntity() ); + ad.setValue( "fetch", manyToOne.fetch() ); + ad.setValue( "optional", manyToOne.optional() ); + + return AnnotationFactory.create( ad ); + } + else if ( annotationType == OneToOne.class ) { + OneToOne oneToOne = (OneToOne) annotation; + List cascades = new ArrayList<>( Arrays.asList( oneToOne.cascade() ) ); + if ( !cascades.contains( CascadeType.ALL ) && !cascades.contains( CascadeType.PERSIST ) ) { + cascades.add( CascadeType.PERSIST ); + } + else { + return annotation; + } + + AnnotationDescriptor ad = new AnnotationDescriptor( annotationType ); + ad.setValue( "cascade", cascades.toArray( new CascadeType[] {} ) ); + ad.setValue( "targetEntity", oneToOne.targetEntity() ); + ad.setValue( "fetch", oneToOne.fetch() ); + ad.setValue( "optional", oneToOne.optional() ); + ad.setValue( "mappedBy", oneToOne.mappedBy() ); + ad.setValue( "orphanRemoval", oneToOne.orphanRemoval() ); + + return AnnotationFactory.create( ad ); + } + } + return annotation; + } + + private void getJoinTable(List annotationList, Element tree, XMLContext.Default defaults) { + addIfNotNull( annotationList, buildJoinTable( tree, defaults ) ); + } + + /* + * no partial overriding possible + */ + private JoinTable buildJoinTable(Element tree, XMLContext.Default defaults) { + Element subelement = tree == null ? null : tree.element( "join-table" ); + final Class annotationType = JoinTable.class; + if ( subelement == null ) { + return null; + } + //ignore java annotation, an element is defined + AnnotationDescriptor annotation = new AnnotationDescriptor( annotationType ); + copyStringAttribute( annotation, subelement, "name", false ); + copyStringAttribute( annotation, subelement, "catalog", false ); + if ( StringHelper.isNotEmpty( defaults.getCatalog() ) + && StringHelper.isEmpty( (String) annotation.valueOf( "catalog" ) ) ) { + annotation.setValue( "catalog", defaults.getCatalog() ); + } + copyStringAttribute( annotation, subelement, "schema", false ); + if ( StringHelper.isNotEmpty( defaults.getSchema() ) + && StringHelper.isEmpty( (String) annotation.valueOf( "schema" ) ) ) { + annotation.setValue( "schema", defaults.getSchema() ); + } + buildUniqueConstraints( annotation, subelement ); + buildIndex( annotation, subelement ); + annotation.setValue( "joinColumns", getJoinColumns( subelement, false ) ); + annotation.setValue( "inverseJoinColumns", getJoinColumns( subelement, true ) ); + return AnnotationFactory.create( annotation ); + } + + /** + * As per section 12.2 of the JPA 2.0 specification, the association + * subelements (many-to-one, one-to-many, one-to-one, many-to-many, + * element-collection) completely override the mapping for the specified + * field or property. Thus, any methods which might in some contexts merge + * with annotations must not do so in this context. + * + * @see #getElementCollection(List, XMLContext.Default) + */ + private void getAssociation( + Class annotationType, List annotationList, XMLContext.Default defaults + ) { + String xmlName = annotationToXml.get( annotationType ); + for ( Element element : elementsForProperty ) { + if ( xmlName.equals( element.getName() ) ) { + AnnotationDescriptor ad = new AnnotationDescriptor( annotationType ); + addTargetClass( element, ad, "target-entity", defaults ); + getFetchType( ad, element ); + getCascades( ad, element, defaults ); + getJoinTable( annotationList, element, defaults ); + buildJoinColumns( annotationList, element ); + Annotation annotation = getPrimaryKeyJoinColumns( element, defaults, false ); + addIfNotNull( annotationList, annotation ); + copyBooleanAttribute( ad, element, "optional" ); + copyBooleanAttribute( ad, element, "orphan-removal" ); + copyStringAttribute( ad, element, "mapped-by", false ); + getOrderBy( annotationList, element ); + getMapKey( annotationList, element ); + getMapKeyClass( annotationList, element, defaults ); + getMapKeyColumn( annotationList, element ); + getOrderColumn( annotationList, element ); + getMapKeyTemporal( annotationList, element ); + getMapKeyEnumerated( annotationList, element ); + annotation = getMapKeyAttributeOverrides( element, defaults ); + addIfNotNull( annotationList, annotation ); + buildMapKeyJoinColumns( annotationList, element ); + getAssociationId( annotationList, element ); + getMapsId( annotationList, element ); + annotationList.add( AnnotationFactory.create( ad ) ); + getAccessType( annotationList, element ); + } + } + if ( elementsForProperty.size() == 0 && defaults.canUseJavaAnnotations() ) { + Annotation annotation = getPhysicalAnnotation( annotationType ); + if ( annotation != null ) { + annotation = overridesDefaultCascadePersist( annotation, defaults ); + annotationList.add( annotation ); + annotation = overridesDefaultsInJoinTable( annotation, defaults ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( JoinColumn.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( JoinColumns.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( PrimaryKeyJoinColumn.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( PrimaryKeyJoinColumns.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( MapKey.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( OrderBy.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( AttributeOverride.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( AttributeOverrides.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( AssociationOverride.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( AssociationOverrides.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( Lob.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( Enumerated.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( Temporal.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( Column.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( Columns.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( MapKeyClass.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( MapKeyTemporal.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( MapKeyEnumerated.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( MapKeyColumn.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( MapKeyJoinColumn.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( MapKeyJoinColumns.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( OrderColumn.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( Cascade.class ); + addIfNotNull( annotationList, annotation ); + } + else if ( isPhysicalAnnotationPresent( ElementCollection.class ) ) { //JPA2 + annotation = overridesDefaultsInJoinTable( getPhysicalAnnotation( ElementCollection.class ), defaults ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( MapKey.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( OrderBy.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( AttributeOverride.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( AttributeOverrides.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( AssociationOverride.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( AssociationOverrides.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( Lob.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( Enumerated.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( Temporal.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( Column.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( OrderColumn.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( MapKeyClass.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( MapKeyTemporal.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( MapKeyEnumerated.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( MapKeyColumn.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( MapKeyJoinColumn.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( MapKeyJoinColumns.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( CollectionTable.class ); + addIfNotNull( annotationList, annotation ); + } + } + } + + private void buildMapKeyJoinColumns(List annotationList, Element element) { + MapKeyJoinColumn[] joinColumns = getMapKeyJoinColumns( element ); + if ( joinColumns.length > 0 ) { + AnnotationDescriptor ad = new AnnotationDescriptor( MapKeyJoinColumns.class ); + ad.setValue( "value", joinColumns ); + annotationList.add( AnnotationFactory.create( ad ) ); + } + } + + private MapKeyJoinColumn[] getMapKeyJoinColumns(Element element) { + List subelements = element != null ? element.elements( "map-key-join-column" ) : null; + List joinColumns = new ArrayList<>(); + if ( subelements != null ) { + for ( Element subelement : subelements ) { + AnnotationDescriptor column = new AnnotationDescriptor( MapKeyJoinColumn.class ); + copyStringAttribute( column, subelement, "name", false ); + copyStringAttribute( column, subelement, "referenced-column-name", false ); + copyBooleanAttribute( column, subelement, "unique" ); + copyBooleanAttribute( column, subelement, "nullable" ); + copyBooleanAttribute( column, subelement, "insertable" ); + copyBooleanAttribute( column, subelement, "updatable" ); + copyStringAttribute( column, subelement, "column-definition", false ); + copyStringAttribute( column, subelement, "table", false ); + joinColumns.add( AnnotationFactory.create( column ) ); + } + } + return joinColumns.toArray( new MapKeyJoinColumn[joinColumns.size()] ); + } + + private AttributeOverrides getMapKeyAttributeOverrides(Element tree, XMLContext.Default defaults) { + List attributes = buildAttributeOverrides( tree, "map-key-attribute-override" ); + return mergeAttributeOverrides( defaults, attributes, false ); + } + + private Cacheable getCacheable(Element element, XMLContext.Default defaults){ + if ( element != null ) { + String attValue = element.attributeValue( "cacheable" ); + if ( attValue != null ) { + AnnotationDescriptor ad = new AnnotationDescriptor( Cacheable.class ); + ad.setValue( "value", Boolean.valueOf( attValue ) ); + return AnnotationFactory.create( ad ); + } + } + if ( defaults.canUseJavaAnnotations() ) { + return getPhysicalAnnotation( Cacheable.class ); + } + else { + return null; + } + } + /** + * Adds a @MapKeyEnumerated annotation to the specified annotationList if the specified element + * contains a map-key-enumerated sub-element. This should only be the case for + * element-collection, many-to-many, or one-to-many associations. + */ + private void getMapKeyEnumerated(List annotationList, Element element) { + Element subelement = element != null ? element.element( "map-key-enumerated" ) : null; + if ( subelement != null ) { + AnnotationDescriptor ad = new AnnotationDescriptor( MapKeyEnumerated.class ); + EnumType value = EnumType.valueOf( subelement.getTextTrim() ); + ad.setValue( "value", value ); + annotationList.add( AnnotationFactory.create( ad ) ); + } + } + + /** + * Adds a @MapKeyTemporal annotation to the specified annotationList if the specified element + * contains a map-key-temporal sub-element. This should only be the case for element-collection, + * many-to-many, or one-to-many associations. + */ + private void getMapKeyTemporal(List annotationList, Element element) { + Element subelement = element != null ? element.element( "map-key-temporal" ) : null; + if ( subelement != null ) { + AnnotationDescriptor ad = new AnnotationDescriptor( MapKeyTemporal.class ); + TemporalType value = TemporalType.valueOf( subelement.getTextTrim() ); + ad.setValue( "value", value ); + annotationList.add( AnnotationFactory.create( ad ) ); + } + } + + /** + * Adds an @OrderColumn annotation to the specified annotationList if the specified element + * contains an order-column sub-element. This should only be the case for element-collection, + * many-to-many, or one-to-many associations. + */ + private void getOrderColumn(List annotationList, Element element) { + Element subelement = element != null ? element.element( "order-column" ) : null; + if ( subelement != null ) { + AnnotationDescriptor ad = new AnnotationDescriptor( OrderColumn.class ); + copyStringAttribute( ad, subelement, "name", false ); + copyBooleanAttribute( ad, subelement, "nullable" ); + copyBooleanAttribute( ad, subelement, "insertable" ); + copyBooleanAttribute( ad, subelement, "updatable" ); + copyStringAttribute( ad, subelement, "column-definition", false ); + annotationList.add( AnnotationFactory.create( ad ) ); + } + } + + /** + * Adds a @MapsId annotation to the specified annotationList if the specified element has the + * maps-id attribute set. This should only be the case for many-to-one or one-to-one + * associations. + */ + private void getMapsId(List annotationList, Element element) { + String attrVal = element.attributeValue( "maps-id" ); + if ( attrVal != null ) { + AnnotationDescriptor ad = new AnnotationDescriptor( MapsId.class ); + ad.setValue( "value", attrVal ); + annotationList.add( AnnotationFactory.create( ad ) ); + } + } + + /** + * Adds an @Id annotation to the specified annotationList if the specified element has the id + * attribute set to true. This should only be the case for many-to-one or one-to-one + * associations. + */ + private void getAssociationId(List annotationList, Element element) { + String attrVal = element.attributeValue( "id" ); + if ( "true".equals( attrVal ) ) { + AnnotationDescriptor ad = new AnnotationDescriptor( Id.class ); + annotationList.add( AnnotationFactory.create( ad ) ); + } + } + + private void addTargetClass(Element element, AnnotationDescriptor ad, String nodeName, XMLContext.Default defaults) { + String className = element.attributeValue( nodeName ); + if ( className != null ) { + Class clazz; + try { + clazz = classLoaderAccess.classForName( XMLContext.buildSafeClassName( className, defaults ) ); + } + catch ( ClassLoadingException e ) { + throw new AnnotationException( + "Unable to find " + element.getPath() + " " + nodeName + ": " + className, e + ); + } + ad.setValue( getJavaAttributeNameFromXMLOne( nodeName ), clazz ); + } + } + + /** + * As per sections 12.2.3.23.9, 12.2.4.8.9 and 12.2.5.3.6 of the JPA 2.0 + * specification, the element-collection subelement completely overrides the + * mapping for the specified field or property. Thus, any methods which + * might in some contexts merge with annotations must not do so in this + * context. + */ + private void getElementCollection(List annotationList, XMLContext.Default defaults) { + for ( Element element : elementsForProperty ) { + if ( "element-collection".equals( element.getName() ) ) { + AnnotationDescriptor ad = new AnnotationDescriptor( ElementCollection.class ); + addTargetClass( element, ad, "target-class", defaults ); + getFetchType( ad, element ); + getOrderBy( annotationList, element ); + getOrderColumn( annotationList, element ); + getMapKey( annotationList, element ); + getMapKeyClass( annotationList, element, defaults ); + getMapKeyTemporal( annotationList, element ); + getMapKeyEnumerated( annotationList, element ); + getMapKeyColumn( annotationList, element ); + buildMapKeyJoinColumns( annotationList, element ); + Annotation annotation = getColumn( element.element( "column" ), false, element ); + addIfNotNull( annotationList, annotation ); + getTemporal( annotationList, element ); + getEnumerated( annotationList, element ); + getLob( annotationList, element ); + //Both map-key-attribute-overrides and attribute-overrides + //translate into AttributeOverride annotations, which need + //need to be wrapped in the same AttributeOverrides annotation. + List attributes = new ArrayList<>(); + attributes.addAll( buildAttributeOverrides( element, "map-key-attribute-override" ) ); + attributes.addAll( buildAttributeOverrides( element, "attribute-override" ) ); + annotation = mergeAttributeOverrides( defaults, attributes, false ); + addIfNotNull( annotationList, annotation ); + annotation = getAssociationOverrides( element, defaults, false ); + addIfNotNull( annotationList, annotation ); + getCollectionTable( annotationList, element, defaults ); + annotationList.add( AnnotationFactory.create( ad ) ); + getAccessType( annotationList, element ); + } + } + } + + private void getOrderBy(List annotationList, Element element) { + Element subelement = element != null ? element.element( "order-by" ) : null; + if ( subelement != null ) { + AnnotationDescriptor ad = new AnnotationDescriptor( OrderBy.class ); + copyStringElement( subelement, ad, "value" ); + annotationList.add( AnnotationFactory.create( ad ) ); + } + } + + private void getMapKey(List annotationList, Element element) { + Element subelement = element != null ? element.element( "map-key" ) : null; + if ( subelement != null ) { + AnnotationDescriptor ad = new AnnotationDescriptor( MapKey.class ); + copyStringAttribute( ad, subelement, "name", false ); + annotationList.add( AnnotationFactory.create( ad ) ); + } + } + + private void getMapKeyColumn(List annotationList, Element element) { + Element subelement = element != null ? element.element( "map-key-column" ) : null; + if ( subelement != null ) { + AnnotationDescriptor ad = new AnnotationDescriptor( MapKeyColumn.class ); + copyStringAttribute( ad, subelement, "name", false ); + copyBooleanAttribute( ad, subelement, "unique" ); + copyBooleanAttribute( ad, subelement, "nullable" ); + copyBooleanAttribute( ad, subelement, "insertable" ); + copyBooleanAttribute( ad, subelement, "updatable" ); + copyStringAttribute( ad, subelement, "column-definition", false ); + copyStringAttribute( ad, subelement, "table", false ); + copyIntegerAttribute( ad, subelement, "length" ); + copyIntegerAttribute( ad, subelement, "precision" ); + copyIntegerAttribute( ad, subelement, "scale" ); + annotationList.add( AnnotationFactory.create( ad ) ); + } + } + + private void getMapKeyClass(List annotationList, Element element, XMLContext.Default defaults) { + String nodeName = "map-key-class"; + Element subelement = element != null ? element.element( nodeName ) : null; + if ( subelement != null ) { + String mapKeyClassName = subelement.attributeValue( "class" ); + AnnotationDescriptor ad = new AnnotationDescriptor( MapKeyClass.class ); + if ( StringHelper.isNotEmpty( mapKeyClassName ) ) { + Class clazz; + try { + clazz = classLoaderAccess.classForName( + XMLContext.buildSafeClassName( mapKeyClassName, defaults ) + ); + } + catch ( ClassLoadingException e ) { + throw new AnnotationException( + "Unable to find " + element.getPath() + " " + nodeName + ": " + mapKeyClassName, e + ); + } + ad.setValue( "value", clazz ); + } + annotationList.add( AnnotationFactory.create( ad ) ); + } + } + + private void getCollectionTable(List annotationList, Element element, XMLContext.Default defaults) { + Element subelement = element != null ? element.element( "collection-table" ) : null; + if ( subelement != null ) { + AnnotationDescriptor annotation = new AnnotationDescriptor( CollectionTable.class ); + copyStringAttribute( annotation, subelement, "name", false ); + copyStringAttribute( annotation, subelement, "catalog", false ); + if ( StringHelper.isNotEmpty( defaults.getCatalog() ) + && StringHelper.isEmpty( (String) annotation.valueOf( "catalog" ) ) ) { + annotation.setValue( "catalog", defaults.getCatalog() ); + } + copyStringAttribute( annotation, subelement, "schema", false ); + if ( StringHelper.isNotEmpty( defaults.getSchema() ) + && StringHelper.isEmpty( (String) annotation.valueOf( "schema" ) ) ) { + annotation.setValue( "schema", defaults.getSchema() ); + } + JoinColumn[] joinColumns = getJoinColumns( subelement, false ); + if ( joinColumns.length > 0 ) { + annotation.setValue( "joinColumns", joinColumns ); + } + buildUniqueConstraints( annotation, subelement ); + buildIndex( annotation, subelement ); + annotationList.add( AnnotationFactory.create( annotation ) ); + } + } + + private void buildJoinColumns(List annotationList, Element element) { + JoinColumn[] joinColumns = getJoinColumns( element, false ); + if ( joinColumns.length > 0 ) { + AnnotationDescriptor ad = new AnnotationDescriptor( JoinColumns.class ); + ad.setValue( "value", joinColumns ); + annotationList.add( AnnotationFactory.create( ad ) ); + } + } + + private void getCascades(AnnotationDescriptor ad, Element element, XMLContext.Default defaults) { + List elements = element != null ? element.elements( "cascade" ) : new ArrayList<>( 0 ); + List cascades = new ArrayList<>(); + for ( Element subelement : elements ) { + if ( subelement.element( "cascade-all" ) != null ) { + cascades.add( CascadeType.ALL ); + } + if ( subelement.element( "cascade-persist" ) != null ) { + cascades.add( CascadeType.PERSIST ); + } + if ( subelement.element( "cascade-merge" ) != null ) { + cascades.add( CascadeType.MERGE ); + } + if ( subelement.element( "cascade-remove" ) != null ) { + cascades.add( CascadeType.REMOVE ); + } + if ( subelement.element( "cascade-refresh" ) != null ) { + cascades.add( CascadeType.REFRESH ); + } + if ( subelement.element( "cascade-detach" ) != null ) { + cascades.add( CascadeType.DETACH ); + } + } + if ( Boolean.TRUE.equals( defaults.getCascadePersist() ) + && !cascades.contains( CascadeType.ALL ) && !cascades.contains( CascadeType.PERSIST ) ) { + cascades.add( CascadeType.PERSIST ); + } + if ( cascades.size() > 0 ) { + ad.setValue( "cascade", cascades.toArray( new CascadeType[cascades.size()] ) ); + } + } + + private void getEmbedded(List annotationList, XMLContext.Default defaults) { + for ( Element element : elementsForProperty ) { + if ( "embedded".equals( element.getName() ) ) { + AnnotationDescriptor ad = new AnnotationDescriptor( Embedded.class ); + annotationList.add( AnnotationFactory.create( ad ) ); + Annotation annotation = getAttributeOverrides( element, defaults, false ); + addIfNotNull( annotationList, annotation ); + annotation = getAssociationOverrides( element, defaults, false ); + addIfNotNull( annotationList, annotation ); + getAccessType( annotationList, element ); + } + } + if ( elementsForProperty.size() == 0 && defaults.canUseJavaAnnotations() ) { + Annotation annotation = getPhysicalAnnotation( Embedded.class ); + if ( annotation != null ) { + annotationList.add( annotation ); + annotation = getPhysicalAnnotation( AttributeOverride.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( AttributeOverrides.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( AssociationOverride.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( AssociationOverrides.class ); + addIfNotNull( annotationList, annotation ); + } + } + } + + private Transient getTransient(XMLContext.Default defaults) { + for ( Element element : elementsForProperty ) { + if ( "transient".equals( element.getName() ) ) { + AnnotationDescriptor ad = new AnnotationDescriptor( Transient.class ); + return AnnotationFactory.create( ad ); + } + } + if ( elementsForProperty.size() == 0 && defaults.canUseJavaAnnotations() ) { + return getPhysicalAnnotation( Transient.class ); + } + else { + return null; + } + } + + private void getVersion(List annotationList, XMLContext.Default defaults) { + for ( Element element : elementsForProperty ) { + if ( "version".equals( element.getName() ) ) { + Annotation annotation = buildColumns( element ); + addIfNotNull( annotationList, annotation ); + getTemporal( annotationList, element ); + AnnotationDescriptor basic = new AnnotationDescriptor( Version.class ); + annotationList.add( AnnotationFactory.create( basic ) ); + getAccessType( annotationList, element ); + } + } + if ( elementsForProperty.size() == 0 && defaults.canUseJavaAnnotations() ) { + //we have nothing, so Java annotations might occur + Annotation annotation = getPhysicalAnnotation( Version.class ); + if ( annotation != null ) { + annotationList.add( annotation ); + annotation = getPhysicalAnnotation( Column.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( Columns.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( Temporal.class ); + addIfNotNull( annotationList, annotation ); + } + } + } + + private void getBasic(List annotationList, XMLContext.Default defaults) { + for ( Element element : elementsForProperty ) { + if ( "basic".equals( element.getName() ) ) { + Annotation annotation = buildColumns( element ); + addIfNotNull( annotationList, annotation ); + getAccessType( annotationList, element ); + getTemporal( annotationList, element ); + getLob( annotationList, element ); + getEnumerated( annotationList, element ); + AnnotationDescriptor basic = new AnnotationDescriptor( Basic.class ); + getFetchType( basic, element ); + copyBooleanAttribute( basic, element, "optional" ); + annotationList.add( AnnotationFactory.create( basic ) ); + } + } + if ( elementsForProperty.size() == 0 && defaults.canUseJavaAnnotations() ) { + //no annotation presence constraint, basic is the default + Annotation annotation = getPhysicalAnnotation( Basic.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( Lob.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( Enumerated.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( Temporal.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( Column.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( Columns.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( AttributeOverride.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( AttributeOverrides.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( AssociationOverride.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( AssociationOverrides.class ); + addIfNotNull( annotationList, annotation ); + } + } + + private void getEnumerated(List annotationList, Element element) { + Element subElement = element != null ? element.element( "enumerated" ) : null; + if ( subElement != null ) { + AnnotationDescriptor ad = new AnnotationDescriptor( Enumerated.class ); + String enumerated = subElement.getTextTrim(); + if ( "ORDINAL".equalsIgnoreCase( enumerated ) ) { + ad.setValue( "value", EnumType.ORDINAL ); + } + else if ( "STRING".equalsIgnoreCase( enumerated ) ) { + ad.setValue( "value", EnumType.STRING ); + } + else if ( StringHelper.isNotEmpty( enumerated ) ) { + throw new AnnotationException( "Unknown EnumType: " + enumerated + ". " + SCHEMA_VALIDATION ); + } + annotationList.add( AnnotationFactory.create( ad ) ); + } + } + + private void getLob(List annotationList, Element element) { + Element subElement = element != null ? element.element( "lob" ) : null; + if ( subElement != null ) { + annotationList.add( AnnotationFactory.create( new AnnotationDescriptor( Lob.class ) ) ); + } + } + + private void getFetchType(AnnotationDescriptor descriptor, Element element) { + String fetchString = element != null ? element.attributeValue( "fetch" ) : null; + if ( fetchString != null ) { + if ( "eager".equalsIgnoreCase( fetchString ) ) { + descriptor.setValue( "fetch", FetchType.EAGER ); + } + else if ( "lazy".equalsIgnoreCase( fetchString ) ) { + descriptor.setValue( "fetch", FetchType.LAZY ); + } + } + } + + private void getEmbeddedId(List annotationList, XMLContext.Default defaults) { + for ( Element element : elementsForProperty ) { + if ( "embedded-id".equals( element.getName() ) ) { + if ( isProcessingId( defaults ) ) { + Annotation annotation = getAttributeOverrides( element, defaults, false ); + addIfNotNull( annotationList, annotation ); + annotation = getAssociationOverrides( element, defaults, false ); + addIfNotNull( annotationList, annotation ); + AnnotationDescriptor ad = new AnnotationDescriptor( EmbeddedId.class ); + annotationList.add( AnnotationFactory.create( ad ) ); + getAccessType( annotationList, element ); + } + } + } + if ( elementsForProperty.size() == 0 && defaults.canUseJavaAnnotations() ) { + Annotation annotation = getPhysicalAnnotation( EmbeddedId.class ); + if ( annotation != null ) { + annotationList.add( annotation ); + annotation = getPhysicalAnnotation( Column.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( Columns.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( GeneratedValue.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( Temporal.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( TableGenerator.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( SequenceGenerator.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( AttributeOverride.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( AttributeOverrides.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( AssociationOverride.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( AssociationOverrides.class ); + addIfNotNull( annotationList, annotation ); + } + } + } + + private void preCalculateElementsForProperty(Element tree) { + elementsForProperty = new ArrayList<>(); + Element element = tree != null ? tree.element( "attributes" ) : null; + //put entity.attributes elements + if ( element != null ) { + for ( Element subelement : (List) element.elements() ) { + if ( propertyName.equals( subelement.attributeValue( "name" ) ) ) { + elementsForProperty.add( subelement ); + } + } + } + //add pre-* etc from entity and pure entity listener classes + if ( tree != null ) { + for ( Element subelement : (List) tree.elements() ) { + if ( propertyName.equals( subelement.attributeValue( "method-name" ) ) ) { + elementsForProperty.add( subelement ); + } + } + } + } + + private void getId(List annotationList, XMLContext.Default defaults) { + for ( Element element : elementsForProperty ) { + if ( "id".equals( element.getName() ) ) { + boolean processId = isProcessingId( defaults ); + if ( processId ) { + Annotation annotation = buildColumns( element ); + addIfNotNull( annotationList, annotation ); + annotation = buildGeneratedValue( element ); + addIfNotNull( annotationList, annotation ); + getTemporal( annotationList, element ); + //FIXME: fix the priority of xml over java for generator names + annotation = getTableGenerator( element, defaults ); + addIfNotNull( annotationList, annotation ); + annotation = getSequenceGenerator( element, defaults ); + addIfNotNull( annotationList, annotation ); + AnnotationDescriptor id = new AnnotationDescriptor( Id.class ); + annotationList.add( AnnotationFactory.create( id ) ); + getAccessType( annotationList, element ); + } + } + } + if ( elementsForProperty.size() == 0 && defaults.canUseJavaAnnotations() ) { + Annotation annotation = getPhysicalAnnotation( Id.class ); + if ( annotation != null ) { + annotationList.add( annotation ); + annotation = getPhysicalAnnotation( Column.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( Columns.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( GeneratedValue.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( Temporal.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( TableGenerator.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( SequenceGenerator.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( AttributeOverride.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( AttributeOverrides.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( AssociationOverride.class ); + addIfNotNull( annotationList, annotation ); + annotation = getPhysicalAnnotation( AssociationOverrides.class ); + addIfNotNull( annotationList, annotation ); + } + } + } + + private boolean isProcessingId(XMLContext.Default defaults) { + boolean isExplicit = defaults.getAccess() != null; + boolean correctAccess = + ( PropertyType.PROPERTY.equals( propertyType ) && AccessType.PROPERTY.equals( defaults.getAccess() ) ) + || ( PropertyType.FIELD.equals( propertyType ) && AccessType.FIELD + .equals( defaults.getAccess() ) ); + boolean hasId = defaults.canUseJavaAnnotations() + && ( isPhysicalAnnotationPresent( Id.class ) || isPhysicalAnnotationPresent( EmbeddedId.class ) ); + //if ( properAccessOnMetadataComplete || properOverridingOnMetadataNonComplete ) { + boolean mirrorAttributeIsId = defaults.canUseJavaAnnotations() && + ( mirroredAttribute != null && + ( mirroredAttribute.isAnnotationPresent( Id.class ) + || mirroredAttribute.isAnnotationPresent( EmbeddedId.class ) ) ); + boolean propertyIsDefault = PropertyType.PROPERTY.equals( propertyType ) + && !mirrorAttributeIsId; + return correctAccess || ( !isExplicit && hasId ) || ( !isExplicit && propertyIsDefault ); + } + + private Columns buildColumns(Element element) { + List subelements = element.elements( "column" ); + List columns = new ArrayList<>( subelements.size() ); + for ( Element subelement : subelements ) { + columns.add( getColumn( subelement, false, element ) ); + } + if ( columns.size() > 0 ) { + AnnotationDescriptor columnsDescr = new AnnotationDescriptor( Columns.class ); + columnsDescr.setValue( "columns", columns.toArray( new Column[columns.size()] ) ); + return AnnotationFactory.create( columnsDescr ); + } + else { + return null; + } + } + + private GeneratedValue buildGeneratedValue(Element element) { + Element subElement = element != null ? element.element( "generated-value" ) : null; + if ( subElement != null ) { + AnnotationDescriptor ad = new AnnotationDescriptor( GeneratedValue.class ); + String strategy = subElement.attributeValue( "strategy" ); + if ( "TABLE".equalsIgnoreCase( strategy ) ) { + ad.setValue( "strategy", GenerationType.TABLE ); + } + else if ( "SEQUENCE".equalsIgnoreCase( strategy ) ) { + ad.setValue( "strategy", GenerationType.SEQUENCE ); + } + else if ( "IDENTITY".equalsIgnoreCase( strategy ) ) { + ad.setValue( "strategy", GenerationType.IDENTITY ); + } + else if ( "AUTO".equalsIgnoreCase( strategy ) ) { + ad.setValue( "strategy", GenerationType.AUTO ); + } + else if ( StringHelper.isNotEmpty( strategy ) ) { + throw new AnnotationException( "Unknown GenerationType: " + strategy + ". " + SCHEMA_VALIDATION ); + } + copyStringAttribute( ad, subElement, "generator", false ); + return AnnotationFactory.create( ad ); + } + else { + return null; + } + } + + private void getTemporal(List annotationList, Element element) { + Element subElement = element != null ? element.element( "temporal" ) : null; + if ( subElement != null ) { + AnnotationDescriptor ad = new AnnotationDescriptor( Temporal.class ); + String temporal = subElement.getTextTrim(); + if ( "DATE".equalsIgnoreCase( temporal ) ) { + ad.setValue( "value", TemporalType.DATE ); + } + else if ( "TIME".equalsIgnoreCase( temporal ) ) { + ad.setValue( "value", TemporalType.TIME ); + } + else if ( "TIMESTAMP".equalsIgnoreCase( temporal ) ) { + ad.setValue( "value", TemporalType.TIMESTAMP ); + } + else if ( StringHelper.isNotEmpty( temporal ) ) { + throw new AnnotationException( "Unknown TemporalType: " + temporal + ". " + SCHEMA_VALIDATION ); + } + annotationList.add( AnnotationFactory.create( ad ) ); + } + } + + private void getAccessType(List annotationList, Element element) { + if ( element == null ) { + return; + } + String access = element.attributeValue( "access" ); + if ( access != null ) { + AnnotationDescriptor ad = new AnnotationDescriptor( Access.class ); + AccessType type; + try { + type = AccessType.valueOf( access ); + } + catch ( IllegalArgumentException e ) { + throw new AnnotationException( access + " is not a valid access type. Check you xml confguration." ); + } + + if ( ( AccessType.PROPERTY.equals( type ) && this.element instanceof Method ) || + ( AccessType.FIELD.equals( type ) && this.element instanceof Field ) ) { + return; + } + + ad.setValue( "value", type ); + annotationList.add( AnnotationFactory.create( ad ) ); + } + } + + /** + * @param mergeWithAnnotations Whether to use Java annotations for this + * element, if present and not disabled by the XMLContext defaults. + * In some contexts (such as an element-collection mapping) merging + * with annotations is never allowed. + */ + private AssociationOverrides getAssociationOverrides(Element tree, XMLContext.Default defaults, boolean mergeWithAnnotations) { + List attributes = buildAssociationOverrides( tree, defaults ); + if ( mergeWithAnnotations && defaults.canUseJavaAnnotations() ) { + AssociationOverride annotation = getPhysicalAnnotation( AssociationOverride.class ); + addAssociationOverrideIfNeeded( annotation, attributes ); + AssociationOverrides annotations = getPhysicalAnnotation( AssociationOverrides.class ); + if ( annotations != null ) { + for ( AssociationOverride current : annotations.value() ) { + addAssociationOverrideIfNeeded( current, attributes ); + } + } + } + if ( attributes.size() > 0 ) { + AnnotationDescriptor ad = new AnnotationDescriptor( AssociationOverrides.class ); + ad.setValue( "value", attributes.toArray( new AssociationOverride[attributes.size()] ) ); + return AnnotationFactory.create( ad ); + } + else { + return null; + } + } + + private List buildAssociationOverrides(Element element, XMLContext.Default defaults) { + List subelements = element == null ? null : element.elements( "association-override" ); + List overrides = new ArrayList<>(); + if ( subelements != null && subelements.size() > 0 ) { + for ( Element current : subelements ) { + AnnotationDescriptor override = new AnnotationDescriptor( AssociationOverride.class ); + copyStringAttribute( override, current, "name", true ); + override.setValue( "joinColumns", getJoinColumns( current, false ) ); + JoinTable joinTable = buildJoinTable( current, defaults ); + if ( joinTable != null ) { + override.setValue( "joinTable", joinTable ); + } + overrides.add( AnnotationFactory.create( override ) ); + } + } + return overrides; + } + + private JoinColumn[] getJoinColumns(Element element, boolean isInverse) { + List subelements = element != null ? + element.elements( isInverse ? "inverse-join-column" : "join-column" ) : + null; + List joinColumns = new ArrayList<>(); + if ( subelements != null ) { + for ( Element subelement : subelements ) { + AnnotationDescriptor column = new AnnotationDescriptor( JoinColumn.class ); + copyStringAttribute( column, subelement, "name", false ); + copyStringAttribute( column, subelement, "referenced-column-name", false ); + copyBooleanAttribute( column, subelement, "unique" ); + copyBooleanAttribute( column, subelement, "nullable" ); + copyBooleanAttribute( column, subelement, "insertable" ); + copyBooleanAttribute( column, subelement, "updatable" ); + copyStringAttribute( column, subelement, "column-definition", false ); + copyStringAttribute( column, subelement, "table", false ); + joinColumns.add( AnnotationFactory.create( column ) ); + } + } + return joinColumns.toArray( new JoinColumn[joinColumns.size()] ); + } + + private void addAssociationOverrideIfNeeded(AssociationOverride annotation, List overrides) { + if ( annotation != null ) { + String overrideName = annotation.name(); + boolean present = false; + for ( AssociationOverride current : overrides ) { + if ( current.name().equals( overrideName ) ) { + present = true; + break; + } + } + if ( !present ) { + overrides.add( annotation ); + } + } + } + + /** + * @param mergeWithAnnotations Whether to use Java annotations for this + * element, if present and not disabled by the XMLContext defaults. + * In some contexts (such as an association mapping) merging with + * annotations is never allowed. + */ + private AttributeOverrides getAttributeOverrides(Element tree, XMLContext.Default defaults, boolean mergeWithAnnotations) { + List attributes = buildAttributeOverrides( tree, "attribute-override" ); + return mergeAttributeOverrides( defaults, attributes, mergeWithAnnotations ); + } + + /** + * @param mergeWithAnnotations Whether to use Java annotations for this + * element, if present and not disabled by the XMLContext defaults. + * In some contexts (such as an association mapping) merging with + * annotations is never allowed. + */ + private AttributeOverrides mergeAttributeOverrides(XMLContext.Default defaults, List attributes, boolean mergeWithAnnotations) { + if ( mergeWithAnnotations && defaults.canUseJavaAnnotations() ) { + AttributeOverride annotation = getPhysicalAnnotation( AttributeOverride.class ); + addAttributeOverrideIfNeeded( annotation, attributes ); + AttributeOverrides annotations = getPhysicalAnnotation( AttributeOverrides.class ); + if ( annotations != null ) { + for ( AttributeOverride current : annotations.value() ) { + addAttributeOverrideIfNeeded( current, attributes ); + } + } + } + if ( attributes.size() > 0 ) { + AnnotationDescriptor ad = new AnnotationDescriptor( AttributeOverrides.class ); + ad.setValue( "value", attributes.toArray( new AttributeOverride[attributes.size()] ) ); + return AnnotationFactory.create( ad ); + } + else { + return null; + } + } + + private List buildAttributeOverrides(Element element, String nodeName) { + List subelements = element == null ? null : element.elements( nodeName ); + return buildAttributeOverrides( subelements, nodeName ); + } + + private List buildAttributeOverrides(List subelements, String nodeName) { + List overrides = new ArrayList<>(); + if ( subelements != null && subelements.size() > 0 ) { + for ( Element current : subelements ) { + if ( !current.getName().equals( nodeName ) ) { + continue; + } + AnnotationDescriptor override = new AnnotationDescriptor( AttributeOverride.class ); + copyStringAttribute( override, current, "name", true ); + Element column = current.element( "column" ); + override.setValue( "column", getColumn( column, true, current ) ); + overrides.add( AnnotationFactory.create( override ) ); + } + } + return overrides; + } + + private Column getColumn(Element element, boolean isMandatory, Element current) { + //Element subelement = element != null ? element.element( "column" ) : null; + if ( element != null ) { + AnnotationDescriptor column = new AnnotationDescriptor( Column.class ); + copyStringAttribute( column, element, "name", false ); + copyBooleanAttribute( column, element, "unique" ); + copyBooleanAttribute( column, element, "nullable" ); + copyBooleanAttribute( column, element, "insertable" ); + copyBooleanAttribute( column, element, "updatable" ); + copyStringAttribute( column, element, "column-definition", false ); + copyStringAttribute( column, element, "table", false ); + copyIntegerAttribute( column, element, "length" ); + copyIntegerAttribute( column, element, "precision" ); + copyIntegerAttribute( column, element, "scale" ); + return (Column) AnnotationFactory.create( column ); + } + else { + if ( isMandatory ) { + throw new AnnotationException( current.getPath() + ".column is mandatory. " + SCHEMA_VALIDATION ); + } + return null; + } + } + + private void addAttributeOverrideIfNeeded(AttributeOverride annotation, List overrides) { + if ( annotation != null ) { + String overrideName = annotation.name(); + boolean present = false; + for ( AttributeOverride current : overrides ) { + if ( current.name().equals( overrideName ) ) { + present = true; + break; + } + } + if ( !present ) { + overrides.add( annotation ); + } + } + } + + private Access getAccessType(Element tree, XMLContext.Default defaults) { + String access = tree == null ? null : tree.attributeValue( "access" ); + if ( access != null ) { + AnnotationDescriptor ad = new AnnotationDescriptor( Access.class ); + AccessType type; + try { + type = AccessType.valueOf( access ); + } + catch ( IllegalArgumentException e ) { + throw new AnnotationException( access + " is not a valid access type. Check you xml confguration." ); + } + ad.setValue( "value", type ); + return AnnotationFactory.create( ad ); + } + else if ( defaults.canUseJavaAnnotations() && isPhysicalAnnotationPresent( Access.class ) ) { + return getPhysicalAnnotation( Access.class ); + } + else if ( defaults.getAccess() != null ) { + AnnotationDescriptor ad = new AnnotationDescriptor( Access.class ); + ad.setValue( "value", defaults.getAccess() ); + return AnnotationFactory.create( ad ); + } + else { + return null; + } + } + + private ExcludeSuperclassListeners getExcludeSuperclassListeners(Element tree, XMLContext.Default defaults) { + return (ExcludeSuperclassListeners) getMarkerAnnotation( ExcludeSuperclassListeners.class, tree, defaults ); + } + + private ExcludeDefaultListeners getExcludeDefaultListeners(Element tree, XMLContext.Default defaults) { + return (ExcludeDefaultListeners) getMarkerAnnotation( ExcludeDefaultListeners.class, tree, defaults ); + } + + private Annotation getMarkerAnnotation( + Class clazz, Element element, XMLContext.Default defaults + ) { + Element subelement = element == null ? null : element.element( annotationToXml.get( clazz ) ); + if ( subelement != null ) { + return AnnotationFactory.create( new AnnotationDescriptor( clazz ) ); + } + else if ( defaults.canUseJavaAnnotations() ) { + //TODO wonder whether it should be excluded so that user can undone it + return getPhysicalAnnotation( clazz ); + } + else { + return null; + } + } + + private SqlResultSetMappings getSqlResultSetMappings(Element tree, XMLContext.Default defaults) { + List results = buildSqlResultsetMappings( tree, defaults, classLoaderAccess ); + if ( defaults.canUseJavaAnnotations() ) { + SqlResultSetMapping annotation = getPhysicalAnnotation( SqlResultSetMapping.class ); + addSqlResultsetMappingIfNeeded( annotation, results ); + SqlResultSetMappings annotations = getPhysicalAnnotation( SqlResultSetMappings.class ); + if ( annotations != null ) { + for ( SqlResultSetMapping current : annotations.value() ) { + addSqlResultsetMappingIfNeeded( current, results ); + } + } + } + if ( results.size() > 0 ) { + AnnotationDescriptor ad = new AnnotationDescriptor( SqlResultSetMappings.class ); + ad.setValue( "value", results.toArray( new SqlResultSetMapping[results.size()] ) ); + return AnnotationFactory.create( ad ); + } + else { + return null; + } + } + + public static List buildNamedEntityGraph( + Element element, + XMLContext.Default defaults, + ClassLoaderAccess classLoaderAccess) { + if ( element == null ) { + return new ArrayList<>(); + } + List namedEntityGraphList = new ArrayList<>(); + List namedEntityGraphElements = element.elements( "named-entity-graph" ); + for ( Element subElement : namedEntityGraphElements ) { + AnnotationDescriptor ann = new AnnotationDescriptor( NamedEntityGraph.class ); + copyStringAttribute( ann, subElement, "name", false ); + copyBooleanAttribute( ann, subElement, "include-all-attributes" ); + bindNamedAttributeNodes( subElement, ann ); + + List subgraphNodes = subElement.elements( "subgraph" ); + List subclassSubgraphNodes = subElement.elements( "subclass-subgraph" ); + if(!subclassSubgraphNodes.isEmpty()) { + subgraphNodes.addAll( subclassSubgraphNodes ); + } + bindNamedSubgraph( defaults, ann, subgraphNodes, classLoaderAccess ); + namedEntityGraphList.add( AnnotationFactory.create( ann ) ); + } + //TODO + return namedEntityGraphList; + } + + private static void bindNamedSubgraph( + XMLContext.Default defaults, + AnnotationDescriptor ann, + List subgraphNodes, + ClassLoaderAccess classLoaderAccess) { + List annSubgraphNodes = new ArrayList<>( ); + for(Element subgraphNode : subgraphNodes){ + AnnotationDescriptor annSubgraphNode = new AnnotationDescriptor( NamedSubgraph.class ); + copyStringAttribute( annSubgraphNode, subgraphNode, "name", true ); + String clazzName = subgraphNode.attributeValue( "class" ); + Class clazz; + try { + clazz = classLoaderAccess.classForName( + XMLContext.buildSafeClassName( clazzName, defaults ) + ); + } + catch ( ClassLoadingException e ) { + throw new AnnotationException( "Unable to find entity-class: " + clazzName, e ); + } + annSubgraphNode.setValue( "type", clazz ); + bindNamedAttributeNodes(subgraphNode, annSubgraphNode); + annSubgraphNodes.add( AnnotationFactory.create( annSubgraphNode ) ); + } + + ann.setValue( "subgraphs", annSubgraphNodes.toArray( new NamedSubgraph[annSubgraphNodes.size()] ) ); + } + + private static void bindNamedAttributeNodes(Element subElement, AnnotationDescriptor ann) { + List namedAttributeNodes = subElement.elements("named-attribute-node"); + List annNamedAttributeNodes = new ArrayList<>( ); + for(Element namedAttributeNode : namedAttributeNodes){ + AnnotationDescriptor annNamedAttributeNode = new AnnotationDescriptor( NamedAttributeNode.class ); + copyStringAttribute( annNamedAttributeNode, namedAttributeNode, "value", "name", true ); + copyStringAttribute( annNamedAttributeNode, namedAttributeNode, "subgraph", false ); + copyStringAttribute( annNamedAttributeNode, namedAttributeNode, "key-subgraph", false ); + annNamedAttributeNodes.add( AnnotationFactory.create( annNamedAttributeNode ) ); + } + ann.setValue( "attributeNodes", annNamedAttributeNodes.toArray( new NamedAttributeNode[annNamedAttributeNodes.size()] ) ); + } + + public static List buildNamedStoreProcedureQueries( + Element element, + XMLContext.Default defaults, + ClassLoaderAccess classLoaderAccess) { + if ( element == null ) { + return new ArrayList<>(); + } + List namedStoredProcedureElements = element.elements( "named-stored-procedure-query" ); + List namedStoredProcedureQueries = new ArrayList<>(); + for ( Object obj : namedStoredProcedureElements ) { + Element subElement = (Element) obj; + AnnotationDescriptor ann = new AnnotationDescriptor( NamedStoredProcedureQuery.class ); + copyStringAttribute( ann, subElement, "name", true ); + copyStringAttribute( ann, subElement, "procedure-name", true ); + + List elements = subElement.elements( "parameter" ); + List storedProcedureParameters = new ArrayList<>(); + + for ( Element parameterElement : elements ) { + AnnotationDescriptor parameterDescriptor = new AnnotationDescriptor( StoredProcedureParameter.class ); + copyStringAttribute( parameterDescriptor, parameterElement, "name", false ); + String modeValue = parameterElement.attributeValue( "mode" ); + if ( modeValue == null ) { + parameterDescriptor.setValue( "mode", ParameterMode.IN ); + } + else { + parameterDescriptor.setValue( "mode", ParameterMode.valueOf( modeValue.toUpperCase(Locale.ROOT) ) ); + } + String clazzName = parameterElement.attributeValue( "class" ); + Class clazz; + try { + clazz = classLoaderAccess.classForName( + XMLContext.buildSafeClassName( clazzName, defaults ) + ); + } + catch ( ClassLoadingException e ) { + throw new AnnotationException( "Unable to find entity-class: " + clazzName, e ); + } + parameterDescriptor.setValue( "type", clazz ); + storedProcedureParameters.add( AnnotationFactory.create( parameterDescriptor ) ); + } + + ann.setValue( + "parameters", + storedProcedureParameters.toArray( new StoredProcedureParameter[storedProcedureParameters.size()] ) + ); + + elements = subElement.elements( "result-class" ); + List returnClasses = new ArrayList<>(); + for ( Element classElement : elements ) { + String clazzName = classElement.getTextTrim(); + Class clazz; + try { + clazz = classLoaderAccess.classForName( + XMLContext.buildSafeClassName( clazzName, defaults ) + ); + } + catch ( ClassLoadingException e ) { + throw new AnnotationException( "Unable to find entity-class: " + clazzName, e ); + } + returnClasses.add( clazz ); + } + ann.setValue( "resultClasses", returnClasses.toArray( new Class[returnClasses.size()] ) ); + + + elements = subElement.elements( "result-set-mapping" ); + List resultSetMappings = new ArrayList<>(); + for ( Element resultSetMappingElement : elements ) { + resultSetMappings.add( resultSetMappingElement.getTextTrim() ); + } + ann.setValue( "resultSetMappings", resultSetMappings.toArray( new String[resultSetMappings.size()] ) ); + elements = subElement.elements( "hint" ); + buildQueryHints( elements, ann ); + namedStoredProcedureQueries.add( AnnotationFactory.create( ann ) ); + } + return namedStoredProcedureQueries; + + } + + public static List buildSqlResultsetMappings( + Element element, + XMLContext.Default defaults, + ClassLoaderAccess classLoaderAccess) { + final List builtResultSetMappings = new ArrayList<>(); + if ( element == null ) { + return builtResultSetMappings; + } + + // iterate over each element + for ( Object resultSetMappingElementObject : element.elements( "sql-result-set-mapping" ) ) { + final Element resultSetMappingElement = (Element) resultSetMappingElementObject; + + final AnnotationDescriptor resultSetMappingAnnotation = new AnnotationDescriptor( SqlResultSetMapping.class ); + copyStringAttribute( resultSetMappingAnnotation, resultSetMappingElement, "name", true ); + + // iterate over the sub-elements, which should include: + // * + // * + // * + + List entityResultAnnotations = null; + List columnResultAnnotations = null; + List constructorResultAnnotations = null; + + for ( Object resultElementObject : resultSetMappingElement.elements() ) { + final Element resultElement = (Element) resultElementObject; + + if ( "entity-result".equals( resultElement.getName() ) ) { + if ( entityResultAnnotations == null ) { + entityResultAnnotations = new ArrayList<>(); + } + // process the + entityResultAnnotations.add( buildEntityResult( resultElement, defaults, classLoaderAccess ) ); + } + else if ( "column-result".equals( resultElement.getName() ) ) { + if ( columnResultAnnotations == null ) { + columnResultAnnotations = new ArrayList<>(); + } + columnResultAnnotations.add( buildColumnResult( resultElement, defaults, classLoaderAccess ) ); + } + else if ( "constructor-result".equals( resultElement.getName() ) ) { + if ( constructorResultAnnotations == null ) { + constructorResultAnnotations = new ArrayList<>(); + } + constructorResultAnnotations.add( buildConstructorResult( resultElement, defaults, classLoaderAccess ) ); + } + else { + // most likely the this code used to handle. I have left the code here, + // but commented it out for now. I'll just log a warning for now. + LOG.debug( "Encountered unrecognized sql-result-set-mapping sub-element : " + resultElement.getName() ); + +// String clazzName = subelement.attributeValue( "result-class" ); +// if ( StringHelper.isNotEmpty( clazzName ) ) { +// Class clazz; +// try { +// clazz = ReflectHelper.classForName( +// XMLContext.buildSafeClassName( clazzName, defaults ), +// JPAOverriddenAnnotationReader.class +// ); +// } +// catch ( ClassNotFoundException e ) { +// throw new AnnotationException( "Unable to find entity-class: " + clazzName, e ); +// } +// ann.setValue( "resultClass", clazz ); +// } + } + } + + if ( entityResultAnnotations != null && !entityResultAnnotations.isEmpty() ) { + resultSetMappingAnnotation.setValue( + "entities", + entityResultAnnotations.toArray( new EntityResult[entityResultAnnotations.size()] ) + ); + } + if ( columnResultAnnotations != null && !columnResultAnnotations.isEmpty() ) { + resultSetMappingAnnotation.setValue( + "columns", + columnResultAnnotations.toArray( new ColumnResult[columnResultAnnotations.size()] ) + ); + } + if ( constructorResultAnnotations != null && !constructorResultAnnotations.isEmpty() ) { + resultSetMappingAnnotation.setValue( + "classes", + constructorResultAnnotations.toArray( new ConstructorResult[constructorResultAnnotations.size()] ) + ); + } + + + // this was part of the old code too, but could never figure out what it is supposed to do... + // copyStringAttribute( ann, subelement, "result-set-mapping", false ); + + builtResultSetMappings.add( AnnotationFactory.create( resultSetMappingAnnotation ) ); + } + + return builtResultSetMappings; + } + + private static EntityResult buildEntityResult( + Element entityResultElement, + XMLContext.Default defaults, + ClassLoaderAccess classLoaderAccess) { + final AnnotationDescriptor entityResultDescriptor = new AnnotationDescriptor( EntityResult.class ); + + final Class entityClass = resolveClassReference( entityResultElement.attributeValue( "entity-class" ), defaults, classLoaderAccess ); + entityResultDescriptor.setValue( "entityClass", entityClass ); + + copyStringAttribute( entityResultDescriptor, entityResultElement, "discriminator-column", false ); + + // process the sub-elements + List fieldResultAnnotations = new ArrayList<>(); + for ( Element fieldResult : (List) entityResultElement.elements( "field-result" ) ) { + AnnotationDescriptor fieldResultDescriptor = new AnnotationDescriptor( FieldResult.class ); + copyStringAttribute( fieldResultDescriptor, fieldResult, "name", true ); + copyStringAttribute( fieldResultDescriptor, fieldResult, "column", true ); + fieldResultAnnotations.add( AnnotationFactory.create( fieldResultDescriptor ) ); + } + entityResultDescriptor.setValue( + "fields", fieldResultAnnotations.toArray( new FieldResult[fieldResultAnnotations.size()] ) + ); + return AnnotationFactory.create( entityResultDescriptor ); + } + + private static Class resolveClassReference( + String className, + XMLContext.Default defaults, + ClassLoaderAccess classLoaderAccess) { + if ( className == null ) { + throw new AnnotationException( " without entity-class. " + SCHEMA_VALIDATION ); + } + try { + return classLoaderAccess.classForName( + XMLContext.buildSafeClassName( className, defaults ) + ); + } + catch ( ClassLoadingException e ) { + throw new AnnotationException( "Unable to find specified class: " + className, e ); + } + } + + private static ColumnResult buildColumnResult( + Element columnResultElement, + XMLContext.Default defaults, + ClassLoaderAccess classLoaderAccess) { +// AnnotationDescriptor columnResultDescriptor = new AnnotationDescriptor( ColumnResult.class ); +// copyStringAttribute( columnResultDescriptor, columnResultElement, "name", true ); +// return AnnotationFactory.create( columnResultDescriptor ); + + AnnotationDescriptor columnResultDescriptor = new AnnotationDescriptor( ColumnResult.class ); + copyStringAttribute( columnResultDescriptor, columnResultElement, "name", true ); + final String columnTypeName = columnResultElement.attributeValue( "class" ); + if ( StringHelper.isNotEmpty( columnTypeName ) ) { + columnResultDescriptor.setValue( "type", resolveClassReference( columnTypeName, defaults, classLoaderAccess ) ); + } + return AnnotationFactory.create( columnResultDescriptor ); + } + + private static ConstructorResult buildConstructorResult( + Element constructorResultElement, + XMLContext.Default defaults, + ClassLoaderAccess classLoaderAccess) { + AnnotationDescriptor constructorResultDescriptor = new AnnotationDescriptor( ConstructorResult.class ); + + final Class entityClass = resolveClassReference( constructorResultElement.attributeValue( "target-class" ), defaults, classLoaderAccess ); + constructorResultDescriptor.setValue( "targetClass", entityClass ); + + List columnResultAnnotations = new ArrayList<>(); + for ( Element columnResultElement : (List) constructorResultElement.elements( "column" ) ) { + columnResultAnnotations.add( buildColumnResult( columnResultElement, defaults, classLoaderAccess ) ); + } + constructorResultDescriptor.setValue( + "columns", + columnResultAnnotations.toArray( new ColumnResult[ columnResultAnnotations.size() ] ) + ); + + return AnnotationFactory.create( constructorResultDescriptor ); + } + + private void addSqlResultsetMappingIfNeeded(SqlResultSetMapping annotation, List resultsets) { + if ( annotation != null ) { + String resultsetName = annotation.name(); + boolean present = false; + for ( SqlResultSetMapping current : resultsets ) { + if ( current.name().equals( resultsetName ) ) { + present = true; + break; + } + } + if ( !present ) { + resultsets.add( annotation ); + } + } + } + + private NamedQueries getNamedQueries(Element tree, XMLContext.Default defaults) { + //TODO avoid the Proxy Creation (@NamedQueries) when possible + List queries = (List) buildNamedQueries( tree, false, defaults, classLoaderAccess ); + if ( defaults.canUseJavaAnnotations() ) { + NamedQuery annotation = getPhysicalAnnotation( NamedQuery.class ); + addNamedQueryIfNeeded( annotation, queries ); + NamedQueries annotations = getPhysicalAnnotation( NamedQueries.class ); + if ( annotations != null ) { + for ( NamedQuery current : annotations.value() ) { + addNamedQueryIfNeeded( current, queries ); + } + } + } + if ( queries.size() > 0 ) { + AnnotationDescriptor ad = new AnnotationDescriptor( NamedQueries.class ); + ad.setValue( "value", queries.toArray( new NamedQuery[queries.size()] ) ); + return AnnotationFactory.create( ad ); + } + else { + return null; + } + } + + private void addNamedQueryIfNeeded(NamedQuery annotation, List queries) { + if ( annotation != null ) { + String queryName = annotation.name(); + boolean present = false; + for ( NamedQuery current : queries ) { + if ( current.name().equals( queryName ) ) { + present = true; + break; + } + } + if ( !present ) { + queries.add( annotation ); + } + } + } + + private NamedEntityGraphs getNamedEntityGraphs(Element tree, XMLContext.Default defaults) { + List queries = buildNamedEntityGraph( tree, defaults, classLoaderAccess ); + if ( defaults.canUseJavaAnnotations() ) { + NamedEntityGraph annotation = getPhysicalAnnotation( NamedEntityGraph.class ); + addNamedEntityGraphIfNeeded( annotation, queries ); + NamedEntityGraphs annotations = getPhysicalAnnotation( NamedEntityGraphs.class ); + if ( annotations != null ) { + for ( NamedEntityGraph current : annotations.value() ) { + addNamedEntityGraphIfNeeded( current, queries ); + } + } + } + if ( queries.size() > 0 ) { + AnnotationDescriptor ad = new AnnotationDescriptor( NamedEntityGraphs.class ); + ad.setValue( "value", queries.toArray( new NamedEntityGraph[queries.size()] ) ); + return AnnotationFactory.create( ad ); + } + else { + return null; + } + } + + private void addNamedEntityGraphIfNeeded(NamedEntityGraph annotation, List queries) { + if ( annotation != null ) { + String queryName = annotation.name(); + boolean present = false; + for ( NamedEntityGraph current : queries ) { + if ( current.name().equals( queryName ) ) { + present = true; + break; + } + } + if ( !present ) { + queries.add( annotation ); + } + } + + } + + private NamedStoredProcedureQueries getNamedStoredProcedureQueries(Element tree, XMLContext.Default defaults) { + List queries = buildNamedStoreProcedureQueries( tree, defaults, classLoaderAccess ); + if ( defaults.canUseJavaAnnotations() ) { + NamedStoredProcedureQuery annotation = getPhysicalAnnotation( NamedStoredProcedureQuery.class ); + addNamedStoredProcedureQueryIfNeeded( annotation, queries ); + NamedStoredProcedureQueries annotations = getPhysicalAnnotation( NamedStoredProcedureQueries.class ); + if ( annotations != null ) { + for ( NamedStoredProcedureQuery current : annotations.value() ) { + addNamedStoredProcedureQueryIfNeeded( current, queries ); + } + } + } + if ( queries.size() > 0 ) { + AnnotationDescriptor ad = new AnnotationDescriptor( NamedStoredProcedureQueries.class ); + ad.setValue( "value", queries.toArray( new NamedStoredProcedureQuery[queries.size()] ) ); + return AnnotationFactory.create( ad ); + } + else { + return null; + } + } + + private void addNamedStoredProcedureQueryIfNeeded(NamedStoredProcedureQuery annotation, List queries) { + if ( annotation != null ) { + String queryName = annotation.name(); + boolean present = false; + for ( NamedStoredProcedureQuery current : queries ) { + if ( current.name().equals( queryName ) ) { + present = true; + break; + } + } + if ( !present ) { + queries.add( annotation ); + } + } + } + + + private NamedNativeQueries getNamedNativeQueries( + Element tree, + XMLContext.Default defaults) { + List queries = (List) buildNamedQueries( tree, true, defaults, classLoaderAccess ); + if ( defaults.canUseJavaAnnotations() ) { + NamedNativeQuery annotation = getPhysicalAnnotation( NamedNativeQuery.class ); + addNamedNativeQueryIfNeeded( annotation, queries ); + NamedNativeQueries annotations = getPhysicalAnnotation( NamedNativeQueries.class ); + if ( annotations != null ) { + for ( NamedNativeQuery current : annotations.value() ) { + addNamedNativeQueryIfNeeded( current, queries ); + } + } + } + if ( queries.size() > 0 ) { + AnnotationDescriptor ad = new AnnotationDescriptor( NamedNativeQueries.class ); + ad.setValue( "value", queries.toArray( new NamedNativeQuery[queries.size()] ) ); + return AnnotationFactory.create( ad ); + } + else { + return null; + } + } + + private void addNamedNativeQueryIfNeeded(NamedNativeQuery annotation, List queries) { + if ( annotation != null ) { + String queryName = annotation.name(); + boolean present = false; + for ( NamedNativeQuery current : queries ) { + if ( current.name().equals( queryName ) ) { + present = true; + break; + } + } + if ( !present ) { + queries.add( annotation ); + } + } + } + + private static void buildQueryHints(List elements, AnnotationDescriptor ann){ + List queryHints = new ArrayList<>( elements.size() ); + for ( Element hint : elements ) { + AnnotationDescriptor hintDescriptor = new AnnotationDescriptor( QueryHint.class ); + String value = hint.attributeValue( "name" ); + if ( value == null ) { + throw new AnnotationException( " without name. " + SCHEMA_VALIDATION ); + } + hintDescriptor.setValue( "name", value ); + value = hint.attributeValue( "value" ); + if ( value == null ) { + throw new AnnotationException( " without value. " + SCHEMA_VALIDATION ); + } + hintDescriptor.setValue( "value", value ); + queryHints.add( AnnotationFactory.create( hintDescriptor ) ); + } + ann.setValue( "hints", queryHints.toArray( new QueryHint[queryHints.size()] ) ); + } + + public static List buildNamedQueries( + Element element, + boolean isNative, + XMLContext.Default defaults, + ClassLoaderAccess classLoaderAccess) { + if ( element == null ) { + return new ArrayList(); + } + List namedQueryElementList = isNative ? + element.elements( "named-native-query" ) : + element.elements( "named-query" ); + List namedQueries = new ArrayList(); + for ( Object aNamedQueryElementList : namedQueryElementList ) { + Element subelement = (Element) aNamedQueryElementList; + AnnotationDescriptor ann = new AnnotationDescriptor( + isNative ? NamedNativeQuery.class : NamedQuery.class + ); + copyStringAttribute( ann, subelement, "name", false ); + Element queryElt = subelement.element( "query" ); + if ( queryElt == null ) { + throw new AnnotationException( "No element found." + SCHEMA_VALIDATION ); + } + copyStringElement( queryElt, ann, "query" ); + List elements = subelement.elements( "hint" ); + buildQueryHints( elements, ann ); + String clazzName = subelement.attributeValue( "result-class" ); + if ( StringHelper.isNotEmpty( clazzName ) ) { + Class clazz; + try { + clazz = classLoaderAccess.classForName( + XMLContext.buildSafeClassName( clazzName, defaults ) + ); + } + catch (ClassLoadingException e) { + throw new AnnotationException( "Unable to find entity-class: " + clazzName, e ); + } + ann.setValue( "resultClass", clazz ); + } + copyStringAttribute( ann, subelement, "result-set-mapping", false ); + namedQueries.add( AnnotationFactory.create( ann ) ); + } + return namedQueries; + } + + private TableGenerator getTableGenerator(Element tree, XMLContext.Default defaults) { + Element element = tree != null ? tree.element( annotationToXml.get( TableGenerator.class ) ) : null; + if ( element != null ) { + return buildTableGeneratorAnnotation( element, defaults ); + } + else if ( defaults.canUseJavaAnnotations() && isPhysicalAnnotationPresent( TableGenerator.class ) ) { + TableGenerator tableAnn = getPhysicalAnnotation( TableGenerator.class ); + if ( StringHelper.isNotEmpty( defaults.getSchema() ) + || StringHelper.isNotEmpty( defaults.getCatalog() ) ) { + AnnotationDescriptor annotation = new AnnotationDescriptor( TableGenerator.class ); + annotation.setValue( "name", tableAnn.name() ); + annotation.setValue( "table", tableAnn.table() ); + annotation.setValue( "catalog", tableAnn.table() ); + if ( StringHelper.isEmpty( (String) annotation.valueOf( "catalog" ) ) + && StringHelper.isNotEmpty( defaults.getCatalog() ) ) { + annotation.setValue( "catalog", defaults.getCatalog() ); + } + annotation.setValue( "schema", tableAnn.table() ); + if ( StringHelper.isEmpty( (String) annotation.valueOf( "schema" ) ) + && StringHelper.isNotEmpty( defaults.getSchema() ) ) { + annotation.setValue( "catalog", defaults.getSchema() ); + } + annotation.setValue( "pkColumnName", tableAnn.pkColumnName() ); + annotation.setValue( "valueColumnName", tableAnn.valueColumnName() ); + annotation.setValue( "pkColumnValue", tableAnn.pkColumnValue() ); + annotation.setValue( "initialValue", tableAnn.initialValue() ); + annotation.setValue( "allocationSize", tableAnn.allocationSize() ); + annotation.setValue( "uniqueConstraints", tableAnn.uniqueConstraints() ); + return AnnotationFactory.create( annotation ); + } + else { + return tableAnn; + } + } + else { + return null; + } + } + + public static TableGenerator buildTableGeneratorAnnotation(Element element, XMLContext.Default defaults) { + AnnotationDescriptor ad = new AnnotationDescriptor( TableGenerator.class ); + copyStringAttribute( ad, element, "name", false ); + copyStringAttribute( ad, element, "table", false ); + copyStringAttribute( ad, element, "catalog", false ); + copyStringAttribute( ad, element, "schema", false ); + copyStringAttribute( ad, element, "pk-column-name", false ); + copyStringAttribute( ad, element, "value-column-name", false ); + copyStringAttribute( ad, element, "pk-column-value", false ); + copyIntegerAttribute( ad, element, "initial-value" ); + copyIntegerAttribute( ad, element, "allocation-size" ); + buildUniqueConstraints( ad, element ); + if ( StringHelper.isEmpty( (String) ad.valueOf( "schema" ) ) + && StringHelper.isNotEmpty( defaults.getSchema() ) ) { + ad.setValue( "schema", defaults.getSchema() ); + } + if ( StringHelper.isEmpty( (String) ad.valueOf( "catalog" ) ) + && StringHelper.isNotEmpty( defaults.getCatalog() ) ) { + ad.setValue( "catalog", defaults.getCatalog() ); + } + return AnnotationFactory.create( ad ); + } + + private SequenceGenerator getSequenceGenerator(Element tree, XMLContext.Default defaults) { + Element element = tree != null ? tree.element( annotationToXml.get( SequenceGenerator.class ) ) : null; + if ( element != null ) { + return buildSequenceGeneratorAnnotation( element ); + } + else if ( defaults.canUseJavaAnnotations() ) { + return getPhysicalAnnotation( SequenceGenerator.class ); + } + else { + return null; + } + } + + public static SequenceGenerator buildSequenceGeneratorAnnotation(Element element) { + if ( element != null ) { + AnnotationDescriptor ad = new AnnotationDescriptor( SequenceGenerator.class ); + copyStringAttribute( ad, element, "name", false ); + copyStringAttribute( ad, element, "sequence-name", false ); + copyIntegerAttribute( ad, element, "initial-value" ); + copyIntegerAttribute( ad, element, "allocation-size" ); + return AnnotationFactory.create( ad ); + } + else { + return null; + } + } + + private DiscriminatorColumn getDiscriminatorColumn(Element tree, XMLContext.Default defaults) { + Element element = tree != null ? tree.element( "discriminator-column" ) : null; + if ( element != null ) { + AnnotationDescriptor ad = new AnnotationDescriptor( DiscriminatorColumn.class ); + copyStringAttribute( ad, element, "name", false ); + copyStringAttribute( ad, element, "column-definition", false ); + String value = element.attributeValue( "discriminator-type" ); + DiscriminatorType type = DiscriminatorType.STRING; + if ( value != null ) { + if ( "STRING".equals( value ) ) { + type = DiscriminatorType.STRING; + } + else if ( "CHAR".equals( value ) ) { + type = DiscriminatorType.CHAR; + } + else if ( "INTEGER".equals( value ) ) { + type = DiscriminatorType.INTEGER; + } + else { + throw new AnnotationException( + "Unknown DiscriminatorType in XML: " + value + " (" + SCHEMA_VALIDATION + ")" + ); + } + } + ad.setValue( "discriminatorType", type ); + copyIntegerAttribute( ad, element, "length" ); + return AnnotationFactory.create( ad ); + } + else if ( defaults.canUseJavaAnnotations() ) { + return getPhysicalAnnotation( DiscriminatorColumn.class ); + } + else { + return null; + } + } + + private DiscriminatorValue getDiscriminatorValue(Element tree, XMLContext.Default defaults) { + Element element = tree != null ? tree.element( "discriminator-value" ) : null; + if ( element != null ) { + AnnotationDescriptor ad = new AnnotationDescriptor( DiscriminatorValue.class ); + copyStringElement( element, ad, "value" ); + return AnnotationFactory.create( ad ); + } + else if ( defaults.canUseJavaAnnotations() ) { + return getPhysicalAnnotation( DiscriminatorValue.class ); + } + else { + return null; + } + } + + private Inheritance getInheritance(Element tree, XMLContext.Default defaults) { + Element element = tree != null ? tree.element( "inheritance" ) : null; + if ( element != null ) { + AnnotationDescriptor ad = new AnnotationDescriptor( Inheritance.class ); + Attribute attr = element.attribute( "strategy" ); + InheritanceType strategy = InheritanceType.SINGLE_TABLE; + if ( attr != null ) { + String value = attr.getValue(); + if ( "SINGLE_TABLE".equals( value ) ) { + strategy = InheritanceType.SINGLE_TABLE; + } + else if ( "JOINED".equals( value ) ) { + strategy = InheritanceType.JOINED; + } + else if ( "TABLE_PER_CLASS".equals( value ) ) { + strategy = InheritanceType.TABLE_PER_CLASS; + } + else { + throw new AnnotationException( + "Unknown InheritanceType in XML: " + value + " (" + SCHEMA_VALIDATION + ")" + ); + } + } + ad.setValue( "strategy", strategy ); + return AnnotationFactory.create( ad ); + } + else if ( defaults.canUseJavaAnnotations() ) { + return getPhysicalAnnotation( Inheritance.class ); + } + else { + return null; + } + } + + private IdClass getIdClass(Element tree, XMLContext.Default defaults) { + Element element = tree == null ? null : tree.element( "id-class" ); + if ( element != null ) { + Attribute attr = element.attribute( "class" ); + if ( attr != null ) { + AnnotationDescriptor ad = new AnnotationDescriptor( IdClass.class ); + Class clazz; + try { + clazz = classLoaderAccess.classForName( XMLContext.buildSafeClassName( attr.getValue(), defaults ) + ); + } + catch ( ClassLoadingException e ) { + throw new AnnotationException( "Unable to find id-class: " + attr.getValue(), e ); + } + ad.setValue( "value", clazz ); + return AnnotationFactory.create( ad ); + } + else { + throw new AnnotationException( "id-class without class. " + SCHEMA_VALIDATION ); + } + } + else if ( defaults.canUseJavaAnnotations() ) { + return getPhysicalAnnotation( IdClass.class ); + } + else { + return null; + } + } + + /** + * @param mergeWithAnnotations Whether to use Java annotations for this + * element, if present and not disabled by the XMLContext defaults. + * In some contexts (such as an association mapping) merging with + * annotations is never allowed. + */ + private PrimaryKeyJoinColumns getPrimaryKeyJoinColumns(Element element, XMLContext.Default defaults, boolean mergeWithAnnotations) { + PrimaryKeyJoinColumn[] columns = buildPrimaryKeyJoinColumns( element ); + if ( mergeWithAnnotations ) { + if ( columns.length == 0 && defaults.canUseJavaAnnotations() ) { + PrimaryKeyJoinColumn annotation = getPhysicalAnnotation( PrimaryKeyJoinColumn.class ); + if ( annotation != null ) { + columns = new PrimaryKeyJoinColumn[] { annotation }; + } + else { + PrimaryKeyJoinColumns annotations = getPhysicalAnnotation( PrimaryKeyJoinColumns.class ); + columns = annotations != null ? annotations.value() : columns; + } + } + } + if ( columns.length > 0 ) { + AnnotationDescriptor ad = new AnnotationDescriptor( PrimaryKeyJoinColumns.class ); + ad.setValue( "value", columns ); + return AnnotationFactory.create( ad ); + } + else { + return null; + } + } + + private Entity getEntity(Element tree, XMLContext.Default defaults) { + if ( tree == null ) { + return defaults.canUseJavaAnnotations() ? getPhysicalAnnotation( Entity.class ) : null; + } + else { + if ( "entity".equals( tree.getName() ) ) { + AnnotationDescriptor entity = new AnnotationDescriptor( Entity.class ); + copyStringAttribute( entity, tree, "name", false ); + if ( defaults.canUseJavaAnnotations() + && StringHelper.isEmpty( (String) entity.valueOf( "name" ) ) ) { + Entity javaAnn = getPhysicalAnnotation( Entity.class ); + if ( javaAnn != null ) { + entity.setValue( "name", javaAnn.name() ); + } + } + return AnnotationFactory.create( entity ); + } + else { + return null; //this is not an entity + } + } + } + + private MappedSuperclass getMappedSuperclass(Element tree, XMLContext.Default defaults) { + if ( tree == null ) { + return defaults.canUseJavaAnnotations() ? getPhysicalAnnotation( MappedSuperclass.class ) : null; + } + else { + if ( "mapped-superclass".equals( tree.getName() ) ) { + AnnotationDescriptor entity = new AnnotationDescriptor( MappedSuperclass.class ); + return AnnotationFactory.create( entity ); + } + else { + return null; //this is not an entity + } + } + } + + private Embeddable getEmbeddable(Element tree, XMLContext.Default defaults) { + if ( tree == null ) { + return defaults.canUseJavaAnnotations() ? getPhysicalAnnotation( Embeddable.class ) : null; + } + else { + if ( "embeddable".equals( tree.getName() ) ) { + AnnotationDescriptor entity = new AnnotationDescriptor( Embeddable.class ); + return AnnotationFactory.create( entity ); + } + else { + return null; //this is not an entity + } + } + } + + private Table getTable(Element tree, XMLContext.Default defaults) { + Element subelement = tree == null ? null : tree.element( "table" ); + if ( subelement == null ) { + //no element but might have some default or some annotation + if ( StringHelper.isNotEmpty( defaults.getCatalog() ) + || StringHelper.isNotEmpty( defaults.getSchema() ) ) { + AnnotationDescriptor annotation = new AnnotationDescriptor( Table.class ); + if ( defaults.canUseJavaAnnotations() ) { + Table table = getPhysicalAnnotation( Table.class ); + if ( table != null ) { + annotation.setValue( "name", table.name() ); + annotation.setValue( "schema", table.schema() ); + annotation.setValue( "catalog", table.catalog() ); + annotation.setValue( "uniqueConstraints", table.uniqueConstraints() ); + annotation.setValue( "indexes", table.indexes() ); + } + } + if ( StringHelper.isEmpty( (String) annotation.valueOf( "schema" ) ) + && StringHelper.isNotEmpty( defaults.getSchema() ) ) { + annotation.setValue( "schema", defaults.getSchema() ); + } + if ( StringHelper.isEmpty( (String) annotation.valueOf( "catalog" ) ) + && StringHelper.isNotEmpty( defaults.getCatalog() ) ) { + annotation.setValue( "catalog", defaults.getCatalog() ); + } + return AnnotationFactory.create( annotation ); + } + else if ( defaults.canUseJavaAnnotations() ) { + return getPhysicalAnnotation( Table.class ); + } + else { + return null; + } + } + else { + //ignore java annotation, an element is defined + AnnotationDescriptor annotation = new AnnotationDescriptor( Table.class ); + copyStringAttribute( annotation, subelement, "name", false ); + copyStringAttribute( annotation, subelement, "catalog", false ); + if ( StringHelper.isNotEmpty( defaults.getCatalog() ) + && StringHelper.isEmpty( (String) annotation.valueOf( "catalog" ) ) ) { + annotation.setValue( "catalog", defaults.getCatalog() ); + } + copyStringAttribute( annotation, subelement, "schema", false ); + if ( StringHelper.isNotEmpty( defaults.getSchema() ) + && StringHelper.isEmpty( (String) annotation.valueOf( "schema" ) ) ) { + annotation.setValue( "schema", defaults.getSchema() ); + } + buildUniqueConstraints( annotation, subelement ); + buildIndex( annotation, subelement ); + return AnnotationFactory.create( annotation ); + } + } + + private SecondaryTables getSecondaryTables(Element tree, XMLContext.Default defaults) { + List elements = tree == null ? + new ArrayList<>() : + (List) tree.elements( "secondary-table" ); + List secondaryTables = new ArrayList<>( 3 ); + for ( Element element : elements ) { + AnnotationDescriptor annotation = new AnnotationDescriptor( SecondaryTable.class ); + copyStringAttribute( annotation, element, "name", false ); + copyStringAttribute( annotation, element, "catalog", false ); + if ( StringHelper.isNotEmpty( defaults.getCatalog() ) + && StringHelper.isEmpty( (String) annotation.valueOf( "catalog" ) ) ) { + annotation.setValue( "catalog", defaults.getCatalog() ); + } + copyStringAttribute( annotation, element, "schema", false ); + if ( StringHelper.isNotEmpty( defaults.getSchema() ) + && StringHelper.isEmpty( (String) annotation.valueOf( "schema" ) ) ) { + annotation.setValue( "schema", defaults.getSchema() ); + } + buildUniqueConstraints( annotation, element ); + buildIndex( annotation, element ); + annotation.setValue( "pkJoinColumns", buildPrimaryKeyJoinColumns( element ) ); + secondaryTables.add( AnnotationFactory.create( annotation ) ); + } + /* + * You can't have both secondary tables in XML and Java, + * since there would be no way to "remove" a secondary table + */ + if ( secondaryTables.size() == 0 && defaults.canUseJavaAnnotations() ) { + SecondaryTable secTableAnn = getPhysicalAnnotation( SecondaryTable.class ); + overridesDefaultInSecondaryTable( secTableAnn, defaults, secondaryTables ); + SecondaryTables secTablesAnn = getPhysicalAnnotation( SecondaryTables.class ); + if ( secTablesAnn != null ) { + for ( SecondaryTable table : secTablesAnn.value() ) { + overridesDefaultInSecondaryTable( table, defaults, secondaryTables ); + } + } + } + if ( secondaryTables.size() > 0 ) { + AnnotationDescriptor descriptor = new AnnotationDescriptor( SecondaryTables.class ); + descriptor.setValue( "value", secondaryTables.toArray( new SecondaryTable[secondaryTables.size()] ) ); + return AnnotationFactory.create( descriptor ); + } + else { + return null; + } + } + + private void overridesDefaultInSecondaryTable( + SecondaryTable secTableAnn, XMLContext.Default defaults, List secondaryTables + ) { + if ( secTableAnn != null ) { + //handle default values + if ( StringHelper.isNotEmpty( defaults.getCatalog() ) + || StringHelper.isNotEmpty( defaults.getSchema() ) ) { + AnnotationDescriptor annotation = new AnnotationDescriptor( SecondaryTable.class ); + annotation.setValue( "name", secTableAnn.name() ); + annotation.setValue( "schema", secTableAnn.schema() ); + annotation.setValue( "catalog", secTableAnn.catalog() ); + annotation.setValue( "uniqueConstraints", secTableAnn.uniqueConstraints() ); + annotation.setValue( "pkJoinColumns", secTableAnn.pkJoinColumns() ); + if ( StringHelper.isEmpty( (String) annotation.valueOf( "schema" ) ) + && StringHelper.isNotEmpty( defaults.getSchema() ) ) { + annotation.setValue( "schema", defaults.getSchema() ); + } + if ( StringHelper.isEmpty( (String) annotation.valueOf( "catalog" ) ) + && StringHelper.isNotEmpty( defaults.getCatalog() ) ) { + annotation.setValue( "catalog", defaults.getCatalog() ); + } + secondaryTables.add( AnnotationFactory.create( annotation ) ); + } + else { + secondaryTables.add( secTableAnn ); + } + } + } + private static void buildIndex(AnnotationDescriptor annotation, Element element){ + List indexElementList = element.elements( "index" ); + Index[] indexes = new Index[indexElementList.size()]; + for(int i=0;i columnNamesElements = subelement.elements( "column-name" ); + String[] columnNames = new String[columnNamesElements.size()]; + int columnNameIndex = 0; + Iterator it = columnNamesElements.listIterator(); + while ( it.hasNext() ) { + Element columnNameElt = (Element) it.next(); + columnNames[columnNameIndex++] = columnNameElt.getTextTrim(); + } + AnnotationDescriptor ucAnn = new AnnotationDescriptor( UniqueConstraint.class ); + copyStringAttribute( ucAnn, subelement, "name", false ); + ucAnn.setValue( "columnNames", columnNames ); + uniqueConstraints[ucIndex++] = AnnotationFactory.create( ucAnn ); + } + annotation.setValue( "uniqueConstraints", uniqueConstraints ); + } + + private PrimaryKeyJoinColumn[] buildPrimaryKeyJoinColumns(Element element) { + if ( element == null ) { + return new PrimaryKeyJoinColumn[] { }; + } + List pkJoinColumnElementList = element.elements( "primary-key-join-column" ); + PrimaryKeyJoinColumn[] pkJoinColumns = new PrimaryKeyJoinColumn[pkJoinColumnElementList.size()]; + int index = 0; + Iterator pkIt = pkJoinColumnElementList.listIterator(); + while ( pkIt.hasNext() ) { + Element subelement = (Element) pkIt.next(); + AnnotationDescriptor pkAnn = new AnnotationDescriptor( PrimaryKeyJoinColumn.class ); + copyStringAttribute( pkAnn, subelement, "name", false ); + copyStringAttribute( pkAnn, subelement, "referenced-column-name", false ); + copyStringAttribute( pkAnn, subelement, "column-definition", false ); + pkJoinColumns[index++] = AnnotationFactory.create( pkAnn ); + } + return pkJoinColumns; + } + + /** + * Copy a string attribute from an XML element to an annotation descriptor. The name of the annotation attribute is + * computed from the name of the XML attribute by {@link #getJavaAttributeNameFromXMLOne(String)}. + * + * @param annotation annotation descriptor where to copy to the attribute. + * @param element XML element from where to copy the attribute. + * @param attributeName name of the XML attribute to copy. + * @param mandatory whether the attribute is mandatory. + */ + private static void copyStringAttribute( + final AnnotationDescriptor annotation, final Element element, + final String attributeName, final boolean mandatory) { + copyStringAttribute( + annotation, + element, + getJavaAttributeNameFromXMLOne( attributeName ), + attributeName, + mandatory + ); + } + + /** + * Copy a string attribute from an XML element to an annotation descriptor. The name of the annotation attribute is + * explicitly given. + * + * @param annotation annotation where to copy to the attribute. + * @param element XML element from where to copy the attribute. + * @param annotationAttributeName name of the annotation attribute where to copy. + * @param attributeName name of the XML attribute to copy. + * @param mandatory whether the attribute is mandatory. + */ + private static void copyStringAttribute( + final AnnotationDescriptor annotation, final Element element, + final String annotationAttributeName, final String attributeName, boolean mandatory) { + String attribute = element.attributeValue( attributeName ); + if ( attribute != null ) { + annotation.setValue( annotationAttributeName, attribute ); + } + else { + if ( mandatory ) { + throw new AnnotationException( + element.getName() + "." + attributeName + " is mandatory in XML overriding. " + SCHEMA_VALIDATION + ); + } + } + } + + private static void copyIntegerAttribute(AnnotationDescriptor annotation, Element element, String attributeName) { + String attribute = element.attributeValue( attributeName ); + if ( attribute != null ) { + String annotationAttributeName = getJavaAttributeNameFromXMLOne( attributeName ); + annotation.setValue( annotationAttributeName, attribute ); + try { + int length = Integer.parseInt( attribute ); + annotation.setValue( annotationAttributeName, length ); + } + catch ( NumberFormatException e ) { + throw new AnnotationException( + element.getPath() + attributeName + " not parseable: " + attribute + " (" + SCHEMA_VALIDATION + ")" + ); + } + } + } + + private static String getJavaAttributeNameFromXMLOne(String attributeName) { + StringBuilder annotationAttributeName = new StringBuilder( attributeName ); + int index = annotationAttributeName.indexOf( WORD_SEPARATOR ); + while ( index != -1 ) { + annotationAttributeName.deleteCharAt( index ); + annotationAttributeName.setCharAt( + index, Character.toUpperCase( annotationAttributeName.charAt( index ) ) + ); + index = annotationAttributeName.indexOf( WORD_SEPARATOR ); + } + return annotationAttributeName.toString(); + } + + private static void copyStringElement(Element element, AnnotationDescriptor ad, String annotationAttribute) { + String discr = element.getTextTrim(); + ad.setValue( annotationAttribute, discr ); + } + + private static void copyBooleanAttribute(AnnotationDescriptor descriptor, Element element, String attribute) { + String attributeValue = element.attributeValue( attribute ); + if ( StringHelper.isNotEmpty( attributeValue ) ) { + String javaAttribute = getJavaAttributeNameFromXMLOne( attribute ); + descriptor.setValue( javaAttribute, Boolean.parseBoolean( attributeValue ) ); + } + } + + private T getPhysicalAnnotation(Class annotationType) { + return element.getAnnotation( annotationType ); + } + + private boolean isPhysicalAnnotationPresent(Class annotationType) { + return element.isAnnotationPresent( annotationType ); + } + + private Annotation[] getPhysicalAnnotations() { + return element.getAnnotations(); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenMetadataProvider.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenMetadataProvider.java new file mode 100644 index 000000000000..6991140d35f1 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenMetadataProvider.java @@ -0,0 +1,230 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.cfg.annotations.reflection.internal; + +import java.lang.reflect.AnnotatedElement; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.persistence.EntityListeners; +import javax.persistence.NamedNativeQuery; +import javax.persistence.NamedQuery; +import javax.persistence.NamedStoredProcedureQuery; +import javax.persistence.SequenceGenerator; +import javax.persistence.SqlResultSetMapping; +import javax.persistence.TableGenerator; + +import org.hibernate.annotations.common.reflection.AnnotationReader; +import org.hibernate.annotations.common.reflection.MetadataProvider; +import org.hibernate.annotations.common.reflection.java.JavaMetadataProvider; +import org.hibernate.boot.internal.ClassLoaderAccessImpl; +import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; +import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; +import org.hibernate.boot.spi.BootstrapContext; +import org.hibernate.boot.spi.ClassLoaderAccess; +import org.hibernate.boot.spi.ClassLoaderAccessDelegateImpl; +import org.hibernate.boot.spi.MetadataBuildingOptions; + +import org.dom4j.Element; + +/** + * MetadataProvider aware of the JPA Deployment descriptor (orm.xml, ...). + * + * @author Emmanuel Bernard + */ +@SuppressWarnings("unchecked") +public final class JPAXMLOverriddenMetadataProvider implements MetadataProvider { + + private static final MetadataProvider STATELESS_BASE_DELEGATE = new JavaMetadataProvider(); + + private final ClassLoaderAccess classLoaderAccess; + private final XMLContext xmlContext; + + /** + * We allow fully disabling XML sources so to improve the efficiency of + * the boot process for those not using it. + */ + private final boolean xmlMappingEnabled; + + private Map defaults; + private Map cache; + + /** + * @deprecated Use {@link JPAXMLOverriddenMetadataProvider#JPAXMLOverriddenMetadataProvider(BootstrapContext)} instead. + */ + @Deprecated + public JPAXMLOverriddenMetadataProvider(final MetadataBuildingOptions metadataBuildingOptions) { + this( new ClassLoaderAccessDelegateImpl() { + ClassLoaderAccess delegate; + + @Override + protected ClassLoaderAccess getDelegate() { + if ( delegate == null ) { + delegate = new ClassLoaderAccessImpl( + metadataBuildingOptions.getTempClassLoader(), + metadataBuildingOptions.getServiceRegistry().getService( ClassLoaderService.class ) + ); + } + return delegate; + } + }, + metadataBuildingOptions.isXmlMappingEnabled() ); + } + + public JPAXMLOverriddenMetadataProvider(BootstrapContext bootstrapContext) { + this( bootstrapContext.getClassLoaderAccess(), + bootstrapContext.getMetadataBuildingOptions().isXmlMappingEnabled() ); + } + + JPAXMLOverriddenMetadataProvider(ClassLoaderAccess classLoaderAccess, boolean xmlMetadataEnabled) { + this.classLoaderAccess = classLoaderAccess; + this.xmlContext = new XMLContext( classLoaderAccess ); + this.xmlMappingEnabled = xmlMetadataEnabled; + } + + //all of the above can be safely rebuilt from XMLContext: only XMLContext this object is serialized + @Override + public AnnotationReader getAnnotationReader(AnnotatedElement annotatedElement) { + if ( cache == null ) { + cache = new HashMap<>(50 ); + } + AnnotationReader reader = cache.get( annotatedElement ); + if (reader == null) { + if ( xmlContext.hasContext() ) { + reader = new JPAXMLOverriddenAnnotationReader( annotatedElement, xmlContext, classLoaderAccess ); + } + else { + reader = STATELESS_BASE_DELEGATE.getAnnotationReader( annotatedElement ); + } + cache.put( annotatedElement, reader ); + } + return reader; + } + + // @Override + // FIXME this method was introduced in HCANN 5.1.1: we can't mark it as @Override yet, + // but it's expected to be invoked when we're running with the right HCANN version. + public void reset() { + //It's better to remove the HashMap, as it could grow rather large: + //when doing a clear() the internal buckets array is not scaled down. + this.cache = null; + } + + @Override + public Map getDefaults() { + if ( xmlMappingEnabled == false ) { + return Collections.emptyMap(); + } + else { + if ( defaults == null ) { + defaults = new HashMap<>(); + XMLContext.Default xmlDefaults = xmlContext.getDefault( null ); + + defaults.put( "schema", xmlDefaults.getSchema() ); + defaults.put( "catalog", xmlDefaults.getCatalog() ); + defaults.put( "delimited-identifier", xmlDefaults.getDelimitedIdentifier() ); + defaults.put( "cascade-persist", xmlDefaults.getCascadePersist() ); + List entityListeners = new ArrayList(); + for ( String className : xmlContext.getDefaultEntityListeners() ) { + try { + entityListeners.add( classLoaderAccess.classForName( className ) ); + } + catch ( ClassLoadingException e ) { + throw new IllegalStateException( "Default entity listener class not found: " + className ); + } + } + defaults.put( EntityListeners.class, entityListeners ); + for ( Element element : xmlContext.getAllDocuments() ) { + @SuppressWarnings( "unchecked" ) + List elements = element.elements( "sequence-generator" ); + List sequenceGenerators = ( List ) defaults.get( SequenceGenerator.class ); + if ( sequenceGenerators == null ) { + sequenceGenerators = new ArrayList<>(); + defaults.put( SequenceGenerator.class, sequenceGenerators ); + } + for ( Element subelement : elements ) { + sequenceGenerators.add( JPAXMLOverriddenAnnotationReader.buildSequenceGeneratorAnnotation( subelement ) ); + } + + elements = element.elements( "table-generator" ); + List tableGenerators = ( List ) defaults.get( TableGenerator.class ); + if ( tableGenerators == null ) { + tableGenerators = new ArrayList<>(); + defaults.put( TableGenerator.class, tableGenerators ); + } + for ( Element subelement : elements ) { + tableGenerators.add( + JPAXMLOverriddenAnnotationReader.buildTableGeneratorAnnotation( + subelement, xmlDefaults + ) + ); + } + + List namedQueries = ( List ) defaults.get( NamedQuery.class ); + if ( namedQueries == null ) { + namedQueries = new ArrayList<>(); + defaults.put( NamedQuery.class, namedQueries ); + } + List currentNamedQueries = JPAXMLOverriddenAnnotationReader.buildNamedQueries( + element, + false, + xmlDefaults, + classLoaderAccess + ); + namedQueries.addAll( currentNamedQueries ); + + List namedNativeQueries = ( List ) defaults.get( NamedNativeQuery.class ); + if ( namedNativeQueries == null ) { + namedNativeQueries = new ArrayList<>(); + defaults.put( NamedNativeQuery.class, namedNativeQueries ); + } + List currentNamedNativeQueries = JPAXMLOverriddenAnnotationReader.buildNamedQueries( + element, + true, + xmlDefaults, + classLoaderAccess + ); + namedNativeQueries.addAll( currentNamedNativeQueries ); + + List sqlResultSetMappings = ( List ) defaults.get( + SqlResultSetMapping.class + ); + if ( sqlResultSetMappings == null ) { + sqlResultSetMappings = new ArrayList<>(); + defaults.put( SqlResultSetMapping.class, sqlResultSetMappings ); + } + List currentSqlResultSetMappings = JPAXMLOverriddenAnnotationReader.buildSqlResultsetMappings( + element, + xmlDefaults, + classLoaderAccess + ); + sqlResultSetMappings.addAll( currentSqlResultSetMappings ); + + List namedStoredProcedureQueries = (List)defaults.get( NamedStoredProcedureQuery.class ); + if(namedStoredProcedureQueries==null){ + namedStoredProcedureQueries = new ArrayList<>( ); + defaults.put( NamedStoredProcedureQuery.class, namedStoredProcedureQueries ); + } + List currentNamedStoredProcedureQueries = JPAXMLOverriddenAnnotationReader + .buildNamedStoreProcedureQueries( + element, + xmlDefaults, + classLoaderAccess + ); + namedStoredProcedureQueries.addAll( currentNamedStoredProcedureQueries ); + } + } + return defaults; + } + } + + public XMLContext getXMLContext() { + return xmlContext; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/XMLContext.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/XMLContext.java new file mode 100644 index 000000000000..9dc7cdc537dd --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/XMLContext.java @@ -0,0 +1,359 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.cfg.annotations.reflection.internal; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.persistence.AccessType; +import javax.persistence.AttributeConverter; + +import org.hibernate.AnnotationException; +import org.hibernate.boot.AttributeConverterInfo; +import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; +import org.hibernate.boot.spi.BootstrapContext; +import org.hibernate.boot.spi.ClassLoaderAccess; +import org.hibernate.cfg.AttributeConverterDefinition; +import org.hibernate.cfg.annotations.reflection.AttributeConverterDefinitionCollector; +import org.hibernate.internal.CoreLogging; +import org.hibernate.internal.CoreMessageLogger; +import org.hibernate.internal.util.StringHelper; + +import org.dom4j.Document; +import org.dom4j.Element; + +/** + * A helper for consuming orm.xml mappings. + * + * @author Emmanuel Bernard + * @author Brett Meyer + */ +public class XMLContext implements Serializable { + private static final CoreMessageLogger LOG = CoreLogging.messageLogger( XMLContext.class ); + + private final ClassLoaderAccess classLoaderAccess; + + private Default globalDefaults; + private Map classOverriding = new HashMap<>(); + private Map defaultsOverriding = new HashMap<>(); + private List defaultElements = new ArrayList<>(); + private List defaultEntityListeners = new ArrayList<>(); + private boolean hasContext = false; + + /** + * @deprecated Use {@link XMLContext#XMLContext(BootstrapContext)} instead. + */ + @Deprecated + public XMLContext(ClassLoaderAccess classLoaderAccess) { + this.classLoaderAccess = classLoaderAccess; + } + + public XMLContext(BootstrapContext bootstrapContext) { + this.classLoaderAccess = bootstrapContext.getClassLoaderAccess(); + } + + /** + * @param doc The xml document to add + * @return Add an xml document to this context and return the list of added class names. + */ + @SuppressWarnings( "unchecked" ) + public List addDocument(Document doc) { + hasContext = true; + List addedClasses = new ArrayList<>(); + Element root = doc.getRootElement(); + //global defaults + Element metadata = root.element( "persistence-unit-metadata" ); + if ( metadata != null ) { + if ( globalDefaults == null ) { + globalDefaults = new Default(); + globalDefaults.setMetadataComplete( + metadata.element( "xml-mapping-metadata-complete" ) != null ? + Boolean.TRUE : + null + ); + Element defaultElement = metadata.element( "persistence-unit-defaults" ); + if ( defaultElement != null ) { + Element unitElement = defaultElement.element( "schema" ); + globalDefaults.setSchema( unitElement != null ? unitElement.getTextTrim() : null ); + unitElement = defaultElement.element( "catalog" ); + globalDefaults.setCatalog( unitElement != null ? unitElement.getTextTrim() : null ); + unitElement = defaultElement.element( "access" ); + setAccess( unitElement, globalDefaults ); + unitElement = defaultElement.element( "cascade-persist" ); + globalDefaults.setCascadePersist( unitElement != null ? Boolean.TRUE : null ); + unitElement = defaultElement.element( "delimited-identifiers" ); + globalDefaults.setDelimitedIdentifiers( unitElement != null ? Boolean.TRUE : null ); + defaultEntityListeners.addAll( addEntityListenerClasses( defaultElement, null, addedClasses ) ); + } + } + else { + LOG.duplicateMetadata(); + } + } + + //entity mapping default + Default entityMappingDefault = new Default(); + Element unitElement = root.element( "package" ); + String packageName = unitElement != null ? unitElement.getTextTrim() : null; + entityMappingDefault.setPackageName( packageName ); + unitElement = root.element( "schema" ); + entityMappingDefault.setSchema( unitElement != null ? unitElement.getTextTrim() : null ); + unitElement = root.element( "catalog" ); + entityMappingDefault.setCatalog( unitElement != null ? unitElement.getTextTrim() : null ); + unitElement = root.element( "access" ); + setAccess( unitElement, entityMappingDefault ); + defaultElements.add( root ); + + setLocalAttributeConverterDefinitions( root.elements( "converter" ) ); + + List entities = root.elements( "entity" ); + addClass( entities, packageName, entityMappingDefault, addedClasses ); + + entities = root.elements( "mapped-superclass" ); + addClass( entities, packageName, entityMappingDefault, addedClasses ); + + entities = root.elements( "embeddable" ); + addClass( entities, packageName, entityMappingDefault, addedClasses ); + return addedClasses; + } + + private void setAccess(Element unitElement, Default defaultType) { + if ( unitElement != null ) { + String access = unitElement.getTextTrim(); + setAccess( access, defaultType ); + } + } + + private void setAccess( String access, Default defaultType) { + AccessType type; + if ( access != null ) { + try { + type = AccessType.valueOf( access ); + } + catch ( IllegalArgumentException e ) { + throw new AnnotationException( "Invalid access type " + access + " (check your xml configuration)" ); + } + defaultType.setAccess( type ); + } + } + + private void addClass(List entities, String packageName, Default defaults, List addedClasses) { + for (Element element : entities) { + String className = buildSafeClassName( element.attributeValue( "class" ), packageName ); + if ( classOverriding.containsKey( className ) ) { + //maybe switch it to warn? + throw new IllegalStateException( "Duplicate XML entry for " + className ); + } + addedClasses.add( className ); + classOverriding.put( className, element ); + Default localDefault = new Default(); + localDefault.override( defaults ); + String metadataCompleteString = element.attributeValue( "metadata-complete" ); + if ( metadataCompleteString != null ) { + localDefault.setMetadataComplete( Boolean.parseBoolean( metadataCompleteString ) ); + } + String access = element.attributeValue( "access" ); + setAccess( access, localDefault ); + defaultsOverriding.put( className, localDefault ); + + LOG.debugf( "Adding XML overriding information for %s", className ); + addEntityListenerClasses( element, packageName, addedClasses ); + } + } + + private List addEntityListenerClasses(Element element, String packageName, List addedClasses) { + List localAddedClasses = new ArrayList<>(); + Element listeners = element.element( "entity-listeners" ); + if ( listeners != null ) { + @SuppressWarnings( "unchecked" ) + List elements = listeners.elements( "entity-listener" ); + for (Element listener : elements) { + String listenerClassName = buildSafeClassName( listener.attributeValue( "class" ), packageName ); + if ( classOverriding.containsKey( listenerClassName ) ) { + //maybe switch it to warn? + if ( "entity-listener".equals( classOverriding.get( listenerClassName ).getName() ) ) { + LOG.duplicateListener( listenerClassName ); + continue; + } + throw new IllegalStateException("Duplicate XML entry for " + listenerClassName); + } + localAddedClasses.add( listenerClassName ); + classOverriding.put( listenerClassName, listener ); + } + } + LOG.debugf( "Adding XML overriding information for listeners: %s", localAddedClasses ); + addedClasses.addAll( localAddedClasses ); + return localAddedClasses; + } + + @SuppressWarnings("unchecked") + private void setLocalAttributeConverterDefinitions(List converterElements) { + for ( Element converterElement : converterElements ) { + final String className = converterElement.attributeValue( "class" ); + final String autoApplyAttribute = converterElement.attributeValue( "auto-apply" ); + final boolean autoApply = autoApplyAttribute != null && Boolean.parseBoolean( autoApplyAttribute ); + + try { + final Class attributeConverterClass = classLoaderAccess.classForName( + className + ); + attributeConverterInfoList.add( + new AttributeConverterDefinition( attributeConverterClass.newInstance(), autoApply ) + ); + } + catch (ClassLoadingException e) { + throw new AnnotationException( "Unable to locate specified AttributeConverter implementation class : " + className, e ); + } + catch (Exception e) { + throw new AnnotationException( "Unable to instantiate specified AttributeConverter implementation class : " + className, e ); + } + } + } + + public static String buildSafeClassName(String className, String defaultPackageName) { + if ( className.indexOf( '.' ) < 0 && StringHelper.isNotEmpty( defaultPackageName ) ) { + className = StringHelper.qualify( defaultPackageName, className ); + } + return className; + } + + public static String buildSafeClassName(String className, XMLContext.Default defaults) { + return buildSafeClassName( className, defaults.getPackageName() ); + } + + public Default getDefault(String className) { + Default xmlDefault = new Default(); + xmlDefault.override( globalDefaults ); + if ( className != null ) { + Default entityMappingOverriding = defaultsOverriding.get( className ); + xmlDefault.override( entityMappingOverriding ); + } + return xmlDefault; + } + + public Element getXMLTree(String className ) { + return classOverriding.get( className ); + } + + public List getAllDocuments() { + return defaultElements; + } + + public boolean hasContext() { + return hasContext; + } + + private List attributeConverterInfoList = new ArrayList<>(); + + public void applyDiscoveredAttributeConverters(AttributeConverterDefinitionCollector collector) { + for ( AttributeConverterInfo info : attributeConverterInfoList ) { + collector.addAttributeConverter( info ); + } + attributeConverterInfoList.clear(); + } + + public static class Default implements Serializable { + private AccessType access; + private String packageName; + private String schema; + private String catalog; + private Boolean metadataComplete; + private Boolean cascadePersist; + private Boolean delimitedIdentifier; + + public AccessType getAccess() { + return access; + } + + protected void setAccess(AccessType access) { + this.access = access; + } + + public String getCatalog() { + return catalog; + } + + protected void setCatalog(String catalog) { + this.catalog = catalog; + } + + public String getPackageName() { + return packageName; + } + + protected void setPackageName(String packageName) { + this.packageName = packageName; + } + + public String getSchema() { + return schema; + } + + protected void setSchema(String schema) { + this.schema = schema; + } + + public Boolean getMetadataComplete() { + return metadataComplete; + } + + public boolean canUseJavaAnnotations() { + return metadataComplete == null || !metadataComplete; + } + + protected void setMetadataComplete(Boolean metadataComplete) { + this.metadataComplete = metadataComplete; + } + + public Boolean getCascadePersist() { + return cascadePersist; + } + + void setCascadePersist(Boolean cascadePersist) { + this.cascadePersist = cascadePersist; + } + + public void override(Default globalDefault) { + if ( globalDefault != null ) { + if ( globalDefault.getAccess() != null ) { + access = globalDefault.getAccess(); + } + 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(); + } + if ( globalDefault.getMetadataComplete() != null ) { + metadataComplete = globalDefault.getMetadataComplete(); + } + //TODO fix that in stone if cascade-persist is set already? + if ( globalDefault.getCascadePersist() != null ) cascadePersist = globalDefault.getCascadePersist(); + } + } + + public void setDelimitedIdentifiers(Boolean delimitedIdentifier) { + this.delimitedIdentifier = delimitedIdentifier; + } + + public Boolean getDelimitedIdentifier() { + return delimitedIdentifier; + } + } + + public List getDefaultEntityListeners() { + return defaultEntityListeners; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/ElementCollectionConverterTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/ElementCollectionConverterTest.java index 2eeb459eaeab..1ee923a43e55 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/ElementCollectionConverterTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/ElementCollectionConverterTest.java @@ -6,6 +6,8 @@ */ package org.hibernate.test.annotations.reflection; +import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder; + import org.hibernate.testing.TestForIssue; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; import org.junit.Test; @@ -13,9 +15,15 @@ import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; import static org.junit.Assert.assertEquals; -@TestForIssue( jiraKey = "HHH-11924") +@TestForIssue(jiraKey = {"HHH-11924", "HHH-14529"}) public class ElementCollectionConverterTest extends BaseCoreFunctionalTestCase { + @Override + protected void prepareBootstrapRegistryBuilder(BootstrapServiceRegistryBuilder builder) { + // FIXME HHH-14529 configure the BootstrapServiceRegistry to use JAXB for orm.xml mappings + super.prepareBootstrapRegistryBuilder( builder ); + } + @Override protected Class[] getAnnotatedClasses() { return new Class[] { diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/JPAXMLOverriddenAnnotationReaderTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/JPAXMLOverriddenAnnotationReaderTest.java new file mode 100644 index 000000000000..7024aad12492 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/JPAXMLOverriddenAnnotationReaderTest.java @@ -0,0 +1,432 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.annotations.reflection; + +import org.dom4j.DocumentException; +import org.dom4j.io.SAXReader; +import org.hibernate.annotations.Columns; +import org.hibernate.cfg.EJB3DTDEntityResolver; +import org.hibernate.cfg.annotations.reflection.JPAOverriddenAnnotationReader; +import org.hibernate.cfg.annotations.reflection.internal.JPAXMLOverriddenAnnotationReader; +import org.hibernate.cfg.annotations.reflection.internal.XMLContext; +import org.hibernate.internal.util.xml.ErrorLogger; +import org.hibernate.internal.util.xml.XMLHelper; + +import org.hibernate.testing.boot.BootstrapContextImpl; +import org.hibernate.testing.junit4.BaseUnitTestCase; +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.boot.ClassLoaderServiceTestingImpl; +import org.junit.Test; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.SAXNotSupportedException; + +import javax.persistence.*; +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +import static org.junit.Assert.*; + +/** + * Tests the new {@link JPAXMLOverriddenAnnotationReader}, + * which will be replacing {@link JPAOverriddenAnnotationReader}. + * {@link JPAOverriddenAnnotationReader} is still the default implementation, + * but we want to switch to {@link JPAXMLOverriddenAnnotationReader} + * as soon as it will be practical. + * + * @see LegacyJPAOverriddenAnnotationReaderTest + * @author Emmanuel Bernard + */ +@TestForIssue(jiraKey = "HHH-14529") +public class JPAXMLOverriddenAnnotationReaderTest extends BaseUnitTestCase { + @Test + public void testMappedSuperclassAnnotations() throws Exception { + XMLContext context = buildContext( + "org/hibernate/test/annotations/reflection/metadata-complete.xml" + ); + JPAXMLOverriddenAnnotationReader reader = new JPAXMLOverriddenAnnotationReader( Organization.class, context, BootstrapContextImpl.INSTANCE ); + assertTrue( reader.isAnnotationPresent( MappedSuperclass.class ) ); + } + + @Test + public void testEntityRelatedAnnotations() throws Exception { + XMLContext context = buildContext( "org/hibernate/test/annotations/reflection/orm.xml" ); + JPAXMLOverriddenAnnotationReader reader = new JPAXMLOverriddenAnnotationReader( Administration.class, context, BootstrapContextImpl.INSTANCE ); + assertNotNull( reader.getAnnotation( Entity.class ) ); + assertEquals( + "Default value in xml entity should not override @Entity.name", "JavaAdministration", + reader.getAnnotation( Entity.class ).name() + ); + 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() ); + assertEquals( + "Proper @Table.uniqueConstraints", 2, + reader.getAnnotation( Table.class ).uniqueConstraints()[0].columnNames().length + ); + String columnName = reader.getAnnotation( Table.class ).uniqueConstraints()[0].columnNames()[0]; + assertTrue( + "Proper @Table.uniqueConstraints", "firstname".equals( columnName ) || "lastname".equals( columnName ) + ); + assertNull( "Both Java and XML used", reader.getAnnotation( SecondaryTable.class ) ); + assertNotNull( "XML does not work", reader.getAnnotation( SecondaryTables.class ) ); + SecondaryTable[] tables = reader.getAnnotation( SecondaryTables.class ).value(); + assertEquals( 1, tables.length ); + assertEquals( "admin2", tables[0].name() ); + assertEquals( "unique constraints ignored", 1, tables[0].uniqueConstraints().length ); + assertEquals( "pk join column ignored", 1, tables[0].pkJoinColumns().length ); + assertEquals( "pk join column ignored", "admin_id", tables[0].pkJoinColumns()[0].name() ); + assertNotNull( "Sequence Overriding not working", reader.getAnnotation( SequenceGenerator.class ) ); + assertEquals( + "wrong sequence name", "seqhilo", reader.getAnnotation( SequenceGenerator.class ).sequenceName() + ); + 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() ); + + reader = new JPAXMLOverriddenAnnotationReader( Match.class, context, BootstrapContextImpl.INSTANCE ); + assertNotNull( reader.getAnnotation( Table.class ) ); + assertEquals( + "Java annotation not taken into account", "matchtable", reader.getAnnotation( Table.class ).name() + ); + 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() ); + assertNotNull( "SecondaryTable swallowed", reader.getAnnotation( SecondaryTables.class ) ); + assertEquals( + "Default schema not taken into account", "myschema", + reader.getAnnotation( SecondaryTables.class ).value()[0].schema() + ); + assertNotNull( reader.getAnnotation( Inheritance.class ) ); + assertEquals( + "inheritance strategy not overriden", InheritanceType.JOINED, + reader.getAnnotation( Inheritance.class ).strategy() + ); + assertNotNull( "NamedQuery not overriden", reader.getAnnotation( NamedQueries.class ) ); + assertEquals( "No deduplication", 3, reader.getAnnotation( NamedQueries.class ).value().length ); + assertEquals( + "deduplication kept the Java version", 1, + reader.getAnnotation( NamedQueries.class ).value()[1].hints().length + ); + assertEquals( + "org.hibernate.timeout", reader.getAnnotation( NamedQueries.class ).value()[1].hints()[0].name() + ); + assertNotNull( "NamedNativeQuery not overriden", reader.getAnnotation( NamedNativeQueries.class ) ); + assertEquals( "No deduplication", 3, reader.getAnnotation( NamedNativeQueries.class ).value().length ); + assertEquals( + "deduplication kept the Java version", 1, + reader.getAnnotation( NamedNativeQueries.class ).value()[1].hints().length + ); + assertEquals( + "org.hibernate.timeout", reader.getAnnotation( NamedNativeQueries.class ).value()[1].hints()[0].name() + ); + assertNotNull( reader.getAnnotation( SqlResultSetMappings.class ) ); + assertEquals( + "competitor1Point", reader.getAnnotation( SqlResultSetMappings.class ).value()[0].columns()[0].name() + ); + assertEquals( + "competitor1Point", + reader.getAnnotation( SqlResultSetMappings.class ).value()[0].entities()[0].fields()[0].column() + ); + assertNotNull( reader.getAnnotation( ExcludeSuperclassListeners.class ) ); + assertNotNull( reader.getAnnotation( ExcludeDefaultListeners.class ) ); + + reader = new JPAXMLOverriddenAnnotationReader( Competition.class, context, BootstrapContextImpl.INSTANCE ); + assertNotNull( reader.getAnnotation( MappedSuperclass.class ) ); + + reader = new JPAXMLOverriddenAnnotationReader( TennisMatch.class, context, BootstrapContextImpl.INSTANCE ); + assertNull( "Mutualize PKJC into PKJCs", reader.getAnnotation( PrimaryKeyJoinColumn.class ) ); + assertNotNull( reader.getAnnotation( PrimaryKeyJoinColumns.class ) ); + assertEquals( + "PrimaryKeyJoinColumn overrden", "id", + reader.getAnnotation( PrimaryKeyJoinColumns.class ).value()[0].name() + ); + assertNotNull( reader.getAnnotation( AttributeOverrides.class ) ); + assertEquals( "Wrong deduplication", 3, reader.getAnnotation( AttributeOverrides.class ).value().length ); + assertEquals( + "Wrong priority (XML vs java annotations)", "fld_net", + reader.getAnnotation( AttributeOverrides.class ).value()[0].column().name() + ); + assertEquals( + "Column mapping", 2, reader.getAnnotation( AttributeOverrides.class ).value()[1].column().scale() + ); + assertEquals( + "Column mapping", true, reader.getAnnotation( AttributeOverrides.class ).value()[1].column().unique() + ); + assertNotNull( reader.getAnnotation( AssociationOverrides.class ) ); + assertEquals( "no XML processing", 1, reader.getAnnotation( AssociationOverrides.class ).value().length ); + assertEquals( + "wrong xml processing", "id", + reader.getAnnotation( AssociationOverrides.class ).value()[0].joinColumns()[0].referencedColumnName() + ); + + + reader = new JPAXMLOverriddenAnnotationReader( SocialSecurityPhysicalAccount.class, context, BootstrapContextImpl.INSTANCE ); + assertNotNull( reader.getAnnotation( IdClass.class ) ); + assertEquals( "id-class not used", SocialSecurityNumber.class, reader.getAnnotation( IdClass.class ).value() ); + assertEquals( + "discriminator-value not used", "Physical", reader.getAnnotation( DiscriminatorValue.class ).value() + ); + assertNotNull( "discriminator-column not used", reader.getAnnotation( DiscriminatorColumn.class ) ); + assertEquals( + "discriminator-column.name default value broken", "DTYPE", + reader.getAnnotation( DiscriminatorColumn.class ).name() + ); + assertEquals( + "discriminator-column.length broken", 34, reader.getAnnotation( DiscriminatorColumn.class ).length() + ); + } + + @Test + public void testEntityRelatedAnnotationsMetadataComplete() throws Exception { + XMLContext context = buildContext( + "org/hibernate/test/annotations/reflection/metadata-complete.xml" + ); + JPAXMLOverriddenAnnotationReader reader = new JPAXMLOverriddenAnnotationReader( Administration.class, context, BootstrapContextImpl.INSTANCE ); + assertNotNull( reader.getAnnotation( Entity.class ) ); + 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() ); + + reader = new JPAXMLOverriddenAnnotationReader( Match.class, context, BootstrapContextImpl.INSTANCE ); + 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() ); + assertNull( "Ignore Java annotation", reader.getAnnotation( SecondaryTable.class ) ); + assertNull( "Ignore Java annotation", reader.getAnnotation( SecondaryTables.class ) ); + assertNull( "Ignore Java annotation", reader.getAnnotation( Inheritance.class ) ); + assertNull( reader.getAnnotation( NamedQueries.class ) ); + assertNull( reader.getAnnotation( NamedNativeQueries.class ) ); + + reader = new JPAXMLOverriddenAnnotationReader( TennisMatch.class, context, BootstrapContextImpl.INSTANCE ); + assertNull( reader.getAnnotation( PrimaryKeyJoinColumn.class ) ); + assertNull( reader.getAnnotation( PrimaryKeyJoinColumns.class ) ); + + reader = new JPAXMLOverriddenAnnotationReader( Competition.class, context, BootstrapContextImpl.INSTANCE ); + assertNull( reader.getAnnotation( MappedSuperclass.class ) ); + + reader = new JPAXMLOverriddenAnnotationReader( SocialSecurityMoralAccount.class, context, BootstrapContextImpl.INSTANCE ); + assertNull( reader.getAnnotation( IdClass.class ) ); + assertNull( reader.getAnnotation( DiscriminatorValue.class ) ); + assertNull( reader.getAnnotation( DiscriminatorColumn.class ) ); + assertNull( reader.getAnnotation( SequenceGenerator.class ) ); + assertNull( reader.getAnnotation( TableGenerator.class ) ); + } + + @Test + public void testIdRelatedAnnotations() throws Exception { + XMLContext context = buildContext( "org/hibernate/test/annotations/reflection/orm.xml" ); + Method method = Administration.class.getDeclaredMethod( "getId" ); + JPAXMLOverriddenAnnotationReader reader = new JPAXMLOverriddenAnnotationReader( method, context, BootstrapContextImpl.INSTANCE ); + assertNull( reader.getAnnotation( Id.class ) ); + assertNull( reader.getAnnotation( Column.class ) ); + Field field = Administration.class.getDeclaredField( "id" ); + reader = new JPAXMLOverriddenAnnotationReader( field, context, BootstrapContextImpl.INSTANCE ); + assertNotNull( reader.getAnnotation( Id.class ) ); + assertNotNull( reader.getAnnotation( GeneratedValue.class ) ); + assertEquals( GenerationType.SEQUENCE, reader.getAnnotation( GeneratedValue.class ).strategy() ); + assertEquals( "generator", reader.getAnnotation( GeneratedValue.class ).generator() ); + assertNotNull( reader.getAnnotation( SequenceGenerator.class ) ); + assertEquals( "seq", reader.getAnnotation( SequenceGenerator.class ).sequenceName() ); + assertNotNull( reader.getAnnotation( Columns.class ) ); + assertEquals( 1, reader.getAnnotation( Columns.class ).columns().length ); + assertEquals( "fld_id", reader.getAnnotation( Columns.class ).columns()[0].name() ); + assertNotNull( reader.getAnnotation( Temporal.class ) ); + assertEquals( TemporalType.DATE, reader.getAnnotation( Temporal.class ).value() ); + + context = buildContext( + "org/hibernate/test/annotations/reflection/metadata-complete.xml" + ); + method = Administration.class.getDeclaredMethod( "getId" ); + reader = new JPAXMLOverriddenAnnotationReader( method, context, BootstrapContextImpl.INSTANCE ); + assertNotNull( + "Default access type when not defined in metadata complete should be property", + reader.getAnnotation( Id.class ) + ); + field = Administration.class.getDeclaredField( "id" ); + reader = new JPAXMLOverriddenAnnotationReader( field, context, BootstrapContextImpl.INSTANCE ); + assertNull( + "Default access type when not defined in metadata complete should be property", + reader.getAnnotation( Id.class ) + ); + + method = BusTrip.class.getDeclaredMethod( "getId" ); + reader = new JPAXMLOverriddenAnnotationReader( method, context, BootstrapContextImpl.INSTANCE ); + assertNull( reader.getAnnotation( EmbeddedId.class ) ); + field = BusTrip.class.getDeclaredField( "id" ); + reader = new JPAXMLOverriddenAnnotationReader( field, context, BootstrapContextImpl.INSTANCE ); + assertNotNull( reader.getAnnotation( EmbeddedId.class ) ); + assertNotNull( reader.getAnnotation( AttributeOverrides.class ) ); + assertEquals( 1, reader.getAnnotation( AttributeOverrides.class ).value().length ); + } + + @Test + public void testBasicRelatedAnnotations() throws Exception { + XMLContext context = buildContext( + "org/hibernate/test/annotations/reflection/metadata-complete.xml" + ); + Field field = BusTrip.class.getDeclaredField( "status" ); + JPAXMLOverriddenAnnotationReader reader = new JPAXMLOverriddenAnnotationReader( field, context, BootstrapContextImpl.INSTANCE ); + assertNotNull( reader.getAnnotation( Enumerated.class ) ); + assertEquals( EnumType.STRING, reader.getAnnotation( Enumerated.class ).value() ); + assertEquals( false, reader.getAnnotation( Basic.class ).optional() ); + field = BusTrip.class.getDeclaredField( "serial" ); + reader = new JPAXMLOverriddenAnnotationReader( field, context, BootstrapContextImpl.INSTANCE ); + assertNotNull( reader.getAnnotation( Lob.class ) ); + assertEquals( "serialbytes", reader.getAnnotation( Columns.class ).columns()[0].name() ); + field = BusTrip.class.getDeclaredField( "terminusTime" ); + reader = new JPAXMLOverriddenAnnotationReader( field, context, BootstrapContextImpl.INSTANCE ); + assertNotNull( reader.getAnnotation( Temporal.class ) ); + assertEquals( TemporalType.TIMESTAMP, reader.getAnnotation( Temporal.class ).value() ); + assertEquals( FetchType.LAZY, reader.getAnnotation( Basic.class ).fetch() ); + + field = BusTripPk.class.getDeclaredField( "busDriver" ); + reader = new JPAXMLOverriddenAnnotationReader( field, context, BootstrapContextImpl.INSTANCE ); + assertNotNull( reader.isAnnotationPresent( Basic.class ) ); + } + + @Test + public void testVersionRelatedAnnotations() throws Exception { + XMLContext context = buildContext( "org/hibernate/test/annotations/reflection/orm.xml" ); + Method method = Administration.class.getDeclaredMethod( "getVersion" ); + JPAXMLOverriddenAnnotationReader reader = new JPAXMLOverriddenAnnotationReader( method, context, BootstrapContextImpl.INSTANCE ); + assertNotNull( reader.getAnnotation( Version.class ) ); + + Field field = Match.class.getDeclaredField( "version" ); + assertNotNull( reader.getAnnotation( Version.class ) ); + } + + @Test + public void testTransientAndEmbeddedRelatedAnnotations() throws Exception { + XMLContext context = buildContext( "org/hibernate/test/annotations/reflection/orm.xml" ); + + Field field = Administration.class.getDeclaredField( "transientField" ); + JPAXMLOverriddenAnnotationReader reader = new JPAXMLOverriddenAnnotationReader( field, context, BootstrapContextImpl.INSTANCE ); + assertNotNull( reader.getAnnotation( Transient.class ) ); + assertNull( reader.getAnnotation( Basic.class ) ); + + field = Match.class.getDeclaredField( "playerASSN" ); + reader = new JPAXMLOverriddenAnnotationReader( field, context, BootstrapContextImpl.INSTANCE ); + assertNotNull( reader.getAnnotation( Embedded.class ) ); + } + + @Test + public void testAssociationRelatedAnnotations() throws Exception { + XMLContext context = buildContext( "org/hibernate/test/annotations/reflection/orm.xml" ); + + Field field = Administration.class.getDeclaredField( "defaultBusTrip" ); + JPAXMLOverriddenAnnotationReader reader = new JPAXMLOverriddenAnnotationReader( field, context, BootstrapContextImpl.INSTANCE ); + assertNotNull( reader.getAnnotation( OneToOne.class ) ); + assertNull( reader.getAnnotation( JoinColumns.class ) ); + assertNotNull( reader.getAnnotation( PrimaryKeyJoinColumns.class ) ); + assertEquals( "pk", reader.getAnnotation( PrimaryKeyJoinColumns.class ).value()[0].name() ); + assertEquals( 5, reader.getAnnotation( OneToOne.class ).cascade().length ); + assertEquals( FetchType.LAZY, reader.getAnnotation( OneToOne.class ).fetch() ); + assertEquals( "test", reader.getAnnotation( OneToOne.class ).mappedBy() ); + + context = buildContext( + "org/hibernate/test/annotations/reflection/metadata-complete.xml" + ); + field = BusTrip.class.getDeclaredField( "players" ); + reader = new JPAXMLOverriddenAnnotationReader( field, context, BootstrapContextImpl.INSTANCE ); + assertNotNull( reader.getAnnotation( OneToMany.class ) ); + assertNotNull( reader.getAnnotation( JoinColumns.class ) ); + assertEquals( 2, reader.getAnnotation( JoinColumns.class ).value().length ); + assertEquals( "driver", reader.getAnnotation( JoinColumns.class ).value()[0].name() ); + assertNotNull( reader.getAnnotation( MapKey.class ) ); + assertEquals( "name", reader.getAnnotation( MapKey.class ).name() ); + + field = BusTrip.class.getDeclaredField( "roads" ); + reader = new JPAXMLOverriddenAnnotationReader( field, context, BootstrapContextImpl.INSTANCE ); + assertNotNull( reader.getAnnotation( ManyToMany.class ) ); + assertNotNull( reader.getAnnotation( JoinTable.class ) ); + assertEquals( "bus_road", reader.getAnnotation( JoinTable.class ).name() ); + assertEquals( 2, reader.getAnnotation( JoinTable.class ).joinColumns().length ); + assertEquals( 1, reader.getAnnotation( JoinTable.class ).inverseJoinColumns().length ); + assertEquals( 2, reader.getAnnotation( JoinTable.class ).uniqueConstraints()[0].columnNames().length ); + assertNotNull( reader.getAnnotation( OrderBy.class ) ); + assertEquals( "maxSpeed", reader.getAnnotation( OrderBy.class ).value() ); + } + + @Test + @TestForIssue(jiraKey = "HHH-11924") + public void testElementCollectionConverter() throws Exception { + XMLContext context = buildContext( "org/hibernate/test/annotations/reflection/orm.xml" ); + + Field field = Company.class.getDeclaredField( "organizations" ); + JPAXMLOverriddenAnnotationReader reader = new JPAXMLOverriddenAnnotationReader( field, context, BootstrapContextImpl.INSTANCE ); + assertNotNull( reader.getAnnotation( ElementCollection.class ) ); + assertNotNull( reader.getAnnotation( Converts.class ) ); + assertNotNull( reader.getAnnotation( Converts.class ).value() ); + assertTrue( reader.getAnnotation( Converts.class ).value().length == 1 ); + assertEquals(OrganizationConverter.class, reader.getAnnotation( Converts.class ).value()[0].converter()); + } + + @Test + public void testEntityListeners() throws Exception { + XMLContext context = buildContext( "org/hibernate/test/annotations/reflection/orm.xml" ); + + Method method = Administration.class.getDeclaredMethod( "calculate" ); + JPAXMLOverriddenAnnotationReader reader = new JPAXMLOverriddenAnnotationReader( method, context, BootstrapContextImpl.INSTANCE ); + assertTrue( reader.isAnnotationPresent( PrePersist.class ) ); + + reader = new JPAXMLOverriddenAnnotationReader( Administration.class, context, BootstrapContextImpl.INSTANCE ); + assertTrue( reader.isAnnotationPresent( EntityListeners.class ) ); + assertEquals( 1, reader.getAnnotation( EntityListeners.class ).value().length ); + assertEquals( LogListener.class, reader.getAnnotation( EntityListeners.class ).value()[0] ); + + method = LogListener.class.getDeclaredMethod( "noLog", Object.class ); + reader = new JPAXMLOverriddenAnnotationReader( method, context, BootstrapContextImpl.INSTANCE ); + assertTrue( reader.isAnnotationPresent( PostLoad.class ) ); + + method = LogListener.class.getDeclaredMethod( "log", Object.class ); + reader = new JPAXMLOverriddenAnnotationReader( method, context, BootstrapContextImpl.INSTANCE ); + assertTrue( reader.isAnnotationPresent( PrePersist.class ) ); + assertFalse( reader.isAnnotationPresent( PostPersist.class ) ); + + assertEquals( 1, context.getDefaultEntityListeners().size() ); + assertEquals( OtherLogListener.class.getName(), context.getDefaultEntityListeners().get( 0 ) ); + } + + private XMLContext buildContext(String ormfile) throws SAXException, DocumentException, IOException { + XMLHelper xmlHelper = new XMLHelper(); + InputStream is = ClassLoaderServiceTestingImpl.INSTANCE.locateResourceStream( ormfile ); + assertNotNull( "ORM.xml not found: " + ormfile, is ); + XMLContext context = new XMLContext( BootstrapContextImpl.INSTANCE ); + ErrorLogger errorLogger = new ErrorLogger(); + SAXReader saxReader = xmlHelper.createSAXReader( errorLogger, EJB3DTDEntityResolver.INSTANCE ); + //saxReader.setValidation( false ); + try { + saxReader.setFeature( "http://apache.org/xml/features/validation/schema", true ); + } + catch ( SAXNotSupportedException e ) { + saxReader.setValidation( false ); + } + org.dom4j.Document doc; + try { + doc = saxReader.read( new InputSource( new BufferedInputStream( is ) ) ); + } + finally { + is.close(); + } + if ( errorLogger.hasErrors() ) { + System.out.println( errorLogger.getErrors().get( 0 ) ); + } + assertFalse( errorLogger.hasErrors() ); + context.addDocument( doc ); + return context; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/LegacyElementCollectionConverterTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/LegacyElementCollectionConverterTest.java new file mode 100644 index 000000000000..70d559357b16 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/LegacyElementCollectionConverterTest.java @@ -0,0 +1,71 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.annotations.reflection; + +import org.hibernate.cfg.annotations.reflection.JPAOverriddenAnnotationReader; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.Test; + +import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; +import static org.junit.Assert.assertEquals; + +/** + * Tests the legacy {@link JPAOverriddenAnnotationReader}, + * which will be replaced with {@link org.hibernate.cfg.annotations.reflection.internal.JPAXMLOverriddenAnnotationReader}. + * {@link JPAOverriddenAnnotationReader} is still the default implementation, + * but we want to switch to {@link org.hibernate.cfg.annotations.reflection.internal.JPAXMLOverriddenAnnotationReader} + * as soon as it will be practical. + * + * @see JPAXMLOverriddenAnnotationReaderTest + * @deprecated This test will be removed in Hibernate ORM 6, along with the legacy {@link JPAOverriddenAnnotationReader}. + */ +@Deprecated +@TestForIssue( jiraKey = "HHH-11924") +public class LegacyElementCollectionConverterTest extends BaseCoreFunctionalTestCase { + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + Company.class, + }; + } + + @Override + protected String[] getXmlFiles() { + return new String[] { "org/hibernate/test/annotations/reflection/element-collection-converter-orm.xml" }; + } + + + @Test + public void testConverterIsAppliedToElementCollection() { + doInHibernate( this::sessionFactory, session -> { + Company company = new Company(); + company.setId( 1L ); + + Organization org1 = new Organization(); + org1.setOrganizationId( "ACME" ); + + company.getOrganizations().add( org1 ); + + session.persist( company ); + } ); + + doInHibernate( this::sessionFactory, session -> { + String organizationId = (String) session + .createNativeQuery( "select organizations from Company_organizations" ) + .getSingleResult(); + assertEquals( "ORG-ACME", organizationId ); + + Company company = session.find( Company.class, 1L ); + + assertEquals( 1, company.getOrganizations().size() ); + assertEquals( "ACME" , company.getOrganizations().get( 0 ).getOrganizationId()); + } ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/JPAOverriddenAnnotationReaderTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/LegacyJPAOverriddenAnnotationReaderTest.java similarity index 88% rename from hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/JPAOverriddenAnnotationReaderTest.java rename to hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/LegacyJPAOverriddenAnnotationReaderTest.java index c79a60e708d2..57561467ccea 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/JPAOverriddenAnnotationReaderTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/LegacyJPAOverriddenAnnotationReaderTest.java @@ -6,8 +6,61 @@ */ package org.hibernate.test.annotations.reflection; -import org.dom4j.DocumentException; -import org.dom4j.io.SAXReader; +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import javax.persistence.AssociationOverrides; +import javax.persistence.AttributeOverrides; +import javax.persistence.Basic; +import javax.persistence.Column; +import javax.persistence.Converts; +import javax.persistence.DiscriminatorColumn; +import javax.persistence.DiscriminatorValue; +import javax.persistence.ElementCollection; +import javax.persistence.Embedded; +import javax.persistence.EmbeddedId; +import javax.persistence.Entity; +import javax.persistence.EntityListeners; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.ExcludeDefaultListeners; +import javax.persistence.ExcludeSuperclassListeners; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.IdClass; +import javax.persistence.Inheritance; +import javax.persistence.InheritanceType; +import javax.persistence.JoinColumns; +import javax.persistence.JoinTable; +import javax.persistence.Lob; +import javax.persistence.ManyToMany; +import javax.persistence.MapKey; +import javax.persistence.MappedSuperclass; +import javax.persistence.NamedNativeQueries; +import javax.persistence.NamedQueries; +import javax.persistence.OneToMany; +import javax.persistence.OneToOne; +import javax.persistence.OrderBy; +import javax.persistence.PostLoad; +import javax.persistence.PostPersist; +import javax.persistence.PrePersist; +import javax.persistence.PrimaryKeyJoinColumn; +import javax.persistence.PrimaryKeyJoinColumns; +import javax.persistence.SecondaryTable; +import javax.persistence.SecondaryTables; +import javax.persistence.SequenceGenerator; +import javax.persistence.SqlResultSetMappings; +import javax.persistence.Table; +import javax.persistence.TableGenerator; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import javax.persistence.Transient; +import javax.persistence.Version; + import org.hibernate.annotations.Columns; import org.hibernate.cfg.EJB3DTDEntityResolver; import org.hibernate.cfg.annotations.reflection.JPAOverriddenAnnotationReader; @@ -15,28 +68,37 @@ import org.hibernate.internal.util.xml.ErrorLogger; import org.hibernate.internal.util.xml.XMLHelper; -import org.hibernate.testing.boot.BootstrapContextImpl; -import org.hibernate.testing.junit4.BaseUnitTestCase; import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.boot.BootstrapContextImpl; import org.hibernate.testing.boot.ClassLoaderServiceTestingImpl; +import org.hibernate.testing.junit4.BaseUnitTestCase; import org.junit.Test; + +import org.dom4j.DocumentException; +import org.dom4j.io.SAXReader; import org.xml.sax.InputSource; import org.xml.sax.SAXException; import org.xml.sax.SAXNotSupportedException; -import javax.persistence.*; -import java.io.BufferedInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.lang.reflect.Field; -import java.lang.reflect.Method; - -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; /** + * Tests the legacy {@link JPAOverriddenAnnotationReader}, + * which will be replaced with {@link org.hibernate.cfg.annotations.reflection.internal.JPAXMLOverriddenAnnotationReader}. + * {@link JPAOverriddenAnnotationReader} is still the default implementation, + * but we want to switch to {@link org.hibernate.cfg.annotations.reflection.internal.JPAXMLOverriddenAnnotationReader} + * as soon as it will be practical. + * + * @see JPAXMLOverriddenAnnotationReaderTest * @author Emmanuel Bernard + * @deprecated This test will be removed in Hibernate ORM 6, along with the legacy {@link JPAOverriddenAnnotationReader}. */ -public class JPAOverriddenAnnotationReaderTest extends BaseUnitTestCase { +@Deprecated +public class LegacyJPAOverriddenAnnotationReaderTest extends BaseUnitTestCase { @Test public void testMappedSuperclassAnnotations() throws Exception { XMLContext context = buildContext( diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/LegacyXMLContextTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/LegacyXMLContextTest.java new file mode 100644 index 000000000000..38ade26b4cae --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/LegacyXMLContextTest.java @@ -0,0 +1,73 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.annotations.reflection; + +import java.io.BufferedInputStream; +import java.io.IOException; +import java.io.InputStream; + +import org.hibernate.cfg.EJB3DTDEntityResolver; +import org.hibernate.cfg.annotations.reflection.XMLContext; +import org.hibernate.internal.util.xml.ErrorLogger; +import org.hibernate.internal.util.xml.XMLHelper; + +import org.hibernate.testing.boot.BootstrapContextImpl; +import org.hibernate.testing.boot.ClassLoaderServiceTestingImpl; +import org.junit.Assert; +import org.junit.Test; + +import org.dom4j.io.SAXReader; +import org.xml.sax.InputSource; +import org.xml.sax.SAXNotSupportedException; + +/** + * Tests the legacy {@link XMLContext}, + * which will be replaced with {@link org.hibernate.cfg.annotations.reflection.internal.XMLContext}. + * {@link XMLContext} is still the default implementation, + * but we want to switch to {@link org.hibernate.cfg.annotations.reflection.internal.XMLContext} + * as soon as it will be practical. + * + * @see XMLContextTest + * @author Emmanuel Bernard + * @deprecated This test will be removed in Hibernate ORM 6, along with the legacy {@link XMLContext}. + */ +public class LegacyXMLContextTest { + @Test + public void testAll() throws Exception { + final XMLHelper xmlHelper = new XMLHelper(); + final XMLContext context = new XMLContext( BootstrapContextImpl.INSTANCE ); + + InputStream is = ClassLoaderServiceTestingImpl.INSTANCE.locateResourceStream( + "org/hibernate/test/annotations/reflection/orm.xml" + ); + Assert.assertNotNull( "ORM.xml not found", is ); + + final ErrorLogger errorLogger = new ErrorLogger(); + final SAXReader saxReader = xmlHelper.createSAXReader( errorLogger, EJB3DTDEntityResolver.INSTANCE ); + + try { + saxReader.setFeature( "http://apache.org/xml/features/validation/schema", true ); + } + catch ( SAXNotSupportedException e ) { + saxReader.setValidation( false ); + } + org.dom4j.Document doc; + try { + doc = saxReader.read( new InputSource( new BufferedInputStream( is ) ) ); + } + finally { + try { + is.close(); + } + catch ( IOException ioe ) { + //log.warn( "Could not close input stream", ioe ); + } + } + Assert.assertFalse( errorLogger.hasErrors() ); + context.addDocument( doc ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/XMLContextTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/XMLContextTest.java index 235fe820e4a3..fb68e62a4604 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/XMLContextTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/XMLContextTest.java @@ -17,16 +17,24 @@ import org.xml.sax.SAXNotSupportedException; import org.hibernate.cfg.EJB3DTDEntityResolver; -import org.hibernate.cfg.annotations.reflection.XMLContext; +import org.hibernate.cfg.annotations.reflection.internal.XMLContext; import org.hibernate.internal.util.xml.ErrorLogger; import org.hibernate.internal.util.xml.XMLHelper; +import org.hibernate.testing.TestForIssue; import org.hibernate.testing.boot.BootstrapContextImpl; import org.hibernate.testing.boot.ClassLoaderServiceTestingImpl; /** + * Tests the new {@link XMLContext}, + * which will be replacing {@link org.hibernate.cfg.annotations.reflection.XMLContext}. + * {@link org.hibernate.cfg.annotations.reflection.XMLContext} is still the default implementation, + * but we want to switch to {@link XMLContext} + * as soon as it will be practical. + * * @author Emmanuel Bernard */ +@TestForIssue(jiraKey = "HHH-14529") public class XMLContextTest { @Test public void testAll() throws Exception { diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlElementCollectionTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlElementCollectionTest.java index 235b7e70a528..73d749f4f00b 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlElementCollectionTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlElementCollectionTest.java @@ -34,12 +34,14 @@ import javax.persistence.TemporalType; import javax.persistence.UniqueConstraint; +import org.hibernate.testing.TestForIssue; import org.junit.Test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +@TestForIssue(jiraKey = "HHH-14529") public class Ejb3XmlElementCollectionTest extends Ejb3XmlTestCase { @Test public void testNoChildren() throws Exception { diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlManyToManyTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlManyToManyTest.java index 01f6170000df..7f37ff436318 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlManyToManyTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlManyToManyTest.java @@ -29,12 +29,14 @@ import javax.persistence.TemporalType; import javax.persistence.UniqueConstraint; +import org.hibernate.testing.TestForIssue; import org.junit.Test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +@TestForIssue(jiraKey = "HHH-14529") public class Ejb3XmlManyToManyTest extends Ejb3XmlTestCase { @Test public void testNoChildren() throws Exception { diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlManyToOneTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlManyToOneTest.java index b0e3c43b2ad3..dfe16a7468f6 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlManyToOneTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlManyToOneTest.java @@ -18,12 +18,14 @@ import javax.persistence.MapsId; import javax.persistence.UniqueConstraint; +import org.hibernate.testing.TestForIssue; import org.junit.Test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +@TestForIssue(jiraKey = "HHH-14529") public class Ejb3XmlManyToOneTest extends Ejb3XmlTestCase { @Test public void testNoJoins() throws Exception { diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlOneToManyTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlOneToManyTest.java index bca6d21c01ac..c1eda4f9d249 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlOneToManyTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlOneToManyTest.java @@ -29,12 +29,14 @@ import javax.persistence.TemporalType; import javax.persistence.UniqueConstraint; +import org.hibernate.testing.TestForIssue; import org.junit.Test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +@TestForIssue(jiraKey = "HHH-14529") public class Ejb3XmlOneToManyTest extends Ejb3XmlTestCase { @Test public void testNoChildren() throws Exception { diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlOneToOneTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlOneToOneTest.java index fb2c0f70b151..e513889c0fc1 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlOneToOneTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlOneToOneTest.java @@ -20,12 +20,14 @@ import javax.persistence.PrimaryKeyJoinColumns; import javax.persistence.UniqueConstraint; +import org.hibernate.testing.TestForIssue; import org.junit.Test; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +@TestForIssue(jiraKey = "HHH-14529") public class Ejb3XmlOneToOneTest extends Ejb3XmlTestCase { @Test public void testNoChildren() throws Exception { diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlTest.java index 2a4964ca0c2b..89bb7873120c 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlTest.java @@ -12,6 +12,7 @@ import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.Transaction; +import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder; import org.hibernate.dialect.CockroachDB192Dialect; import org.hibernate.dialect.PostgreSQL81Dialect; import org.hibernate.dialect.PostgreSQLDialect; @@ -19,6 +20,7 @@ import org.hibernate.persister.collection.BasicCollectionPersister; import org.hibernate.testing.SkipForDialect; +import org.hibernate.testing.TestForIssue; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; import org.junit.Test; @@ -28,7 +30,15 @@ /** * @author Emmanuel Bernard */ +@TestForIssue(jiraKey = "HHH-14529") public class Ejb3XmlTest extends BaseCoreFunctionalTestCase { + + @Override + protected void prepareBootstrapRegistryBuilder(BootstrapServiceRegistryBuilder builder) { + // FIXME HHH-14529 configure the BootstrapServiceRegistry to use JAXB for orm.xml mappings + super.prepareBootstrapRegistryBuilder( builder ); + } + @Test @SkipForDialect(value = {PostgreSQL81Dialect.class, PostgreSQLDialect.class, CockroachDB192Dialect.class}, comment = "postgresql jdbc driver does not implement the setQueryTimeout method") diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlTestCase.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlTestCase.java index 3c96ba4df1cb..c4ebbed1d651 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlTestCase.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlTestCase.java @@ -13,8 +13,8 @@ import org.dom4j.Document; import org.dom4j.io.SAXReader; -import org.hibernate.cfg.annotations.reflection.JPAOverriddenAnnotationReader; -import org.hibernate.cfg.annotations.reflection.XMLContext; +import org.hibernate.cfg.annotations.reflection.internal.JPAXMLOverriddenAnnotationReader; +import org.hibernate.cfg.annotations.reflection.internal.XMLContext; import org.hibernate.testing.boot.BootstrapContextImpl; import org.hibernate.testing.junit4.BaseUnitTestCase; @@ -28,8 +28,8 @@ * XML to JPA annotations. The configuration is built within each test, and no * database is used. Thus, no schema generation or cleanup will be performed. */ -abstract class Ejb3XmlTestCase extends BaseUnitTestCase { - protected JPAOverriddenAnnotationReader reader; +public abstract class Ejb3XmlTestCase extends BaseUnitTestCase { + protected JPAXMLOverriddenAnnotationReader reader; protected void assertAnnotationPresent(Class annotationType) { assertTrue( @@ -45,11 +45,11 @@ protected void assertAnnotationNotPresent(Class annotation ); } - protected JPAOverriddenAnnotationReader getReader(Class entityClass, String fieldName, String ormResourceName) + protected JPAXMLOverriddenAnnotationReader getReader(Class entityClass, String fieldName, String ormResourceName) throws Exception { AnnotatedElement el = getAnnotatedElement( entityClass, fieldName ); XMLContext xmlContext = getContext( ormResourceName ); - return new JPAOverriddenAnnotationReader( el, xmlContext, BootstrapContextImpl.INSTANCE ); + return new JPAXMLOverriddenAnnotationReader( el, xmlContext, BootstrapContextImpl.INSTANCE ); } protected AnnotatedElement getAnnotatedElement(Class entityClass, String fieldName) throws Exception { diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlElementCollectionTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlElementCollectionTest.java new file mode 100644 index 000000000000..7d46e662bfcd --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlElementCollectionTest.java @@ -0,0 +1,716 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.annotations.xml.ejb3; + +import javax.persistence.Access; +import javax.persistence.AccessType; +import javax.persistence.AssociationOverride; +import javax.persistence.AssociationOverrides; +import javax.persistence.AttributeOverride; +import javax.persistence.AttributeOverrides; +import javax.persistence.CollectionTable; +import javax.persistence.Column; +import javax.persistence.ElementCollection; +import javax.persistence.EnumType; +import javax.persistence.Enumerated; +import javax.persistence.FetchType; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.Lob; +import javax.persistence.MapKey; +import javax.persistence.MapKeyClass; +import javax.persistence.MapKeyColumn; +import javax.persistence.MapKeyEnumerated; +import javax.persistence.MapKeyJoinColumn; +import javax.persistence.MapKeyJoinColumns; +import javax.persistence.MapKeyTemporal; +import javax.persistence.OrderBy; +import javax.persistence.OrderColumn; +import javax.persistence.Temporal; +import javax.persistence.TemporalType; +import javax.persistence.UniqueConstraint; + +import org.hibernate.cfg.annotations.reflection.JPAOverriddenAnnotationReader; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * Equivalent to {@link org.hibernate.test.annotations.xml.ejb3.Ejb3XmlElementCollectionTest} + * for the legacy {@link JPAOverriddenAnnotationReader}. + * + * @author Emmanuel Bernard + * @deprecated This test will be removed in Hibernate ORM 6, along with the legacy {@link JPAOverriddenAnnotationReader}. + */ +@Deprecated +public class LegacyEjb3XmlElementCollectionTest extends LegacyEjb3XmlTestCase { + @Test + public void testNoChildren() throws Exception { + reader = getReader( Entity2.class, "field1", "element-collection.orm1.xml" ); + assertAnnotationPresent( ElementCollection.class ); + assertAnnotationNotPresent( OrderBy.class ); + assertAnnotationNotPresent( OrderColumn.class ); + assertAnnotationNotPresent( MapKey.class ); + assertAnnotationNotPresent( MapKeyClass.class ); + assertAnnotationNotPresent( MapKeyTemporal.class ); + assertAnnotationNotPresent( MapKeyEnumerated.class ); + assertAnnotationNotPresent( MapKeyColumn.class ); + assertAnnotationNotPresent( MapKeyJoinColumns.class ); + assertAnnotationNotPresent( MapKeyJoinColumn.class ); + assertAnnotationNotPresent( Column.class ); + assertAnnotationNotPresent( Temporal.class ); + assertAnnotationNotPresent( Enumerated.class ); + assertAnnotationNotPresent( Lob.class ); + assertAnnotationNotPresent( AttributeOverride.class ); + assertAnnotationNotPresent( AttributeOverrides.class ); + assertAnnotationNotPresent( AssociationOverride.class ); + assertAnnotationNotPresent( AssociationOverrides.class ); + assertAnnotationNotPresent( CollectionTable.class ); + assertAnnotationNotPresent( Access.class ); + ElementCollection relAnno = reader.getAnnotation( ElementCollection.class ); + assertEquals( FetchType.LAZY, relAnno.fetch() ); + assertEquals( void.class, relAnno.targetClass() ); + } + + @Test + public void testOrderBy() throws Exception { + reader = getReader( Entity2.class, "field1", "element-collection.orm2.xml" ); + assertAnnotationPresent( ElementCollection.class ); + assertAnnotationPresent( OrderBy.class ); + assertAnnotationNotPresent( OrderColumn.class ); + assertEquals( + "col1 ASC, col2 DESC", reader.getAnnotation( OrderBy.class ) + .value() + ); + } + + @Test + public void testOrderColumnNoAttributes() throws Exception { + reader = getReader( Entity2.class, "field1", "element-collection.orm3.xml" ); + assertAnnotationPresent( ElementCollection.class ); + assertAnnotationNotPresent( OrderBy.class ); + assertAnnotationPresent( OrderColumn.class ); + OrderColumn orderColumnAnno = reader.getAnnotation( OrderColumn.class ); + assertEquals( "", orderColumnAnno.columnDefinition() ); + assertEquals( "", orderColumnAnno.name() ); + assertTrue( orderColumnAnno.insertable() ); + assertTrue( orderColumnAnno.nullable() ); + assertTrue( orderColumnAnno.updatable() ); + } + + @Test + public void testOrderColumnAllAttributes() throws Exception { + reader = getReader( Entity2.class, "field1", "element-collection.orm4.xml" ); + assertAnnotationPresent( ElementCollection.class ); + assertAnnotationNotPresent( OrderBy.class ); + assertAnnotationPresent( OrderColumn.class ); + OrderColumn orderColumnAnno = reader.getAnnotation( OrderColumn.class ); + assertEquals( "int", orderColumnAnno.columnDefinition() ); + assertEquals( "col1", orderColumnAnno.name() ); + assertFalse( orderColumnAnno.insertable() ); + assertFalse( orderColumnAnno.nullable() ); + assertFalse( orderColumnAnno.updatable() ); + } + + @Test + public void testMapKeyNoAttributes() throws Exception { + reader = getReader( Entity3.class, "field1", "element-collection.orm5.xml" ); + assertAnnotationPresent( ElementCollection.class ); + assertAnnotationPresent( MapKey.class ); + assertAnnotationNotPresent( MapKeyClass.class ); + assertAnnotationNotPresent( MapKeyTemporal.class ); + assertAnnotationNotPresent( MapKeyEnumerated.class ); + assertAnnotationNotPresent( MapKeyColumn.class ); + assertAnnotationNotPresent( MapKeyJoinColumns.class ); + assertAnnotationNotPresent( MapKeyJoinColumn.class ); + assertEquals( "", reader.getAnnotation( MapKey.class ).name() ); + } + + @Test + public void testMapKeyAllAttributes() throws Exception { + reader = getReader( Entity3.class, "field1", "element-collection.orm6.xml" ); + assertAnnotationPresent( ElementCollection.class ); + assertAnnotationPresent( MapKey.class ); + assertAnnotationNotPresent( MapKeyClass.class ); + assertAnnotationNotPresent( MapKeyTemporal.class ); + assertAnnotationNotPresent( MapKeyEnumerated.class ); + assertAnnotationNotPresent( MapKeyColumn.class ); + assertAnnotationNotPresent( MapKeyJoinColumns.class ); + assertAnnotationNotPresent( MapKeyJoinColumn.class ); + assertEquals( "field2", reader.getAnnotation( MapKey.class ).name() ); + } + + @Test + public void testMapKeyClass() throws Exception { + reader = getReader( Entity3.class, "field1", "element-collection.orm7.xml" ); + assertAnnotationPresent( ElementCollection.class ); + assertAnnotationNotPresent( MapKey.class ); + assertAnnotationPresent( MapKeyClass.class ); + assertAnnotationNotPresent( MapKeyTemporal.class ); + assertAnnotationNotPresent( MapKeyEnumerated.class ); + assertAnnotationNotPresent( MapKeyColumn.class ); + assertAnnotationNotPresent( MapKeyJoinColumns.class ); + assertAnnotationNotPresent( MapKeyJoinColumn.class ); + assertEquals( + Entity2.class, reader.getAnnotation( MapKeyClass.class ) + .value() + ); + } + + @Test + public void testMapKeyTemporal() throws Exception { + reader = getReader( Entity3.class, "field1", "element-collection.orm8.xml" ); + assertAnnotationPresent( ElementCollection.class ); + assertAnnotationNotPresent( MapKey.class ); + assertAnnotationNotPresent( MapKeyClass.class ); + assertAnnotationPresent( MapKeyTemporal.class ); + assertAnnotationNotPresent( MapKeyEnumerated.class ); + assertAnnotationNotPresent( MapKeyColumn.class ); + assertAnnotationNotPresent( MapKeyJoinColumns.class ); + assertAnnotationNotPresent( MapKeyJoinColumn.class ); + assertEquals( + TemporalType.DATE, reader.getAnnotation( + MapKeyTemporal.class + ).value() + ); + } + + @Test + public void testMapKeyEnumerated() throws Exception { + reader = getReader( Entity3.class, "field1", "element-collection.orm9.xml" ); + assertAnnotationPresent( ElementCollection.class ); + assertAnnotationNotPresent( MapKey.class ); + assertAnnotationNotPresent( MapKeyClass.class ); + assertAnnotationNotPresent( MapKeyTemporal.class ); + assertAnnotationPresent( MapKeyEnumerated.class ); + assertAnnotationNotPresent( MapKeyColumn.class ); + assertAnnotationNotPresent( MapKeyJoinColumns.class ); + assertAnnotationNotPresent( MapKeyJoinColumn.class ); + assertEquals( + EnumType.STRING, reader.getAnnotation( + MapKeyEnumerated.class + ).value() + ); + } + + /** + * When there's a single map key attribute override, we still wrap it with + * an AttributeOverrides annotation. + */ + @Test + public void testSingleMapKeyAttributeOverride() throws Exception { + reader = getReader( Entity3.class, "field1", "element-collection.orm10.xml" ); + assertAnnotationPresent( ElementCollection.class ); + assertAnnotationNotPresent( MapKey.class ); + assertAnnotationNotPresent( MapKeyClass.class ); + assertAnnotationNotPresent( MapKeyTemporal.class ); + assertAnnotationNotPresent( MapKeyEnumerated.class ); + assertAnnotationNotPresent( MapKeyColumn.class ); + assertAnnotationNotPresent( MapKeyJoinColumns.class ); + assertAnnotationNotPresent( MapKeyJoinColumn.class ); + assertAnnotationNotPresent( AttributeOverride.class ); + assertAnnotationPresent( AttributeOverrides.class ); + AttributeOverrides overridesAnno = reader + .getAnnotation( AttributeOverrides.class ); + AttributeOverride[] overrides = overridesAnno.value(); + assertEquals( 1, overrides.length ); + assertEquals( "field1", overrides[0].name() ); + assertEquals( "col1", overrides[0].column().name() ); + } + + @Test + public void testMultipleMapKeyAttributeOverrides() throws Exception { + reader = getReader( Entity3.class, "field1", "element-collection.orm11.xml" ); + assertAnnotationPresent( ElementCollection.class ); + assertAnnotationNotPresent( MapKey.class ); + assertAnnotationNotPresent( MapKeyClass.class ); + assertAnnotationNotPresent( MapKeyTemporal.class ); + assertAnnotationNotPresent( MapKeyEnumerated.class ); + assertAnnotationNotPresent( MapKeyColumn.class ); + assertAnnotationNotPresent( MapKeyJoinColumns.class ); + assertAnnotationNotPresent( MapKeyJoinColumn.class ); + assertAnnotationNotPresent( AttributeOverride.class ); + assertAnnotationPresent( AttributeOverrides.class ); + AttributeOverrides overridesAnno = reader + .getAnnotation( AttributeOverrides.class ); + AttributeOverride[] overrides = overridesAnno.value(); + assertEquals( 2, overrides.length ); + assertEquals( "field1", overrides[0].name() ); + assertEquals( "", overrides[0].column().name() ); + assertFalse( overrides[0].column().unique() ); + assertTrue( overrides[0].column().nullable() ); + assertTrue( overrides[0].column().insertable() ); + assertTrue( overrides[0].column().updatable() ); + assertEquals( "", overrides[0].column().columnDefinition() ); + assertEquals( "", overrides[0].column().table() ); + assertEquals( 255, overrides[0].column().length() ); + assertEquals( 0, overrides[0].column().precision() ); + assertEquals( 0, overrides[0].column().scale() ); + assertEquals( "field2", overrides[1].name() ); + assertEquals( "col1", overrides[1].column().name() ); + assertTrue( overrides[1].column().unique() ); + assertFalse( overrides[1].column().nullable() ); + assertFalse( overrides[1].column().insertable() ); + assertFalse( overrides[1].column().updatable() ); + assertEquals( "int", overrides[1].column().columnDefinition() ); + assertEquals( "table1", overrides[1].column().table() ); + assertEquals( 50, overrides[1].column().length() ); + assertEquals( 2, overrides[1].column().precision() ); + assertEquals( 1, overrides[1].column().scale() ); + } + + @Test + public void testMapKeyColumnNoAttributes() throws Exception { + reader = getReader( Entity3.class, "field1", "element-collection.orm12.xml" ); + assertAnnotationPresent( ElementCollection.class ); + assertAnnotationNotPresent( MapKey.class ); + assertAnnotationNotPresent( MapKeyClass.class ); + assertAnnotationNotPresent( MapKeyTemporal.class ); + assertAnnotationNotPresent( MapKeyEnumerated.class ); + assertAnnotationPresent( MapKeyColumn.class ); + assertAnnotationNotPresent( MapKeyJoinColumns.class ); + assertAnnotationNotPresent( MapKeyJoinColumn.class ); + MapKeyColumn keyColAnno = reader.getAnnotation( MapKeyColumn.class ); + assertEquals( "", keyColAnno.columnDefinition() ); + assertEquals( "", keyColAnno.name() ); + assertEquals( "", keyColAnno.table() ); + assertFalse( keyColAnno.nullable() ); + assertTrue( keyColAnno.insertable() ); + assertFalse( keyColAnno.unique() ); + assertTrue( keyColAnno.updatable() ); + assertEquals( 255, keyColAnno.length() ); + assertEquals( 0, keyColAnno.precision() ); + assertEquals( 0, keyColAnno.scale() ); + } + + @Test + public void testMapKeyColumnAllAttributes() throws Exception { + reader = getReader( Entity3.class, "field1", "element-collection.orm13.xml" ); + assertAnnotationPresent( ElementCollection.class ); + assertAnnotationNotPresent( MapKey.class ); + assertAnnotationNotPresent( MapKeyClass.class ); + assertAnnotationNotPresent( MapKeyTemporal.class ); + assertAnnotationNotPresent( MapKeyEnumerated.class ); + assertAnnotationPresent( MapKeyColumn.class ); + assertAnnotationNotPresent( MapKeyJoinColumns.class ); + assertAnnotationNotPresent( MapKeyJoinColumn.class ); + MapKeyColumn keyColAnno = reader.getAnnotation( MapKeyColumn.class ); + assertEquals( "int", keyColAnno.columnDefinition() ); + assertEquals( "col1", keyColAnno.name() ); + assertEquals( "table1", keyColAnno.table() ); + assertTrue( keyColAnno.nullable() ); + assertFalse( keyColAnno.insertable() ); + assertTrue( keyColAnno.unique() ); + assertFalse( keyColAnno.updatable() ); + assertEquals( 50, keyColAnno.length() ); + assertEquals( 2, keyColAnno.precision() ); + assertEquals( 1, keyColAnno.scale() ); + } + + /** + * When there's a single map key join column, we still wrap it with a + * MapKeyJoinColumns annotation. + */ + @Test + public void testSingleMapKeyJoinColumn() throws Exception { + reader = getReader( Entity3.class, "field1", "element-collection.orm14.xml" ); + assertAnnotationPresent( ElementCollection.class ); + assertAnnotationNotPresent( MapKey.class ); + assertAnnotationNotPresent( MapKeyClass.class ); + assertAnnotationNotPresent( MapKeyTemporal.class ); + assertAnnotationNotPresent( MapKeyEnumerated.class ); + assertAnnotationNotPresent( MapKeyColumn.class ); + assertAnnotationPresent( MapKeyJoinColumns.class ); + assertAnnotationNotPresent( MapKeyJoinColumn.class ); + MapKeyJoinColumns joinColumnsAnno = reader + .getAnnotation( MapKeyJoinColumns.class ); + MapKeyJoinColumn[] joinColumns = joinColumnsAnno.value(); + assertEquals( 1, joinColumns.length ); + assertEquals( "col1", joinColumns[0].name() ); + } + + @Test + public void testMultipleMapKeyJoinColumns() throws Exception { + reader = getReader( Entity3.class, "field1", "element-collection.orm15.xml" ); + assertAnnotationPresent( ElementCollection.class ); + assertAnnotationNotPresent( MapKey.class ); + assertAnnotationNotPresent( MapKeyClass.class ); + assertAnnotationNotPresent( MapKeyTemporal.class ); + assertAnnotationNotPresent( MapKeyEnumerated.class ); + assertAnnotationNotPresent( MapKeyColumn.class ); + assertAnnotationPresent( MapKeyJoinColumns.class ); + assertAnnotationNotPresent( MapKeyJoinColumn.class ); + MapKeyJoinColumns joinColumnsAnno = reader + .getAnnotation( MapKeyJoinColumns.class ); + MapKeyJoinColumn[] joinColumns = joinColumnsAnno.value(); + assertEquals( 2, joinColumns.length ); + assertEquals( "", joinColumns[0].name() ); + assertEquals( "", joinColumns[0].referencedColumnName() ); + assertFalse( joinColumns[0].unique() ); + assertFalse( joinColumns[0].nullable() ); + assertTrue( joinColumns[0].insertable() ); + assertTrue( joinColumns[0].updatable() ); + assertEquals( "", joinColumns[0].columnDefinition() ); + assertEquals( "", joinColumns[0].table() ); + assertEquals( "col1", joinColumns[1].name() ); + assertEquals( "col2", joinColumns[1].referencedColumnName() ); + assertTrue( joinColumns[1].unique() ); + assertTrue( joinColumns[1].nullable() ); + assertFalse( joinColumns[1].insertable() ); + assertFalse( joinColumns[1].updatable() ); + assertEquals( "int", joinColumns[1].columnDefinition() ); + assertEquals( "table1", joinColumns[1].table() ); + } + + @Test + public void testColumnNoAttributes() throws Exception { + reader = getReader( Entity3.class, "field1", "element-collection.orm16.xml" ); + assertAnnotationPresent( ElementCollection.class ); + assertAnnotationPresent( Column.class ); + Column column = reader.getAnnotation( Column.class ); + assertEquals( "", column.name() ); + assertFalse( column.unique() ); + assertTrue( column.nullable() ); + assertTrue( column.insertable() ); + assertTrue( column.updatable() ); + assertEquals( "", column.columnDefinition() ); + assertEquals( "", column.table() ); + assertEquals( 255, column.length() ); + assertEquals( 0, column.precision() ); + assertEquals( 0, column.scale() ); + } + + @Test + public void testColumnAllAttributes() throws Exception { + reader = getReader( Entity3.class, "field1", "element-collection.orm17.xml" ); + assertAnnotationPresent( ElementCollection.class ); + assertAnnotationPresent( Column.class ); + Column column = reader.getAnnotation( Column.class ); + assertEquals( "col1", column.name() ); + assertTrue( column.unique() ); + assertFalse( column.nullable() ); + assertFalse( column.insertable() ); + assertFalse( column.updatable() ); + assertEquals( "int", column.columnDefinition() ); + assertEquals( "table1", column.table() ); + assertEquals( 50, column.length() ); + assertEquals( 2, column.precision() ); + assertEquals( 1, column.scale() ); + } + + @Test + public void testTemporal() throws Exception { + reader = getReader( Entity3.class, "field1", "element-collection.orm18.xml" ); + assertAnnotationPresent( ElementCollection.class ); + assertAnnotationPresent( Temporal.class ); + assertAnnotationNotPresent( Enumerated.class ); + assertAnnotationNotPresent( Lob.class ); + assertEquals( + TemporalType.DATE, reader.getAnnotation( + Temporal.class + ).value() + ); + } + + @Test + public void testEnumerated() throws Exception { + reader = getReader( Entity3.class, "field1", "element-collection.orm19.xml" ); + assertAnnotationPresent( ElementCollection.class ); + assertAnnotationNotPresent( Temporal.class ); + assertAnnotationPresent( Enumerated.class ); + assertAnnotationNotPresent( Lob.class ); + assertEquals( + EnumType.STRING, reader.getAnnotation( + Enumerated.class + ).value() + ); + } + + @Test + public void testLob() throws Exception { + reader = getReader( Entity3.class, "field1", "element-collection.orm20.xml" ); + assertAnnotationPresent( ElementCollection.class ); + assertAnnotationNotPresent( Temporal.class ); + assertAnnotationNotPresent( Enumerated.class ); + assertAnnotationPresent( Lob.class ); + } + + /** + * When there's a single attribute override, we still wrap it with an + * AttributeOverrides annotation. + */ + @Test + public void testSingleAttributeOverride() throws Exception { + reader = getReader( Entity3.class, "field1", "element-collection.orm21.xml" ); + assertAnnotationPresent( ElementCollection.class ); + assertAnnotationNotPresent( AttributeOverride.class ); + assertAnnotationPresent( AttributeOverrides.class ); + AttributeOverrides overridesAnno = reader + .getAnnotation( AttributeOverrides.class ); + AttributeOverride[] overrides = overridesAnno.value(); + assertEquals( 1, overrides.length ); + assertEquals( "field1", overrides[0].name() ); + assertEquals( "col1", overrides[0].column().name() ); + } + + @Test + public void testMultipleAttributeOverrides() throws Exception { + reader = getReader( Entity3.class, "field1", "element-collection.orm22.xml" ); + assertAnnotationPresent( ElementCollection.class ); + assertAnnotationNotPresent( AttributeOverride.class ); + assertAnnotationPresent( AttributeOverrides.class ); + AttributeOverrides overridesAnno = reader + .getAnnotation( AttributeOverrides.class ); + AttributeOverride[] overrides = overridesAnno.value(); + assertEquals( 2, overrides.length ); + assertEquals( "field1", overrides[0].name() ); + assertEquals( "", overrides[0].column().name() ); + assertFalse( overrides[0].column().unique() ); + assertTrue( overrides[0].column().nullable() ); + assertTrue( overrides[0].column().insertable() ); + assertTrue( overrides[0].column().updatable() ); + assertEquals( "", overrides[0].column().columnDefinition() ); + assertEquals( "", overrides[0].column().table() ); + assertEquals( 255, overrides[0].column().length() ); + assertEquals( 0, overrides[0].column().precision() ); + assertEquals( 0, overrides[0].column().scale() ); + assertEquals( "field2", overrides[1].name() ); + assertEquals( "col1", overrides[1].column().name() ); + assertTrue( overrides[1].column().unique() ); + assertFalse( overrides[1].column().nullable() ); + assertFalse( overrides[1].column().insertable() ); + assertFalse( overrides[1].column().updatable() ); + assertEquals( "int", overrides[1].column().columnDefinition() ); + assertEquals( "table1", overrides[1].column().table() ); + assertEquals( 50, overrides[1].column().length() ); + assertEquals( 2, overrides[1].column().precision() ); + assertEquals( 1, overrides[1].column().scale() ); + } + + /** + * Tests that map-key-attribute-override and attribute-override elements + * both end up in the AttributeOverrides annotation. + */ + @Test + public void testMixedAttributeOverrides() throws Exception { + reader = getReader( Entity3.class, "field1", "element-collection.orm23.xml" ); + assertAnnotationPresent( ElementCollection.class ); + assertAnnotationNotPresent( AttributeOverride.class ); + assertAnnotationPresent( AttributeOverrides.class ); + AttributeOverrides overridesAnno = reader + .getAnnotation( AttributeOverrides.class ); + AttributeOverride[] overrides = overridesAnno.value(); + assertEquals( 2, overrides.length ); + assertEquals( "field1", overrides[0].name() ); + assertEquals( "col1", overrides[0].column().name() ); + assertEquals( "field2", overrides[1].name() ); + assertEquals( "col2", overrides[1].column().name() ); + } + + /** + * When there's a single association override, we still wrap it with an + * AssociationOverrides annotation. + */ + @Test + public void testSingleAssociationOverride() throws Exception { + reader = getReader( Entity3.class, "field1", "element-collection.orm24.xml" ); + assertAnnotationPresent( ElementCollection.class ); + assertAnnotationNotPresent( AssociationOverride.class ); + assertAnnotationPresent( AssociationOverrides.class ); + AssociationOverrides overridesAnno = reader.getAnnotation( AssociationOverrides.class ); + AssociationOverride[] overrides = overridesAnno.value(); + assertEquals( 1, overrides.length ); + assertEquals( "association1", overrides[0].name() ); + assertEquals( 0, overrides[0].joinColumns().length ); + assertEquals( "", overrides[0].joinTable().name() ); + } + + @Test + public void testMultipleAssociationOverridesJoinColumns() throws Exception { + reader = getReader( Entity3.class, "field1", "element-collection.orm25.xml" ); + assertAnnotationPresent( ElementCollection.class ); + assertAnnotationNotPresent( AssociationOverride.class ); + assertAnnotationPresent( AssociationOverrides.class ); + AssociationOverrides overridesAnno = reader.getAnnotation( AssociationOverrides.class ); + AssociationOverride[] overrides = overridesAnno.value(); + assertEquals( 2, overrides.length ); + //First, an association using join table + assertEquals( "association1", overrides[0].name() ); + assertEquals( 0, overrides[0].joinColumns().length ); + + JoinTable joinTableAnno = overrides[0].joinTable(); + assertEquals( "catalog1", joinTableAnno.catalog() ); + assertEquals( "table1", joinTableAnno.name() ); + assertEquals( "schema1", joinTableAnno.schema() ); + + //JoinColumns + JoinColumn[] joinColumns = joinTableAnno.joinColumns(); + assertEquals( 2, joinColumns.length ); + assertEquals( "", joinColumns[0].name() ); + assertEquals( "", joinColumns[0].referencedColumnName() ); + assertEquals( "", joinColumns[0].table() ); + assertEquals( "", joinColumns[0].columnDefinition() ); + assertTrue( joinColumns[0].insertable() ); + assertTrue( joinColumns[0].updatable() ); + assertTrue( joinColumns[0].nullable() ); + assertFalse( joinColumns[0].unique() ); + assertEquals( "col1", joinColumns[1].name() ); + assertEquals( "col2", joinColumns[1].referencedColumnName() ); + assertEquals( "table2", joinColumns[1].table() ); + assertEquals( "int", joinColumns[1].columnDefinition() ); + assertFalse( joinColumns[1].insertable() ); + assertFalse( joinColumns[1].updatable() ); + assertFalse( joinColumns[1].nullable() ); + assertTrue( joinColumns[1].unique() ); + + //InverseJoinColumns + JoinColumn[] inverseJoinColumns = joinTableAnno.inverseJoinColumns(); + assertEquals( 2, inverseJoinColumns.length ); + assertEquals( "", inverseJoinColumns[0].name() ); + assertEquals( "", inverseJoinColumns[0].referencedColumnName() ); + assertEquals( "", inverseJoinColumns[0].table() ); + assertEquals( "", inverseJoinColumns[0].columnDefinition() ); + assertTrue( inverseJoinColumns[0].insertable() ); + assertTrue( inverseJoinColumns[0].updatable() ); + assertTrue( inverseJoinColumns[0].nullable() ); + assertFalse( inverseJoinColumns[0].unique() ); + assertEquals( "col3", inverseJoinColumns[1].name() ); + assertEquals( "col4", inverseJoinColumns[1].referencedColumnName() ); + assertEquals( "table3", inverseJoinColumns[1].table() ); + assertEquals( "int", inverseJoinColumns[1].columnDefinition() ); + assertFalse( inverseJoinColumns[1].insertable() ); + assertFalse( inverseJoinColumns[1].updatable() ); + assertFalse( inverseJoinColumns[1].nullable() ); + assertTrue( inverseJoinColumns[1].unique() ); + + //UniqueConstraints + UniqueConstraint[] uniqueConstraints = joinTableAnno + .uniqueConstraints(); + assertEquals( 2, uniqueConstraints.length ); + assertEquals( "", uniqueConstraints[0].name() ); + assertEquals( 1, uniqueConstraints[0].columnNames().length ); + assertEquals( "col5", uniqueConstraints[0].columnNames()[0] ); + assertEquals( "uq1", uniqueConstraints[1].name() ); + assertEquals( 2, uniqueConstraints[1].columnNames().length ); + assertEquals( "col6", uniqueConstraints[1].columnNames()[0] ); + assertEquals( "col7", uniqueConstraints[1].columnNames()[1] ); + + //Second, an association using join columns + assertEquals( "association2", overrides[1].name() ); + + //JoinColumns + joinColumns = overrides[1].joinColumns(); + assertEquals( 2, joinColumns.length ); + assertEquals( "", joinColumns[0].name() ); + assertEquals( "", joinColumns[0].referencedColumnName() ); + assertEquals( "", joinColumns[0].table() ); + assertEquals( "", joinColumns[0].columnDefinition() ); + assertTrue( joinColumns[0].insertable() ); + assertTrue( joinColumns[0].updatable() ); + assertTrue( joinColumns[0].nullable() ); + assertFalse( joinColumns[0].unique() ); + assertEquals( "col8", joinColumns[1].name() ); + assertEquals( "col9", joinColumns[1].referencedColumnName() ); + assertEquals( "table4", joinColumns[1].table() ); + assertEquals( "int", joinColumns[1].columnDefinition() ); + assertFalse( joinColumns[1].insertable() ); + assertFalse( joinColumns[1].updatable() ); + assertFalse( joinColumns[1].nullable() ); + assertTrue( joinColumns[1].unique() ); + } + + @Test + public void testCollectionTableNoChildren() throws Exception { + reader = getReader( Entity3.class, "field1", "element-collection.orm26.xml" ); + assertAnnotationPresent( ElementCollection.class ); + assertAnnotationPresent( CollectionTable.class ); + CollectionTable tableAnno = reader.getAnnotation( CollectionTable.class ); + assertEquals( "", tableAnno.name() ); + assertEquals( "", tableAnno.catalog() ); + assertEquals( "", tableAnno.schema() ); + assertEquals( 0, tableAnno.joinColumns().length ); + assertEquals( 0, tableAnno.uniqueConstraints().length ); + } + + @Test + public void testCollectionTableAllChildren() throws Exception { + reader = getReader( Entity3.class, "field1", "element-collection.orm27.xml" ); + assertAnnotationPresent( ElementCollection.class ); + assertAnnotationPresent( CollectionTable.class ); + CollectionTable tableAnno = reader.getAnnotation( CollectionTable.class ); + assertEquals( "table1", tableAnno.name() ); + assertEquals( "catalog1", tableAnno.catalog() ); + assertEquals( "schema1", tableAnno.schema() ); + + //JoinColumns + JoinColumn[] joinColumns = tableAnno.joinColumns(); + assertEquals( 2, joinColumns.length ); + assertEquals( "", joinColumns[0].name() ); + assertEquals( "", joinColumns[0].referencedColumnName() ); + assertEquals( "", joinColumns[0].table() ); + assertEquals( "", joinColumns[0].columnDefinition() ); + assertTrue( joinColumns[0].insertable() ); + assertTrue( joinColumns[0].updatable() ); + assertTrue( joinColumns[0].nullable() ); + assertFalse( joinColumns[0].unique() ); + assertEquals( "col1", joinColumns[1].name() ); + assertEquals( "col2", joinColumns[1].referencedColumnName() ); + assertEquals( "table2", joinColumns[1].table() ); + assertEquals( "int", joinColumns[1].columnDefinition() ); + assertFalse( joinColumns[1].insertable() ); + assertFalse( joinColumns[1].updatable() ); + assertFalse( joinColumns[1].nullable() ); + assertTrue( joinColumns[1].unique() ); + + //UniqueConstraints + UniqueConstraint[] uniqueConstraints = tableAnno.uniqueConstraints(); + assertEquals( 2, uniqueConstraints.length ); + assertEquals( "", uniqueConstraints[0].name() ); + assertEquals( 1, uniqueConstraints[0].columnNames().length ); + assertEquals( "col3", uniqueConstraints[0].columnNames()[0] ); + assertEquals( "uq1", uniqueConstraints[1].name() ); + assertEquals( 2, uniqueConstraints[1].columnNames().length ); + assertEquals( "col4", uniqueConstraints[1].columnNames()[0] ); + assertEquals( "col5", uniqueConstraints[1].columnNames()[1] ); + } + + @Test + public void testAllAttributes() throws Exception { + reader = getReader( Entity2.class, "field1", "element-collection.orm28.xml" ); + assertAnnotationPresent( ElementCollection.class ); + assertAnnotationNotPresent( OrderBy.class ); + assertAnnotationNotPresent( OrderColumn.class ); + assertAnnotationNotPresent( MapKey.class ); + assertAnnotationNotPresent( MapKeyClass.class ); + assertAnnotationNotPresent( MapKeyTemporal.class ); + assertAnnotationNotPresent( MapKeyEnumerated.class ); + assertAnnotationNotPresent( MapKeyColumn.class ); + assertAnnotationNotPresent( MapKeyJoinColumns.class ); + assertAnnotationNotPresent( MapKeyJoinColumn.class ); + assertAnnotationNotPresent( Column.class ); + assertAnnotationNotPresent( Temporal.class ); + assertAnnotationNotPresent( Enumerated.class ); + assertAnnotationNotPresent( Lob.class ); + assertAnnotationNotPresent( AttributeOverride.class ); + assertAnnotationNotPresent( AttributeOverrides.class ); + assertAnnotationNotPresent( AssociationOverride.class ); + assertAnnotationNotPresent( AssociationOverrides.class ); + assertAnnotationNotPresent( CollectionTable.class ); + assertAnnotationPresent( Access.class ); + ElementCollection relAnno = reader.getAnnotation( ElementCollection.class ); + assertEquals( FetchType.EAGER, relAnno.fetch() ); + assertEquals( Entity3.class, relAnno.targetClass() ); + assertEquals( + AccessType.PROPERTY, reader.getAnnotation( Access.class ) + .value() + ); + } + +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlManyToManyTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlManyToManyTest.java new file mode 100644 index 000000000000..e80c00e08e8d --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlManyToManyTest.java @@ -0,0 +1,508 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.annotations.xml.ejb3; + +import javax.persistence.Access; +import javax.persistence.AccessType; +import javax.persistence.AttributeOverride; +import javax.persistence.AttributeOverrides; +import javax.persistence.CascadeType; +import javax.persistence.EnumType; +import javax.persistence.FetchType; +import javax.persistence.JoinColumn; +import javax.persistence.JoinColumns; +import javax.persistence.JoinTable; +import javax.persistence.ManyToMany; +import javax.persistence.MapKey; +import javax.persistence.MapKeyClass; +import javax.persistence.MapKeyColumn; +import javax.persistence.MapKeyEnumerated; +import javax.persistence.MapKeyJoinColumn; +import javax.persistence.MapKeyJoinColumns; +import javax.persistence.MapKeyTemporal; +import javax.persistence.OrderBy; +import javax.persistence.OrderColumn; +import javax.persistence.TemporalType; +import javax.persistence.UniqueConstraint; + +import org.hibernate.cfg.annotations.reflection.JPAOverriddenAnnotationReader; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * Equivalent to {@link org.hibernate.test.annotations.xml.ejb3.Ejb3XmlManyToManyTest} + * for the legacy {@link JPAOverriddenAnnotationReader}. + * + * @author Emmanuel Bernard + * @deprecated This test will be removed in Hibernate ORM 6, along with the legacy {@link JPAOverriddenAnnotationReader}. + */ +@Deprecated +public class LegacyEjb3XmlManyToManyTest extends LegacyEjb3XmlTestCase { + @Test + public void testNoChildren() throws Exception { + reader = getReader( Entity2.class, "field1", "many-to-many.orm1.xml" ); + assertAnnotationPresent( ManyToMany.class ); + assertAnnotationNotPresent( OrderBy.class ); + assertAnnotationNotPresent( OrderColumn.class ); + assertAnnotationNotPresent( MapKey.class ); + assertAnnotationNotPresent( MapKeyClass.class ); + assertAnnotationNotPresent( MapKeyTemporal.class ); + assertAnnotationNotPresent( MapKeyEnumerated.class ); + assertAnnotationNotPresent( MapKeyColumn.class ); + assertAnnotationNotPresent( MapKeyJoinColumns.class ); + assertAnnotationNotPresent( MapKeyJoinColumn.class ); + assertAnnotationNotPresent( JoinTable.class ); + assertAnnotationNotPresent( Access.class ); + ManyToMany relAnno = reader.getAnnotation( ManyToMany.class ); + assertEquals( 0, relAnno.cascade().length ); + assertEquals( FetchType.LAZY, relAnno.fetch() ); + assertEquals( "", relAnno.mappedBy() ); + assertEquals( void.class, relAnno.targetEntity() ); + } + + @Test + public void testOrderBy() throws Exception { + reader = getReader( Entity2.class, "field1", "many-to-many.orm2.xml" ); + assertAnnotationPresent( ManyToMany.class ); + assertAnnotationPresent( OrderBy.class ); + assertAnnotationNotPresent( OrderColumn.class ); + assertEquals( + "col1 ASC, col2 DESC", reader.getAnnotation( OrderBy.class ) + .value() + ); + } + + @Test + public void testOrderColumnNoAttributes() throws Exception { + reader = getReader( Entity2.class, "field1", "many-to-many.orm3.xml" ); + assertAnnotationPresent( ManyToMany.class ); + assertAnnotationNotPresent( OrderBy.class ); + assertAnnotationPresent( OrderColumn.class ); + OrderColumn orderColumnAnno = reader.getAnnotation( OrderColumn.class ); + assertEquals( "", orderColumnAnno.columnDefinition() ); + assertEquals( "", orderColumnAnno.name() ); + assertTrue( orderColumnAnno.insertable() ); + assertTrue( orderColumnAnno.nullable() ); + assertTrue( orderColumnAnno.updatable() ); + } + + @Test + public void testOrderColumnAllAttributes() throws Exception { + reader = getReader( Entity2.class, "field1", "many-to-many.orm4.xml" ); + assertAnnotationPresent( ManyToMany.class ); + assertAnnotationNotPresent( OrderBy.class ); + assertAnnotationPresent( OrderColumn.class ); + OrderColumn orderColumnAnno = reader.getAnnotation( OrderColumn.class ); + assertEquals( "int", orderColumnAnno.columnDefinition() ); + assertEquals( "col1", orderColumnAnno.name() ); + assertFalse( orderColumnAnno.insertable() ); + assertFalse( orderColumnAnno.nullable() ); + assertFalse( orderColumnAnno.updatable() ); + } + + @Test + public void testMapKeyNoAttributes() throws Exception { + reader = getReader( Entity3.class, "field1", "many-to-many.orm5.xml" ); + assertAnnotationPresent( ManyToMany.class ); + assertAnnotationPresent( MapKey.class ); + assertAnnotationNotPresent( MapKeyClass.class ); + assertAnnotationNotPresent( MapKeyTemporal.class ); + assertAnnotationNotPresent( MapKeyEnumerated.class ); + assertAnnotationNotPresent( MapKeyColumn.class ); + assertAnnotationNotPresent( MapKeyJoinColumns.class ); + assertAnnotationNotPresent( MapKeyJoinColumn.class ); + assertEquals( "", reader.getAnnotation( MapKey.class ).name() ); + } + + @Test + public void testMapKeyAllAttributes() throws Exception { + reader = getReader( Entity3.class, "field1", "many-to-many.orm6.xml" ); + assertAnnotationPresent( ManyToMany.class ); + assertAnnotationPresent( MapKey.class ); + assertAnnotationNotPresent( MapKeyClass.class ); + assertAnnotationNotPresent( MapKeyTemporal.class ); + assertAnnotationNotPresent( MapKeyEnumerated.class ); + assertAnnotationNotPresent( MapKeyColumn.class ); + assertAnnotationNotPresent( MapKeyJoinColumns.class ); + assertAnnotationNotPresent( MapKeyJoinColumn.class ); + assertEquals( "field2", reader.getAnnotation( MapKey.class ).name() ); + } + + @Test + public void testMapKeyClass() throws Exception { + reader = getReader( Entity3.class, "field1", "many-to-many.orm7.xml" ); + assertAnnotationPresent( ManyToMany.class ); + assertAnnotationNotPresent( MapKey.class ); + assertAnnotationPresent( MapKeyClass.class ); + assertAnnotationNotPresent( MapKeyTemporal.class ); + assertAnnotationNotPresent( MapKeyEnumerated.class ); + assertAnnotationNotPresent( MapKeyColumn.class ); + assertAnnotationNotPresent( MapKeyJoinColumns.class ); + assertAnnotationNotPresent( MapKeyJoinColumn.class ); + assertEquals( + Entity2.class, reader.getAnnotation( MapKeyClass.class ) + .value() + ); + } + + @Test + public void testMapKeyTemporal() throws Exception { + reader = getReader( Entity3.class, "field1", "many-to-many.orm8.xml" ); + assertAnnotationPresent( ManyToMany.class ); + assertAnnotationNotPresent( MapKey.class ); + assertAnnotationNotPresent( MapKeyClass.class ); + assertAnnotationPresent( MapKeyTemporal.class ); + assertAnnotationNotPresent( MapKeyEnumerated.class ); + assertAnnotationNotPresent( MapKeyColumn.class ); + assertAnnotationNotPresent( MapKeyJoinColumns.class ); + assertAnnotationNotPresent( MapKeyJoinColumn.class ); + assertEquals( + TemporalType.DATE, reader.getAnnotation( + MapKeyTemporal.class + ).value() + ); + } + + @Test + public void testMapKeyEnumerated() throws Exception { + reader = getReader( Entity3.class, "field1", "many-to-many.orm9.xml" ); + assertAnnotationPresent( ManyToMany.class ); + assertAnnotationNotPresent( MapKey.class ); + assertAnnotationNotPresent( MapKeyClass.class ); + assertAnnotationNotPresent( MapKeyTemporal.class ); + assertAnnotationPresent( MapKeyEnumerated.class ); + assertAnnotationNotPresent( MapKeyColumn.class ); + assertAnnotationNotPresent( MapKeyJoinColumns.class ); + assertAnnotationNotPresent( MapKeyJoinColumn.class ); + assertEquals( + EnumType.STRING, reader.getAnnotation( + MapKeyEnumerated.class + ).value() + ); + } + + /** + * When there's a single map key attribute override, we still wrap it with + * an AttributeOverrides annotation. + */ + @Test + public void testSingleMapKeyAttributeOverride() throws Exception { + reader = getReader( Entity3.class, "field1", "many-to-many.orm10.xml" ); + assertAnnotationPresent( ManyToMany.class ); + assertAnnotationNotPresent( MapKey.class ); + assertAnnotationNotPresent( MapKeyClass.class ); + assertAnnotationNotPresent( MapKeyTemporal.class ); + assertAnnotationNotPresent( MapKeyEnumerated.class ); + assertAnnotationNotPresent( MapKeyColumn.class ); + assertAnnotationNotPresent( MapKeyJoinColumns.class ); + assertAnnotationNotPresent( MapKeyJoinColumn.class ); + assertAnnotationNotPresent( AttributeOverride.class ); + assertAnnotationPresent( AttributeOverrides.class ); + AttributeOverrides overridesAnno = reader + .getAnnotation( AttributeOverrides.class ); + AttributeOverride[] overrides = overridesAnno.value(); + assertEquals( 1, overrides.length ); + assertEquals( "field1", overrides[0].name() ); + assertEquals( "col1", overrides[0].column().name() ); + } + + @Test + public void testMultipleMapKeyAttributeOverrides() throws Exception { + reader = getReader( Entity3.class, "field1", "many-to-many.orm11.xml" ); + assertAnnotationPresent( ManyToMany.class ); + assertAnnotationNotPresent( MapKey.class ); + assertAnnotationNotPresent( MapKeyClass.class ); + assertAnnotationNotPresent( MapKeyTemporal.class ); + assertAnnotationNotPresent( MapKeyEnumerated.class ); + assertAnnotationNotPresent( MapKeyColumn.class ); + assertAnnotationNotPresent( MapKeyJoinColumns.class ); + assertAnnotationNotPresent( MapKeyJoinColumn.class ); + assertAnnotationNotPresent( AttributeOverride.class ); + assertAnnotationPresent( AttributeOverrides.class ); + AttributeOverrides overridesAnno = reader + .getAnnotation( AttributeOverrides.class ); + AttributeOverride[] overrides = overridesAnno.value(); + assertEquals( 2, overrides.length ); + assertEquals( "field1", overrides[0].name() ); + assertEquals( "", overrides[0].column().name() ); + assertFalse( overrides[0].column().unique() ); + assertTrue( overrides[0].column().nullable() ); + assertTrue( overrides[0].column().insertable() ); + assertTrue( overrides[0].column().updatable() ); + assertEquals( "", overrides[0].column().columnDefinition() ); + assertEquals( "", overrides[0].column().table() ); + assertEquals( 255, overrides[0].column().length() ); + assertEquals( 0, overrides[0].column().precision() ); + assertEquals( 0, overrides[0].column().scale() ); + assertEquals( "field2", overrides[1].name() ); + assertEquals( "col1", overrides[1].column().name() ); + assertTrue( overrides[1].column().unique() ); + assertFalse( overrides[1].column().nullable() ); + assertFalse( overrides[1].column().insertable() ); + assertFalse( overrides[1].column().updatable() ); + assertEquals( "int", overrides[1].column().columnDefinition() ); + assertEquals( "table1", overrides[1].column().table() ); + assertEquals( 50, overrides[1].column().length() ); + assertEquals( 2, overrides[1].column().precision() ); + assertEquals( 1, overrides[1].column().scale() ); + } + + @Test + public void testMapKeyColumnNoAttributes() throws Exception { + reader = getReader( Entity3.class, "field1", "many-to-many.orm12.xml" ); + assertAnnotationPresent( ManyToMany.class ); + assertAnnotationNotPresent( MapKey.class ); + assertAnnotationNotPresent( MapKeyClass.class ); + assertAnnotationNotPresent( MapKeyTemporal.class ); + assertAnnotationNotPresent( MapKeyEnumerated.class ); + assertAnnotationPresent( MapKeyColumn.class ); + assertAnnotationNotPresent( MapKeyJoinColumns.class ); + assertAnnotationNotPresent( MapKeyJoinColumn.class ); + MapKeyColumn keyColAnno = reader.getAnnotation( MapKeyColumn.class ); + assertEquals( "", keyColAnno.columnDefinition() ); + assertEquals( "", keyColAnno.name() ); + assertEquals( "", keyColAnno.table() ); + assertFalse( keyColAnno.nullable() ); + assertTrue( keyColAnno.insertable() ); + assertFalse( keyColAnno.unique() ); + assertTrue( keyColAnno.updatable() ); + assertEquals( 255, keyColAnno.length() ); + assertEquals( 0, keyColAnno.precision() ); + assertEquals( 0, keyColAnno.scale() ); + } + + @Test + public void testMapKeyColumnAllAttributes() throws Exception { + reader = getReader( Entity3.class, "field1", "many-to-many.orm13.xml" ); + assertAnnotationPresent( ManyToMany.class ); + assertAnnotationNotPresent( MapKey.class ); + assertAnnotationNotPresent( MapKeyClass.class ); + assertAnnotationNotPresent( MapKeyTemporal.class ); + assertAnnotationNotPresent( MapKeyEnumerated.class ); + assertAnnotationPresent( MapKeyColumn.class ); + assertAnnotationNotPresent( MapKeyJoinColumns.class ); + assertAnnotationNotPresent( MapKeyJoinColumn.class ); + MapKeyColumn keyColAnno = reader.getAnnotation( MapKeyColumn.class ); + assertEquals( "int", keyColAnno.columnDefinition() ); + assertEquals( "col1", keyColAnno.name() ); + assertEquals( "table1", keyColAnno.table() ); + assertTrue( keyColAnno.nullable() ); + assertFalse( keyColAnno.insertable() ); + assertTrue( keyColAnno.unique() ); + assertFalse( keyColAnno.updatable() ); + assertEquals( 50, keyColAnno.length() ); + assertEquals( 2, keyColAnno.precision() ); + assertEquals( 1, keyColAnno.scale() ); + } + + /** + * When there's a single map key join column, we still wrap it with a + * MapKeyJoinColumns annotation. + */ + @Test + public void testSingleMapKeyJoinColumn() throws Exception { + reader = getReader( Entity3.class, "field1", "many-to-many.orm14.xml" ); + assertAnnotationPresent( ManyToMany.class ); + assertAnnotationNotPresent( MapKey.class ); + assertAnnotationNotPresent( MapKeyClass.class ); + assertAnnotationNotPresent( MapKeyTemporal.class ); + assertAnnotationNotPresent( MapKeyEnumerated.class ); + assertAnnotationNotPresent( MapKeyColumn.class ); + assertAnnotationPresent( MapKeyJoinColumns.class ); + assertAnnotationNotPresent( MapKeyJoinColumn.class ); + MapKeyJoinColumns joinColumnsAnno = reader + .getAnnotation( MapKeyJoinColumns.class ); + MapKeyJoinColumn[] joinColumns = joinColumnsAnno.value(); + assertEquals( 1, joinColumns.length ); + assertEquals( "col1", joinColumns[0].name() ); + } + + @Test + public void testMultipleMapKeyJoinColumns() throws Exception { + reader = getReader( Entity3.class, "field1", "many-to-many.orm15.xml" ); + assertAnnotationPresent( ManyToMany.class ); + assertAnnotationNotPresent( MapKey.class ); + assertAnnotationNotPresent( MapKeyClass.class ); + assertAnnotationNotPresent( MapKeyTemporal.class ); + assertAnnotationNotPresent( MapKeyEnumerated.class ); + assertAnnotationNotPresent( MapKeyColumn.class ); + assertAnnotationPresent( MapKeyJoinColumns.class ); + assertAnnotationNotPresent( MapKeyJoinColumn.class ); + MapKeyJoinColumns joinColumnsAnno = reader + .getAnnotation( MapKeyJoinColumns.class ); + MapKeyJoinColumn[] joinColumns = joinColumnsAnno.value(); + assertEquals( 2, joinColumns.length ); + assertEquals( "", joinColumns[0].name() ); + assertEquals( "", joinColumns[0].referencedColumnName() ); + assertFalse( joinColumns[0].unique() ); + assertFalse( joinColumns[0].nullable() ); + assertTrue( joinColumns[0].insertable() ); + assertTrue( joinColumns[0].updatable() ); + assertEquals( "", joinColumns[0].columnDefinition() ); + assertEquals( "", joinColumns[0].table() ); + assertEquals( "col1", joinColumns[1].name() ); + assertEquals( "col2", joinColumns[1].referencedColumnName() ); + assertTrue( joinColumns[1].unique() ); + assertTrue( joinColumns[1].nullable() ); + assertFalse( joinColumns[1].insertable() ); + assertFalse( joinColumns[1].updatable() ); + assertEquals( "int", joinColumns[1].columnDefinition() ); + assertEquals( "table1", joinColumns[1].table() ); + } + + @Test + public void testJoinTableNoChildren() throws Exception { + reader = getReader( Entity2.class, "field1", "many-to-many.orm16.xml" ); + assertAnnotationPresent( ManyToMany.class ); + assertAnnotationPresent( JoinTable.class ); + assertAnnotationNotPresent( JoinColumns.class ); + assertAnnotationNotPresent( JoinColumn.class ); + JoinTable joinTableAnno = reader.getAnnotation( JoinTable.class ); + assertEquals( "", joinTableAnno.catalog() ); + assertEquals( "", joinTableAnno.name() ); + assertEquals( "", joinTableAnno.schema() ); + assertEquals( 0, joinTableAnno.joinColumns().length ); + assertEquals( 0, joinTableAnno.inverseJoinColumns().length ); + assertEquals( 0, joinTableAnno.uniqueConstraints().length ); + } + + @Test + public void testJoinTableAllChildren() throws Exception { + reader = getReader( Entity2.class, "field1", "many-to-many.orm17.xml" ); + assertAnnotationPresent( ManyToMany.class ); + assertAnnotationPresent( JoinTable.class ); + assertAnnotationNotPresent( JoinColumns.class ); + assertAnnotationNotPresent( JoinColumn.class ); + JoinTable joinTableAnno = reader.getAnnotation( JoinTable.class ); + assertEquals( "cat1", joinTableAnno.catalog() ); + assertEquals( "table1", joinTableAnno.name() ); + assertEquals( "schema1", joinTableAnno.schema() ); + + // JoinColumns + JoinColumn[] joinColumns = joinTableAnno.joinColumns(); + assertEquals( 2, joinColumns.length ); + assertEquals( "", joinColumns[0].name() ); + assertEquals( "", joinColumns[0].referencedColumnName() ); + assertEquals( "", joinColumns[0].table() ); + assertEquals( "", joinColumns[0].columnDefinition() ); + assertTrue( joinColumns[0].insertable() ); + assertTrue( joinColumns[0].updatable() ); + assertTrue( joinColumns[0].nullable() ); + assertFalse( joinColumns[0].unique() ); + assertEquals( "col1", joinColumns[1].name() ); + assertEquals( "col2", joinColumns[1].referencedColumnName() ); + assertEquals( "table2", joinColumns[1].table() ); + assertEquals( "int", joinColumns[1].columnDefinition() ); + assertFalse( joinColumns[1].insertable() ); + assertFalse( joinColumns[1].updatable() ); + assertFalse( joinColumns[1].nullable() ); + assertTrue( joinColumns[1].unique() ); + + // InverseJoinColumns + JoinColumn[] inverseJoinColumns = joinTableAnno.inverseJoinColumns(); + assertEquals( 2, inverseJoinColumns.length ); + assertEquals( "", inverseJoinColumns[0].name() ); + assertEquals( "", inverseJoinColumns[0].referencedColumnName() ); + assertEquals( "", inverseJoinColumns[0].table() ); + assertEquals( "", inverseJoinColumns[0].columnDefinition() ); + assertTrue( inverseJoinColumns[0].insertable() ); + assertTrue( inverseJoinColumns[0].updatable() ); + assertTrue( inverseJoinColumns[0].nullable() ); + assertFalse( inverseJoinColumns[0].unique() ); + assertEquals( "col3", inverseJoinColumns[1].name() ); + assertEquals( "col4", inverseJoinColumns[1].referencedColumnName() ); + assertEquals( "table3", inverseJoinColumns[1].table() ); + assertEquals( "int", inverseJoinColumns[1].columnDefinition() ); + assertFalse( inverseJoinColumns[1].insertable() ); + assertFalse( inverseJoinColumns[1].updatable() ); + assertFalse( inverseJoinColumns[1].nullable() ); + assertTrue( inverseJoinColumns[1].unique() ); + + // UniqueConstraints + UniqueConstraint[] uniqueConstraints = joinTableAnno + .uniqueConstraints(); + assertEquals( 2, uniqueConstraints.length ); + assertEquals( "", uniqueConstraints[0].name() ); + assertEquals( 1, uniqueConstraints[0].columnNames().length ); + assertEquals( "col5", uniqueConstraints[0].columnNames()[0] ); + assertEquals( "uq1", uniqueConstraints[1].name() ); + assertEquals( 2, uniqueConstraints[1].columnNames().length ); + assertEquals( "col6", uniqueConstraints[1].columnNames()[0] ); + assertEquals( "col7", uniqueConstraints[1].columnNames()[1] ); + } + + @Test + public void testCascadeAll() throws Exception { + reader = getReader( Entity2.class, "field1", "many-to-many.orm18.xml" ); + assertAnnotationPresent( ManyToMany.class ); + ManyToMany relAnno = reader.getAnnotation( ManyToMany.class ); + assertEquals( 1, relAnno.cascade().length ); + assertEquals( CascadeType.ALL, relAnno.cascade()[0] ); + } + + @Test + public void testCascadeSomeWithDefaultPersist() throws Exception { + reader = getReader( Entity2.class, "field1", "many-to-many.orm19.xml" ); + assertAnnotationPresent( ManyToMany.class ); + ManyToMany relAnno = reader.getAnnotation( ManyToMany.class ); + assertEquals( 4, relAnno.cascade().length ); + assertEquals( CascadeType.REMOVE, relAnno.cascade()[0] ); + assertEquals( CascadeType.REFRESH, relAnno.cascade()[1] ); + assertEquals( CascadeType.DETACH, relAnno.cascade()[2] ); + assertEquals( CascadeType.PERSIST, relAnno.cascade()[3] ); + } + + /** + * Make sure that it doesn't break the handler when {@link CascadeType#ALL} + * is specified in addition to a default cascade-persist or individual + * cascade settings. + */ + @Test + public void testCascadeAllPlusMore() throws Exception { + reader = getReader( Entity2.class, "field1", "many-to-many.orm20.xml" ); + assertAnnotationPresent( ManyToMany.class ); + ManyToMany relAnno = reader.getAnnotation( ManyToMany.class ); + assertEquals( 6, relAnno.cascade().length ); + assertEquals( CascadeType.ALL, relAnno.cascade()[0] ); + assertEquals( CascadeType.PERSIST, relAnno.cascade()[1] ); + assertEquals( CascadeType.MERGE, relAnno.cascade()[2] ); + assertEquals( CascadeType.REMOVE, relAnno.cascade()[3] ); + assertEquals( CascadeType.REFRESH, relAnno.cascade()[4] ); + assertEquals( CascadeType.DETACH, relAnno.cascade()[5] ); + } + + @Test + public void testAllAttributes() throws Exception { + reader = getReader( Entity2.class, "field1", "many-to-many.orm21.xml" ); + assertAnnotationPresent( ManyToMany.class ); + assertAnnotationNotPresent( OrderBy.class ); + assertAnnotationNotPresent( OrderColumn.class ); + assertAnnotationNotPresent( MapKey.class ); + assertAnnotationNotPresent( MapKeyClass.class ); + assertAnnotationNotPresent( MapKeyTemporal.class ); + assertAnnotationNotPresent( MapKeyEnumerated.class ); + assertAnnotationNotPresent( MapKeyColumn.class ); + assertAnnotationNotPresent( MapKeyJoinColumns.class ); + assertAnnotationNotPresent( MapKeyJoinColumn.class ); + assertAnnotationNotPresent( JoinTable.class ); + assertAnnotationPresent( Access.class ); + ManyToMany relAnno = reader.getAnnotation( ManyToMany.class ); + assertEquals( 0, relAnno.cascade().length ); + assertEquals( FetchType.EAGER, relAnno.fetch() ); + assertEquals( "field2", relAnno.mappedBy() ); + assertEquals( Entity3.class, relAnno.targetEntity() ); + assertEquals( + AccessType.PROPERTY, reader.getAnnotation( Access.class ) + .value() + ); + } + +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlManyToOneTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlManyToOneTest.java new file mode 100644 index 000000000000..e665be4f2ef4 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlManyToOneTest.java @@ -0,0 +1,245 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.annotations.xml.ejb3; + +import javax.persistence.Access; +import javax.persistence.AccessType; +import javax.persistence.CascadeType; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.JoinColumns; +import javax.persistence.JoinTable; +import javax.persistence.ManyToOne; +import javax.persistence.MapsId; +import javax.persistence.UniqueConstraint; + +import org.hibernate.cfg.annotations.reflection.JPAOverriddenAnnotationReader; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * Equivalent to {@link org.hibernate.test.annotations.xml.ejb3.Ejb3XmlManyToOneTest} + * for the legacy {@link JPAOverriddenAnnotationReader}. + * + * @author Emmanuel Bernard + * @deprecated This test will be removed in Hibernate ORM 6, along with the legacy {@link JPAOverriddenAnnotationReader}. + */ +@Deprecated +public class LegacyEjb3XmlManyToOneTest extends LegacyEjb3XmlTestCase { + @Test + public void testNoJoins() throws Exception { + reader = getReader( Entity1.class, "field1", "many-to-one.orm1.xml" ); + assertAnnotationPresent( ManyToOne.class ); + assertAnnotationNotPresent( JoinColumn.class ); + assertAnnotationNotPresent( JoinColumns.class ); + assertAnnotationNotPresent( JoinTable.class ); + assertAnnotationNotPresent( Id.class ); + assertAnnotationNotPresent( MapsId.class ); + assertAnnotationNotPresent( Access.class ); + ManyToOne relAnno = reader.getAnnotation( ManyToOne.class ); + assertEquals( 0, relAnno.cascade().length ); + assertEquals( FetchType.EAGER, relAnno.fetch() ); + assertTrue( relAnno.optional() ); + assertEquals( void.class, relAnno.targetEntity() ); + } + + /** + * When there's a single join column, we still wrap it with a JoinColumns + * annotation. + */ + @Test + public void testSingleJoinColumn() throws Exception { + reader = getReader( Entity1.class, "field1", "many-to-one.orm2.xml" ); + assertAnnotationPresent( ManyToOne.class ); + assertAnnotationNotPresent( JoinColumn.class ); + assertAnnotationPresent( JoinColumns.class ); + assertAnnotationNotPresent( JoinTable.class ); + JoinColumns joinColumnsAnno = reader.getAnnotation( JoinColumns.class ); + JoinColumn[] joinColumns = joinColumnsAnno.value(); + assertEquals( 1, joinColumns.length ); + assertEquals( "col1", joinColumns[0].name() ); + assertEquals( "col2", joinColumns[0].referencedColumnName() ); + assertEquals( "table1", joinColumns[0].table() ); + } + + @Test + public void testMultipleJoinColumns() throws Exception { + reader = getReader( Entity1.class, "field1", "many-to-one.orm3.xml" ); + assertAnnotationPresent( ManyToOne.class ); + assertAnnotationNotPresent( JoinColumn.class ); + assertAnnotationPresent( JoinColumns.class ); + assertAnnotationNotPresent( JoinTable.class ); + JoinColumns joinColumnsAnno = reader.getAnnotation( JoinColumns.class ); + JoinColumn[] joinColumns = joinColumnsAnno.value(); + assertEquals( 2, joinColumns.length ); + assertEquals( "", joinColumns[0].name() ); + assertEquals( "", joinColumns[0].referencedColumnName() ); + assertEquals( "", joinColumns[0].table() ); + assertEquals( "", joinColumns[0].columnDefinition() ); + assertTrue( joinColumns[0].insertable() ); + assertTrue( joinColumns[0].updatable() ); + assertTrue( joinColumns[0].nullable() ); + assertFalse( joinColumns[0].unique() ); + assertEquals( "col1", joinColumns[1].name() ); + assertEquals( "col2", joinColumns[1].referencedColumnName() ); + assertEquals( "table1", joinColumns[1].table() ); + assertEquals( "int", joinColumns[1].columnDefinition() ); + assertFalse( joinColumns[1].insertable() ); + assertFalse( joinColumns[1].updatable() ); + assertFalse( joinColumns[1].nullable() ); + assertTrue( joinColumns[1].unique() ); + } + + @Test + public void testJoinTableNoChildren() throws Exception { + reader = getReader( Entity1.class, "field1", "many-to-one.orm4.xml" ); + assertAnnotationPresent( ManyToOne.class ); + assertAnnotationNotPresent( JoinColumn.class ); + assertAnnotationNotPresent( JoinColumns.class ); + assertAnnotationPresent( JoinTable.class ); + JoinTable joinTableAnno = reader.getAnnotation( JoinTable.class ); + assertEquals( "", joinTableAnno.catalog() ); + assertEquals( "", joinTableAnno.name() ); + assertEquals( "", joinTableAnno.schema() ); + assertEquals( 0, joinTableAnno.joinColumns().length ); + assertEquals( 0, joinTableAnno.inverseJoinColumns().length ); + assertEquals( 0, joinTableAnno.uniqueConstraints().length ); + } + + @Test + public void testJoinTableAllChildren() throws Exception { + reader = getReader( Entity1.class, "field1", "many-to-one.orm5.xml" ); + assertAnnotationPresent( ManyToOne.class ); + assertAnnotationNotPresent( JoinColumn.class ); + assertAnnotationNotPresent( JoinColumns.class ); + assertAnnotationPresent( JoinTable.class ); + JoinTable joinTableAnno = reader.getAnnotation( JoinTable.class ); + assertEquals( "cat1", joinTableAnno.catalog() ); + assertEquals( "table1", joinTableAnno.name() ); + assertEquals( "schema1", joinTableAnno.schema() ); + + // JoinColumns + JoinColumn[] joinColumns = joinTableAnno.joinColumns(); + assertEquals( 2, joinColumns.length ); + assertEquals( "", joinColumns[0].name() ); + assertEquals( "", joinColumns[0].referencedColumnName() ); + assertEquals( "", joinColumns[0].table() ); + assertEquals( "", joinColumns[0].columnDefinition() ); + assertTrue( joinColumns[0].insertable() ); + assertTrue( joinColumns[0].updatable() ); + assertTrue( joinColumns[0].nullable() ); + assertFalse( joinColumns[0].unique() ); + assertEquals( "col1", joinColumns[1].name() ); + assertEquals( "col2", joinColumns[1].referencedColumnName() ); + assertEquals( "table2", joinColumns[1].table() ); + assertEquals( "int", joinColumns[1].columnDefinition() ); + assertFalse( joinColumns[1].insertable() ); + assertFalse( joinColumns[1].updatable() ); + assertFalse( joinColumns[1].nullable() ); + assertTrue( joinColumns[1].unique() ); + + // InverseJoinColumns + JoinColumn[] inverseJoinColumns = joinTableAnno.inverseJoinColumns(); + assertEquals( 2, inverseJoinColumns.length ); + assertEquals( "", inverseJoinColumns[0].name() ); + assertEquals( "", inverseJoinColumns[0].referencedColumnName() ); + assertEquals( "", inverseJoinColumns[0].table() ); + assertEquals( "", inverseJoinColumns[0].columnDefinition() ); + assertTrue( inverseJoinColumns[0].insertable() ); + assertTrue( inverseJoinColumns[0].updatable() ); + assertTrue( inverseJoinColumns[0].nullable() ); + assertFalse( inverseJoinColumns[0].unique() ); + assertEquals( "col3", inverseJoinColumns[1].name() ); + assertEquals( "col4", inverseJoinColumns[1].referencedColumnName() ); + assertEquals( "table3", inverseJoinColumns[1].table() ); + assertEquals( "int", inverseJoinColumns[1].columnDefinition() ); + assertFalse( inverseJoinColumns[1].insertable() ); + assertFalse( inverseJoinColumns[1].updatable() ); + assertFalse( inverseJoinColumns[1].nullable() ); + assertTrue( inverseJoinColumns[1].unique() ); + + // UniqueConstraints + UniqueConstraint[] uniqueConstraints = joinTableAnno + .uniqueConstraints(); + assertEquals( 2, uniqueConstraints.length ); + assertEquals( "", uniqueConstraints[0].name() ); + assertEquals( 1, uniqueConstraints[0].columnNames().length ); + assertEquals( "col5", uniqueConstraints[0].columnNames()[0] ); + assertEquals( "uq1", uniqueConstraints[1].name() ); + assertEquals( 2, uniqueConstraints[1].columnNames().length ); + assertEquals( "col6", uniqueConstraints[1].columnNames()[0] ); + assertEquals( "col7", uniqueConstraints[1].columnNames()[1] ); + } + + @Test + public void testAllAttributes() throws Exception { + reader = getReader( Entity1.class, "field1", "many-to-one.orm6.xml" ); + assertAnnotationPresent( ManyToOne.class ); + assertAnnotationNotPresent( JoinColumn.class ); + assertAnnotationNotPresent( JoinColumns.class ); + assertAnnotationNotPresent( JoinTable.class ); + assertAnnotationPresent( Id.class ); + assertAnnotationPresent( MapsId.class ); + assertAnnotationPresent( Access.class ); + ManyToOne relAnno = reader.getAnnotation( ManyToOne.class ); + assertEquals( 0, relAnno.cascade().length ); + assertEquals( FetchType.LAZY, relAnno.fetch() ); + assertFalse( relAnno.optional() ); + assertEquals( Entity3.class, relAnno.targetEntity() ); + assertEquals( "col1", reader.getAnnotation( MapsId.class ).value() ); + assertEquals( + AccessType.PROPERTY, reader.getAnnotation( Access.class ) + .value() + ); + } + + @Test + public void testCascadeAll() throws Exception { + reader = getReader( Entity1.class, "field1", "many-to-one.orm7.xml" ); + assertAnnotationPresent( ManyToOne.class ); + ManyToOne relAnno = reader.getAnnotation( ManyToOne.class ); + assertEquals( 1, relAnno.cascade().length ); + assertEquals( CascadeType.ALL, relAnno.cascade()[0] ); + } + + @Test + public void testCascadeSomeWithDefaultPersist() throws Exception { + reader = getReader( Entity1.class, "field1", "many-to-one.orm8.xml" ); + assertAnnotationPresent( ManyToOne.class ); + ManyToOne relAnno = reader.getAnnotation( ManyToOne.class ); + assertEquals( 4, relAnno.cascade().length ); + assertEquals( CascadeType.REMOVE, relAnno.cascade()[0] ); + assertEquals( CascadeType.REFRESH, relAnno.cascade()[1] ); + assertEquals( CascadeType.DETACH, relAnno.cascade()[2] ); + assertEquals( CascadeType.PERSIST, relAnno.cascade()[3] ); + } + + /** + * Make sure that it doesn't break the handler when {@link CascadeType#ALL} + * is specified in addition to a default cascade-persist or individual + * cascade settings. + */ + @Test + public void testCascadeAllPlusMore() throws Exception { + reader = getReader( Entity1.class, "field1", "many-to-one.orm9.xml" ); + assertAnnotationPresent( ManyToOne.class ); + ManyToOne relAnno = reader.getAnnotation( ManyToOne.class ); + assertEquals( 6, relAnno.cascade().length ); + assertEquals( CascadeType.ALL, relAnno.cascade()[0] ); + assertEquals( CascadeType.PERSIST, relAnno.cascade()[1] ); + assertEquals( CascadeType.MERGE, relAnno.cascade()[2] ); + assertEquals( CascadeType.REMOVE, relAnno.cascade()[3] ); + assertEquals( CascadeType.REFRESH, relAnno.cascade()[4] ); + assertEquals( CascadeType.DETACH, relAnno.cascade()[5] ); + } + +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlOneToManyTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlOneToManyTest.java new file mode 100644 index 000000000000..b531fabecf21 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlOneToManyTest.java @@ -0,0 +1,561 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.annotations.xml.ejb3; + +import javax.persistence.Access; +import javax.persistence.AccessType; +import javax.persistence.AttributeOverride; +import javax.persistence.AttributeOverrides; +import javax.persistence.CascadeType; +import javax.persistence.EnumType; +import javax.persistence.FetchType; +import javax.persistence.JoinColumn; +import javax.persistence.JoinColumns; +import javax.persistence.JoinTable; +import javax.persistence.MapKey; +import javax.persistence.MapKeyClass; +import javax.persistence.MapKeyColumn; +import javax.persistence.MapKeyEnumerated; +import javax.persistence.MapKeyJoinColumn; +import javax.persistence.MapKeyJoinColumns; +import javax.persistence.MapKeyTemporal; +import javax.persistence.OneToMany; +import javax.persistence.OrderBy; +import javax.persistence.OrderColumn; +import javax.persistence.TemporalType; +import javax.persistence.UniqueConstraint; + +import org.hibernate.cfg.annotations.reflection.JPAOverriddenAnnotationReader; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * Equivalent to {@link org.hibernate.test.annotations.xml.ejb3.Ejb3XmlOneToManyTest} + * for the legacy {@link JPAOverriddenAnnotationReader}. + * + * @author Emmanuel Bernard + * @deprecated This test will be removed in Hibernate ORM 6, along with the legacy {@link JPAOverriddenAnnotationReader}. + */ +@Deprecated +public class LegacyEjb3XmlOneToManyTest extends LegacyEjb3XmlTestCase { + @Test + public void testNoChildren() throws Exception { + reader = getReader( Entity2.class, "field1", "one-to-many.orm1.xml" ); + assertAnnotationPresent( OneToMany.class ); + assertAnnotationNotPresent( OrderBy.class ); + assertAnnotationNotPresent( OrderColumn.class ); + assertAnnotationNotPresent( MapKey.class ); + assertAnnotationNotPresent( MapKeyClass.class ); + assertAnnotationNotPresent( MapKeyTemporal.class ); + assertAnnotationNotPresent( MapKeyEnumerated.class ); + assertAnnotationNotPresent( MapKeyColumn.class ); + assertAnnotationNotPresent( MapKeyJoinColumns.class ); + assertAnnotationNotPresent( MapKeyJoinColumn.class ); + assertAnnotationNotPresent( JoinTable.class ); + assertAnnotationNotPresent( JoinColumns.class ); + assertAnnotationNotPresent( JoinColumn.class ); + assertAnnotationNotPresent( Access.class ); + OneToMany relAnno = reader.getAnnotation( OneToMany.class ); + assertEquals( 0, relAnno.cascade().length ); + assertEquals( FetchType.LAZY, relAnno.fetch() ); + assertEquals( "", relAnno.mappedBy() ); + assertFalse( relAnno.orphanRemoval() ); + assertEquals( void.class, relAnno.targetEntity() ); + } + + @Test + public void testOrderBy() throws Exception { + reader = getReader( Entity2.class, "field1", "one-to-many.orm2.xml" ); + assertAnnotationPresent( OneToMany.class ); + assertAnnotationPresent( OrderBy.class ); + assertAnnotationNotPresent( OrderColumn.class ); + assertEquals( + "col1 ASC, col2 DESC", reader.getAnnotation( OrderBy.class ) + .value() + ); + } + + @Test + public void testOrderColumnNoAttributes() throws Exception { + reader = getReader( Entity2.class, "field1", "one-to-many.orm3.xml" ); + assertAnnotationPresent( OneToMany.class ); + assertAnnotationNotPresent( OrderBy.class ); + assertAnnotationPresent( OrderColumn.class ); + OrderColumn orderColumnAnno = reader.getAnnotation( OrderColumn.class ); + assertEquals( "", orderColumnAnno.columnDefinition() ); + assertEquals( "", orderColumnAnno.name() ); + assertTrue( orderColumnAnno.insertable() ); + assertTrue( orderColumnAnno.nullable() ); + assertTrue( orderColumnAnno.updatable() ); + } + + @Test + public void testOrderColumnAllAttributes() throws Exception { + reader = getReader( Entity2.class, "field1", "one-to-many.orm4.xml" ); + assertAnnotationPresent( OneToMany.class ); + assertAnnotationNotPresent( OrderBy.class ); + assertAnnotationPresent( OrderColumn.class ); + OrderColumn orderColumnAnno = reader.getAnnotation( OrderColumn.class ); + assertEquals( "int", orderColumnAnno.columnDefinition() ); + assertEquals( "col1", orderColumnAnno.name() ); + assertFalse( orderColumnAnno.insertable() ); + assertFalse( orderColumnAnno.nullable() ); + assertFalse( orderColumnAnno.updatable() ); + } + + @Test + public void testMapKeyNoAttributes() throws Exception { + reader = getReader( Entity3.class, "field1", "one-to-many.orm5.xml" ); + assertAnnotationPresent( OneToMany.class ); + assertAnnotationPresent( MapKey.class ); + assertAnnotationNotPresent( MapKeyClass.class ); + assertAnnotationNotPresent( MapKeyTemporal.class ); + assertAnnotationNotPresent( MapKeyEnumerated.class ); + assertAnnotationNotPresent( MapKeyColumn.class ); + assertAnnotationNotPresent( MapKeyJoinColumns.class ); + assertAnnotationNotPresent( MapKeyJoinColumn.class ); + assertEquals( "", reader.getAnnotation( MapKey.class ).name() ); + } + + @Test + public void testMapKeyAllAttributes() throws Exception { + reader = getReader( Entity3.class, "field1", "one-to-many.orm6.xml" ); + assertAnnotationPresent( OneToMany.class ); + assertAnnotationPresent( MapKey.class ); + assertAnnotationNotPresent( MapKeyClass.class ); + assertAnnotationNotPresent( MapKeyTemporal.class ); + assertAnnotationNotPresent( MapKeyEnumerated.class ); + assertAnnotationNotPresent( MapKeyColumn.class ); + assertAnnotationNotPresent( MapKeyJoinColumns.class ); + assertAnnotationNotPresent( MapKeyJoinColumn.class ); + assertEquals( "field2", reader.getAnnotation( MapKey.class ).name() ); + } + + @Test + public void testMapKeyClass() throws Exception { + reader = getReader( Entity3.class, "field1", "one-to-many.orm7.xml" ); + assertAnnotationPresent( OneToMany.class ); + assertAnnotationNotPresent( MapKey.class ); + assertAnnotationPresent( MapKeyClass.class ); + assertAnnotationNotPresent( MapKeyTemporal.class ); + assertAnnotationNotPresent( MapKeyEnumerated.class ); + assertAnnotationNotPresent( MapKeyColumn.class ); + assertAnnotationNotPresent( MapKeyJoinColumns.class ); + assertAnnotationNotPresent( MapKeyJoinColumn.class ); + assertEquals( + Entity2.class, reader.getAnnotation( MapKeyClass.class ) + .value() + ); + } + + @Test + public void testMapKeyTemporal() throws Exception { + reader = getReader( Entity3.class, "field1", "one-to-many.orm8.xml" ); + assertAnnotationPresent( OneToMany.class ); + assertAnnotationNotPresent( MapKey.class ); + assertAnnotationNotPresent( MapKeyClass.class ); + assertAnnotationPresent( MapKeyTemporal.class ); + assertAnnotationNotPresent( MapKeyEnumerated.class ); + assertAnnotationNotPresent( MapKeyColumn.class ); + assertAnnotationNotPresent( MapKeyJoinColumns.class ); + assertAnnotationNotPresent( MapKeyJoinColumn.class ); + assertEquals( + TemporalType.DATE, reader.getAnnotation( + MapKeyTemporal.class + ).value() + ); + } + + @Test + public void testMapKeyEnumerated() throws Exception { + reader = getReader( Entity3.class, "field1", "one-to-many.orm9.xml" ); + assertAnnotationPresent( OneToMany.class ); + assertAnnotationNotPresent( MapKey.class ); + assertAnnotationNotPresent( MapKeyClass.class ); + assertAnnotationNotPresent( MapKeyTemporal.class ); + assertAnnotationPresent( MapKeyEnumerated.class ); + assertAnnotationNotPresent( MapKeyColumn.class ); + assertAnnotationNotPresent( MapKeyJoinColumns.class ); + assertAnnotationNotPresent( MapKeyJoinColumn.class ); + assertEquals( + EnumType.STRING, reader.getAnnotation( + MapKeyEnumerated.class + ).value() + ); + } + + /** + * When there's a single map key attribute override, we still wrap it with + * an AttributeOverrides annotation. + */ + @Test + public void testSingleMapKeyAttributeOverride() throws Exception { + reader = getReader( Entity3.class, "field1", "one-to-many.orm10.xml" ); + assertAnnotationPresent( OneToMany.class ); + assertAnnotationNotPresent( MapKey.class ); + assertAnnotationNotPresent( MapKeyClass.class ); + assertAnnotationNotPresent( MapKeyTemporal.class ); + assertAnnotationNotPresent( MapKeyEnumerated.class ); + assertAnnotationNotPresent( MapKeyColumn.class ); + assertAnnotationNotPresent( MapKeyJoinColumns.class ); + assertAnnotationNotPresent( MapKeyJoinColumn.class ); + assertAnnotationNotPresent( AttributeOverride.class ); + assertAnnotationPresent( AttributeOverrides.class ); + AttributeOverrides overridesAnno = reader + .getAnnotation( AttributeOverrides.class ); + AttributeOverride[] overrides = overridesAnno.value(); + assertEquals( 1, overrides.length ); + assertEquals( "field1", overrides[0].name() ); + assertEquals( "col1", overrides[0].column().name() ); + } + + @Test + public void testMultipleMapKeyAttributeOverrides() throws Exception { + reader = getReader( Entity3.class, "field1", "one-to-many.orm11.xml" ); + assertAnnotationPresent( OneToMany.class ); + assertAnnotationNotPresent( MapKey.class ); + assertAnnotationNotPresent( MapKeyClass.class ); + assertAnnotationNotPresent( MapKeyTemporal.class ); + assertAnnotationNotPresent( MapKeyEnumerated.class ); + assertAnnotationNotPresent( MapKeyColumn.class ); + assertAnnotationNotPresent( MapKeyJoinColumns.class ); + assertAnnotationNotPresent( MapKeyJoinColumn.class ); + assertAnnotationNotPresent( AttributeOverride.class ); + assertAnnotationPresent( AttributeOverrides.class ); + AttributeOverrides overridesAnno = reader + .getAnnotation( AttributeOverrides.class ); + AttributeOverride[] overrides = overridesAnno.value(); + assertEquals( 2, overrides.length ); + assertEquals( "field1", overrides[0].name() ); + assertEquals( "", overrides[0].column().name() ); + assertFalse( overrides[0].column().unique() ); + assertTrue( overrides[0].column().nullable() ); + assertTrue( overrides[0].column().insertable() ); + assertTrue( overrides[0].column().updatable() ); + assertEquals( "", overrides[0].column().columnDefinition() ); + assertEquals( "", overrides[0].column().table() ); + assertEquals( 255, overrides[0].column().length() ); + assertEquals( 0, overrides[0].column().precision() ); + assertEquals( 0, overrides[0].column().scale() ); + assertEquals( "field2", overrides[1].name() ); + assertEquals( "col1", overrides[1].column().name() ); + assertTrue( overrides[1].column().unique() ); + assertFalse( overrides[1].column().nullable() ); + assertFalse( overrides[1].column().insertable() ); + assertFalse( overrides[1].column().updatable() ); + assertEquals( "int", overrides[1].column().columnDefinition() ); + assertEquals( "table1", overrides[1].column().table() ); + assertEquals( 50, overrides[1].column().length() ); + assertEquals( 2, overrides[1].column().precision() ); + assertEquals( 1, overrides[1].column().scale() ); + } + + @Test + public void testMapKeyColumnNoAttributes() throws Exception { + reader = getReader( Entity3.class, "field1", "one-to-many.orm12.xml" ); + assertAnnotationPresent( OneToMany.class ); + assertAnnotationNotPresent( MapKey.class ); + assertAnnotationNotPresent( MapKeyClass.class ); + assertAnnotationNotPresent( MapKeyTemporal.class ); + assertAnnotationNotPresent( MapKeyEnumerated.class ); + assertAnnotationPresent( MapKeyColumn.class ); + assertAnnotationNotPresent( MapKeyJoinColumns.class ); + assertAnnotationNotPresent( MapKeyJoinColumn.class ); + MapKeyColumn keyColAnno = reader.getAnnotation( MapKeyColumn.class ); + assertEquals( "", keyColAnno.columnDefinition() ); + assertEquals( "", keyColAnno.name() ); + assertEquals( "", keyColAnno.table() ); + assertFalse( keyColAnno.nullable() ); + assertTrue( keyColAnno.insertable() ); + assertFalse( keyColAnno.unique() ); + assertTrue( keyColAnno.updatable() ); + assertEquals( 255, keyColAnno.length() ); + assertEquals( 0, keyColAnno.precision() ); + assertEquals( 0, keyColAnno.scale() ); + } + + @Test + public void testMapKeyColumnAllAttributes() throws Exception { + reader = getReader( Entity3.class, "field1", "one-to-many.orm13.xml" ); + assertAnnotationPresent( OneToMany.class ); + assertAnnotationNotPresent( MapKey.class ); + assertAnnotationNotPresent( MapKeyClass.class ); + assertAnnotationNotPresent( MapKeyTemporal.class ); + assertAnnotationNotPresent( MapKeyEnumerated.class ); + assertAnnotationPresent( MapKeyColumn.class ); + assertAnnotationNotPresent( MapKeyJoinColumns.class ); + assertAnnotationNotPresent( MapKeyJoinColumn.class ); + MapKeyColumn keyColAnno = reader.getAnnotation( MapKeyColumn.class ); + assertEquals( "int", keyColAnno.columnDefinition() ); + assertEquals( "col1", keyColAnno.name() ); + assertEquals( "table1", keyColAnno.table() ); + assertTrue( keyColAnno.nullable() ); + assertFalse( keyColAnno.insertable() ); + assertTrue( keyColAnno.unique() ); + assertFalse( keyColAnno.updatable() ); + assertEquals( 50, keyColAnno.length() ); + assertEquals( 2, keyColAnno.precision() ); + assertEquals( 1, keyColAnno.scale() ); + } + + /** + * When there's a single map key join column, we still wrap it with a + * MapKeyJoinColumns annotation. + */ + @Test + public void testSingleMapKeyJoinColumn() throws Exception { + reader = getReader( Entity3.class, "field1", "one-to-many.orm14.xml" ); + assertAnnotationPresent( OneToMany.class ); + assertAnnotationNotPresent( MapKey.class ); + assertAnnotationNotPresent( MapKeyClass.class ); + assertAnnotationNotPresent( MapKeyTemporal.class ); + assertAnnotationNotPresent( MapKeyEnumerated.class ); + assertAnnotationNotPresent( MapKeyColumn.class ); + assertAnnotationPresent( MapKeyJoinColumns.class ); + assertAnnotationNotPresent( MapKeyJoinColumn.class ); + MapKeyJoinColumns joinColumnsAnno = reader + .getAnnotation( MapKeyJoinColumns.class ); + MapKeyJoinColumn[] joinColumns = joinColumnsAnno.value(); + assertEquals( 1, joinColumns.length ); + assertEquals( "col1", joinColumns[0].name() ); + } + + @Test + public void testMultipleMapKeyJoinColumns() throws Exception { + reader = getReader( Entity3.class, "field1", "one-to-many.orm15.xml" ); + assertAnnotationPresent( OneToMany.class ); + assertAnnotationNotPresent( MapKey.class ); + assertAnnotationNotPresent( MapKeyClass.class ); + assertAnnotationNotPresent( MapKeyTemporal.class ); + assertAnnotationNotPresent( MapKeyEnumerated.class ); + assertAnnotationNotPresent( MapKeyColumn.class ); + assertAnnotationPresent( MapKeyJoinColumns.class ); + assertAnnotationNotPresent( MapKeyJoinColumn.class ); + MapKeyJoinColumns joinColumnsAnno = reader + .getAnnotation( MapKeyJoinColumns.class ); + MapKeyJoinColumn[] joinColumns = joinColumnsAnno.value(); + assertEquals( 2, joinColumns.length ); + assertEquals( "", joinColumns[0].name() ); + assertEquals( "", joinColumns[0].referencedColumnName() ); + assertFalse( joinColumns[0].unique() ); + assertFalse( joinColumns[0].nullable() ); + assertTrue( joinColumns[0].insertable() ); + assertTrue( joinColumns[0].updatable() ); + assertEquals( "", joinColumns[0].columnDefinition() ); + assertEquals( "", joinColumns[0].table() ); + assertEquals( "col1", joinColumns[1].name() ); + assertEquals( "col2", joinColumns[1].referencedColumnName() ); + assertTrue( joinColumns[1].unique() ); + assertTrue( joinColumns[1].nullable() ); + assertFalse( joinColumns[1].insertable() ); + assertFalse( joinColumns[1].updatable() ); + assertEquals( "int", joinColumns[1].columnDefinition() ); + assertEquals( "table1", joinColumns[1].table() ); + } + + @Test + public void testJoinTableNoChildren() throws Exception { + reader = getReader( Entity2.class, "field1", "one-to-many.orm16.xml" ); + assertAnnotationPresent( OneToMany.class ); + assertAnnotationPresent( JoinTable.class ); + assertAnnotationNotPresent( JoinColumns.class ); + assertAnnotationNotPresent( JoinColumn.class ); + JoinTable joinTableAnno = reader.getAnnotation( JoinTable.class ); + assertEquals( "", joinTableAnno.catalog() ); + assertEquals( "", joinTableAnno.name() ); + assertEquals( "", joinTableAnno.schema() ); + assertEquals( 0, joinTableAnno.joinColumns().length ); + assertEquals( 0, joinTableAnno.inverseJoinColumns().length ); + assertEquals( 0, joinTableAnno.uniqueConstraints().length ); + } + + @Test + public void testJoinTableAllChildren() throws Exception { + reader = getReader( Entity2.class, "field1", "one-to-many.orm17.xml" ); + assertAnnotationPresent( OneToMany.class ); + assertAnnotationPresent( JoinTable.class ); + assertAnnotationNotPresent( JoinColumns.class ); + assertAnnotationNotPresent( JoinColumn.class ); + JoinTable joinTableAnno = reader.getAnnotation( JoinTable.class ); + assertEquals( "cat1", joinTableAnno.catalog() ); + assertEquals( "table1", joinTableAnno.name() ); + assertEquals( "schema1", joinTableAnno.schema() ); + + // JoinColumns + JoinColumn[] joinColumns = joinTableAnno.joinColumns(); + assertEquals( 2, joinColumns.length ); + assertEquals( "", joinColumns[0].name() ); + assertEquals( "", joinColumns[0].referencedColumnName() ); + assertEquals( "", joinColumns[0].table() ); + assertEquals( "", joinColumns[0].columnDefinition() ); + assertTrue( joinColumns[0].insertable() ); + assertTrue( joinColumns[0].updatable() ); + assertTrue( joinColumns[0].nullable() ); + assertFalse( joinColumns[0].unique() ); + assertEquals( "col1", joinColumns[1].name() ); + assertEquals( "col2", joinColumns[1].referencedColumnName() ); + assertEquals( "table2", joinColumns[1].table() ); + assertEquals( "int", joinColumns[1].columnDefinition() ); + assertFalse( joinColumns[1].insertable() ); + assertFalse( joinColumns[1].updatable() ); + assertFalse( joinColumns[1].nullable() ); + assertTrue( joinColumns[1].unique() ); + + // InverseJoinColumns + JoinColumn[] inverseJoinColumns = joinTableAnno.inverseJoinColumns(); + assertEquals( 2, inverseJoinColumns.length ); + assertEquals( "", inverseJoinColumns[0].name() ); + assertEquals( "", inverseJoinColumns[0].referencedColumnName() ); + assertEquals( "", inverseJoinColumns[0].table() ); + assertEquals( "", inverseJoinColumns[0].columnDefinition() ); + assertTrue( inverseJoinColumns[0].insertable() ); + assertTrue( inverseJoinColumns[0].updatable() ); + assertTrue( inverseJoinColumns[0].nullable() ); + assertFalse( inverseJoinColumns[0].unique() ); + assertEquals( "col3", inverseJoinColumns[1].name() ); + assertEquals( "col4", inverseJoinColumns[1].referencedColumnName() ); + assertEquals( "table3", inverseJoinColumns[1].table() ); + assertEquals( "int", inverseJoinColumns[1].columnDefinition() ); + assertFalse( inverseJoinColumns[1].insertable() ); + assertFalse( inverseJoinColumns[1].updatable() ); + assertFalse( inverseJoinColumns[1].nullable() ); + assertTrue( inverseJoinColumns[1].unique() ); + + // UniqueConstraints + UniqueConstraint[] uniqueConstraints = joinTableAnno + .uniqueConstraints(); + assertEquals( 2, uniqueConstraints.length ); + assertEquals( "", uniqueConstraints[0].name() ); + assertEquals( 1, uniqueConstraints[0].columnNames().length ); + assertEquals( "col5", uniqueConstraints[0].columnNames()[0] ); + assertEquals( "uq1", uniqueConstraints[1].name() ); + assertEquals( 2, uniqueConstraints[1].columnNames().length ); + assertEquals( "col6", uniqueConstraints[1].columnNames()[0] ); + assertEquals( "col7", uniqueConstraints[1].columnNames()[1] ); + } + + /** + * When there's a single join column, we still wrap it with a JoinColumns + * annotation. + */ + @Test + public void testSingleJoinColumn() throws Exception { + reader = getReader( Entity2.class, "field1", "one-to-many.orm18.xml" ); + assertAnnotationPresent( OneToMany.class ); + assertAnnotationNotPresent( JoinColumn.class ); + assertAnnotationPresent( JoinColumns.class ); + assertAnnotationNotPresent( JoinTable.class ); + JoinColumns joinColumnsAnno = reader.getAnnotation( JoinColumns.class ); + JoinColumn[] joinColumns = joinColumnsAnno.value(); + assertEquals( 1, joinColumns.length ); + assertEquals( "col1", joinColumns[0].name() ); + assertEquals( "col2", joinColumns[0].referencedColumnName() ); + assertEquals( "table1", joinColumns[0].table() ); + } + + @Test + public void testMultipleJoinColumns() throws Exception { + reader = getReader( Entity2.class, "field1", "one-to-many.orm19.xml" ); + assertAnnotationPresent( OneToMany.class ); + assertAnnotationNotPresent( JoinColumn.class ); + assertAnnotationPresent( JoinColumns.class ); + assertAnnotationNotPresent( JoinTable.class ); + JoinColumns joinColumnsAnno = reader.getAnnotation( JoinColumns.class ); + JoinColumn[] joinColumns = joinColumnsAnno.value(); + assertEquals( 2, joinColumns.length ); + assertEquals( "", joinColumns[0].name() ); + assertEquals( "", joinColumns[0].referencedColumnName() ); + assertEquals( "", joinColumns[0].table() ); + assertEquals( "", joinColumns[0].columnDefinition() ); + assertTrue( joinColumns[0].insertable() ); + assertTrue( joinColumns[0].updatable() ); + assertTrue( joinColumns[0].nullable() ); + assertFalse( joinColumns[0].unique() ); + assertEquals( "col1", joinColumns[1].name() ); + assertEquals( "col2", joinColumns[1].referencedColumnName() ); + assertEquals( "table1", joinColumns[1].table() ); + assertEquals( "int", joinColumns[1].columnDefinition() ); + assertFalse( joinColumns[1].insertable() ); + assertFalse( joinColumns[1].updatable() ); + assertFalse( joinColumns[1].nullable() ); + assertTrue( joinColumns[1].unique() ); + } + + @Test + public void testCascadeAll() throws Exception { + reader = getReader( Entity2.class, "field1", "one-to-many.orm20.xml" ); + assertAnnotationPresent( OneToMany.class ); + OneToMany relAnno = reader.getAnnotation( OneToMany.class ); + assertEquals( 1, relAnno.cascade().length ); + assertEquals( CascadeType.ALL, relAnno.cascade()[0] ); + } + + @Test + public void testCascadeSomeWithDefaultPersist() throws Exception { + reader = getReader( Entity2.class, "field1", "one-to-many.orm21.xml" ); + assertAnnotationPresent( OneToMany.class ); + OneToMany relAnno = reader.getAnnotation( OneToMany.class ); + assertEquals( 4, relAnno.cascade().length ); + assertEquals( CascadeType.REMOVE, relAnno.cascade()[0] ); + assertEquals( CascadeType.REFRESH, relAnno.cascade()[1] ); + assertEquals( CascadeType.DETACH, relAnno.cascade()[2] ); + assertEquals( CascadeType.PERSIST, relAnno.cascade()[3] ); + } + + /** + * Make sure that it doesn't break the handler when {@link CascadeType#ALL} + * is specified in addition to a default cascade-persist or individual + * cascade settings. + */ + @Test + public void testCascadeAllPlusMore() throws Exception { + reader = getReader( Entity2.class, "field1", "one-to-many.orm22.xml" ); + assertAnnotationPresent( OneToMany.class ); + OneToMany relAnno = reader.getAnnotation( OneToMany.class ); + assertEquals( 6, relAnno.cascade().length ); + assertEquals( CascadeType.ALL, relAnno.cascade()[0] ); + assertEquals( CascadeType.PERSIST, relAnno.cascade()[1] ); + assertEquals( CascadeType.MERGE, relAnno.cascade()[2] ); + assertEquals( CascadeType.REMOVE, relAnno.cascade()[3] ); + assertEquals( CascadeType.REFRESH, relAnno.cascade()[4] ); + assertEquals( CascadeType.DETACH, relAnno.cascade()[5] ); + } + + @Test + public void testAllAttributes() throws Exception { + reader = getReader( Entity2.class, "field1", "one-to-many.orm23.xml" ); + assertAnnotationPresent( OneToMany.class ); + assertAnnotationNotPresent( OrderBy.class ); + assertAnnotationNotPresent( OrderColumn.class ); + assertAnnotationNotPresent( MapKey.class ); + assertAnnotationNotPresent( MapKeyClass.class ); + assertAnnotationNotPresent( MapKeyTemporal.class ); + assertAnnotationNotPresent( MapKeyEnumerated.class ); + assertAnnotationNotPresent( MapKeyColumn.class ); + assertAnnotationNotPresent( MapKeyJoinColumns.class ); + assertAnnotationNotPresent( MapKeyJoinColumn.class ); + assertAnnotationNotPresent( JoinTable.class ); + assertAnnotationNotPresent( JoinColumns.class ); + assertAnnotationNotPresent( JoinColumn.class ); + assertAnnotationPresent( Access.class ); + OneToMany relAnno = reader.getAnnotation( OneToMany.class ); + assertEquals( 0, relAnno.cascade().length ); + assertEquals( FetchType.EAGER, relAnno.fetch() ); + assertEquals( "field2", relAnno.mappedBy() ); + assertTrue( relAnno.orphanRemoval() ); + assertEquals( Entity3.class, relAnno.targetEntity() ); + assertEquals( + AccessType.PROPERTY, reader.getAnnotation( Access.class ) + .value() + ); + } + +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlOneToOneTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlOneToOneTest.java new file mode 100644 index 000000000000..45c5e5e8448b --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlOneToOneTest.java @@ -0,0 +1,309 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.annotations.xml.ejb3; + +import javax.persistence.Access; +import javax.persistence.AccessType; +import javax.persistence.CascadeType; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.JoinColumns; +import javax.persistence.JoinTable; +import javax.persistence.MapsId; +import javax.persistence.OneToOne; +import javax.persistence.PrimaryKeyJoinColumn; +import javax.persistence.PrimaryKeyJoinColumns; +import javax.persistence.UniqueConstraint; + +import org.hibernate.cfg.annotations.reflection.JPAOverriddenAnnotationReader; + +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +/** + * Equivalent to {@link org.hibernate.test.annotations.xml.ejb3.Ejb3XmlOneToOneTest} + * for the legacy {@link JPAOverriddenAnnotationReader}. + * + * @author Emmanuel Bernard + * @deprecated This test will be removed in Hibernate ORM 6, along with the legacy {@link JPAOverriddenAnnotationReader}. + */ +@Deprecated +public class LegacyEjb3XmlOneToOneTest extends LegacyEjb3XmlTestCase { + @Test + public void testNoChildren() throws Exception { + reader = getReader( Entity1.class, "field1", "one-to-one.orm1.xml" ); + assertAnnotationPresent( OneToOne.class ); + assertAnnotationNotPresent( MapsId.class ); + assertAnnotationNotPresent( Id.class ); + assertAnnotationNotPresent( PrimaryKeyJoinColumn.class ); + assertAnnotationNotPresent( PrimaryKeyJoinColumns.class ); + assertAnnotationNotPresent( JoinColumns.class ); + assertAnnotationNotPresent( JoinColumn.class ); + assertAnnotationNotPresent( JoinTable.class ); + assertAnnotationNotPresent( Access.class ); + OneToOne relAnno = reader.getAnnotation( OneToOne.class ); + assertEquals( 0, relAnno.cascade().length ); + assertEquals( FetchType.EAGER, relAnno.fetch() ); + assertEquals( "", relAnno.mappedBy() ); + assertTrue( relAnno.optional() ); + assertFalse( relAnno.orphanRemoval() ); + assertEquals( void.class, relAnno.targetEntity() ); + } + + /** + * When there's a single primary key join column, we still wrap it with + * a PrimaryKeyJoinColumns annotation. + */ + @Test + public void testSinglePrimaryKeyJoinColumn() throws Exception { + reader = getReader( Entity1.class, "field1", "one-to-one.orm2.xml" ); + assertAnnotationPresent( OneToOne.class ); + assertAnnotationNotPresent( PrimaryKeyJoinColumn.class ); + assertAnnotationPresent( PrimaryKeyJoinColumns.class ); + PrimaryKeyJoinColumns joinColumnsAnno = + reader.getAnnotation( PrimaryKeyJoinColumns.class ); + assertAnnotationNotPresent( JoinColumns.class ); + assertAnnotationNotPresent( JoinColumn.class ); + assertAnnotationNotPresent( JoinTable.class ); + PrimaryKeyJoinColumn[] joinColumns = joinColumnsAnno.value(); + assertEquals( 1, joinColumns.length ); + assertEquals( "col1", joinColumns[0].name() ); + assertEquals( "col2", joinColumns[0].referencedColumnName() ); + assertEquals( "int", joinColumns[0].columnDefinition() ); + } + + @Test + public void testMultiplePrimaryKeyJoinColumn() throws Exception { + reader = getReader( Entity1.class, "field1", "one-to-one.orm3.xml" ); + assertAnnotationPresent( OneToOne.class ); + assertAnnotationNotPresent( PrimaryKeyJoinColumn.class ); + assertAnnotationPresent( PrimaryKeyJoinColumns.class ); + assertAnnotationNotPresent( JoinColumns.class ); + assertAnnotationNotPresent( JoinColumn.class ); + assertAnnotationNotPresent( JoinTable.class ); + PrimaryKeyJoinColumns joinColumnsAnno = + reader.getAnnotation( PrimaryKeyJoinColumns.class ); + PrimaryKeyJoinColumn[] joinColumns = joinColumnsAnno.value(); + assertEquals( 2, joinColumns.length ); + assertEquals( "", joinColumns[0].name() ); + assertEquals( "", joinColumns[0].referencedColumnName() ); + assertEquals( "", joinColumns[0].columnDefinition() ); + assertEquals( "col1", joinColumns[1].name() ); + assertEquals( "col2", joinColumns[1].referencedColumnName() ); + assertEquals( "int", joinColumns[1].columnDefinition() ); + } + + /** + * When there's a single join column, we still wrap it with a JoinColumns + * annotation. + */ + @Test + public void testSingleJoinColumn() throws Exception { + reader = getReader( Entity1.class, "field1", "one-to-one.orm4.xml" ); + assertAnnotationPresent( OneToOne.class ); + assertAnnotationNotPresent( PrimaryKeyJoinColumn.class ); + assertAnnotationNotPresent( PrimaryKeyJoinColumns.class ); + assertAnnotationPresent( JoinColumns.class ); + assertAnnotationNotPresent( JoinColumn.class ); + assertAnnotationNotPresent( JoinTable.class ); + JoinColumns joinColumnsAnno = reader.getAnnotation( JoinColumns.class ); + JoinColumn[] joinColumns = joinColumnsAnno.value(); + assertEquals( 1, joinColumns.length ); + assertEquals( "col1", joinColumns[0].name() ); + assertEquals( "col2", joinColumns[0].referencedColumnName() ); + assertEquals( "table1", joinColumns[0].table() ); + } + + @Test + public void testMultipleJoinColumns() throws Exception { + reader = getReader( Entity1.class, "field1", "one-to-one.orm5.xml" ); + assertAnnotationPresent( OneToOne.class ); + assertAnnotationNotPresent( PrimaryKeyJoinColumn.class ); + assertAnnotationNotPresent( PrimaryKeyJoinColumns.class ); + assertAnnotationNotPresent( JoinColumn.class ); + assertAnnotationPresent( JoinColumns.class ); + assertAnnotationNotPresent( JoinTable.class ); + JoinColumns joinColumnsAnno = reader.getAnnotation( JoinColumns.class ); + JoinColumn[] joinColumns = joinColumnsAnno.value(); + assertEquals( 2, joinColumns.length ); + assertEquals( "", joinColumns[0].name() ); + assertEquals( "", joinColumns[0].referencedColumnName() ); + assertEquals( "", joinColumns[0].table() ); + assertEquals( "", joinColumns[0].columnDefinition() ); + assertTrue( joinColumns[0].insertable() ); + assertTrue( joinColumns[0].updatable() ); + assertTrue( joinColumns[0].nullable() ); + assertFalse( joinColumns[0].unique() ); + assertEquals( "col1", joinColumns[1].name() ); + assertEquals( "col2", joinColumns[1].referencedColumnName() ); + assertEquals( "table1", joinColumns[1].table() ); + assertEquals( "int", joinColumns[1].columnDefinition() ); + assertFalse( joinColumns[1].insertable() ); + assertFalse( joinColumns[1].updatable() ); + assertFalse( joinColumns[1].nullable() ); + assertTrue( joinColumns[1].unique() ); + } + + @Test + public void testJoinTableNoChildren() throws Exception { + reader = getReader( Entity1.class, "field1", "one-to-one.orm6.xml" ); + assertAnnotationPresent( OneToOne.class ); + assertAnnotationNotPresent( PrimaryKeyJoinColumn.class ); + assertAnnotationNotPresent( PrimaryKeyJoinColumns.class ); + assertAnnotationPresent( JoinTable.class ); + assertAnnotationNotPresent( JoinColumns.class ); + assertAnnotationNotPresent( JoinColumn.class ); + JoinTable joinTableAnno = reader.getAnnotation( JoinTable.class ); + assertEquals( "", joinTableAnno.catalog() ); + assertEquals( "", joinTableAnno.name() ); + assertEquals( "", joinTableAnno.schema() ); + assertEquals( 0, joinTableAnno.joinColumns().length ); + assertEquals( 0, joinTableAnno.inverseJoinColumns().length ); + assertEquals( 0, joinTableAnno.uniqueConstraints().length ); + } + + @Test + public void testJoinTableAllChildren() throws Exception { + reader = getReader( Entity1.class, "field1", "one-to-one.orm7.xml" ); + assertAnnotationPresent( OneToOne.class ); + assertAnnotationNotPresent( PrimaryKeyJoinColumn.class ); + assertAnnotationNotPresent( PrimaryKeyJoinColumns.class ); + assertAnnotationPresent( JoinTable.class ); + assertAnnotationNotPresent( JoinColumns.class ); + assertAnnotationNotPresent( JoinColumn.class ); + JoinTable joinTableAnno = reader.getAnnotation( JoinTable.class ); + assertEquals( "cat1", joinTableAnno.catalog() ); + assertEquals( "table1", joinTableAnno.name() ); + assertEquals( "schema1", joinTableAnno.schema() ); + + // JoinColumns + JoinColumn[] joinColumns = joinTableAnno.joinColumns(); + assertEquals( 2, joinColumns.length ); + assertEquals( "", joinColumns[0].name() ); + assertEquals( "", joinColumns[0].referencedColumnName() ); + assertEquals( "", joinColumns[0].table() ); + assertEquals( "", joinColumns[0].columnDefinition() ); + assertTrue( joinColumns[0].insertable() ); + assertTrue( joinColumns[0].updatable() ); + assertTrue( joinColumns[0].nullable() ); + assertFalse( joinColumns[0].unique() ); + assertEquals( "col1", joinColumns[1].name() ); + assertEquals( "col2", joinColumns[1].referencedColumnName() ); + assertEquals( "table2", joinColumns[1].table() ); + assertEquals( "int", joinColumns[1].columnDefinition() ); + assertFalse( joinColumns[1].insertable() ); + assertFalse( joinColumns[1].updatable() ); + assertFalse( joinColumns[1].nullable() ); + assertTrue( joinColumns[1].unique() ); + + // InverseJoinColumns + JoinColumn[] inverseJoinColumns = joinTableAnno.inverseJoinColumns(); + assertEquals( 2, inverseJoinColumns.length ); + assertEquals( "", inverseJoinColumns[0].name() ); + assertEquals( "", inverseJoinColumns[0].referencedColumnName() ); + assertEquals( "", inverseJoinColumns[0].table() ); + assertEquals( "", inverseJoinColumns[0].columnDefinition() ); + assertTrue( inverseJoinColumns[0].insertable() ); + assertTrue( inverseJoinColumns[0].updatable() ); + assertTrue( inverseJoinColumns[0].nullable() ); + assertFalse( inverseJoinColumns[0].unique() ); + assertEquals( "col3", inverseJoinColumns[1].name() ); + assertEquals( "col4", inverseJoinColumns[1].referencedColumnName() ); + assertEquals( "table3", inverseJoinColumns[1].table() ); + assertEquals( "int", inverseJoinColumns[1].columnDefinition() ); + assertFalse( inverseJoinColumns[1].insertable() ); + assertFalse( inverseJoinColumns[1].updatable() ); + assertFalse( inverseJoinColumns[1].nullable() ); + assertTrue( inverseJoinColumns[1].unique() ); + + // UniqueConstraints + UniqueConstraint[] uniqueConstraints = joinTableAnno + .uniqueConstraints(); + assertEquals( 2, uniqueConstraints.length ); + assertEquals( "", uniqueConstraints[0].name() ); + assertEquals( 1, uniqueConstraints[0].columnNames().length ); + assertEquals( "col5", uniqueConstraints[0].columnNames()[0] ); + assertEquals( "uq1", uniqueConstraints[1].name() ); + assertEquals( 2, uniqueConstraints[1].columnNames().length ); + assertEquals( "col6", uniqueConstraints[1].columnNames()[0] ); + assertEquals( "col7", uniqueConstraints[1].columnNames()[1] ); + } + + @Test + public void testCascadeAll() throws Exception { + reader = getReader( Entity1.class, "field1", "one-to-one.orm8.xml" ); + assertAnnotationPresent( OneToOne.class ); + OneToOne relAnno = reader.getAnnotation( OneToOne.class ); + assertEquals( 1, relAnno.cascade().length ); + assertEquals( CascadeType.ALL, relAnno.cascade()[0] ); + } + + @Test + public void testCascadeSomeWithDefaultPersist() throws Exception { + reader = getReader( Entity1.class, "field1", "one-to-one.orm9.xml" ); + assertAnnotationPresent( OneToOne.class ); + OneToOne relAnno = reader.getAnnotation( OneToOne.class ); + assertEquals( 4, relAnno.cascade().length ); + assertEquals( CascadeType.REMOVE, relAnno.cascade()[0] ); + assertEquals( CascadeType.REFRESH, relAnno.cascade()[1] ); + assertEquals( CascadeType.DETACH, relAnno.cascade()[2] ); + assertEquals( CascadeType.PERSIST, relAnno.cascade()[3] ); + } + + /** + * Make sure that it doesn't break the handler when {@link CascadeType#ALL} + * is specified in addition to a default cascade-persist or individual + * cascade settings. + */ + @Test + public void testCascadeAllPlusMore() throws Exception { + reader = getReader( Entity1.class, "field1", "one-to-one.orm10.xml" ); + assertAnnotationPresent( OneToOne.class ); + OneToOne relAnno = reader.getAnnotation( OneToOne.class ); + assertEquals( 6, relAnno.cascade().length ); + assertEquals( CascadeType.ALL, relAnno.cascade()[0] ); + assertEquals( CascadeType.PERSIST, relAnno.cascade()[1] ); + assertEquals( CascadeType.MERGE, relAnno.cascade()[2] ); + assertEquals( CascadeType.REMOVE, relAnno.cascade()[3] ); + assertEquals( CascadeType.REFRESH, relAnno.cascade()[4] ); + assertEquals( CascadeType.DETACH, relAnno.cascade()[5] ); + } + + @Test + public void testAllAttributes() throws Exception { + reader = getReader( Entity1.class, "field1", "one-to-one.orm11.xml" ); + assertAnnotationPresent( OneToOne.class ); + assertAnnotationPresent( MapsId.class ); + assertAnnotationPresent( Id.class ); + assertAnnotationNotPresent( PrimaryKeyJoinColumn.class ); + assertAnnotationNotPresent( PrimaryKeyJoinColumns.class ); + assertAnnotationNotPresent( JoinColumns.class ); + assertAnnotationNotPresent( JoinColumn.class ); + assertAnnotationNotPresent( JoinTable.class ); + assertAnnotationPresent( Access.class ); + OneToOne relAnno = reader.getAnnotation( OneToOne.class ); + assertEquals( 0, relAnno.cascade().length ); + assertEquals( FetchType.LAZY, relAnno.fetch() ); + assertEquals( "field2", relAnno.mappedBy() ); + assertFalse( relAnno.optional() ); + assertTrue( relAnno.orphanRemoval() ); + assertEquals( Entity3.class, relAnno.targetEntity() ); + assertEquals( + AccessType.PROPERTY, reader.getAnnotation( Access.class ) + .value() + ); + assertEquals( + "field3", reader.getAnnotation( MapsId.class ) + .value() + ); + } + +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlTest.java new file mode 100644 index 000000000000..dae470e238c8 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlTest.java @@ -0,0 +1,148 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.annotations.xml.ejb3; + +import java.util.Date; +import java.util.List; + +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.Transaction; +import org.hibernate.cfg.annotations.reflection.JPAOverriddenAnnotationReader; +import org.hibernate.dialect.CockroachDB192Dialect; +import org.hibernate.dialect.PostgreSQL81Dialect; +import org.hibernate.dialect.PostgreSQLDialect; +import org.hibernate.dialect.TeradataDialect; +import org.hibernate.persister.collection.BasicCollectionPersister; + +import org.hibernate.testing.SkipForDialect; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +/** + * Equivalent to {@link org.hibernate.test.annotations.xml.ejb3.Ejb3XmlTest} + * for the legacy {@link JPAOverriddenAnnotationReader}. + * + * @author Emmanuel Bernard + * @deprecated This test will be removed in Hibernate ORM 6, along with the legacy {@link JPAOverriddenAnnotationReader}. + */ +@Deprecated +public class LegacyEjb3XmlTest extends BaseCoreFunctionalTestCase { + @Test + @SkipForDialect(value = {PostgreSQL81Dialect.class, PostgreSQLDialect.class, CockroachDB192Dialect.class}, + comment = "postgresql jdbc driver does not implement the setQueryTimeout method") + @SkipForDialect(value = TeradataDialect.class, + jiraKey = "HHH-8190", + comment = "uses Teradata reserved word - year") + public void testEjb3Xml() throws Exception { + Session s = openSession(); + Transaction tx = s.beginTransaction(); + CarModel model = new CarModel(); + model.setYear( new Date() ); + Manufacturer manufacturer = new Manufacturer(); + //s.persist( manufacturer ); + model.setManufacturer( manufacturer ); + manufacturer.getModels().add( model ); + s.persist( model ); + s.flush(); + s.clear(); + + model.setYear( new Date() ); + manufacturer = (Manufacturer) s.get( Manufacturer.class, manufacturer.getId() ); + @SuppressWarnings("unchecked") + List cars = s.getNamedQuery( "allModelsPerManufacturer" ) + .setParameter( "manufacturer", manufacturer ) + .list(); + assertEquals( 1, cars.size() ); + for ( Model car : cars ) { + assertNotNull( car.getManufacturer() ); + s.delete( manufacturer ); + s.delete( car ); + } + tx.rollback(); + s.close(); + } + + @Test + public void testXMLEntityHandled() throws Exception { + Session s = openSession(); + s.getTransaction().begin(); + Lighter l = new Lighter(); + l.name = "Blue"; + l.power = "400F"; + s.persist( l ); + s.flush(); + s.getTransaction().rollback(); + s.close(); + } + + @Test + public void testXmlDefaultOverriding() throws Exception { + Session s = openSession(); + Transaction tx = s.beginTransaction(); + Manufacturer manufacturer = new Manufacturer(); + s.persist( manufacturer ); + s.flush(); + s.clear(); + + assertEquals( 1, s.getNamedQuery( "manufacturer.findAll" ).list().size() ); + tx.rollback(); + s.close(); + } + + @Test + @SuppressWarnings("unchecked") + public void testMapXMLSupport() throws Exception { + Session s = openSession(); + SessionFactory sf = s.getSessionFactory(); + Transaction tx = s.beginTransaction(); + + // Verify that we can persist an object with a couple Map mappings + VicePresident vpSales = new VicePresident(); + vpSales.name = "Dwight"; + Company company = new Company(); + company.conferenceRoomExtensions.put( "8932", "x1234" ); + company.organization.put( "sales", vpSales ); + s.persist( company ); + s.flush(); + s.clear(); + + // For the element-collection, check that the orm.xml entries are honored. + // This includes: map-key-column/column/collection-table/join-column + BasicCollectionPersister confRoomMeta = (BasicCollectionPersister) sf.getCollectionMetadata( Company.class.getName() + ".conferenceRoomExtensions" ); + assertEquals( "company_id", confRoomMeta.getKeyColumnNames()[0] ); + assertEquals( "phone_extension", confRoomMeta.getElementColumnNames()[0] ); + assertEquals( "room_number", confRoomMeta.getIndexColumnNames()[0] ); + assertEquals( "phone_extension_lookup", confRoomMeta.getTableName() ); + tx.rollback(); + s.close(); + } + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + CarModel.class, + Manufacturer.class, + Model.class, + Light.class + //Lighter.class xml only entuty + }; + } + + @Override + protected String[] getXmlFiles() { + return new String[] { + "org/hibernate/test/annotations/xml/ejb3/orm.xml", + "org/hibernate/test/annotations/xml/ejb3/orm2.xml", + "org/hibernate/test/annotations/xml/ejb3/orm3.xml", + "org/hibernate/test/annotations/xml/ejb3/orm4.xml" + }; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlTestCase.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlTestCase.java new file mode 100644 index 000000000000..e22dfea26ea4 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlTestCase.java @@ -0,0 +1,82 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.annotations.xml.ejb3; + +import java.io.InputStream; +import java.lang.annotation.Annotation; +import java.lang.reflect.AnnotatedElement; + +import org.hibernate.cfg.annotations.reflection.JPAOverriddenAnnotationReader; +import org.hibernate.cfg.annotations.reflection.XMLContext; + +import org.hibernate.testing.boot.BootstrapContextImpl; +import org.hibernate.testing.junit4.BaseUnitTestCase; + +import org.dom4j.Document; +import org.dom4j.io.SAXReader; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +/** + * Test superclass to provide utility methods for testing the mapping of JPA + * XML to JPA annotations. The configuration is built within each test, and no + * database is used. Thus, no schema generation or cleanup will be performed. + *

+ * Equivalent to {@link org.hibernate.test.annotations.xml.ejb3.Ejb3XmlTest} + * for the legacy {@link JPAOverriddenAnnotationReader}. + * + * @author Emmanuel Bernard + * @deprecated This test will be removed in Hibernate ORM 6, along with the legacy {@link JPAOverriddenAnnotationReader}. + */ +@Deprecated +abstract class LegacyEjb3XmlTestCase extends BaseUnitTestCase { + protected JPAOverriddenAnnotationReader reader; + + protected void assertAnnotationPresent(Class annotationType) { + assertTrue( + "Expected annotation " + annotationType.getSimpleName() + " was not present", + reader.isAnnotationPresent( annotationType ) + ); + } + + protected void assertAnnotationNotPresent(Class annotationType) { + assertFalse( + "Unexpected annotation " + annotationType.getSimpleName() + " was present", + reader.isAnnotationPresent( annotationType ) + ); + } + + protected JPAOverriddenAnnotationReader getReader(Class entityClass, String fieldName, String ormResourceName) + throws Exception { + AnnotatedElement el = getAnnotatedElement( entityClass, fieldName ); + XMLContext xmlContext = getContext( ormResourceName ); + return new JPAOverriddenAnnotationReader( el, xmlContext, BootstrapContextImpl.INSTANCE ); + } + + protected AnnotatedElement getAnnotatedElement(Class entityClass, String fieldName) throws Exception { + return entityClass.getDeclaredField( fieldName ); + } + + protected XMLContext getContext(String resourceName) throws Exception { + InputStream is = getClass().getResourceAsStream( resourceName ); + assertNotNull( "Could not load resource " + resourceName, is ); + return getContext( is ); + } + + protected XMLContext getContext(InputStream is) throws Exception { + XMLContext xmlContext = new XMLContext( BootstrapContextImpl.INSTANCE ); + SAXReader reader = new SAXReader(); + reader.setFeature( "http://apache.org/xml/features/nonvalidating/load-external-dtd", false ); + reader.setFeature( "http://xml.org/sax/features/external-general-entities", false ); + reader.setFeature( "http://xml.org/sax/features/external-parameter-entities", false ); + Document doc = reader.read( is ); + xmlContext.addDocument( doc ); + return xmlContext; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyNonExistentOrmVersionTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyNonExistentOrmVersionTest.java new file mode 100644 index 000000000000..74509b879ca3 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyNonExistentOrmVersionTest.java @@ -0,0 +1,42 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.annotations.xml.ejb3; + +import org.hibernate.InvalidMappingException; +import org.hibernate.boot.MetadataSources; +import org.hibernate.cfg.annotations.reflection.JPAOverriddenAnnotationReader; +import org.hibernate.internal.util.xml.UnsupportedOrmXsdVersionException; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseUnitTestCase; +import org.junit.Test; + +import static org.junit.Assert.fail; + +/** + * Equivalent to {@link org.hibernate.test.annotations.xml.ejb3.NonExistentOrmVersionTest} + * for the legacy {@link JPAOverriddenAnnotationReader}. + * + * @author Emmanuel Bernard + * @deprecated This test will be removed in Hibernate ORM 6, along with the legacy {@link JPAOverriddenAnnotationReader}. + */ +@TestForIssue(jiraKey = "HHH-6271") +public class LegacyNonExistentOrmVersionTest extends BaseUnitTestCase { + @Test + public void testNonExistentOrmVersion() { + try { + new MetadataSources() + .addResource( "org/hibernate/test/annotations/xml/ejb3/orm5.xml" ) + .buildMetadata(); + fail( "Expecting failure due to unsupported xsd version" ); + } + catch ( InvalidMappingException expected ) { + } + catch ( UnsupportedOrmXsdVersionException expected ) { + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyOrmVersion1SupportedTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyOrmVersion1SupportedTest.java new file mode 100644 index 000000000000..763b79f605d2 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyOrmVersion1SupportedTest.java @@ -0,0 +1,68 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.annotations.xml.ejb3; + +import org.hibernate.Session; +import org.hibernate.Transaction; +import org.hibernate.cfg.annotations.reflection.JPAOverriddenAnnotationReader; +import org.hibernate.internal.CoreMessageLogger; +import org.hibernate.internal.util.xml.ErrorLogger; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.hibernate.testing.logger.LoggerInspectionRule; +import org.hibernate.testing.logger.Triggerable; +import org.junit.Rule; +import org.junit.Test; + +import org.jboss.logging.Logger; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; + +/** + * Equivalent to {@link org.hibernate.test.annotations.xml.ejb3.OrmVersion1SupportedTest} + * for the legacy {@link JPAOverriddenAnnotationReader}. + * + * @author Emmanuel Bernard + * @deprecated This test will be removed in Hibernate ORM 6, along with the legacy {@link JPAOverriddenAnnotationReader}. + */ +@TestForIssue(jiraKey = "HHH-6271") +public class LegacyOrmVersion1SupportedTest extends BaseCoreFunctionalTestCase { + + @Rule + public LoggerInspectionRule logInspection = new LoggerInspectionRule( + Logger.getMessageLogger( + CoreMessageLogger.class, + ErrorLogger.class.getName() + ) + ); + + @Test + public void testOrm1Support() { + Triggerable triggerable = logInspection.watchForLogMessages( "HHH00196" ); + + Session s = openSession(); + Transaction tx = s.beginTransaction(); + Light light = new Light(); + light.name = "the light at the end of the tunnel"; + s.persist( light ); + s.flush(); + s.clear(); + + assertEquals( 1, s.getNamedQuery( "find.the.light" ).list().size() ); + tx.rollback(); + s.close(); + + assertFalse( triggerable.wasTriggered() ); + } + + @Override + protected String[] getXmlFiles() { + return new String[] { "org/hibernate/test/annotations/xml/ejb3/orm2.xml" }; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyPreParsedOrmXmlTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyPreParsedOrmXmlTest.java new file mode 100644 index 000000000000..9d3e4654b210 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyPreParsedOrmXmlTest.java @@ -0,0 +1,58 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.annotations.xml.ejb3; + +import java.io.IOException; +import java.io.InputStream; +import java.io.UncheckedIOException; + +import org.hibernate.boot.jaxb.spi.Binding; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.annotations.reflection.JPAOverriddenAnnotationReader; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.hibernate.test.annotations.xml.ejb3.PreParsedOrmXmlTest.NonAnnotatedEntity; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +/** + * Equivalent to {@link org.hibernate.test.annotations.xml.ejb3.PreParsedOrmXmlTest} + * for the legacy {@link JPAOverriddenAnnotationReader}. + * + * @author Emmanuel Bernard + * @deprecated This test will be removed in Hibernate ORM 6, along with the legacy {@link JPAOverriddenAnnotationReader}. + */ +@TestForIssue(jiraKey = "HHH-14530") +public class LegacyPreParsedOrmXmlTest extends BaseCoreFunctionalTestCase { + + @Override + protected void addMappings(Configuration configuration) { + super.addMappings( configuration ); + try (InputStream xmlStream = Thread.currentThread().getContextClassLoader() + .getResourceAsStream( "org/hibernate/test/annotations/xml/ejb3/pre-parsed-orm.xml" )) { + Binding parsed = configuration.getXmlMappingBinderAccess().bind( xmlStream ); + configuration.addXmlMapping( parsed ); + } + catch (IOException e) { + throw new UncheckedIOException( e ); + } + } + + @Test + public void testPreParsedOrmXml() { + // Just check that the entity can be persisted, which means the mapping file was taken into account + NonAnnotatedEntity persistedEntity = new NonAnnotatedEntity( "someName" ); + inTransaction( s -> s.persist( persistedEntity ) ); + inTransaction( s -> { + NonAnnotatedEntity retrievedEntity = s.find( NonAnnotatedEntity.class, persistedEntity.getId() ); + assertThat( retrievedEntity ).extracting( NonAnnotatedEntity::getName ) + .isEqualTo( persistedEntity.getName() ); + } ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/NonExistentOrmVersionTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/NonExistentOrmVersionTest.java index 986c9c077e2d..63e9df91b67b 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/NonExistentOrmVersionTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/NonExistentOrmVersionTest.java @@ -8,6 +8,7 @@ import org.hibernate.InvalidMappingException; import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder; import org.hibernate.internal.util.xml.UnsupportedOrmXsdVersionException; import org.hibernate.testing.TestForIssue; @@ -16,12 +17,13 @@ import static org.junit.Assert.fail; -@TestForIssue(jiraKey = "HHH-6271") +@TestForIssue(jiraKey = {"HHH-6271", "HHH-14529"}) public class NonExistentOrmVersionTest extends BaseUnitTestCase { @Test public void testNonExistentOrmVersion() { + // FIXME HHH-14529 configure the BootstrapServiceRegistry to use JAXB for orm.xml mappings try { - new MetadataSources() + new MetadataSources( new BootstrapServiceRegistryBuilder().build() ) .addResource( "org/hibernate/test/annotations/xml/ejb3/orm5.xml" ) .buildMetadata(); fail( "Expecting failure due to unsupported xsd version" ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/OrmVersion1SupportedTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/OrmVersion1SupportedTest.java index 03658267dd2a..f56ccd780edf 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/OrmVersion1SupportedTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/OrmVersion1SupportedTest.java @@ -8,6 +8,7 @@ import org.hibernate.Session; import org.hibernate.Transaction; +import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.xml.ErrorLogger; @@ -23,9 +24,15 @@ import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; -@TestForIssue(jiraKey = "HHH-6271") +@TestForIssue(jiraKey = {"HHH-6271", "HHH-14529"}) public class OrmVersion1SupportedTest extends BaseCoreFunctionalTestCase { + @Override + protected void prepareBootstrapRegistryBuilder(BootstrapServiceRegistryBuilder builder) { + // FIXME HHH-14529 configure the BootstrapServiceRegistry to use JAXB for orm.xml mappings + super.prepareBootstrapRegistryBuilder( builder ); + } + @Rule public LoggerInspectionRule logInspection = new LoggerInspectionRule( Logger.getMessageLogger( diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/PreParsedOrmXmlTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/PreParsedOrmXmlTest.java index 04640901d860..0fa294fe0335 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/PreParsedOrmXmlTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/PreParsedOrmXmlTest.java @@ -11,6 +11,7 @@ import java.io.UncheckedIOException; import org.hibernate.boot.jaxb.spi.Binding; +import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder; import org.hibernate.cfg.Configuration; import org.hibernate.testing.TestForIssue; @@ -19,9 +20,15 @@ import static org.assertj.core.api.Assertions.assertThat; -@TestForIssue(jiraKey = "HHH-14530") +@TestForIssue(jiraKey = {"HHH-14530", "HHH-14529"}) public class PreParsedOrmXmlTest extends BaseCoreFunctionalTestCase { + @Override + protected void prepareBootstrapRegistryBuilder(BootstrapServiceRegistryBuilder builder) { + // FIXME HHH-14529 configure the BootstrapServiceRegistry to use JAXB for orm.xml mappings + super.prepareBootstrapRegistryBuilder( builder ); + } + @Override protected void addMappings(Configuration configuration) { super.addMappings( configuration ); From ef6bb2679bc386a8eaa01ef415381476343cf370 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Fri, 26 Mar 2021 10:36:51 +0100 Subject: [PATCH 095/644] HHH-14529 Remove an unused orm.xml file from tests --- .../org/hibernate/test/cfg/orm-serializable.xml | 15 --------------- 1 file changed, 15 deletions(-) delete mode 100644 hibernate-core/src/test/java/org/hibernate/test/cfg/orm-serializable.xml diff --git a/hibernate-core/src/test/java/org/hibernate/test/cfg/orm-serializable.xml b/hibernate-core/src/test/java/org/hibernate/test/cfg/orm-serializable.xml deleted file mode 100644 index c9620d83b8a0..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/test/cfg/orm-serializable.xml +++ /dev/null @@ -1,15 +0,0 @@ - - - - - - From e8cd9f891752c48f18ae65b435b7afc9a2164419 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Fri, 26 Mar 2021 11:40:03 +0100 Subject: [PATCH 096/644] HHH-14529 Clean up constructors in JPAXMLOverriddenMetadataProvider and related --- .../JPAXMLOverriddenAnnotationReader.java | 6 ++-- .../JPAXMLOverriddenMetadataProvider.java | 35 ++----------------- .../reflection/internal/XMLContext.java | 7 ++-- 3 files changed, 6 insertions(+), 42 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenAnnotationReader.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenAnnotationReader.java index 4e2a630952ee..bac75d36ad90 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenAnnotationReader.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenAnnotationReader.java @@ -250,10 +250,7 @@ private enum PropertyType { private transient List elementsForProperty; private AccessibleObject mirroredAttribute; - /** - * @deprecated Use {@link #JPAXMLOverriddenAnnotationReader(AnnotatedElement, XMLContext, BootstrapContext)} instead. - */ - public JPAXMLOverriddenAnnotationReader( + JPAXMLOverriddenAnnotationReader( AnnotatedElement el, XMLContext xmlContext, ClassLoaderAccess classLoaderAccess) { @@ -318,6 +315,7 @@ else if ( methodName.startsWith( "is" ) ) { } } + // For tests only public JPAXMLOverriddenAnnotationReader( AnnotatedElement el, XMLContext xmlContext, diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenMetadataProvider.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenMetadataProvider.java index 6991140d35f1..fc78a879be5a 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenMetadataProvider.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenMetadataProvider.java @@ -23,13 +23,9 @@ import org.hibernate.annotations.common.reflection.AnnotationReader; import org.hibernate.annotations.common.reflection.MetadataProvider; import org.hibernate.annotations.common.reflection.java.JavaMetadataProvider; -import org.hibernate.boot.internal.ClassLoaderAccessImpl; -import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; import org.hibernate.boot.spi.BootstrapContext; import org.hibernate.boot.spi.ClassLoaderAccess; -import org.hibernate.boot.spi.ClassLoaderAccessDelegateImpl; -import org.hibernate.boot.spi.MetadataBuildingOptions; import org.dom4j.Element; @@ -55,37 +51,10 @@ public final class JPAXMLOverriddenMetadataProvider implements MetadataProvider private Map defaults; private Map cache; - /** - * @deprecated Use {@link JPAXMLOverriddenMetadataProvider#JPAXMLOverriddenMetadataProvider(BootstrapContext)} instead. - */ - @Deprecated - public JPAXMLOverriddenMetadataProvider(final MetadataBuildingOptions metadataBuildingOptions) { - this( new ClassLoaderAccessDelegateImpl() { - ClassLoaderAccess delegate; - - @Override - protected ClassLoaderAccess getDelegate() { - if ( delegate == null ) { - delegate = new ClassLoaderAccessImpl( - metadataBuildingOptions.getTempClassLoader(), - metadataBuildingOptions.getServiceRegistry().getService( ClassLoaderService.class ) - ); - } - return delegate; - } - }, - metadataBuildingOptions.isXmlMappingEnabled() ); - } - public JPAXMLOverriddenMetadataProvider(BootstrapContext bootstrapContext) { - this( bootstrapContext.getClassLoaderAccess(), - bootstrapContext.getMetadataBuildingOptions().isXmlMappingEnabled() ); - } - - JPAXMLOverriddenMetadataProvider(ClassLoaderAccess classLoaderAccess, boolean xmlMetadataEnabled) { - this.classLoaderAccess = classLoaderAccess; + this.classLoaderAccess = bootstrapContext.getClassLoaderAccess(); this.xmlContext = new XMLContext( classLoaderAccess ); - this.xmlMappingEnabled = xmlMetadataEnabled; + this.xmlMappingEnabled = bootstrapContext.getMetadataBuildingOptions().isXmlMappingEnabled(); } //all of the above can be safely rebuilt from XMLContext: only XMLContext this object is serialized diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/XMLContext.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/XMLContext.java index 9dc7cdc537dd..ffa00e83225d 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/XMLContext.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/XMLContext.java @@ -46,14 +46,11 @@ public class XMLContext implements Serializable { private List defaultEntityListeners = new ArrayList<>(); private boolean hasContext = false; - /** - * @deprecated Use {@link XMLContext#XMLContext(BootstrapContext)} instead. - */ - @Deprecated - public XMLContext(ClassLoaderAccess classLoaderAccess) { + XMLContext(ClassLoaderAccess classLoaderAccess) { this.classLoaderAccess = classLoaderAccess; } + // For tests only public XMLContext(BootstrapContext bootstrapContext) { this.classLoaderAccess = bootstrapContext.getClassLoaderAccess(); } From 8ab3a2f7e925d267fe607d3990d7f0e6223ba5a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Fri, 26 Mar 2021 11:58:35 +0100 Subject: [PATCH 097/644] HHH-14529 Configuration and wiring to prefer JAXB over DOM4J for orm.xml handling --- .../boot/internal/BootstrapContextImpl.java | 11 ++- .../boot/internal/MetadataBuilderImpl.java | 13 ++- .../internal/DefaultXmlMappingOptions.java | 12 +++ .../boot/jaxb/internal/MappingBinder.java | 44 +++++++--- .../boot/jaxb/spi/XmlMappingOptions.java | 86 +++++++++++++++++++ .../process/spi/MetadataBuildingProcess.java | 20 ++--- ...AnnotationMetadataSourceProcessorImpl.java | 27 +++++- .../internal/StrategySelectorBuilder.java | 4 + ...ractDelegatingMetadataBuildingOptions.java | 5 +- .../boot/spi/MetadataBuildingOptions.java | 5 +- .../boot/spi/XmlMappingBinderAccess.java | 8 +- .../org/hibernate/cfg/AvailableSettings.java | 1 - .../reflection/JPAMetadataProvider.java | 26 ++++-- .../JPAOverriddenAnnotationReader.java | 12 ++- .../annotations/reflection/XMLContext.java | 7 +- .../JPAXMLOverriddenAnnotationReader.java | 3 +- .../JPAXMLOverriddenMetadataProvider.java | 9 +- .../reflection/internal/XMLContext.java | 12 +++ ...ngOptionsStrategyRegistrationProvider.java | 66 ++++++++++++++ .../ElementCollectionConverterTest.java | 3 +- .../annotations/xml/ejb3/Ejb3XmlTest.java | 3 +- .../xml/ejb3/NonExistentOrmVersionTest.java | 6 +- .../xml/ejb3/OrmVersion1SupportedTest.java | 3 +- .../xml/ejb3/PreParsedOrmXmlTest.java | 3 +- ...stry.selector.StrategyRegistrationProvider | 1 + .../AdditionalJaxbMappingProducerImpl.java | 14 ++- .../boot/internal/EnversServiceImpl.java | 9 -- 27 files changed, 341 insertions(+), 72 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/DefaultXmlMappingOptions.java create mode 100644 hibernate-core/src/main/java/org/hibernate/boot/jaxb/spi/XmlMappingOptions.java create mode 100644 hibernate-core/src/test/java/org/hibernate/internal/util/xml/XmlMappingOptionsStrategyRegistrationProvider.java create mode 100644 hibernate-core/src/test/resources/META-INF/services/org.hibernate.boot.registry.selector.StrategyRegistrationProvider diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/BootstrapContextImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/BootstrapContextImpl.java index 476b9843f45c..6f05fafad590 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/BootstrapContextImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/BootstrapContextImpl.java @@ -31,6 +31,7 @@ import org.hibernate.boot.spi.MetadataBuildingOptions; import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.annotations.reflection.JPAMetadataProvider; +import org.hibernate.cfg.annotations.reflection.internal.JPAXMLOverriddenMetadataProvider; import org.hibernate.dialect.function.SQLFunction; import org.hibernate.engine.config.spi.ConfigurationService; import org.hibernate.jpa.internal.MutableJpaComplianceImpl; @@ -83,10 +84,10 @@ public BootstrapContextImpl( final ClassLoaderService classLoaderService = serviceRegistry.getService( ClassLoaderService.class ); this.classLoaderAccess = new ClassLoaderAccessImpl( classLoaderService ); - this.hcannReflectionManager = generateHcannReflectionManager(); final StrategySelector strategySelector = serviceRegistry.getService( StrategySelector.class ); final ConfigurationService configService = serviceRegistry.getService( ConfigurationService.class ); + this.hcannReflectionManager = generateHcannReflectionManager(); this.jpaCompliance = new MutableJpaComplianceImpl( configService.getSettings(), false ); this.scanOptions = new StandardScanOptions( @@ -309,7 +310,13 @@ public void addCacheRegionDefinition(CacheRegionDefinition cacheRegionDefinition private JavaReflectionManager generateHcannReflectionManager() { final JavaReflectionManager reflectionManager = new JavaReflectionManager(); - reflectionManager.setMetadataProvider( new JPAMetadataProvider( this ) ); + if ( metadataBuildingOptions.getXmlMappingOptions().isPreferJaxb() ) { + reflectionManager.setMetadataProvider( new JPAXMLOverriddenMetadataProvider( this ) ); + } + else { + // Legacy implementation based on DOM4J, for backwards compatibility. + reflectionManager.setMetadataProvider( new JPAMetadataProvider( this ) ); + } return reflectionManager; } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/MetadataBuilderImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/MetadataBuilderImpl.java index f5ebda41eda8..0b0195d2d97c 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/MetadataBuilderImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/MetadataBuilderImpl.java @@ -30,6 +30,7 @@ import org.hibernate.boot.cfgxml.spi.CfgXmlAccessService; import org.hibernate.boot.cfgxml.spi.LoadedConfig; import org.hibernate.boot.cfgxml.spi.MappingReference; +import org.hibernate.boot.jaxb.spi.XmlMappingOptions; import org.hibernate.boot.model.IdGeneratorStrategyInterpreter; import org.hibernate.boot.model.TypeContributions; import org.hibernate.boot.model.TypeContributor; @@ -622,7 +623,7 @@ public static class MetadataBuildingOptionsImpl private IdGeneratorInterpreterImpl idGenerationTypeInterpreter = new IdGeneratorInterpreterImpl(); private String schemaCharset; - private boolean xmlMappingEnabled; + private final XmlMappingOptions xmlMappingOptions; public MetadataBuildingOptionsImpl(StandardServiceRegistry serviceRegistry) { this.serviceRegistry = serviceRegistry; @@ -634,11 +635,7 @@ public MetadataBuildingOptionsImpl(StandardServiceRegistry serviceRegistry) { this.multiTenancyStrategy = MultiTenancyStrategy.determineMultiTenancyStrategy( configService.getSettings() ); - this.xmlMappingEnabled = configService.getSetting( - AvailableSettings.XML_MAPPING_ENABLED, - StandardConverters.BOOLEAN, - true - ); + xmlMappingOptions = XmlMappingOptions.get( serviceRegistry ); this.implicitDiscriminatorsForJoinedInheritanceSupported = configService.getSetting( AvailableSettings.IMPLICIT_DISCRIMINATOR_COLUMNS_FOR_JOINED_SUBCLASS, @@ -926,8 +923,8 @@ public String getSchemaCharset() { } @Override - public boolean isXmlMappingEnabled() { - return xmlMappingEnabled; + public XmlMappingOptions getXmlMappingOptions() { + return xmlMappingOptions; } /** diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/DefaultXmlMappingOptions.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/DefaultXmlMappingOptions.java new file mode 100644 index 000000000000..9812b21fc984 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/DefaultXmlMappingOptions.java @@ -0,0 +1,12 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.boot.jaxb.internal; + +import org.hibernate.boot.jaxb.spi.XmlMappingOptions; + +public class DefaultXmlMappingOptions implements XmlMappingOptions { +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/MappingBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/MappingBinder.java index 8dd1e96b1ea0..ba0049988b75 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/MappingBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/MappingBinder.java @@ -20,7 +20,9 @@ import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmHibernateMapping; import org.hibernate.boot.jaxb.internal.stax.HbmEventReader; import org.hibernate.boot.jaxb.internal.stax.JpaOrmXmlEventReader; +import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappings; import org.hibernate.boot.jaxb.spi.Binding; +import org.hibernate.boot.jaxb.spi.XmlMappingOptions; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.xsd.MappingXsdSupport; import org.hibernate.internal.util.config.ConfigurationException; @@ -39,18 +41,18 @@ public class MappingBinder extends AbstractBinder { private final XMLEventFactory xmlEventFactory = XMLEventFactory.newInstance(); - private JAXBContext hbmJaxbContext; + private final XmlMappingOptions options; - public MappingBinder(ClassLoaderService classLoaderService) { - this( classLoaderService, true ); - } + private JAXBContext hbmJaxbContext; + private JAXBContext entityMappingsJaxbContext; - public MappingBinder(ClassLoaderService classLoaderService, boolean validateXml) { + public MappingBinder(ClassLoaderService classLoaderService, boolean validateXml, XmlMappingOptions options) { super( classLoaderService, validateXml ); + this.options = options; } @Override - protected Binding doBind( + protected Binding doBind( XMLEventReader staxEventReader, StartElement rootElementStartEvent, Origin origin) { @@ -63,12 +65,20 @@ protected Binding doBind( return new Binding<>( hbmBindings, origin ); } else { -// final XMLEventReader reader = new JpaOrmXmlEventReader( staxEventReader ); -// return jaxb( reader, LocalSchema.MAPPING.getSchema(), JaxbEntityMappings.class, origin ); - try { - final XMLEventReader reader = new JpaOrmXmlEventReader( staxEventReader, xmlEventFactory ); - return new Binding<>( toDom4jDocument( reader, origin ), origin ); + if ( options.isPreferJaxb() ) { + log.debugf( "Performing JAXB binding of orm.xml document : %s", origin.toString() ); + + XMLEventReader reader = new JpaOrmXmlEventReader( staxEventReader, xmlEventFactory ); + JaxbEntityMappings bindingRoot = jaxb( reader, MappingXsdSupport.INSTANCE.latestJpaDescriptor().getSchema(), entityMappingsJaxbContext(), origin ); + return new Binding<>( bindingRoot, origin ); + } + else { + log.debugf( "Performing DOM4J binding of orm.xml document : %s", origin.toString() ); + + final XMLEventReader reader = new JpaOrmXmlEventReader( staxEventReader, xmlEventFactory ); + return new Binding<>( toDom4jDocument( reader, origin ), origin ); + } } catch (JpaOrmXmlEventReader.BadVersionException e) { throw new UnsupportedOrmXsdVersionException( e.getRequestedVersion(), origin ); @@ -88,6 +98,18 @@ private JAXBContext hbmJaxbContext() { return hbmJaxbContext; } + private JAXBContext entityMappingsJaxbContext() { + if ( entityMappingsJaxbContext == null ) { + try { + entityMappingsJaxbContext = JAXBContext.newInstance( JaxbEntityMappings.class ); + } + catch ( JAXBException e ) { + throw new ConfigurationException( "Unable to build orm.xml JAXBContext", e ); + } + } + return entityMappingsJaxbContext; + } + private Document toDom4jDocument(XMLEventReader jpaOrmXmlEventReader, Origin origin) { // todo : do we need to build a DocumentFactory instance for use here? // historically we did that to set TCCL since, iirc, dom4j uses TCCL diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/spi/XmlMappingOptions.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/spi/XmlMappingOptions.java new file mode 100644 index 000000000000..5247ef82ccc0 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/spi/XmlMappingOptions.java @@ -0,0 +1,86 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.boot.jaxb.spi; + +import org.hibernate.boot.jaxb.internal.DefaultXmlMappingOptions; +import org.hibernate.boot.registry.selector.spi.StrategySelector; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.engine.config.spi.ConfigurationService; +import org.hibernate.engine.config.spi.StandardConverters; +import org.hibernate.service.ServiceRegistry; + +/** + * The options of XML mapping. + *

+ * We're using an interface instead of simply configuration properties, + * so that we can override the options easily in integrations (Quarkus) + * and tests (to run the tests multiple times with different options). + */ +public interface XmlMappingOptions { + + String DEFAULT_NAME = "default"; + + static XmlMappingOptions get(ServiceRegistry serviceRegistry) { + final ConfigurationService configService = serviceRegistry.getService( ConfigurationService.class ); + + // The config service may be null if we're using a BootstrapServiceRegistry, + // since configuration properties are unknown at that point. + // That can happen with MetadataSources in particular, + // because for some reason we allow MetadataSources to be built before the StandardServiceRegistry + // (and Quarkus relies on that). + // That's why we prefer to rely on strategies (see below): + // they can be customized without relying on configuration properties + // through the service loader. + boolean xmlMappingEnabled = configService == null || configService.getSetting( + AvailableSettings.XML_MAPPING_ENABLED, + StandardConverters.BOOLEAN, + true + ); + + XmlMappingOptions result; + if ( !xmlMappingEnabled ) { + result = new XmlMappingOptions() { + @Override + public boolean isEnabled() { + return false; + } + }; + } + else { + StrategySelector strategySelector = serviceRegistry.getService( StrategySelector.class ); + result = strategySelector.resolveDefaultableStrategy( + XmlMappingOptions.class, + XmlMappingOptions.DEFAULT_NAME, + new DefaultXmlMappingOptions() + ); + } + + return result; + } + + /** + * Allows to skip processing of XML Mapping. + * This is for people using exclusively annotations to define their model, and might + * be able to improve efficiency of booting Hibernate ORM. + * By default, the XML mapping is taken into account. + */ + default boolean isEnabled() { + return true; + } + + /** + * Whether to prefer JAXB implementations for XML parsing, + * or to rely on legacy behavior (JAXB for hbm.xml, DOM4J for orm.xml and Envers). + *

+ * This option will be removed in a future major version (probably ORM 6.0) + * where JAXB will always be used. + */ + default boolean isPreferJaxb() { + return false; + } + +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/process/spi/MetadataBuildingProcess.java b/hibernate-core/src/main/java/org/hibernate/boot/model/process/spi/MetadataBuildingProcess.java index 6b40eac9aee3..1457f3c12923 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/process/spi/MetadataBuildingProcess.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/process/spi/MetadataBuildingProcess.java @@ -15,6 +15,7 @@ import org.hibernate.boot.internal.InFlightMetadataCollectorImpl; import org.hibernate.boot.internal.MetadataBuildingContextRootImpl; import org.hibernate.boot.jaxb.internal.MappingBinder; +import org.hibernate.boot.jaxb.spi.XmlMappingOptions; import org.hibernate.boot.model.TypeContributions; import org.hibernate.boot.model.TypeContributor; import org.hibernate.boot.model.process.internal.ManagedResourcesImpl; @@ -32,11 +33,8 @@ import org.hibernate.boot.spi.MetadataBuildingOptions; import org.hibernate.boot.spi.MetadataContributor; import org.hibernate.boot.spi.MetadataImplementor; -import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.MetadataSourceType; import org.hibernate.dialect.Dialect; -import org.hibernate.engine.config.spi.ConfigurationService; -import org.hibernate.engine.config.spi.StandardConverters; import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.type.BasicType; import org.hibernate.type.BasicTypeRegistry; @@ -98,16 +96,11 @@ public static ManagedResources prepare( final MetadataSources sources, final BootstrapContext bootstrapContext) { final ManagedResourcesImpl managedResources = ManagedResourcesImpl.baseline( sources, bootstrapContext ); - final ConfigurationService configService = bootstrapContext.getServiceRegistry().getService( ConfigurationService.class ); - final boolean xmlMappingEnabled = configService.getSetting( - AvailableSettings.XML_MAPPING_ENABLED, - StandardConverters.BOOLEAN, - true - ); + XmlMappingOptions xmlMappingOptions = XmlMappingOptions.get( bootstrapContext.getServiceRegistry() ); ScanningCoordinator.INSTANCE.coordinateScan( managedResources, bootstrapContext, - xmlMappingEnabled ? sources.getXmlMappingBinderAccess() : null + xmlMappingOptions.isEnabled() ? sources.getXmlMappingBinderAccess() : null ); return managedResources; } @@ -157,7 +150,7 @@ public static MetadataImplementor complete( final MetadataSourceProcessor processor = new MetadataSourceProcessor() { private final MetadataSourceProcessor hbmProcessor = - options.isXmlMappingEnabled() + options.getXmlMappingOptions().isEnabled() ? new HbmMetadataSourceProcessorImpl( managedResources, rootMetadataBuildingContext ) : new NoOpMetadataSourceProcessorImpl(); @@ -294,13 +287,14 @@ public void finishUp() { metadataCollector.processSecondPasses( rootMetadataBuildingContext ); - if ( options.isXmlMappingEnabled() ) { + XmlMappingOptions xmlMappingOptions = options.getXmlMappingOptions(); + if ( xmlMappingOptions.isEnabled() ) { Iterable producers = classLoaderService.loadJavaServices( AdditionalJaxbMappingProducer.class ); if ( producers != null ) { final EntityHierarchyBuilder hierarchyBuilder = new EntityHierarchyBuilder(); // final MappingBinder mappingBinder = new MappingBinder( true ); // We need to disable validation here. It seems Envers is not producing valid (according to schema) XML - final MappingBinder mappingBinder = new MappingBinder( classLoaderService, false ); + final MappingBinder mappingBinder = new MappingBinder( classLoaderService, false, xmlMappingOptions ); for ( AdditionalJaxbMappingProducer producer : producers ) { log.tracef( "Calling AdditionalJaxbMappingProducer : %s", producer ); Collection additionalMappings = producer.produceAdditionalMappings( diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/annotations/AnnotationMetadataSourceProcessorImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/annotations/AnnotationMetadataSourceProcessorImpl.java index 9fe1d5ed8342..f336e4551cf2 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/annotations/AnnotationMetadataSourceProcessorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/annotations/AnnotationMetadataSourceProcessorImpl.java @@ -22,17 +22,21 @@ import org.hibernate.annotations.common.reflection.XClass; import org.hibernate.boot.AttributeConverterInfo; import org.hibernate.boot.internal.MetadataBuildingContextRootImpl; +import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappings; import org.hibernate.boot.jaxb.spi.Binding; +import org.hibernate.boot.jaxb.spi.XmlMappingOptions; import org.hibernate.boot.model.convert.spi.ConverterDescriptor; import org.hibernate.boot.model.process.spi.ManagedResources; import org.hibernate.boot.model.source.spi.MetadataSourceProcessor; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.spi.JpaOrmXmlPersistenceUnitDefaultAware; import org.hibernate.boot.spi.JpaOrmXmlPersistenceUnitDefaultAware.JpaOrmXmlPersistenceUnitDefaults; +import org.hibernate.boot.spi.MetadataBuildingOptions; import org.hibernate.cfg.AnnotationBinder; import org.hibernate.cfg.InheritanceState; import org.hibernate.cfg.annotations.reflection.AttributeConverterDefinitionCollector; import org.hibernate.cfg.annotations.reflection.JPAMetadataProvider; +import org.hibernate.cfg.annotations.reflection.internal.JPAXMLOverriddenMetadataProvider; import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.collections.CollectionHelper; @@ -75,11 +79,29 @@ public AnnotationMetadataSourceProcessorImpl( final AttributeConverterManager attributeConverterManager = new AttributeConverterManager( rootMetadataBuildingContext ); this.classLoaderService = rootMetadataBuildingContext.getBuildingOptions().getServiceRegistry().getService( ClassLoaderService.class ); - if ( rootMetadataBuildingContext.getBuildingOptions().isXmlMappingEnabled() ) { - + MetadataBuildingOptions metadataBuildingOptions = rootMetadataBuildingContext.getBuildingOptions(); + XmlMappingOptions xmlMappingOptions = metadataBuildingOptions.getXmlMappingOptions(); + if ( xmlMappingOptions.isEnabled() ) { // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Ewww. This is temporary until we migrate to Jandex + StAX for annotation binding + if ( xmlMappingOptions.isPreferJaxb() ) { + final JPAXMLOverriddenMetadataProvider jpaMetadataProvider = (JPAXMLOverriddenMetadataProvider) ( (MetadataProviderInjector) reflectionManager ) + .getMetadataProvider(); + for ( Binding xmlBinding : managedResources.getXmlMappingBindings() ) { + Object root = xmlBinding.getRoot(); + if ( !(root instanceof JaxbEntityMappings) ) { + continue; + } + JaxbEntityMappings entityMappings = (JaxbEntityMappings) xmlBinding.getRoot(); + final List classNames = jpaMetadataProvider.getXMLContext().addDocument( entityMappings ); + for ( String className : classNames ) { + xClasses.add( toXClass( className, reflectionManager, classLoaderService ) ); + } + } + jpaMetadataProvider.getXMLContext().applyDiscoveredAttributeConverters( attributeConverterManager ); + } + else { final JPAMetadataProvider jpaMetadataProvider = (JPAMetadataProvider) ( (MetadataProviderInjector) reflectionManager ) .getMetadataProvider(); for ( Binding xmlBinding : managedResources.getXmlMappingBindings() ) { @@ -94,6 +116,7 @@ public AnnotationMetadataSourceProcessorImpl( } } jpaMetadataProvider.getXMLContext().applyDiscoveredAttributeConverters( attributeConverterManager ); + } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/registry/selector/internal/StrategySelectorBuilder.java b/hibernate-core/src/main/java/org/hibernate/boot/registry/selector/internal/StrategySelectorBuilder.java index 0d0f48c3c8e3..a09c90cc5f2e 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/registry/selector/internal/StrategySelectorBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/registry/selector/internal/StrategySelectorBuilder.java @@ -9,6 +9,8 @@ import java.util.ArrayList; import java.util.List; +import org.hibernate.boot.jaxb.internal.DefaultXmlMappingOptions; +import org.hibernate.boot.jaxb.spi.XmlMappingOptions; import org.hibernate.boot.model.naming.ImplicitNamingStrategy; import org.hibernate.boot.model.naming.ImplicitNamingStrategyComponentPathImpl; import org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl; @@ -100,6 +102,8 @@ public StrategySelector buildSelector(ClassLoaderService classLoaderService) { addMultiTableBulkIdStrategies( strategySelector ); addImplicitNamingStrategies( strategySelector ); addCacheKeysFactories( strategySelector ); + strategySelector.registerStrategyImplementor( XmlMappingOptions.class, XmlMappingOptions.DEFAULT_NAME, + DefaultXmlMappingOptions.class ); // apply auto-discovered registrations for ( StrategyRegistrationProvider provider : classLoaderService.loadJavaServices( StrategyRegistrationProvider.class ) ) { diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingMetadataBuildingOptions.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingMetadataBuildingOptions.java index 3b8be18e370e..b2abe158798c 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingMetadataBuildingOptions.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingMetadataBuildingOptions.java @@ -18,6 +18,7 @@ import org.hibernate.boot.archive.scan.spi.ScanEnvironment; import org.hibernate.boot.archive.scan.spi.ScanOptions; import org.hibernate.boot.archive.spi.ArchiveDescriptorFactory; +import org.hibernate.boot.jaxb.spi.XmlMappingOptions; import org.hibernate.boot.model.IdGeneratorStrategyInterpreter; import org.hibernate.boot.model.naming.ImplicitNamingStrategy; import org.hibernate.boot.model.naming.PhysicalNamingStrategy; @@ -203,8 +204,8 @@ public String getSchemaCharset() { } @Override - public boolean isXmlMappingEnabled() { - return delegate.isXmlMappingEnabled(); + public XmlMappingOptions getXmlMappingOptions() { + return delegate.getXmlMappingOptions(); } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/MetadataBuildingOptions.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/MetadataBuildingOptions.java index 65a964e92433..0fc02ca34293 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/spi/MetadataBuildingOptions.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/MetadataBuildingOptions.java @@ -17,6 +17,7 @@ import org.hibernate.boot.archive.scan.spi.ScanEnvironment; import org.hibernate.boot.archive.scan.spi.ScanOptions; import org.hibernate.boot.archive.spi.ArchiveDescriptorFactory; +import org.hibernate.boot.jaxb.spi.XmlMappingOptions; import org.hibernate.boot.model.IdGeneratorStrategyInterpreter; import org.hibernate.boot.model.naming.ImplicitNamingStrategy; import org.hibernate.boot.model.naming.PhysicalNamingStrategy; @@ -251,8 +252,8 @@ default String getSchemaCharset() { return null; } - default boolean isXmlMappingEnabled() { - return true; + default XmlMappingOptions getXmlMappingOptions() { + return XmlMappingOptions.get( getServiceRegistry() ); } /** diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/XmlMappingBinderAccess.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/XmlMappingBinderAccess.java index 8102865f2acd..fa7014840b71 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/spi/XmlMappingBinderAccess.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/XmlMappingBinderAccess.java @@ -20,7 +20,11 @@ import org.hibernate.boot.jaxb.internal.MappingBinder; import org.hibernate.boot.jaxb.internal.UrlXmlSource; import org.hibernate.boot.jaxb.spi.Binding; +import org.hibernate.boot.jaxb.spi.XmlMappingOptions; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.engine.config.spi.ConfigurationService; +import org.hibernate.engine.config.spi.StandardConverters; import org.hibernate.service.ServiceRegistry; import org.jboss.logging.Logger; @@ -37,10 +41,12 @@ public class XmlMappingBinderAccess { public XmlMappingBinderAccess(ServiceRegistry serviceRegistry) { this.classLoaderService = serviceRegistry.getService( ClassLoaderService.class ); + XmlMappingOptions xmlMappingOptions = XmlMappingOptions.get( serviceRegistry ); + // NOTE : The boolean here indicates whether or not to perform validation as we load XML documents. // Should we expose this setting? Disabling would speed up JAXP and JAXB at runtime, but potentially // at the cost of less obvious errors when a document is not valid. - this.mappingBinder = new MappingBinder( serviceRegistry.getService( ClassLoaderService.class ), true ); + this.mappingBinder = new MappingBinder( classLoaderService, true, xmlMappingOptions ); } public MappingBinder getMappingBinder() { diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java index cc547527859e..65ef3f9afa89 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java @@ -698,7 +698,6 @@ public interface AvailableSettings extends org.hibernate.jpa.AvailableSettings { */ String XML_MAPPING_ENABLED = "hibernate.xml_mapping_enabled"; - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // SessionFactoryBuilder level settings // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/JPAMetadataProvider.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/JPAMetadataProvider.java index 967523143fbd..5579a01c79f0 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/JPAMetadataProvider.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/JPAMetadataProvider.java @@ -30,6 +30,7 @@ import org.hibernate.boot.spi.ClassLoaderAccess; import org.hibernate.boot.spi.ClassLoaderAccessDelegateImpl; import org.hibernate.boot.spi.MetadataBuildingOptions; +import org.hibernate.cfg.annotations.reflection.internal.JPAXMLOverriddenMetadataProvider; import org.dom4j.Element; @@ -37,7 +38,13 @@ * MetadataProvider aware of the JPA Deployment descriptor * * @author Emmanuel Bernard + * + * @deprecated This class is not API: do not use it from application code. + * This class will be removed in Hibernate ORM 6.0. + * For implementation code, use {@link JPAXMLOverriddenMetadataProvider} + * instead. */ +@Deprecated @SuppressWarnings("unchecked") public final class JPAMetadataProvider implements MetadataProvider { @@ -74,12 +81,12 @@ protected ClassLoaderAccess getDelegate() { return delegate; } }, - metadataBuildingOptions.isXmlMappingEnabled() ); + metadataBuildingOptions.getXmlMappingOptions().isEnabled() ); } public JPAMetadataProvider(BootstrapContext bootstrapContext) { this( bootstrapContext.getClassLoaderAccess(), - bootstrapContext.getMetadataBuildingOptions().isXmlMappingEnabled() ); + bootstrapContext.getMetadataBuildingOptions().getXmlMappingOptions().isEnabled() ); } JPAMetadataProvider(ClassLoaderAccess classLoaderAccess, boolean xmlMetadataEnabled) { @@ -147,7 +154,8 @@ public Map getDefaults() { defaults.put( SequenceGenerator.class, sequenceGenerators ); } for ( Element subelement : elements ) { - sequenceGenerators.add( JPAOverriddenAnnotationReader.buildSequenceGeneratorAnnotation( subelement ) ); + sequenceGenerators.add( JPAOverriddenAnnotationReader + .buildSequenceGeneratorAnnotation( subelement ) ); } elements = element.elements( "table-generator" ); @@ -169,7 +177,8 @@ public Map getDefaults() { namedQueries = new ArrayList<>(); defaults.put( NamedQuery.class, namedQueries ); } - List currentNamedQueries = JPAOverriddenAnnotationReader.buildNamedQueries( + List currentNamedQueries = JPAOverriddenAnnotationReader + .buildNamedQueries( element, false, xmlDefaults, @@ -182,7 +191,8 @@ public Map getDefaults() { namedNativeQueries = new ArrayList<>(); defaults.put( NamedNativeQuery.class, namedNativeQueries ); } - List currentNamedNativeQueries = JPAOverriddenAnnotationReader.buildNamedQueries( + List currentNamedNativeQueries = JPAOverriddenAnnotationReader + .buildNamedQueries( element, true, xmlDefaults, @@ -197,7 +207,8 @@ public Map getDefaults() { sqlResultSetMappings = new ArrayList<>(); defaults.put( SqlResultSetMapping.class, sqlResultSetMappings ); } - List currentSqlResultSetMappings = JPAOverriddenAnnotationReader.buildSqlResultsetMappings( + List currentSqlResultSetMappings = JPAOverriddenAnnotationReader + .buildSqlResultsetMappings( element, xmlDefaults, classLoaderAccess @@ -209,7 +220,8 @@ public Map getDefaults() { namedStoredProcedureQueries = new ArrayList<>( ); defaults.put( NamedStoredProcedureQuery.class, namedStoredProcedureQueries ); } - List currentNamedStoredProcedureQueries = JPAOverriddenAnnotationReader.buildNamedStoreProcedureQueries( + List currentNamedStoredProcedureQueries = JPAOverriddenAnnotationReader + .buildNamedStoreProcedureQueries( element, xmlDefaults, classLoaderAccess diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/JPAOverriddenAnnotationReader.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/JPAOverriddenAnnotationReader.java index b9adae8b41f2..895da45b37df 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/JPAOverriddenAnnotationReader.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/JPAOverriddenAnnotationReader.java @@ -126,6 +126,7 @@ import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; import org.hibernate.boot.spi.BootstrapContext; import org.hibernate.boot.spi.ClassLoaderAccess; +import org.hibernate.cfg.annotations.reflection.internal.JPAXMLOverriddenAnnotationReader; import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.StringHelper; @@ -140,7 +141,13 @@ * @author Davide Marchignoli * @author Emmanuel Bernard * @author Hardy Ferentschik + * + * @deprecated This class is not API: do not use it from application code. + * This class will be removed in Hibernate ORM 6.0. + * For implementation code, use {@link JPAXMLOverriddenAnnotationReader} + * instead. */ +@Deprecated @SuppressWarnings("unchecked") public class JPAOverriddenAnnotationReader implements AnnotationReader { private static final CoreMessageLogger LOG = CoreLogging.messageLogger( JPAOverriddenAnnotationReader.class ); @@ -884,7 +891,7 @@ private JoinTable buildJoinTable(Element tree, XMLContext.Default defaults) { * field or property. Thus, any methods which might in some contexts merge * with annotations must not do so in this context. * - * @see #getElementCollection(List, org.hibernate.cfg.annotations.reflection.XMLContext.Default) + * @see #getElementCollection(List, XMLContext.Default) */ private void getAssociation( Class annotationType, List annotationList, XMLContext.Default defaults @@ -2691,7 +2698,8 @@ private IdClass getIdClass(Element tree, XMLContext.Default defaults) { AnnotationDescriptor ad = new AnnotationDescriptor( IdClass.class ); Class clazz; try { - clazz = classLoaderAccess.classForName( XMLContext.buildSafeClassName( attr.getValue(), defaults ) + clazz = classLoaderAccess.classForName( XMLContext + .buildSafeClassName( attr.getValue(), defaults ) ); } catch ( ClassLoadingException e ) { diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/XMLContext.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/XMLContext.java index 8aef32bc9bbe..9cde55fea7c0 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/XMLContext.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/XMLContext.java @@ -32,7 +32,12 @@ * * @author Emmanuel Bernard * @author Brett Meyer + * + * @deprecated This class is not API: do not use it from application code. + * This class will be removed in Hibernate ORM 6.0. + * For implementation code, use {@link org.hibernate.cfg.annotations.reflection.internal.XMLContext} instead. */ +@Deprecated public class XMLContext implements Serializable { private static final CoreMessageLogger LOG = CoreLogging.messageLogger( XMLContext.class ); @@ -222,7 +227,7 @@ public static String buildSafeClassName(String className, String defaultPackageN return className; } - public static String buildSafeClassName(String className, XMLContext.Default defaults) { + public static String buildSafeClassName(String className, Default defaults) { return buildSafeClassName( className, defaults.getPackageName() ); } diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenAnnotationReader.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenAnnotationReader.java index bac75d36ad90..30cbae7208b4 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenAnnotationReader.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenAnnotationReader.java @@ -142,6 +142,8 @@ * @author Emmanuel Bernard * @author Hardy Ferentschik */ +// FIXME HHH-14529 Change this class to use JaxbEntityMappings instead of Document. +// I'm delaying this change in order to keep the commits simpler and easier to review. @SuppressWarnings("unchecked") public class JPAXMLOverriddenAnnotationReader implements AnnotationReader { private static final CoreMessageLogger LOG = CoreLogging.messageLogger( JPAXMLOverriddenAnnotationReader.class ); @@ -323,7 +325,6 @@ public JPAXMLOverriddenAnnotationReader( this( el, xmlContext, bootstrapContext.getClassLoaderAccess() ); } - public T getAnnotation(Class annotationType) { initAnnotations(); return (T) annotationsMap.get( annotationType ); diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenMetadataProvider.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenMetadataProvider.java index fc78a879be5a..6c65829d0999 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenMetadataProvider.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenMetadataProvider.java @@ -23,6 +23,7 @@ import org.hibernate.annotations.common.reflection.AnnotationReader; import org.hibernate.annotations.common.reflection.MetadataProvider; import org.hibernate.annotations.common.reflection.java.JavaMetadataProvider; +import org.hibernate.boot.jaxb.spi.XmlMappingOptions; import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; import org.hibernate.boot.spi.BootstrapContext; import org.hibernate.boot.spi.ClassLoaderAccess; @@ -34,6 +35,8 @@ * * @author Emmanuel Bernard */ +// FIXME HHH-14529 Change this class to use JaxbEntityMappings instead of Document. +// I'm delaying this change in order to keep the commits simpler and easier to review. @SuppressWarnings("unchecked") public final class JPAXMLOverriddenMetadataProvider implements MetadataProvider { @@ -46,7 +49,7 @@ public final class JPAXMLOverriddenMetadataProvider implements MetadataProvider * We allow fully disabling XML sources so to improve the efficiency of * the boot process for those not using it. */ - private final boolean xmlMappingEnabled; + private final XmlMappingOptions xmlMappingOptions; private Map defaults; private Map cache; @@ -54,7 +57,7 @@ public final class JPAXMLOverriddenMetadataProvider implements MetadataProvider public JPAXMLOverriddenMetadataProvider(BootstrapContext bootstrapContext) { this.classLoaderAccess = bootstrapContext.getClassLoaderAccess(); this.xmlContext = new XMLContext( classLoaderAccess ); - this.xmlMappingEnabled = bootstrapContext.getMetadataBuildingOptions().isXmlMappingEnabled(); + this.xmlMappingOptions = bootstrapContext.getMetadataBuildingOptions().getXmlMappingOptions(); } //all of the above can be safely rebuilt from XMLContext: only XMLContext this object is serialized @@ -87,7 +90,7 @@ public void reset() { @Override public Map getDefaults() { - if ( xmlMappingEnabled == false ) { + if ( !xmlMappingOptions.isEnabled() ) { return Collections.emptyMap(); } else { diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/XMLContext.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/XMLContext.java index ffa00e83225d..513fbd6aa87c 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/XMLContext.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/XMLContext.java @@ -16,10 +16,12 @@ import org.hibernate.AnnotationException; import org.hibernate.boot.AttributeConverterInfo; +import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappings; import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; import org.hibernate.boot.spi.BootstrapContext; import org.hibernate.boot.spi.ClassLoaderAccess; import org.hibernate.cfg.AttributeConverterDefinition; +import org.hibernate.cfg.NotYetImplementedException; import org.hibernate.cfg.annotations.reflection.AttributeConverterDefinitionCollector; import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreMessageLogger; @@ -34,6 +36,8 @@ * @author Emmanuel Bernard * @author Brett Meyer */ +// FIXME HHH-14529 Change this class to use JaxbEntityMappings instead of Document. +// I'm delaying this change in order to keep the commits simpler and easier to review. public class XMLContext implements Serializable { private static final CoreMessageLogger LOG = CoreLogging.messageLogger( XMLContext.class ); @@ -55,6 +59,14 @@ public XMLContext(BootstrapContext bootstrapContext) { this.classLoaderAccess = bootstrapContext.getClassLoaderAccess(); } + /** + * @param entityMappings The xml entity mappings to add + * @return Add an xml document to this context and return the list of added class names. + */ + public List addDocument(JaxbEntityMappings entityMappings) { + throw new NotYetImplementedException("HHH-14529 Implementation in progress"); + } + /** * @param doc The xml document to add * @return Add an xml document to this context and return the list of added class names. diff --git a/hibernate-core/src/test/java/org/hibernate/internal/util/xml/XmlMappingOptionsStrategyRegistrationProvider.java b/hibernate-core/src/test/java/org/hibernate/internal/util/xml/XmlMappingOptionsStrategyRegistrationProvider.java new file mode 100644 index 000000000000..97c6a617ce42 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/internal/util/xml/XmlMappingOptionsStrategyRegistrationProvider.java @@ -0,0 +1,66 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.internal.util.xml; + +import java.util.Collections; + +import org.hibernate.boot.jaxb.spi.XmlMappingOptions; +import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder; +import org.hibernate.boot.registry.selector.SimpleStrategyRegistrationImpl; +import org.hibernate.boot.registry.selector.StrategyRegistration; +import org.hibernate.boot.registry.selector.StrategyRegistrationProvider; + +import org.jboss.logging.Logger; + +/** + * A strategy registration provider that allows running the whole test suite with different XML mapping options. + *

+ * By default, this provider does nothing. + * In some CI jobs, we set the system property {@value STRATEGY_PROPERTY_KEY} + * to re-run the whole test suite using JAXB for orm.xml parsing instead of dom4j. + */ +public class XmlMappingOptionsStrategyRegistrationProvider implements StrategyRegistrationProvider { + + protected final Logger log = Logger.getLogger( getClass() ); + + private static final String STRATEGY_PROPERTY_KEY = "testing.mapping.xml.strategy"; + + public static void applyJaxbStrategy(BootstrapServiceRegistryBuilder builder) { + builder.applyStrategySelector( XmlMappingOptions.class, XmlMappingOptions.DEFAULT_NAME, + PreferJaxbXmlMappingOptions.class + ); + } + + @Override + public Iterable getStrategyRegistrations() { + switch ( getStrategyFromSystemProperties() ) { + case "jaxb": + log.warn( "Overriding the default configuration because of a test system property:" + + " will favor jaxb when parsing XML mapping." ); + return Collections.singleton( + new SimpleStrategyRegistrationImpl<>( XmlMappingOptions.class, + PreferJaxbXmlMappingOptions.class, + XmlMappingOptions.DEFAULT_NAME ) + ); + case "default": + default: + return Collections.emptyList(); + } + } + + private static String getStrategyFromSystemProperties() { + String strategy = System.getProperty( STRATEGY_PROPERTY_KEY ); + return strategy == null || strategy.isEmpty() ? "default" : strategy; + } + + public static class PreferJaxbXmlMappingOptions implements XmlMappingOptions { + @Override + public boolean isPreferJaxb() { + return true; + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/ElementCollectionConverterTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/ElementCollectionConverterTest.java index 1ee923a43e55..e0357054dd3c 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/ElementCollectionConverterTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/ElementCollectionConverterTest.java @@ -7,6 +7,7 @@ package org.hibernate.test.annotations.reflection; import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder; +import org.hibernate.internal.util.xml.XmlMappingOptionsStrategyRegistrationProvider; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; @@ -20,8 +21,8 @@ public class ElementCollectionConverterTest extends BaseCoreFunctionalTestCase { @Override protected void prepareBootstrapRegistryBuilder(BootstrapServiceRegistryBuilder builder) { - // FIXME HHH-14529 configure the BootstrapServiceRegistry to use JAXB for orm.xml mappings super.prepareBootstrapRegistryBuilder( builder ); + XmlMappingOptionsStrategyRegistrationProvider.applyJaxbStrategy( builder ); } @Override diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlTest.java index 89bb7873120c..96335a4d416d 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlTest.java @@ -17,6 +17,7 @@ import org.hibernate.dialect.PostgreSQL81Dialect; import org.hibernate.dialect.PostgreSQLDialect; import org.hibernate.dialect.TeradataDialect; +import org.hibernate.internal.util.xml.XmlMappingOptionsStrategyRegistrationProvider; import org.hibernate.persister.collection.BasicCollectionPersister; import org.hibernate.testing.SkipForDialect; @@ -35,8 +36,8 @@ public class Ejb3XmlTest extends BaseCoreFunctionalTestCase { @Override protected void prepareBootstrapRegistryBuilder(BootstrapServiceRegistryBuilder builder) { - // FIXME HHH-14529 configure the BootstrapServiceRegistry to use JAXB for orm.xml mappings super.prepareBootstrapRegistryBuilder( builder ); + XmlMappingOptionsStrategyRegistrationProvider.applyJaxbStrategy( builder ); } @Test diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/NonExistentOrmVersionTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/NonExistentOrmVersionTest.java index 63e9df91b67b..13a8535ca90a 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/NonExistentOrmVersionTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/NonExistentOrmVersionTest.java @@ -10,6 +10,7 @@ import org.hibernate.boot.MetadataSources; import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder; import org.hibernate.internal.util.xml.UnsupportedOrmXsdVersionException; +import org.hibernate.internal.util.xml.XmlMappingOptionsStrategyRegistrationProvider; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.junit4.BaseUnitTestCase; @@ -21,9 +22,10 @@ public class NonExistentOrmVersionTest extends BaseUnitTestCase { @Test public void testNonExistentOrmVersion() { - // FIXME HHH-14529 configure the BootstrapServiceRegistry to use JAXB for orm.xml mappings try { - new MetadataSources( new BootstrapServiceRegistryBuilder().build() ) + BootstrapServiceRegistryBuilder builder = new BootstrapServiceRegistryBuilder(); + XmlMappingOptionsStrategyRegistrationProvider.applyJaxbStrategy( builder ); + new MetadataSources( builder.build() ) .addResource( "org/hibernate/test/annotations/xml/ejb3/orm5.xml" ) .buildMetadata(); fail( "Expecting failure due to unsupported xsd version" ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/OrmVersion1SupportedTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/OrmVersion1SupportedTest.java index f56ccd780edf..ef227c81ae6d 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/OrmVersion1SupportedTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/OrmVersion1SupportedTest.java @@ -11,6 +11,7 @@ import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.xml.ErrorLogger; +import org.hibernate.internal.util.xml.XmlMappingOptionsStrategyRegistrationProvider; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; @@ -29,8 +30,8 @@ public class OrmVersion1SupportedTest extends BaseCoreFunctionalTestCase { @Override protected void prepareBootstrapRegistryBuilder(BootstrapServiceRegistryBuilder builder) { - // FIXME HHH-14529 configure the BootstrapServiceRegistry to use JAXB for orm.xml mappings super.prepareBootstrapRegistryBuilder( builder ); + XmlMappingOptionsStrategyRegistrationProvider.applyJaxbStrategy( builder ); } @Rule diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/PreParsedOrmXmlTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/PreParsedOrmXmlTest.java index 0fa294fe0335..057c4ede5d60 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/PreParsedOrmXmlTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/PreParsedOrmXmlTest.java @@ -13,6 +13,7 @@ import org.hibernate.boot.jaxb.spi.Binding; import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder; import org.hibernate.cfg.Configuration; +import org.hibernate.internal.util.xml.XmlMappingOptionsStrategyRegistrationProvider; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; @@ -25,8 +26,8 @@ public class PreParsedOrmXmlTest extends BaseCoreFunctionalTestCase { @Override protected void prepareBootstrapRegistryBuilder(BootstrapServiceRegistryBuilder builder) { - // FIXME HHH-14529 configure the BootstrapServiceRegistry to use JAXB for orm.xml mappings super.prepareBootstrapRegistryBuilder( builder ); + XmlMappingOptionsStrategyRegistrationProvider.applyJaxbStrategy( builder ); } @Override diff --git a/hibernate-core/src/test/resources/META-INF/services/org.hibernate.boot.registry.selector.StrategyRegistrationProvider b/hibernate-core/src/test/resources/META-INF/services/org.hibernate.boot.registry.selector.StrategyRegistrationProvider new file mode 100644 index 000000000000..98148e1689bf --- /dev/null +++ b/hibernate-core/src/test/resources/META-INF/services/org.hibernate.boot.registry.selector.StrategyRegistrationProvider @@ -0,0 +1 @@ +org.hibernate.internal.util.xml.XmlMappingOptionsStrategyRegistrationProvider \ No newline at end of file diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/boot/internal/AdditionalJaxbMappingProducerImpl.java b/hibernate-envers/src/main/java/org/hibernate/envers/boot/internal/AdditionalJaxbMappingProducerImpl.java index 37b0c95c9ecc..8a18b931ed98 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/boot/internal/AdditionalJaxbMappingProducerImpl.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/boot/internal/AdditionalJaxbMappingProducerImpl.java @@ -24,11 +24,14 @@ import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmHibernateMapping; import org.hibernate.boot.jaxb.internal.MappingBinder; import org.hibernate.boot.jaxb.spi.Binding; +import org.hibernate.boot.jaxb.spi.XmlMappingOptions; import org.hibernate.boot.model.source.internal.hbm.MappingDocument; import org.hibernate.boot.spi.AdditionalJaxbMappingProducer; import org.hibernate.boot.spi.MetadataBuildingContext; +import org.hibernate.boot.spi.MetadataBuildingOptions; import org.hibernate.boot.spi.MetadataImplementor; import org.hibernate.envers.configuration.internal.MappingCollector; +import org.hibernate.internal.util.config.ConfigurationHelper; import org.hibernate.service.ServiceRegistry; import org.jboss.jandex.IndexView; @@ -39,6 +42,8 @@ import org.dom4j.io.OutputFormat; import org.dom4j.io.XMLWriter; +import static org.hibernate.cfg.AvailableSettings.XML_MAPPING_ENABLED; + /** * @author Steve Ebersole */ @@ -51,7 +56,8 @@ public Collection produceAdditionalMappings( IndexView jandexIndex, final MappingBinder mappingBinder, final MetadataBuildingContext buildingContext) { - final ServiceRegistry serviceRegistry = metadata.getMetadataBuildingOptions().getServiceRegistry(); + MetadataBuildingOptions metadataBuildingOptions = metadata.getMetadataBuildingOptions(); + final ServiceRegistry serviceRegistry = metadataBuildingOptions.getServiceRegistry(); final EnversService enversService = serviceRegistry.getService( EnversService.class ); if ( !enversService.isEnabled() ) { @@ -59,6 +65,12 @@ public Collection produceAdditionalMappings( return Collections.emptyList(); } + if ( !metadataBuildingOptions.getXmlMappingOptions().isEnabled() ) { + throw new HibernateException( "Hibernate Envers currently requires XML mapping to be enabled." + + " Please don't disable setting `" + XML_MAPPING_ENABLED + + "`; alternatively disable Hibernate Envers." ); + } + final ArrayList additionalMappingDocuments = new ArrayList<>(); // atm we do not have distinct origin info for envers diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/boot/internal/EnversServiceImpl.java b/hibernate-envers/src/main/java/org/hibernate/envers/boot/internal/EnversServiceImpl.java index f0ab2ad6f21e..05d749b3b195 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/boot/internal/EnversServiceImpl.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/boot/internal/EnversServiceImpl.java @@ -9,14 +9,11 @@ import java.util.Map; import java.util.Properties; -import org.hibernate.HibernateException; import org.hibernate.MappingException; import org.hibernate.annotations.common.reflection.ReflectionManager; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.spi.MetadataImplementor; -import org.hibernate.cfg.AvailableSettings; import org.hibernate.engine.config.spi.ConfigurationService; -import org.hibernate.engine.config.spi.StandardConverters; import org.hibernate.envers.configuration.internal.AuditEntitiesConfiguration; import org.hibernate.envers.configuration.internal.EntitiesConfigurator; import org.hibernate.envers.configuration.internal.GlobalConfiguration; @@ -39,8 +36,6 @@ import org.jboss.logging.Logger; -import static org.hibernate.cfg.AvailableSettings.XML_MAPPING_ENABLED; - /** * Provides central access to Envers' configuration. * @@ -89,10 +84,6 @@ public void configure(Map configurationValues) { ); } this.integrationEnabled = ConfigurationHelper.getBoolean( INTEGRATION_ENABLED, configurationValues, true ); - boolean xmlMappingEnabled = ConfigurationHelper.getBoolean( XML_MAPPING_ENABLED, configurationValues, true ); - if ( this.integrationEnabled && !xmlMappingEnabled ) { - throw new HibernateException( "Hibernate Envers currently requires XML mapping to be enabled. Please don't disable setting `" + XML_MAPPING_ENABLED + "`; alternatively disable Hibernate Envers." ); - } log.infof( "Envers integration enabled? : %s", integrationEnabled ); } From bbc25cf28bdcc0c1b765395961345dd2ac6f89c7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Fri, 26 Mar 2021 13:05:57 +0100 Subject: [PATCH 098/644] HHH-14529 Add common interface for JaxbEntity and JaxbMappedSuperclass --- .../mapping/spi/EntityOrMappedSuperclass.java | 66 +++++++++++++++++++ .../src/main/xjb/mapping-bindings.xjb | 2 + 2 files changed, 68 insertions(+) create mode 100644 hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/EntityOrMappedSuperclass.java diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/EntityOrMappedSuperclass.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/EntityOrMappedSuperclass.java new file mode 100644 index 000000000000..5355dd8bbc26 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/EntityOrMappedSuperclass.java @@ -0,0 +1,66 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.boot.jaxb.mapping.spi; + +/** + * Common interface for JAXB bindings representing entities and mapped-superclasses. + */ +public interface EntityOrMappedSuperclass extends ManagedType { + + String getDescription(); + + void setDescription(String value); + + JaxbIdClass getIdClass(); + + void setIdClass(JaxbIdClass value); + + JaxbEmptyType getExcludeDefaultListeners(); + + void setExcludeDefaultListeners(JaxbEmptyType value); + + JaxbEmptyType getExcludeSuperclassListeners(); + + void setExcludeSuperclassListeners(JaxbEmptyType value); + + JaxbEntityListeners getEntityListeners(); + + void setEntityListeners(JaxbEntityListeners value); + + JaxbPrePersist getPrePersist(); + + void setPrePersist(JaxbPrePersist value); + + JaxbPostPersist getPostPersist(); + + void setPostPersist(JaxbPostPersist value); + + JaxbPreRemove getPreRemove(); + + void setPreRemove(JaxbPreRemove value); + + JaxbPostRemove getPostRemove(); + + void setPostRemove(JaxbPostRemove value); + + JaxbPreUpdate getPreUpdate(); + + void setPreUpdate(JaxbPreUpdate value); + + JaxbPostUpdate getPostUpdate(); + + void setPostUpdate(JaxbPostUpdate value); + + JaxbPostLoad getPostLoad(); + + void setPostLoad(JaxbPostLoad value); + + JaxbAttributes getAttributes(); + + void setAttributes(JaxbAttributes value); + +} diff --git a/hibernate-core/src/main/xjb/mapping-bindings.xjb b/hibernate-core/src/main/xjb/mapping-bindings.xjb index 8ee8f838c3fd..5bd32a491484 100644 --- a/hibernate-core/src/main/xjb/mapping-bindings.xjb +++ b/hibernate-core/src/main/xjb/mapping-bindings.xjb @@ -81,12 +81,14 @@ org.hibernate.boot.jaxb.mapping.spi.ManagedType + org.hibernate.boot.jaxb.mapping.spi.EntityOrMappedSuperclass org.hibernate.boot.jaxb.mapping.spi.ManagedType org.hibernate.boot.jaxb.mapping.spi.ManagedType + org.hibernate.boot.jaxb.mapping.spi.EntityOrMappedSuperclass From efe5424d3502c19546b7372e30fef598535e93a0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Fri, 26 Mar 2021 13:22:09 +0100 Subject: [PATCH 099/644] HHH-14529 Add a few missing enum mappings for orm.xml --- .../internal/ConstraintModeMarshalling.java | 24 +++++++++++++++++++ .../internal/GenerationTypeMarshalling.java | 24 +++++++++++++++++++ .../internal/InheritanceTypeMarshalling.java | 24 +++++++++++++++++++ .../src/main/xjb/mapping-bindings.xjb | 18 ++++++++++++++ 4 files changed, 90 insertions(+) create mode 100644 hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/ConstraintModeMarshalling.java create mode 100644 hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/GenerationTypeMarshalling.java create mode 100644 hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/InheritanceTypeMarshalling.java diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/ConstraintModeMarshalling.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/ConstraintModeMarshalling.java new file mode 100644 index 000000000000..48049d56a763 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/ConstraintModeMarshalling.java @@ -0,0 +1,24 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.boot.jaxb.mapping.internal; + +import javax.persistence.ConstraintMode; + +/** + * Marshalling support for dealing with JPA ConstraintMode enums. Plugged into JAXB for binding + * + * @author Steve Ebersole + */ +public class ConstraintModeMarshalling { + public static ConstraintMode fromXml(String name) { + return ConstraintMode.valueOf( name ); + } + + public static String toXml(ConstraintMode accessType) { + return accessType.name(); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/GenerationTypeMarshalling.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/GenerationTypeMarshalling.java new file mode 100644 index 000000000000..04e815d939a8 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/GenerationTypeMarshalling.java @@ -0,0 +1,24 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.boot.jaxb.mapping.internal; + +import javax.persistence.GenerationType; + +/** + * Marshalling support for dealing with JPA GenerationType enums. Plugged into JAXB for binding + * + * @author Steve Ebersole + */ +public class GenerationTypeMarshalling { + public static GenerationType fromXml(String name) { + return GenerationType.valueOf( name ); + } + + public static String toXml(GenerationType accessType) { + return accessType.name(); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/InheritanceTypeMarshalling.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/InheritanceTypeMarshalling.java new file mode 100644 index 000000000000..93668921b7e2 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/internal/InheritanceTypeMarshalling.java @@ -0,0 +1,24 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.boot.jaxb.mapping.internal; + +import javax.persistence.InheritanceType; + +/** + * Marshalling support for dealing with JPA InheritanceType enums. Plugged into JAXB for binding + * + * @author Steve Ebersole + */ +public class InheritanceTypeMarshalling { + public static InheritanceType fromXml(String name) { + return InheritanceType.valueOf( name ); + } + + public static String toXml(InheritanceType accessType) { + return accessType.name(); + } +} diff --git a/hibernate-core/src/main/xjb/mapping-bindings.xjb b/hibernate-core/src/main/xjb/mapping-bindings.xjb index 5bd32a491484..707a76e6681e 100644 --- a/hibernate-core/src/main/xjb/mapping-bindings.xjb +++ b/hibernate-core/src/main/xjb/mapping-bindings.xjb @@ -59,6 +59,24 @@ printMethod="org.hibernate.boot.jaxb.mapping.internal.TemporalTypeMarshalling.toXml" /> + + + + + + + + + + + + org.hibernate.boot.jaxb.mapping.spi.SchemaAware From b4dd2e272f4c57610ef274ecf646aea6a8f051d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Fri, 26 Mar 2021 13:32:13 +0100 Subject: [PATCH 100/644] HHH-14529 Add a few missing methods to the JAXB representation of ManagedType --- .../boot/jaxb/mapping/spi/EntityOrMappedSuperclass.java | 4 ---- .../org/hibernate/boot/jaxb/mapping/spi/ManagedType.java | 9 +++++++++ 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/EntityOrMappedSuperclass.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/EntityOrMappedSuperclass.java index 5355dd8bbc26..a09d57ff304c 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/EntityOrMappedSuperclass.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/EntityOrMappedSuperclass.java @@ -10,10 +10,6 @@ * Common interface for JAXB bindings representing entities and mapped-superclasses. */ public interface EntityOrMappedSuperclass extends ManagedType { - - String getDescription(); - - void setDescription(String value); JaxbIdClass getIdClass(); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/ManagedType.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/ManagedType.java index ab70cbf6d3db..7d8da934bd0b 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/ManagedType.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/ManagedType.java @@ -16,6 +16,11 @@ * @author Steve Ebersole */ public interface ManagedType { + + String getDescription(); + + void setDescription(String value); + String getClazz(); void setClazz(String className); @@ -25,4 +30,8 @@ public interface ManagedType { void setMetadataComplete(Boolean isMetadataComplete); AccessType getAccess(); + + void setAccess(AccessType value); + + AttributesContainer getAttributes(); } From 437af3b4da6ff00ea3cb798a2c4533ecaa4d7b4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Fri, 26 Mar 2021 15:47:03 +0100 Subject: [PATCH 101/644] HHH-14529 Add a common interface for JaxbEntity, JaxbMappedSuperclass and JaxbEntityListener --- .../mapping/spi/EntityOrMappedSuperclass.java | 2 +- .../spi/LifecycleCallbackContainer.java | 45 +++++++++++++++++++ .../src/main/xjb/mapping-bindings.xjb | 7 ++- 3 files changed, 52 insertions(+), 2 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/LifecycleCallbackContainer.java diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/EntityOrMappedSuperclass.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/EntityOrMappedSuperclass.java index a09d57ff304c..0c33cec1ae1b 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/EntityOrMappedSuperclass.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/EntityOrMappedSuperclass.java @@ -9,7 +9,7 @@ /** * Common interface for JAXB bindings representing entities and mapped-superclasses. */ -public interface EntityOrMappedSuperclass extends ManagedType { +public interface EntityOrMappedSuperclass extends ManagedType, LifecycleCallbackContainer { JaxbIdClass getIdClass(); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/LifecycleCallbackContainer.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/LifecycleCallbackContainer.java new file mode 100644 index 000000000000..7c0550491e23 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/LifecycleCallbackContainer.java @@ -0,0 +1,45 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.boot.jaxb.mapping.spi; + +public interface LifecycleCallbackContainer { + String getDescription(); + + void setDescription(String value); + + JaxbPrePersist getPrePersist(); + + void setPrePersist(JaxbPrePersist value); + + JaxbPostPersist getPostPersist(); + + void setPostPersist(JaxbPostPersist value); + + JaxbPreRemove getPreRemove(); + + void setPreRemove(JaxbPreRemove value); + + JaxbPostRemove getPostRemove(); + + void setPostRemove(JaxbPostRemove value); + + JaxbPreUpdate getPreUpdate(); + + void setPreUpdate(JaxbPreUpdate value); + + JaxbPostUpdate getPostUpdate(); + + void setPostUpdate(JaxbPostUpdate value); + + JaxbPostLoad getPostLoad(); + + void setPostLoad(JaxbPostLoad value); + + String getClazz(); + + void setClazz(String value); +} diff --git a/hibernate-core/src/main/xjb/mapping-bindings.xjb b/hibernate-core/src/main/xjb/mapping-bindings.xjb index 707a76e6681e..c17120a23da3 100644 --- a/hibernate-core/src/main/xjb/mapping-bindings.xjb +++ b/hibernate-core/src/main/xjb/mapping-bindings.xjb @@ -100,6 +100,7 @@ org.hibernate.boot.jaxb.mapping.spi.ManagedType org.hibernate.boot.jaxb.mapping.spi.EntityOrMappedSuperclass + org.hibernate.boot.jaxb.mapping.spi.LifecycleCallbackContainer org.hibernate.boot.jaxb.mapping.spi.ManagedType @@ -107,6 +108,11 @@ org.hibernate.boot.jaxb.mapping.spi.ManagedType org.hibernate.boot.jaxb.mapping.spi.EntityOrMappedSuperclass + org.hibernate.boot.jaxb.mapping.spi.LifecycleCallbackContainer + + + + org.hibernate.boot.jaxb.mapping.spi.LifecycleCallbackContainer @@ -173,7 +179,6 @@ org.hibernate.boot.jaxb.mapping.spi.AttributesContainer - From 10aee2a9fa2b652ed42ff209f9abaf6226a28d9f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Fri, 26 Mar 2021 16:59:09 +0100 Subject: [PATCH 102/644] HHH-14529 Add a common interface for Jaxb representations of associations --- .../mapping/spi/AssociationAttribute.java | 23 +++++++++++++++++++ .../src/main/xjb/mapping-bindings.xjb | 4 ++++ 2 files changed, 27 insertions(+) create mode 100644 hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/AssociationAttribute.java diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/AssociationAttribute.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/AssociationAttribute.java new file mode 100644 index 000000000000..f9784577abb8 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/AssociationAttribute.java @@ -0,0 +1,23 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.boot.jaxb.mapping.spi; + +public interface AssociationAttribute extends PersistentAttribute, FetchableAttribute { + + JaxbJoinTable getJoinTable(); + + void setJoinTable(JaxbJoinTable value); + + JaxbCascadeType getCascade(); + + void setCascade(JaxbCascadeType value); + + String getTargetEntity(); + + void setTargetEntity(String value); + +} diff --git a/hibernate-core/src/main/xjb/mapping-bindings.xjb b/hibernate-core/src/main/xjb/mapping-bindings.xjb index c17120a23da3..1c611dcf0165 100644 --- a/hibernate-core/src/main/xjb/mapping-bindings.xjb +++ b/hibernate-core/src/main/xjb/mapping-bindings.xjb @@ -127,14 +127,17 @@ org.hibernate.boot.jaxb.mapping.spi.PersistentAttribute org.hibernate.boot.jaxb.mapping.spi.FetchableAttribute + org.hibernate.boot.jaxb.mapping.spi.AssociationAttribute org.hibernate.boot.jaxb.mapping.spi.PersistentAttribute org.hibernate.boot.jaxb.mapping.spi.CollectionAttribute + org.hibernate.boot.jaxb.mapping.spi.AssociationAttribute org.hibernate.boot.jaxb.mapping.spi.PersistentAttribute org.hibernate.boot.jaxb.mapping.spi.FetchableAttribute + org.hibernate.boot.jaxb.mapping.spi.AssociationAttribute org.hibernate.boot.jaxb.mapping.spi.PersistentAttribute @@ -145,6 +148,7 @@ org.hibernate.boot.jaxb.mapping.spi.PersistentAttribute org.hibernate.boot.jaxb.mapping.spi.CollectionAttribute + org.hibernate.boot.jaxb.mapping.spi.AssociationAttribute org.hibernate.boot.jaxb.mapping.spi.PersistentAttribute From ac4f4ff4ad3c260c5ec996ba668a7760c8c429bf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Tue, 30 Mar 2021 16:20:03 +0200 Subject: [PATCH 103/644] HHH-14529 Implement the (opt-in) orm.xml handling using JAXB --- .../boot/jaxb/mapping/spi/NamedQuery.java | 31 + .../JPAXMLOverriddenAnnotationReader.java | 1762 ++++++++--------- .../JPAXMLOverriddenMetadataProvider.java | 34 +- .../PropertyMappingElementCollector.java | 214 ++ .../reflection/internal/XMLContext.java | 184 +- .../src/main/xjb/mapping-bindings.xjb | 6 +- .../internal/util/xml/XMLMappingHelper.java | 51 + .../JPAXMLOverriddenAnnotationReaderTest.java | 37 +- .../reflection/XMLContextTest.java | 55 +- .../annotations/xml/ejb3/Ejb3XmlTestCase.java | 32 +- 10 files changed, 1309 insertions(+), 1097 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/NamedQuery.java create mode 100644 hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/PropertyMappingElementCollector.java create mode 100644 hibernate-core/src/test/java/org/hibernate/internal/util/xml/XMLMappingHelper.java diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/NamedQuery.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/NamedQuery.java new file mode 100644 index 000000000000..79ded21dc1d3 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/mapping/spi/NamedQuery.java @@ -0,0 +1,31 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.boot.jaxb.mapping.spi; + +import java.io.Serializable; +import java.util.List; +import javax.persistence.LockModeType; + +public interface NamedQuery extends Serializable { + String getDescription(); + + void setDescription(String value); + + String getQuery(); + + void setQuery(String value); + + LockModeType getLockMode(); + + void setLockMode(LockModeType value); + + List getHint(); + + String getName(); + + void setName(String value); +} diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenAnnotationReader.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenAnnotationReader.java index 30cbae7208b4..c91855d43efa 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenAnnotationReader.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenAnnotationReader.java @@ -14,13 +14,13 @@ import java.lang.reflect.Method; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; -import java.util.Iterator; import java.util.List; -import java.util.Locale; import java.util.Map; import java.util.Set; +import java.util.function.Function; import javax.persistence.Access; import javax.persistence.AccessType; import javax.persistence.AssociationOverride; @@ -123,6 +123,67 @@ import org.hibernate.annotations.common.annotationfactory.AnnotationFactory; import org.hibernate.annotations.common.reflection.AnnotationReader; import org.hibernate.annotations.common.reflection.ReflectionUtil; +import org.hibernate.boot.jaxb.mapping.spi.AssociationAttribute; +import org.hibernate.boot.jaxb.mapping.spi.AttributesContainer; +import org.hibernate.boot.jaxb.mapping.spi.EntityOrMappedSuperclass; +import org.hibernate.boot.jaxb.mapping.spi.JaxbAssociationOverride; +import org.hibernate.boot.jaxb.mapping.spi.JaxbAttributeOverride; +import org.hibernate.boot.jaxb.mapping.spi.JaxbAttributes; +import org.hibernate.boot.jaxb.mapping.spi.JaxbBasic; +import org.hibernate.boot.jaxb.mapping.spi.JaxbCascadeType; +import org.hibernate.boot.jaxb.mapping.spi.JaxbCollectionTable; +import org.hibernate.boot.jaxb.mapping.spi.JaxbColumn; +import org.hibernate.boot.jaxb.mapping.spi.JaxbColumnResult; +import org.hibernate.boot.jaxb.mapping.spi.JaxbConstructorResult; +import org.hibernate.boot.jaxb.mapping.spi.JaxbConvert; +import org.hibernate.boot.jaxb.mapping.spi.JaxbDiscriminatorColumn; +import org.hibernate.boot.jaxb.mapping.spi.JaxbElementCollection; +import org.hibernate.boot.jaxb.mapping.spi.JaxbEmbeddable; +import org.hibernate.boot.jaxb.mapping.spi.JaxbEmbedded; +import org.hibernate.boot.jaxb.mapping.spi.JaxbEmbeddedId; +import org.hibernate.boot.jaxb.mapping.spi.JaxbEmptyType; +import org.hibernate.boot.jaxb.mapping.spi.JaxbEntity; +import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityListener; +import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityListeners; +import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityResult; +import org.hibernate.boot.jaxb.mapping.spi.JaxbFieldResult; +import org.hibernate.boot.jaxb.mapping.spi.JaxbGeneratedValue; +import org.hibernate.boot.jaxb.mapping.spi.JaxbId; +import org.hibernate.boot.jaxb.mapping.spi.JaxbIdClass; +import org.hibernate.boot.jaxb.mapping.spi.JaxbIndex; +import org.hibernate.boot.jaxb.mapping.spi.JaxbInheritance; +import org.hibernate.boot.jaxb.mapping.spi.JaxbJoinColumn; +import org.hibernate.boot.jaxb.mapping.spi.JaxbJoinTable; +import org.hibernate.boot.jaxb.mapping.spi.JaxbLob; +import org.hibernate.boot.jaxb.mapping.spi.JaxbManyToMany; +import org.hibernate.boot.jaxb.mapping.spi.JaxbManyToOne; +import org.hibernate.boot.jaxb.mapping.spi.JaxbMapKey; +import org.hibernate.boot.jaxb.mapping.spi.JaxbMapKeyClass; +import org.hibernate.boot.jaxb.mapping.spi.JaxbMapKeyColumn; +import org.hibernate.boot.jaxb.mapping.spi.JaxbMapKeyJoinColumn; +import org.hibernate.boot.jaxb.mapping.spi.JaxbMappedSuperclass; +import org.hibernate.boot.jaxb.mapping.spi.JaxbNamedAttributeNode; +import org.hibernate.boot.jaxb.mapping.spi.JaxbNamedEntityGraph; +import org.hibernate.boot.jaxb.mapping.spi.JaxbNamedNativeQuery; +import org.hibernate.boot.jaxb.mapping.spi.JaxbNamedQuery; +import org.hibernate.boot.jaxb.mapping.spi.JaxbNamedStoredProcedureQuery; +import org.hibernate.boot.jaxb.mapping.spi.JaxbNamedSubgraph; +import org.hibernate.boot.jaxb.mapping.spi.JaxbOneToMany; +import org.hibernate.boot.jaxb.mapping.spi.JaxbOneToOne; +import org.hibernate.boot.jaxb.mapping.spi.JaxbOrderColumn; +import org.hibernate.boot.jaxb.mapping.spi.JaxbPrimaryKeyJoinColumn; +import org.hibernate.boot.jaxb.mapping.spi.JaxbQueryHint; +import org.hibernate.boot.jaxb.mapping.spi.JaxbSecondaryTable; +import org.hibernate.boot.jaxb.mapping.spi.JaxbSequenceGenerator; +import org.hibernate.boot.jaxb.mapping.spi.JaxbSqlResultSetMapping; +import org.hibernate.boot.jaxb.mapping.spi.JaxbStoredProcedureParameter; +import org.hibernate.boot.jaxb.mapping.spi.JaxbTable; +import org.hibernate.boot.jaxb.mapping.spi.JaxbTableGenerator; +import org.hibernate.boot.jaxb.mapping.spi.JaxbTransient; +import org.hibernate.boot.jaxb.mapping.spi.JaxbUniqueConstraint; +import org.hibernate.boot.jaxb.mapping.spi.JaxbVersion; +import org.hibernate.boot.jaxb.mapping.spi.LifecycleCallbackContainer; +import org.hibernate.boot.jaxb.mapping.spi.ManagedType; import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; import org.hibernate.boot.spi.BootstrapContext; import org.hibernate.boot.spi.ClassLoaderAccess; @@ -131,8 +192,8 @@ import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.StringHelper; -import org.dom4j.Attribute; -import org.dom4j.Element; +import static org.hibernate.cfg.annotations.reflection.internal.PropertyMappingElementCollector.JAXB_TRANSIENT_NAME; +import static org.hibernate.cfg.annotations.reflection.internal.PropertyMappingElementCollector.PERSISTENT_ATTRIBUTE_NAME; /** * Encapsulates the overriding of Java annotations from an EJB 3.0 descriptor (orm.xml, ...). @@ -249,7 +310,7 @@ private enum PropertyType { private final PropertyType propertyType; private transient Annotation[] annotations; private transient Map annotationsMap; - private transient List elementsForProperty; + private transient PropertyMappingElementCollector elementsForProperty; private AccessibleObject mirroredAttribute; JPAXMLOverriddenAnnotationReader( @@ -349,7 +410,7 @@ private void initAnnotations() { XMLContext.Default defaults = xmlContext.getDefault( className ); if ( className != null && propertyName == null ) { //is a class - Element tree = xmlContext.getXMLTree( className ); + ManagedType managedTypeOverride = xmlContext.getManagedTypeOverride( className ); Annotation[] annotations = getPhysicalAnnotations(); List annotationList = new ArrayList<>( annotations.length + 5 ); annotationsMap = new HashMap<>( annotations.length + 5 ); @@ -359,40 +420,41 @@ private void initAnnotations() { annotationList.add( annotation ); } } - addIfNotNull( annotationList, getEntity( tree, defaults ) ); - addIfNotNull( annotationList, getMappedSuperclass( tree, defaults ) ); - addIfNotNull( annotationList, getEmbeddable( tree, defaults ) ); - addIfNotNull( annotationList, getTable( tree, defaults ) ); - addIfNotNull( annotationList, getSecondaryTables( tree, defaults ) ); - addIfNotNull( annotationList, getPrimaryKeyJoinColumns( tree, defaults, true ) ); - addIfNotNull( annotationList, getIdClass( tree, defaults ) ); - addIfNotNull( annotationList, getCacheable( tree, defaults ) ); - addIfNotNull( annotationList, getInheritance( tree, defaults ) ); - addIfNotNull( annotationList, getDiscriminatorValue( tree, defaults ) ); - addIfNotNull( annotationList, getDiscriminatorColumn( tree, defaults ) ); - addIfNotNull( annotationList, getSequenceGenerator( tree, defaults ) ); - addIfNotNull( annotationList, getTableGenerator( tree, defaults ) ); - addIfNotNull( annotationList, getNamedQueries( tree, defaults ) ); - addIfNotNull( annotationList, getNamedNativeQueries( tree, defaults ) ); - addIfNotNull( annotationList, getNamedStoredProcedureQueries( tree, defaults ) ); - addIfNotNull( annotationList, getNamedEntityGraphs( tree, defaults ) ); - addIfNotNull( annotationList, getSqlResultSetMappings( tree, defaults ) ); - addIfNotNull( annotationList, getExcludeDefaultListeners( tree, defaults ) ); - addIfNotNull( annotationList, getExcludeSuperclassListeners( tree, defaults ) ); - addIfNotNull( annotationList, getAccessType( tree, defaults ) ); - addIfNotNull( annotationList, getAttributeOverrides( tree, defaults, true ) ); - addIfNotNull( annotationList, getAssociationOverrides( tree, defaults, true ) ); - addIfNotNull( annotationList, getEntityListeners( tree, defaults ) ); - addIfNotNull( annotationList, getConverts( tree, defaults ) ); + addIfNotNull( annotationList, getEntity( managedTypeOverride, defaults ) ); + addIfNotNull( annotationList, getMappedSuperclass( managedTypeOverride, defaults ) ); + addIfNotNull( annotationList, getEmbeddable( managedTypeOverride, defaults ) ); + addIfNotNull( annotationList, getTable( managedTypeOverride, defaults ) ); + addIfNotNull( annotationList, getSecondaryTables( managedTypeOverride, defaults ) ); + addIfNotNull( annotationList, getPrimaryKeyJoinColumns( managedTypeOverride, defaults ) ); + addIfNotNull( annotationList, getIdClass( managedTypeOverride, defaults ) ); + addIfNotNull( annotationList, getCacheable( managedTypeOverride, defaults ) ); + addIfNotNull( annotationList, getInheritance( managedTypeOverride, defaults ) ); + addIfNotNull( annotationList, getDiscriminatorValue( managedTypeOverride, defaults ) ); + addIfNotNull( annotationList, getDiscriminatorColumn( managedTypeOverride, defaults ) ); + addIfNotNull( annotationList, getSequenceGenerator( managedTypeOverride, defaults ) ); + addIfNotNull( annotationList, getTableGenerator( managedTypeOverride, defaults ) ); + addIfNotNull( annotationList, getNamedQueries( managedTypeOverride, defaults ) ); + addIfNotNull( annotationList, getNamedNativeQueries( managedTypeOverride, defaults ) ); + addIfNotNull( annotationList, getNamedStoredProcedureQueries( managedTypeOverride, defaults ) ); + addIfNotNull( annotationList, getNamedEntityGraphs( managedTypeOverride, defaults ) ); + addIfNotNull( annotationList, getSqlResultSetMappings( managedTypeOverride, defaults ) ); + addIfNotNull( annotationList, getExcludeDefaultListeners( managedTypeOverride, defaults ) ); + addIfNotNull( annotationList, getExcludeSuperclassListeners( managedTypeOverride, defaults ) ); + addIfNotNull( annotationList, getAccessType( managedTypeOverride, defaults ) ); + addIfNotNull( annotationList, getAttributeOverrides( managedTypeOverride, defaults ) ); + addIfNotNull( annotationList, getAssociationOverrides( managedTypeOverride, defaults ) ); + addIfNotNull( annotationList, getEntityListeners( managedTypeOverride, defaults ) ); + addIfNotNull( annotationList, getConverts( managedTypeOverride, defaults ) ); this.annotations = annotationList.toArray( new Annotation[annotationList.size()] ); for ( Annotation ann : this.annotations ) { annotationsMap.put( ann.annotationType(), ann ); } - checkForOrphanProperties( tree ); + checkForOrphanProperties( managedTypeOverride ); } else if ( className != null ) { //&& propertyName != null ) { //always true but less confusing - Element tree = xmlContext.getXMLTree( className ); + ManagedType managedTypeOverride = xmlContext.getManagedTypeOverride( className ); + JaxbEntityListener entityListenerOverride = xmlContext.getEntityListenerOverride( className ); Annotation[] annotations = getPhysicalAnnotations(); List annotationList = new ArrayList<>( annotations.length + 5 ); annotationsMap = new HashMap<>( annotations.length + 5 ); @@ -402,7 +464,7 @@ else if ( className != null ) { //&& propertyName != null ) { //always true but annotationList.add( annotation ); } } - preCalculateElementsForProperty( tree ); + preCalculateElementsForProperty( managedTypeOverride, entityListenerOverride ); Transient transientAnn = getTransient( defaults ); if ( transientAnn != null ) { annotationList.add( transientAnn ); @@ -417,12 +479,12 @@ else if ( className != null ) { //&& propertyName != null ) { //always true but getEmbedded( annotationList, defaults ); getBasic( annotationList, defaults ); getVersion( annotationList, defaults ); - getAssociation( ManyToOne.class, annotationList, defaults ); - getAssociation( OneToOne.class, annotationList, defaults ); - getAssociation( OneToMany.class, annotationList, defaults ); - getAssociation( ManyToMany.class, annotationList, defaults ); - getAssociation( Any.class, annotationList, defaults ); - getAssociation( ManyToAny.class, annotationList, defaults ); + getManyToOne( annotationList, defaults ); + getOneToOne( annotationList, defaults ); + getOneToMany( annotationList, defaults ); + getManyToMany( annotationList, defaults ); + getAny( annotationList, defaults ); + getManyToAny( annotationList, defaults ); getElementCollection( annotationList, defaults ); addIfNotNull( annotationList, getSequenceGenerator( elementsForProperty, defaults ) ); addIfNotNull( annotationList, getTableGenerator( elementsForProperty, defaults ) ); @@ -445,7 +507,7 @@ else if ( className != null ) { //&& propertyName != null ) { //always true but } } - private Annotation getConvertsForAttribute(List elementsForProperty, XMLContext.Default defaults) { + private Annotation getConvertsForAttribute(PropertyMappingElementCollector elementsForProperty, XMLContext.Default defaults) { // NOTE : we use a map here to make sure that an xml and annotation referring to the same attribute // properly overrides. Very sparse map, yes, but easy setup. // todo : revisit this @@ -453,19 +515,18 @@ private Annotation getConvertsForAttribute(List elementsForProperty, XM final Map convertAnnotationsMap = new HashMap<>(); - for ( Element element : elementsForProperty ) { - final boolean isBasic = "basic".equals( element.getName() ); - final boolean isEmbedded = "embedded".equals( element.getName() ); - final boolean isElementCollection = "element-collection".equals(element.getName()); - - final boolean canHaveConverts = isBasic || isEmbedded || isElementCollection; - - if ( !canHaveConverts ) { - continue; + for ( JaxbBasic element : elementsForProperty.getBasic() ) { + JaxbConvert convert = element.getConvert(); + if ( convert != null ) { + applyXmlDefinedConverts( Collections.singletonList( convert ), defaults, null, + convertAnnotationsMap ); } - - final String attributeNamePrefix = isBasic ? null : propertyName; - applyXmlDefinedConverts( element, defaults, attributeNamePrefix, convertAnnotationsMap ); + } + for ( JaxbEmbedded element : elementsForProperty.getEmbedded() ) { + applyXmlDefinedConverts( element.getConvert(), defaults, propertyName, convertAnnotationsMap ); + } + for ( JaxbElementCollection element : elementsForProperty.getElementCollection() ) { + applyXmlDefinedConverts( element.getConvert(), defaults, propertyName, convertAnnotationsMap ); } // NOTE : per section 12.2.3.16 of the spec is additive, although only if "metadata-complete" is not @@ -485,13 +546,13 @@ private Annotation getConvertsForAttribute(List elementsForProperty, XM return null; } - private Converts getConverts(Element tree, XMLContext.Default defaults) { + private Converts getConverts(ManagedType root, XMLContext.Default defaults) { // NOTE : we use a map here to make sure that an xml and annotation referring to the same attribute // properly overrides. Bit sparse, but easy... final Map convertAnnotationsMap = new HashMap<>(); - if ( tree != null ) { - applyXmlDefinedConverts( tree, defaults, null, convertAnnotationsMap ); + if ( root instanceof JaxbEntity ) { + applyXmlDefinedConverts( ( (JaxbEntity) root ).getConvert(), defaults, null, convertAnnotationsMap ); } // NOTE : per section 12.2.3.16 of the spec is additive, although only if "metadata-complete" is not @@ -511,20 +572,19 @@ private Converts getConverts(Element tree, XMLContext.Default defaults) { } private void applyXmlDefinedConverts( - Element containingElement, + List elements, XMLContext.Default defaults, String attributeNamePrefix, Map convertAnnotationsMap) { - final List convertElements = containingElement.elements( "convert" ); - for ( Element convertElement : convertElements ) { + for ( JaxbConvert convertElement : elements ) { final AnnotationDescriptor convertAnnotationDescriptor = new AnnotationDescriptor( Convert.class ); - copyStringAttribute( convertAnnotationDescriptor, convertElement, "attribute-name", false ); - copyBooleanAttribute( convertAnnotationDescriptor, convertElement, "disable-conversion" ); + copyAttribute( convertAnnotationDescriptor, "attribute-name", convertElement.getAttributeName(), false ); + copyAttribute( convertAnnotationDescriptor, "disable-conversion", convertElement.isDisableConversion(), false ); - final Attribute converterClassAttr = convertElement.attribute( "converter" ); - if ( converterClassAttr != null ) { + final String converter = convertElement.getConverter(); + if ( converter != null ) { final String converterClassName = XMLContext.buildSafeClassName( - converterClassAttr.getValue(), + converter, defaults ); try { @@ -584,7 +644,7 @@ private void applyPhysicalConvertAnnotations( } } - private void checkForOrphanProperties(Element tree) { + private void checkForOrphanProperties(ManagedType root) { Class clazz; try { clazz = classLoaderAccess.classForName( className ); @@ -592,9 +652,9 @@ private void checkForOrphanProperties(Element tree) { catch ( ClassLoadingException e ) { return; //a primitive type most likely } - Element element = tree != null ? tree.element( "attributes" ) : null; + AttributesContainer container = root != null ? root.getAttributes() : null; //put entity.attributes elements - if ( element != null ) { + if ( container != null ) { //precompute the list of properties //TODO is it really useful... Set properties = new HashSet<>(); @@ -610,12 +670,38 @@ else if ( name.startsWith( "is" ) ) { properties.add( Introspector.decapitalize( name.substring( "is".length() ) ) ); } } - for ( Element subelement : (List) element.elements() ) { - String propertyName = subelement.attributeValue( "name" ); - if ( !properties.contains( propertyName ) ) { - LOG.propertyNotFound( StringHelper.qualify( className, propertyName ) ); - } + if ( container instanceof JaxbAttributes ) { + JaxbAttributes jaxbAttributes = (JaxbAttributes) container; + checkForOrphanProperties( jaxbAttributes.getId(), properties, PERSISTENT_ATTRIBUTE_NAME ); + checkForOrphanProperties( jaxbAttributes.getEmbeddedId(), properties, PERSISTENT_ATTRIBUTE_NAME ); + checkForOrphanProperties( jaxbAttributes.getVersion(), properties, PERSISTENT_ATTRIBUTE_NAME ); } + checkForOrphanProperties( container.getBasic(), properties, PERSISTENT_ATTRIBUTE_NAME ); + checkForOrphanProperties( container.getManyToOne(), properties, PERSISTENT_ATTRIBUTE_NAME ); + checkForOrphanProperties( container.getOneToMany(), properties, PERSISTENT_ATTRIBUTE_NAME ); + checkForOrphanProperties( container.getOneToOne(), properties, PERSISTENT_ATTRIBUTE_NAME ); + checkForOrphanProperties( container.getManyToMany(), properties, PERSISTENT_ATTRIBUTE_NAME ); + checkForOrphanProperties( container.getElementCollection(), properties, PERSISTENT_ATTRIBUTE_NAME ); + checkForOrphanProperties( container.getEmbedded(), properties, PERSISTENT_ATTRIBUTE_NAME ); + checkForOrphanProperties( container.getTransient(), properties, JAXB_TRANSIENT_NAME ); + } + } + + private void checkForOrphanProperties(List elements, Set properties, + Function nameGetter) { + for ( T element : elements ) { + checkForOrphanProperties( element, properties, nameGetter ); + } + } + + private void checkForOrphanProperties(T element, Set properties, + Function nameGetter) { + if ( element == null ) { + return; + } + String propertyName = nameGetter.apply( element ); + if ( !properties.contains( propertyName ) ) { + LOG.propertyNotFound( StringHelper.qualify( className, propertyName ) ); } } @@ -635,14 +721,14 @@ private Annotation addIfNotNull(List annotationList, Annotation anno } //TODO mutualize the next 2 methods - private Annotation getTableGenerator(List elementsForProperty, XMLContext.Default defaults) { - for ( Element element : elementsForProperty ) { - Element subelement = element != null ? element.element( annotationToXml.get( TableGenerator.class ) ) : null; + private Annotation getTableGenerator(PropertyMappingElementCollector elementsForProperty, XMLContext.Default defaults) { + for ( JaxbId element : elementsForProperty.getId() ) { + JaxbTableGenerator subelement = element.getTableGenerator(); if ( subelement != null ) { return buildTableGeneratorAnnotation( subelement, defaults ); } } - if ( elementsForProperty.size() == 0 && defaults.canUseJavaAnnotations() ) { + if ( elementsForProperty.isEmpty() && defaults.canUseJavaAnnotations() ) { return getPhysicalAnnotation( TableGenerator.class ); } else { @@ -650,14 +736,14 @@ private Annotation getTableGenerator(List elementsForProperty, XMLConte } } - private Annotation getSequenceGenerator(List elementsForProperty, XMLContext.Default defaults) { - for ( Element element : elementsForProperty ) { - Element subelement = element != null ? element.element( annotationToXml.get( SequenceGenerator.class ) ) : null; + private Annotation getSequenceGenerator(PropertyMappingElementCollector elementsForProperty, XMLContext.Default defaults) { + for ( JaxbId element : elementsForProperty.getId() ) { + JaxbSequenceGenerator subelement = element.getSequenceGenerator(); if ( subelement != null ) { return buildSequenceGeneratorAnnotation( subelement ); } } - if ( elementsForProperty.size() == 0 && defaults.canUseJavaAnnotations() ) { + if ( elementsForProperty.isEmpty() && defaults.canUseJavaAnnotations() ) { return getPhysicalAnnotation( SequenceGenerator.class ); } else { @@ -667,43 +753,40 @@ private Annotation getSequenceGenerator(List elementsForProperty, XMLCo private void processEventAnnotations(List annotationList, XMLContext.Default defaults) { boolean eventElement = false; - for ( Element element : elementsForProperty ) { - String elementName = element.getName(); - if ( "pre-persist".equals( elementName ) ) { - AnnotationDescriptor ad = new AnnotationDescriptor( PrePersist.class ); - annotationList.add( AnnotationFactory.create( ad ) ); - eventElement = true; - } - else if ( "pre-remove".equals( elementName ) ) { - AnnotationDescriptor ad = new AnnotationDescriptor( PreRemove.class ); - annotationList.add( AnnotationFactory.create( ad ) ); - eventElement = true; - } - else if ( "pre-update".equals( elementName ) ) { - AnnotationDescriptor ad = new AnnotationDescriptor( PreUpdate.class ); - annotationList.add( AnnotationFactory.create( ad ) ); - eventElement = true; - } - else if ( "post-persist".equals( elementName ) ) { - AnnotationDescriptor ad = new AnnotationDescriptor( PostPersist.class ); - annotationList.add( AnnotationFactory.create( ad ) ); - eventElement = true; - } - else if ( "post-remove".equals( elementName ) ) { - AnnotationDescriptor ad = new AnnotationDescriptor( PostRemove.class ); - annotationList.add( AnnotationFactory.create( ad ) ); - eventElement = true; - } - else if ( "post-update".equals( elementName ) ) { - AnnotationDescriptor ad = new AnnotationDescriptor( PostUpdate.class ); - annotationList.add( AnnotationFactory.create( ad ) ); - eventElement = true; - } - else if ( "post-load".equals( elementName ) ) { - AnnotationDescriptor ad = new AnnotationDescriptor( PostLoad.class ); - annotationList.add( AnnotationFactory.create( ad ) ); - eventElement = true; - } + if ( !elementsForProperty.getPrePersist().isEmpty() ) { + AnnotationDescriptor ad = new AnnotationDescriptor( PrePersist.class ); + annotationList.add( AnnotationFactory.create( ad ) ); + eventElement = true; + } + else if ( !elementsForProperty.getPreRemove().isEmpty() ) { + AnnotationDescriptor ad = new AnnotationDescriptor( PreRemove.class ); + annotationList.add( AnnotationFactory.create( ad ) ); + eventElement = true; + } + else if ( !elementsForProperty.getPreUpdate().isEmpty() ) { + AnnotationDescriptor ad = new AnnotationDescriptor( PreUpdate.class ); + annotationList.add( AnnotationFactory.create( ad ) ); + eventElement = true; + } + else if ( !elementsForProperty.getPostPersist().isEmpty() ) { + AnnotationDescriptor ad = new AnnotationDescriptor( PostPersist.class ); + annotationList.add( AnnotationFactory.create( ad ) ); + eventElement = true; + } + else if ( !elementsForProperty.getPostRemove().isEmpty() ) { + AnnotationDescriptor ad = new AnnotationDescriptor( PostRemove.class ); + annotationList.add( AnnotationFactory.create( ad ) ); + eventElement = true; + } + else if ( !elementsForProperty.getPostUpdate().isEmpty() ) { + AnnotationDescriptor ad = new AnnotationDescriptor( PostUpdate.class ); + annotationList.add( AnnotationFactory.create( ad ) ); + eventElement = true; + } + else if ( !elementsForProperty.getPostLoad().isEmpty() ) { + AnnotationDescriptor ad = new AnnotationDescriptor( PostLoad.class ); + annotationList.add( AnnotationFactory.create( ad ) ); + eventElement = true; } if ( !eventElement && defaults.canUseJavaAnnotations() ) { Annotation ann = getPhysicalAnnotation( PrePersist.class ); @@ -723,12 +806,12 @@ else if ( "post-load".equals( elementName ) ) { } } - private EntityListeners getEntityListeners(Element tree, XMLContext.Default defaults) { - Element element = tree != null ? tree.element( "entity-listeners" ) : null; + private EntityListeners getEntityListeners(ManagedType root, XMLContext.Default defaults) { + JaxbEntityListeners element = root instanceof EntityOrMappedSuperclass ? ( (EntityOrMappedSuperclass) root ).getEntityListeners() : null; if ( element != null ) { List entityListenerClasses = new ArrayList<>(); - for ( Element subelement : (List) element.elements( "entity-listener" ) ) { - String className = subelement.attributeValue( "class" ); + for ( JaxbEntityListener subelement : element.getEntityListener() ) { + String className = subelement.getClazz(); try { entityListenerClasses.add( classLoaderAccess.classForName( @@ -738,7 +821,7 @@ private EntityListeners getEntityListeners(Element tree, XMLContext.Default defa } catch ( ClassLoadingException e ) { throw new AnnotationException( - "Unable to find " + element.getPath() + ".class: " + className, e + "Unable to find class: " + className, e ); } } @@ -844,39 +927,68 @@ else if ( annotationType == OneToOne.class ) { return annotation; } - private void getJoinTable(List annotationList, Element tree, XMLContext.Default defaults) { - addIfNotNull( annotationList, buildJoinTable( tree, defaults ) ); + private void getJoinTable(List annotationList, AssociationAttribute associationAttribute, + XMLContext.Default defaults) { + addIfNotNull( annotationList, buildJoinTable( associationAttribute.getJoinTable(), defaults ) ); } /* * no partial overriding possible */ - private JoinTable buildJoinTable(Element tree, XMLContext.Default defaults) { - Element subelement = tree == null ? null : tree.element( "join-table" ); + private JoinTable buildJoinTable(JaxbJoinTable subelement, XMLContext.Default defaults) { final Class annotationType = JoinTable.class; if ( subelement == null ) { return null; } //ignore java annotation, an element is defined AnnotationDescriptor annotation = new AnnotationDescriptor( annotationType ); - copyStringAttribute( annotation, subelement, "name", false ); - copyStringAttribute( annotation, subelement, "catalog", false ); + copyAttribute( annotation, "name", subelement.getName(), false ); + copyAttribute( annotation, "catalog", subelement.getCatalog(), false ); if ( StringHelper.isNotEmpty( defaults.getCatalog() ) && StringHelper.isEmpty( (String) annotation.valueOf( "catalog" ) ) ) { annotation.setValue( "catalog", defaults.getCatalog() ); } - copyStringAttribute( annotation, subelement, "schema", false ); + copyAttribute( annotation, "schema", subelement.getSchema(), false ); if ( StringHelper.isNotEmpty( defaults.getSchema() ) && StringHelper.isEmpty( (String) annotation.valueOf( "schema" ) ) ) { annotation.setValue( "schema", defaults.getSchema() ); } - buildUniqueConstraints( annotation, subelement ); - buildIndex( annotation, subelement ); - annotation.setValue( "joinColumns", getJoinColumns( subelement, false ) ); - annotation.setValue( "inverseJoinColumns", getJoinColumns( subelement, true ) ); + buildUniqueConstraints( annotation, subelement.getUniqueConstraint() ); + buildIndex( annotation, subelement.getIndex() ); + annotation.setValue( "joinColumns", getJoinColumns( subelement.getJoinColumn(), false ) ); + annotation.setValue( "inverseJoinColumns", getJoinColumns( subelement.getInverseJoinColumn(), true ) ); return AnnotationFactory.create( annotation ); } + private void getOneToMany(List annotationList, XMLContext.Default defaults) { + Class annotationType = OneToMany.class; + List elements = elementsForProperty.getOneToMany(); + for ( JaxbOneToMany element : elements ) { + AnnotationDescriptor ad = new AnnotationDescriptor( annotationType ); + addTargetClass( element.getTargetEntity(), ad, "target-entity", defaults ); + getFetchType( ad, element.getFetch() ); + getCascades( ad, element.getCascade(), defaults ); + getJoinTable( annotationList, element, defaults ); + buildJoinColumns( annotationList, element.getJoinColumn() ); + copyAttribute( ad, "orphan-removal", element.isOrphanRemoval(), false ); + copyAttribute( ad, "mapped-by", element.getMappedBy(), false ); + annotationList.add( AnnotationFactory.create( ad ) ); + + getOrderBy( annotationList, element.getOrderBy() ); + getMapKey( annotationList, element.getMapKey() ); + getMapKeyClass( annotationList, element.getMapKeyClass(), defaults ); + getMapKeyColumn( annotationList, element.getMapKeyColumn() ); + getOrderColumn( annotationList, element.getOrderColumn() ); + getMapKeyTemporal( annotationList, element.getMapKeyTemporal() ); + getMapKeyEnumerated( annotationList, element.getMapKeyEnumerated() ); + Annotation annotation = getMapKeyAttributeOverrides( element.getMapKeyAttributeOverride(), defaults ); + addIfNotNull( annotationList, annotation ); + getMapKeyJoinColumns( annotationList, element.getMapKeyJoinColumn() ); + getAccessType( annotationList, element.getAccess() ); + } + afterGetAssociation( annotationType, annotationList, defaults ); + } + /** * As per section 12.2 of the JPA 2.0 specification, the association * subelements (many-to-one, one-to-many, one-to-one, many-to-many, @@ -886,40 +998,100 @@ private JoinTable buildJoinTable(Element tree, XMLContext.Default defaults) { * * @see #getElementCollection(List, XMLContext.Default) */ - private void getAssociation( - Class annotationType, List annotationList, XMLContext.Default defaults - ) { - String xmlName = annotationToXml.get( annotationType ); - for ( Element element : elementsForProperty ) { - if ( xmlName.equals( element.getName() ) ) { - AnnotationDescriptor ad = new AnnotationDescriptor( annotationType ); - addTargetClass( element, ad, "target-entity", defaults ); - getFetchType( ad, element ); - getCascades( ad, element, defaults ); - getJoinTable( annotationList, element, defaults ); - buildJoinColumns( annotationList, element ); - Annotation annotation = getPrimaryKeyJoinColumns( element, defaults, false ); - addIfNotNull( annotationList, annotation ); - copyBooleanAttribute( ad, element, "optional" ); - copyBooleanAttribute( ad, element, "orphan-removal" ); - copyStringAttribute( ad, element, "mapped-by", false ); - getOrderBy( annotationList, element ); - getMapKey( annotationList, element ); - getMapKeyClass( annotationList, element, defaults ); - getMapKeyColumn( annotationList, element ); - getOrderColumn( annotationList, element ); - getMapKeyTemporal( annotationList, element ); - getMapKeyEnumerated( annotationList, element ); - annotation = getMapKeyAttributeOverrides( element, defaults ); - addIfNotNull( annotationList, annotation ); - buildMapKeyJoinColumns( annotationList, element ); - getAssociationId( annotationList, element ); - getMapsId( annotationList, element ); - annotationList.add( AnnotationFactory.create( ad ) ); - getAccessType( annotationList, element ); - } + private void getOneToOne(List annotationList, XMLContext.Default defaults) { + Class annotationType = OneToOne.class; + List elements = elementsForProperty.getOneToOne(); + for ( JaxbOneToOne element : elements ) { + AnnotationDescriptor ad = new AnnotationDescriptor( annotationType ); + addTargetClass( element.getTargetEntity(), ad, "target-entity", defaults ); + getFetchType( ad, element.getFetch() ); + getCascades( ad, element.getCascade(), defaults ); + getJoinTable( annotationList, element, defaults ); + buildJoinColumns( annotationList, element.getJoinColumn() ); + Annotation annotation = getPrimaryKeyJoinColumns( element.getPrimaryKeyJoinColumn(), defaults, false ); + addIfNotNull( annotationList, annotation ); + copyAttribute( ad, "optional", element.isOptional(), false ); + copyAttribute( ad, "orphan-removal", element.isOrphanRemoval(), false ); + copyAttribute( ad, "mapped-by", element.getMappedBy(), false ); + annotationList.add( AnnotationFactory.create( ad ) ); + + getAssociationId( annotationList, element.isId() ); + getMapsId( annotationList, element.getMapsId() ); + getAccessType( annotationList, element.getAccess() ); } - if ( elementsForProperty.size() == 0 && defaults.canUseJavaAnnotations() ) { + afterGetAssociation( annotationType, annotationList, defaults ); + } + + /** + * @see #getOneToOne(List, XMLContext.Default) + * @see #getElementCollection(List, XMLContext.Default) + */ + private void getManyToOne(List annotationList, XMLContext.Default defaults) { + Class annotationType = ManyToOne.class; + List elements = elementsForProperty.getManyToOne(); + for ( JaxbManyToOne element : elements ) { + AnnotationDescriptor ad = new AnnotationDescriptor( annotationType ); + addTargetClass( element.getTargetEntity(), ad, "target-entity", defaults ); + getFetchType( ad, element.getFetch() ); + getCascades( ad, element.getCascade(), defaults ); + getJoinTable( annotationList, element, defaults ); + buildJoinColumns( annotationList, element.getJoinColumn() ); + copyAttribute( ad, "optional", element.isOptional(), false ); + annotationList.add( AnnotationFactory.create( ad ) ); + + getAssociationId( annotationList, element.isId() ); + getMapsId( annotationList, element.getMapsId() ); + getAccessType( annotationList, element.getAccess() ); + } + afterGetAssociation( annotationType, annotationList, defaults ); + } + + /** + * @see #getOneToOne(List, XMLContext.Default) + * @see #getElementCollection(List, XMLContext.Default) + */ + private void getManyToMany(List annotationList, XMLContext.Default defaults) { + Class annotationType = ManyToMany.class; + List elements = elementsForProperty.getManyToMany(); + for ( JaxbManyToMany element : elements ) { + AnnotationDescriptor ad = new AnnotationDescriptor( annotationType ); + addTargetClass( element.getTargetEntity(), ad, "target-entity", defaults ); + getFetchType( ad, element.getFetch() ); + getCascades( ad, element.getCascade(), defaults ); + getJoinTable( annotationList, element, defaults ); + copyAttribute( ad, "mapped-by", element.getMappedBy(), false ); + annotationList.add( AnnotationFactory.create( ad ) ); + + getOrderBy( annotationList, element.getOrderBy() ); + getMapKey( annotationList, element.getMapKey() ); + getMapKeyClass( annotationList, element.getMapKeyClass(), defaults ); + getMapKeyColumn( annotationList, element.getMapKeyColumn() ); + getOrderColumn( annotationList, element.getOrderColumn() ); + getMapKeyTemporal( annotationList, element.getMapKeyTemporal() ); + getMapKeyEnumerated( annotationList, element.getMapKeyEnumerated() ); + Annotation annotation = getMapKeyAttributeOverrides( element.getMapKeyAttributeOverride(), defaults ); + addIfNotNull( annotationList, annotation ); + getMapKeyJoinColumns( annotationList, element.getMapKeyJoinColumn() ); + getAccessType( annotationList, element.getAccess() ); + } + afterGetAssociation( annotationType, annotationList, defaults ); + } + + private void getAny(List annotationList, XMLContext.Default defaults) { + // No support for "any" in JPA's orm.xml; we will just use the "physical" annotations. + // TODO HHH-10176 We should allow "any" associations, but the JPA XSD doesn't allow that. We would need our own XSD. + afterGetAssociation( Any.class, annotationList, defaults ); + } + + private void getManyToAny(List annotationList, XMLContext.Default defaults) { + // No support for "many-to-any" in JPA's orm.xml; we will just use the annotations. + // TODO HHH-10176 We should allow "many-to-any" associations, but the JPA XSD doesn't allow that. We would need our own XSD. + afterGetAssociation( ManyToAny.class, annotationList, defaults ); + } + + private void afterGetAssociation(Class annotationType, List annotationList, + XMLContext.Default defaults) { + if ( elementsForProperty.isEmpty() && defaults.canUseJavaAnnotations() ) { Annotation annotation = getPhysicalAnnotation( annotationType ); if ( annotation != null ) { annotation = overridesDefaultCascadePersist( annotation, defaults ); @@ -1016,8 +1188,8 @@ else if ( isPhysicalAnnotationPresent( ElementCollection.class ) ) { //JPA2 } } - private void buildMapKeyJoinColumns(List annotationList, Element element) { - MapKeyJoinColumn[] joinColumns = getMapKeyJoinColumns( element ); + private void getMapKeyJoinColumns(List annotationList, List elements) { + MapKeyJoinColumn[] joinColumns = buildMapKeyJoinColumns( elements ); if ( joinColumns.length > 0 ) { AnnotationDescriptor ad = new AnnotationDescriptor( MapKeyJoinColumns.class ); ad.setValue( "value", joinColumns ); @@ -1025,37 +1197,36 @@ private void buildMapKeyJoinColumns(List annotationList, Element ele } } - private MapKeyJoinColumn[] getMapKeyJoinColumns(Element element) { - List subelements = element != null ? element.elements( "map-key-join-column" ) : null; + private MapKeyJoinColumn[] buildMapKeyJoinColumns(List elements) { List joinColumns = new ArrayList<>(); - if ( subelements != null ) { - for ( Element subelement : subelements ) { + if ( elements != null ) { + for ( JaxbMapKeyJoinColumn element : elements ) { AnnotationDescriptor column = new AnnotationDescriptor( MapKeyJoinColumn.class ); - copyStringAttribute( column, subelement, "name", false ); - copyStringAttribute( column, subelement, "referenced-column-name", false ); - copyBooleanAttribute( column, subelement, "unique" ); - copyBooleanAttribute( column, subelement, "nullable" ); - copyBooleanAttribute( column, subelement, "insertable" ); - copyBooleanAttribute( column, subelement, "updatable" ); - copyStringAttribute( column, subelement, "column-definition", false ); - copyStringAttribute( column, subelement, "table", false ); + copyAttribute( column, "name", element.getName(), false ); + copyAttribute( column, "referenced-column-name", element.getReferencedColumnName(), false ); + copyAttribute( column, "unique", element.isUnique(), false ); + copyAttribute( column, "nullable", element.isNullable(), false ); + copyAttribute( column, "insertable", element.isInsertable(), false ); + copyAttribute( column, "updatable", element.isUpdatable(), false ); + copyAttribute( column, "column-definition", element.getColumnDefinition(), false ); + copyAttribute( column, "table", element.getTable(), false ); joinColumns.add( AnnotationFactory.create( column ) ); } } return joinColumns.toArray( new MapKeyJoinColumn[joinColumns.size()] ); } - private AttributeOverrides getMapKeyAttributeOverrides(Element tree, XMLContext.Default defaults) { - List attributes = buildAttributeOverrides( tree, "map-key-attribute-override" ); + private AttributeOverrides getMapKeyAttributeOverrides(List elements, XMLContext.Default defaults) { + List attributes = buildAttributeOverrides( elements, "map-key-attribute-override" ); return mergeAttributeOverrides( defaults, attributes, false ); } - private Cacheable getCacheable(Element element, XMLContext.Default defaults){ - if ( element != null ) { - String attValue = element.attributeValue( "cacheable" ); + private Cacheable getCacheable(ManagedType root, XMLContext.Default defaults){ + if ( root instanceof JaxbEntity ) { + Boolean attValue = ( (JaxbEntity) root ).isCacheable(); if ( attValue != null ) { AnnotationDescriptor ad = new AnnotationDescriptor( Cacheable.class ); - ad.setValue( "value", Boolean.valueOf( attValue ) ); + ad.setValue( "value", attValue ); return AnnotationFactory.create( ad ); } } @@ -1071,12 +1242,10 @@ private Cacheable getCacheable(Element element, XMLContext.Default defaults){ * contains a map-key-enumerated sub-element. This should only be the case for * element-collection, many-to-many, or one-to-many associations. */ - private void getMapKeyEnumerated(List annotationList, Element element) { - Element subelement = element != null ? element.element( "map-key-enumerated" ) : null; - if ( subelement != null ) { + private void getMapKeyEnumerated(List annotationList, EnumType enumType) { + if ( enumType != null ) { AnnotationDescriptor ad = new AnnotationDescriptor( MapKeyEnumerated.class ); - EnumType value = EnumType.valueOf( subelement.getTextTrim() ); - ad.setValue( "value", value ); + ad.setValue( "value", enumType ); annotationList.add( AnnotationFactory.create( ad ) ); } } @@ -1086,12 +1255,10 @@ private void getMapKeyEnumerated(List annotationList, Element elemen * contains a map-key-temporal sub-element. This should only be the case for element-collection, * many-to-many, or one-to-many associations. */ - private void getMapKeyTemporal(List annotationList, Element element) { - Element subelement = element != null ? element.element( "map-key-temporal" ) : null; - if ( subelement != null ) { + private void getMapKeyTemporal(List annotationList, TemporalType temporalType) { + if ( temporalType != null ) { AnnotationDescriptor ad = new AnnotationDescriptor( MapKeyTemporal.class ); - TemporalType value = TemporalType.valueOf( subelement.getTextTrim() ); - ad.setValue( "value", value ); + ad.setValue( "value", temporalType ); annotationList.add( AnnotationFactory.create( ad ) ); } } @@ -1101,15 +1268,14 @@ private void getMapKeyTemporal(List annotationList, Element element) * contains an order-column sub-element. This should only be the case for element-collection, * many-to-many, or one-to-many associations. */ - private void getOrderColumn(List annotationList, Element element) { - Element subelement = element != null ? element.element( "order-column" ) : null; - if ( subelement != null ) { + private void getOrderColumn(List annotationList, JaxbOrderColumn element) { + if ( element != null ) { AnnotationDescriptor ad = new AnnotationDescriptor( OrderColumn.class ); - copyStringAttribute( ad, subelement, "name", false ); - copyBooleanAttribute( ad, subelement, "nullable" ); - copyBooleanAttribute( ad, subelement, "insertable" ); - copyBooleanAttribute( ad, subelement, "updatable" ); - copyStringAttribute( ad, subelement, "column-definition", false ); + copyAttribute( ad, "name", element.getName(), false ); + copyAttribute( ad, "nullable", element.isNullable(), false ); + copyAttribute( ad, "insertable", element.isInsertable(), false ); + copyAttribute( ad, "updatable", element.isUpdatable(), false ); + copyAttribute( ad, "column-definition", element.getColumnDefinition(), false ); annotationList.add( AnnotationFactory.create( ad ) ); } } @@ -1119,11 +1285,10 @@ private void getOrderColumn(List annotationList, Element element) { * maps-id attribute set. This should only be the case for many-to-one or one-to-one * associations. */ - private void getMapsId(List annotationList, Element element) { - String attrVal = element.attributeValue( "maps-id" ); - if ( attrVal != null ) { + private void getMapsId(List annotationList, String mapsId) { + if ( mapsId != null ) { AnnotationDescriptor ad = new AnnotationDescriptor( MapsId.class ); - ad.setValue( "value", attrVal ); + ad.setValue( "value", mapsId ); annotationList.add( AnnotationFactory.create( ad ) ); } } @@ -1133,24 +1298,22 @@ private void getMapsId(List annotationList, Element element) { * attribute set to true. This should only be the case for many-to-one or one-to-one * associations. */ - private void getAssociationId(List annotationList, Element element) { - String attrVal = element.attributeValue( "id" ); - if ( "true".equals( attrVal ) ) { + private void getAssociationId(List annotationList, Boolean isId) { + if ( Boolean.TRUE.equals( isId ) ) { AnnotationDescriptor ad = new AnnotationDescriptor( Id.class ); annotationList.add( AnnotationFactory.create( ad ) ); } } - private void addTargetClass(Element element, AnnotationDescriptor ad, String nodeName, XMLContext.Default defaults) { - String className = element.attributeValue( nodeName ); + private void addTargetClass(String className, AnnotationDescriptor ad, String nodeName, XMLContext.Default defaults) { if ( className != null ) { - Class clazz; + Class clazz; try { clazz = classLoaderAccess.classForName( XMLContext.buildSafeClassName( className, defaults ) ); } catch ( ClassLoadingException e ) { throw new AnnotationException( - "Unable to find " + element.getPath() + " " + nodeName + ": " + className, e + "Unable to find " + nodeName + ": " + className, e ); } ad.setValue( getJavaAttributeNameFromXMLOne( nodeName ), clazz ); @@ -1165,82 +1328,76 @@ private void addTargetClass(Element element, AnnotationDescriptor ad, String nod * context. */ private void getElementCollection(List annotationList, XMLContext.Default defaults) { - for ( Element element : elementsForProperty ) { - if ( "element-collection".equals( element.getName() ) ) { - AnnotationDescriptor ad = new AnnotationDescriptor( ElementCollection.class ); - addTargetClass( element, ad, "target-class", defaults ); - getFetchType( ad, element ); - getOrderBy( annotationList, element ); - getOrderColumn( annotationList, element ); - getMapKey( annotationList, element ); - getMapKeyClass( annotationList, element, defaults ); - getMapKeyTemporal( annotationList, element ); - getMapKeyEnumerated( annotationList, element ); - getMapKeyColumn( annotationList, element ); - buildMapKeyJoinColumns( annotationList, element ); - Annotation annotation = getColumn( element.element( "column" ), false, element ); - addIfNotNull( annotationList, annotation ); - getTemporal( annotationList, element ); - getEnumerated( annotationList, element ); - getLob( annotationList, element ); - //Both map-key-attribute-overrides and attribute-overrides - //translate into AttributeOverride annotations, which need - //need to be wrapped in the same AttributeOverrides annotation. - List attributes = new ArrayList<>(); - attributes.addAll( buildAttributeOverrides( element, "map-key-attribute-override" ) ); - attributes.addAll( buildAttributeOverrides( element, "attribute-override" ) ); - annotation = mergeAttributeOverrides( defaults, attributes, false ); - addIfNotNull( annotationList, annotation ); - annotation = getAssociationOverrides( element, defaults, false ); - addIfNotNull( annotationList, annotation ); - getCollectionTable( annotationList, element, defaults ); - annotationList.add( AnnotationFactory.create( ad ) ); - getAccessType( annotationList, element ); - } + for ( JaxbElementCollection element : elementsForProperty.getElementCollection() ) { + AnnotationDescriptor ad = new AnnotationDescriptor( ElementCollection.class ); + addTargetClass( element.getTargetClass(), ad, "target-class", defaults ); + getFetchType( ad, element.getFetch() ); + getOrderBy( annotationList, element.getOrderBy() ); + getOrderColumn( annotationList, element.getOrderColumn() ); + getMapKey( annotationList, element.getMapKey() ); + getMapKeyClass( annotationList, element.getMapKeyClass(), defaults ); + getMapKeyTemporal( annotationList, element.getMapKeyTemporal() ); + getMapKeyEnumerated( annotationList, element.getMapKeyEnumerated() ); + getMapKeyColumn( annotationList, element.getMapKeyColumn() ); + getMapKeyJoinColumns( annotationList, element.getMapKeyJoinColumn() ); + Annotation annotation = getColumn( element.getColumn(), false, "element-collection" ); + addIfNotNull( annotationList, annotation ); + getTemporal( annotationList, element.getTemporal() ); + getEnumerated( annotationList, element.getEnumerated() ); + getLob( annotationList, element.getLob() ); + //Both map-key-attribute-overrides and attribute-overrides + //translate into AttributeOverride annotations, which need + //need to be wrapped in the same AttributeOverrides annotation. + List attributes = new ArrayList<>(); + attributes.addAll( buildAttributeOverrides( element.getMapKeyAttributeOverride(), "map-key-attribute-override" ) ); + attributes.addAll( buildAttributeOverrides( element.getAttributeOverride(), "attribute-override" ) ); + annotation = mergeAttributeOverrides( defaults, attributes, false ); + addIfNotNull( annotationList, annotation ); + annotation = getAssociationOverrides( element.getAssociationOverride(), defaults, false ); + addIfNotNull( annotationList, annotation ); + getCollectionTable( annotationList, element.getCollectionTable(), defaults ); + annotationList.add( AnnotationFactory.create( ad ) ); + getAccessType( annotationList, element.getAccess() ); } } - private void getOrderBy(List annotationList, Element element) { - Element subelement = element != null ? element.element( "order-by" ) : null; - if ( subelement != null ) { + private void getOrderBy(List annotationList, String orderBy) { + if ( orderBy != null ) { AnnotationDescriptor ad = new AnnotationDescriptor( OrderBy.class ); - copyStringElement( subelement, ad, "value" ); + ad.setValue( "value", orderBy ); annotationList.add( AnnotationFactory.create( ad ) ); } } - private void getMapKey(List annotationList, Element element) { - Element subelement = element != null ? element.element( "map-key" ) : null; - if ( subelement != null ) { + private void getMapKey(List annotationList, JaxbMapKey element) { + if ( element != null ) { AnnotationDescriptor ad = new AnnotationDescriptor( MapKey.class ); - copyStringAttribute( ad, subelement, "name", false ); + copyAttribute( ad, "name", element.getName(), false ); annotationList.add( AnnotationFactory.create( ad ) ); } } - private void getMapKeyColumn(List annotationList, Element element) { - Element subelement = element != null ? element.element( "map-key-column" ) : null; - if ( subelement != null ) { + private void getMapKeyColumn(List annotationList, JaxbMapKeyColumn element) { + if ( element != null ) { AnnotationDescriptor ad = new AnnotationDescriptor( MapKeyColumn.class ); - copyStringAttribute( ad, subelement, "name", false ); - copyBooleanAttribute( ad, subelement, "unique" ); - copyBooleanAttribute( ad, subelement, "nullable" ); - copyBooleanAttribute( ad, subelement, "insertable" ); - copyBooleanAttribute( ad, subelement, "updatable" ); - copyStringAttribute( ad, subelement, "column-definition", false ); - copyStringAttribute( ad, subelement, "table", false ); - copyIntegerAttribute( ad, subelement, "length" ); - copyIntegerAttribute( ad, subelement, "precision" ); - copyIntegerAttribute( ad, subelement, "scale" ); + copyAttribute( ad, "name", element.getName(), false ); + copyAttribute( ad, "unique", element.isUnique(), false ); + copyAttribute( ad, "nullable", element.isNullable(), false ); + copyAttribute( ad, "insertable", element.isInsertable(), false ); + copyAttribute( ad, "updatable", element.isUpdatable(), false ); + copyAttribute( ad, "column-definition", element.getColumnDefinition(), false ); + copyAttribute( ad, "table", element.getTable(), false ); + copyAttribute( ad, "length", element.getLength(), false ); + copyAttribute( ad, "precision", element.getPrecision(), false ); + copyAttribute( ad, "scale", element.getScale(), false ); annotationList.add( AnnotationFactory.create( ad ) ); } } - private void getMapKeyClass(List annotationList, Element element, XMLContext.Default defaults) { + private void getMapKeyClass(List annotationList, JaxbMapKeyClass element, XMLContext.Default defaults) { String nodeName = "map-key-class"; - Element subelement = element != null ? element.element( nodeName ) : null; - if ( subelement != null ) { - String mapKeyClassName = subelement.attributeValue( "class" ); + if ( element != null ) { + String mapKeyClassName = element.getClazz(); AnnotationDescriptor ad = new AnnotationDescriptor( MapKeyClass.class ); if ( StringHelper.isNotEmpty( mapKeyClassName ) ) { Class clazz; @@ -1251,7 +1408,7 @@ private void getMapKeyClass(List annotationList, Element element, XM } catch ( ClassLoadingException e ) { throw new AnnotationException( - "Unable to find " + element.getPath() + " " + nodeName + ": " + mapKeyClassName, e + "Unable to find " + nodeName + ": " + mapKeyClassName, e ); } ad.setValue( "value", clazz ); @@ -1260,33 +1417,32 @@ private void getMapKeyClass(List annotationList, Element element, XM } } - private void getCollectionTable(List annotationList, Element element, XMLContext.Default defaults) { - Element subelement = element != null ? element.element( "collection-table" ) : null; - if ( subelement != null ) { + private void getCollectionTable(List annotationList, JaxbCollectionTable element, XMLContext.Default defaults) { + if ( element != null ) { AnnotationDescriptor annotation = new AnnotationDescriptor( CollectionTable.class ); - copyStringAttribute( annotation, subelement, "name", false ); - copyStringAttribute( annotation, subelement, "catalog", false ); + copyAttribute( annotation, "name", element.getName(), false ); + copyAttribute( annotation, "catalog", element.getCatalog(), false ); if ( StringHelper.isNotEmpty( defaults.getCatalog() ) && StringHelper.isEmpty( (String) annotation.valueOf( "catalog" ) ) ) { annotation.setValue( "catalog", defaults.getCatalog() ); } - copyStringAttribute( annotation, subelement, "schema", false ); + copyAttribute( annotation, "schema", element.getSchema(), false ); if ( StringHelper.isNotEmpty( defaults.getSchema() ) && StringHelper.isEmpty( (String) annotation.valueOf( "schema" ) ) ) { annotation.setValue( "schema", defaults.getSchema() ); } - JoinColumn[] joinColumns = getJoinColumns( subelement, false ); + JoinColumn[] joinColumns = getJoinColumns( element.getJoinColumn(), false ); if ( joinColumns.length > 0 ) { annotation.setValue( "joinColumns", joinColumns ); } - buildUniqueConstraints( annotation, subelement ); - buildIndex( annotation, subelement ); + buildUniqueConstraints( annotation, element.getUniqueConstraint() ); + buildIndex( annotation, element.getIndex() ); annotationList.add( AnnotationFactory.create( annotation ) ); } } - private void buildJoinColumns(List annotationList, Element element) { - JoinColumn[] joinColumns = getJoinColumns( element, false ); + private void buildJoinColumns(List annotationList, List elements) { + JoinColumn[] joinColumns = getJoinColumns( elements, false ); if ( joinColumns.length > 0 ) { AnnotationDescriptor ad = new AnnotationDescriptor( JoinColumns.class ); ad.setValue( "value", joinColumns ); @@ -1294,26 +1450,25 @@ private void buildJoinColumns(List annotationList, Element element) } } - private void getCascades(AnnotationDescriptor ad, Element element, XMLContext.Default defaults) { - List elements = element != null ? element.elements( "cascade" ) : new ArrayList<>( 0 ); + private void getCascades(AnnotationDescriptor ad, JaxbCascadeType element, XMLContext.Default defaults) { List cascades = new ArrayList<>(); - for ( Element subelement : elements ) { - if ( subelement.element( "cascade-all" ) != null ) { + if ( element != null ) { + if ( element.getCascadeAll() != null ) { cascades.add( CascadeType.ALL ); } - if ( subelement.element( "cascade-persist" ) != null ) { + if ( element.getCascadePersist() != null ) { cascades.add( CascadeType.PERSIST ); } - if ( subelement.element( "cascade-merge" ) != null ) { + if ( element.getCascadeMerge() != null ) { cascades.add( CascadeType.MERGE ); } - if ( subelement.element( "cascade-remove" ) != null ) { + if ( element.getCascadeRemove() != null ) { cascades.add( CascadeType.REMOVE ); } - if ( subelement.element( "cascade-refresh" ) != null ) { + if ( element.getCascadeRefresh() != null ) { cascades.add( CascadeType.REFRESH ); } - if ( subelement.element( "cascade-detach" ) != null ) { + if ( element.getCascadeDetach() != null ) { cascades.add( CascadeType.DETACH ); } } @@ -1327,18 +1482,16 @@ private void getCascades(AnnotationDescriptor ad, Element element, XMLContext.De } private void getEmbedded(List annotationList, XMLContext.Default defaults) { - for ( Element element : elementsForProperty ) { - if ( "embedded".equals( element.getName() ) ) { - AnnotationDescriptor ad = new AnnotationDescriptor( Embedded.class ); - annotationList.add( AnnotationFactory.create( ad ) ); - Annotation annotation = getAttributeOverrides( element, defaults, false ); - addIfNotNull( annotationList, annotation ); - annotation = getAssociationOverrides( element, defaults, false ); - addIfNotNull( annotationList, annotation ); - getAccessType( annotationList, element ); - } + for ( JaxbEmbedded element : elementsForProperty.getEmbedded() ) { + AnnotationDescriptor ad = new AnnotationDescriptor( Embedded.class ); + annotationList.add( AnnotationFactory.create( ad ) ); + Annotation annotation = getAttributeOverrides( element.getAttributeOverride(), defaults, false ); + addIfNotNull( annotationList, annotation ); + annotation = getAssociationOverrides( element.getAssociationOverride(), defaults, false ); + addIfNotNull( annotationList, annotation ); + getAccessType( annotationList, element.getAccess() ); } - if ( elementsForProperty.size() == 0 && defaults.canUseJavaAnnotations() ) { + if ( elementsForProperty.isEmpty() && defaults.canUseJavaAnnotations() ) { Annotation annotation = getPhysicalAnnotation( Embedded.class ); if ( annotation != null ) { annotationList.add( annotation ); @@ -1355,13 +1508,11 @@ private void getEmbedded(List annotationList, XMLContext.Default def } private Transient getTransient(XMLContext.Default defaults) { - for ( Element element : elementsForProperty ) { - if ( "transient".equals( element.getName() ) ) { - AnnotationDescriptor ad = new AnnotationDescriptor( Transient.class ); - return AnnotationFactory.create( ad ); - } + if ( !elementsForProperty.getTransient().isEmpty() ) { + AnnotationDescriptor ad = new AnnotationDescriptor( Transient.class ); + return AnnotationFactory.create( ad ); } - if ( elementsForProperty.size() == 0 && defaults.canUseJavaAnnotations() ) { + if ( elementsForProperty.isEmpty() && defaults.canUseJavaAnnotations() ) { return getPhysicalAnnotation( Transient.class ); } else { @@ -1370,17 +1521,15 @@ private Transient getTransient(XMLContext.Default defaults) { } private void getVersion(List annotationList, XMLContext.Default defaults) { - for ( Element element : elementsForProperty ) { - if ( "version".equals( element.getName() ) ) { - Annotation annotation = buildColumns( element ); - addIfNotNull( annotationList, annotation ); - getTemporal( annotationList, element ); - AnnotationDescriptor basic = new AnnotationDescriptor( Version.class ); - annotationList.add( AnnotationFactory.create( basic ) ); - getAccessType( annotationList, element ); - } + for ( JaxbVersion element : elementsForProperty.getVersion() ) { + Annotation annotation = buildColumns( element.getColumn(), "version" ); + addIfNotNull( annotationList, annotation ); + getTemporal( annotationList, element.getTemporal() ); + AnnotationDescriptor basic = new AnnotationDescriptor( Version.class ); + annotationList.add( AnnotationFactory.create( basic ) ); + getAccessType( annotationList, element.getAccess() ); } - if ( elementsForProperty.size() == 0 && defaults.canUseJavaAnnotations() ) { + if ( elementsForProperty.isEmpty() && defaults.canUseJavaAnnotations() ) { //we have nothing, so Java annotations might occur Annotation annotation = getPhysicalAnnotation( Version.class ); if ( annotation != null ) { @@ -1396,21 +1545,19 @@ private void getVersion(List annotationList, XMLContext.Default defa } private void getBasic(List annotationList, XMLContext.Default defaults) { - for ( Element element : elementsForProperty ) { - if ( "basic".equals( element.getName() ) ) { - Annotation annotation = buildColumns( element ); - addIfNotNull( annotationList, annotation ); - getAccessType( annotationList, element ); - getTemporal( annotationList, element ); - getLob( annotationList, element ); - getEnumerated( annotationList, element ); - AnnotationDescriptor basic = new AnnotationDescriptor( Basic.class ); - getFetchType( basic, element ); - copyBooleanAttribute( basic, element, "optional" ); - annotationList.add( AnnotationFactory.create( basic ) ); - } - } - if ( elementsForProperty.size() == 0 && defaults.canUseJavaAnnotations() ) { + for ( JaxbBasic element : elementsForProperty.getBasic() ) { + Annotation annotation = buildColumns( element.getColumn(), "basic" ); + addIfNotNull( annotationList, annotation ); + getAccessType( annotationList, element.getAccess() ); + getTemporal( annotationList, element.getTemporal() ); + getLob( annotationList, element.getLob() ); + getEnumerated( annotationList, element.getEnumerated() ); + AnnotationDescriptor basic = new AnnotationDescriptor( Basic.class ); + getFetchType( basic, element.getFetch() ); + copyAttribute( basic, "optional", element.isOptional(), false ); + annotationList.add( AnnotationFactory.create( basic ) ); + } + if ( elementsForProperty.isEmpty() && defaults.canUseJavaAnnotations() ) { //no annotation presence constraint, basic is the default Annotation annotation = getPhysicalAnnotation( Basic.class ); addIfNotNull( annotationList, annotation ); @@ -1435,58 +1582,38 @@ private void getBasic(List annotationList, XMLContext.Default defaul } } - private void getEnumerated(List annotationList, Element element) { - Element subElement = element != null ? element.element( "enumerated" ) : null; - if ( subElement != null ) { + private void getEnumerated(List annotationList, EnumType enumType) { + if ( enumType != null ) { AnnotationDescriptor ad = new AnnotationDescriptor( Enumerated.class ); - String enumerated = subElement.getTextTrim(); - if ( "ORDINAL".equalsIgnoreCase( enumerated ) ) { - ad.setValue( "value", EnumType.ORDINAL ); - } - else if ( "STRING".equalsIgnoreCase( enumerated ) ) { - ad.setValue( "value", EnumType.STRING ); - } - else if ( StringHelper.isNotEmpty( enumerated ) ) { - throw new AnnotationException( "Unknown EnumType: " + enumerated + ". " + SCHEMA_VALIDATION ); - } + ad.setValue( "value", enumType ); annotationList.add( AnnotationFactory.create( ad ) ); } } - private void getLob(List annotationList, Element element) { - Element subElement = element != null ? element.element( "lob" ) : null; - if ( subElement != null ) { + private void getLob(List annotationList, JaxbLob element) { + if ( element != null ) { annotationList.add( AnnotationFactory.create( new AnnotationDescriptor( Lob.class ) ) ); } } - private void getFetchType(AnnotationDescriptor descriptor, Element element) { - String fetchString = element != null ? element.attributeValue( "fetch" ) : null; - if ( fetchString != null ) { - if ( "eager".equalsIgnoreCase( fetchString ) ) { - descriptor.setValue( "fetch", FetchType.EAGER ); - } - else if ( "lazy".equalsIgnoreCase( fetchString ) ) { - descriptor.setValue( "fetch", FetchType.LAZY ); - } + private void getFetchType(AnnotationDescriptor descriptor, FetchType type) { + if ( type != null ) { + descriptor.setValue( "fetch", type ); } } private void getEmbeddedId(List annotationList, XMLContext.Default defaults) { - for ( Element element : elementsForProperty ) { - if ( "embedded-id".equals( element.getName() ) ) { - if ( isProcessingId( defaults ) ) { - Annotation annotation = getAttributeOverrides( element, defaults, false ); - addIfNotNull( annotationList, annotation ); - annotation = getAssociationOverrides( element, defaults, false ); - addIfNotNull( annotationList, annotation ); - AnnotationDescriptor ad = new AnnotationDescriptor( EmbeddedId.class ); - annotationList.add( AnnotationFactory.create( ad ) ); - getAccessType( annotationList, element ); - } + for ( JaxbEmbeddedId element : elementsForProperty.getEmbeddedId() ) { + if ( isProcessingId( defaults ) ) { + Annotation annotation = getAttributeOverrides( element.getAttributeOverride(), defaults, false ); + addIfNotNull( annotationList, annotation ); + // TODO HHH-10176 We should allow association overrides here, but the JPA XSD doesn't allow that. We would need our own XSD. + AnnotationDescriptor ad = new AnnotationDescriptor( EmbeddedId.class ); + annotationList.add( AnnotationFactory.create( ad ) ); + getAccessType( annotationList, element.getAccess() ); } } - if ( elementsForProperty.size() == 0 && defaults.canUseJavaAnnotations() ) { + if ( elementsForProperty.isEmpty() && defaults.canUseJavaAnnotations() ) { Annotation annotation = getPhysicalAnnotation( EmbeddedId.class ); if ( annotation != null ) { annotationList.add( annotation ); @@ -1514,49 +1641,42 @@ private void getEmbeddedId(List annotationList, XMLContext.Default d } } - private void preCalculateElementsForProperty(Element tree) { - elementsForProperty = new ArrayList<>(); - Element element = tree != null ? tree.element( "attributes" ) : null; + private void preCalculateElementsForProperty(ManagedType managedType, JaxbEntityListener entityListener) { + elementsForProperty = new PropertyMappingElementCollector( propertyName ); + AttributesContainer attributes = managedType == null ? null : managedType.getAttributes(); //put entity.attributes elements - if ( element != null ) { - for ( Element subelement : (List) element.elements() ) { - if ( propertyName.equals( subelement.attributeValue( "name" ) ) ) { - elementsForProperty.add( subelement ); - } - } + if ( attributes != null ) { + elementsForProperty.collectPersistentAttributesIfMatching( attributes ); } //add pre-* etc from entity and pure entity listener classes - if ( tree != null ) { - for ( Element subelement : (List) tree.elements() ) { - if ( propertyName.equals( subelement.attributeValue( "method-name" ) ) ) { - elementsForProperty.add( subelement ); - } - } + if ( managedType instanceof LifecycleCallbackContainer ) { + elementsForProperty.collectLifecycleCallbacksIfMatching( (LifecycleCallbackContainer) managedType ); + } + if ( entityListener != null ) { + elementsForProperty.collectLifecycleCallbacksIfMatching( entityListener ); } } private void getId(List annotationList, XMLContext.Default defaults) { - for ( Element element : elementsForProperty ) { - if ( "id".equals( element.getName() ) ) { - boolean processId = isProcessingId( defaults ); - if ( processId ) { - Annotation annotation = buildColumns( element ); - addIfNotNull( annotationList, annotation ); - annotation = buildGeneratedValue( element ); - addIfNotNull( annotationList, annotation ); - getTemporal( annotationList, element ); - //FIXME: fix the priority of xml over java for generator names - annotation = getTableGenerator( element, defaults ); - addIfNotNull( annotationList, annotation ); - annotation = getSequenceGenerator( element, defaults ); - addIfNotNull( annotationList, annotation ); - AnnotationDescriptor id = new AnnotationDescriptor( Id.class ); - annotationList.add( AnnotationFactory.create( id ) ); - getAccessType( annotationList, element ); - } - } - } - if ( elementsForProperty.size() == 0 && defaults.canUseJavaAnnotations() ) { + for ( JaxbId element : elementsForProperty.getId() ) { + boolean processId = isProcessingId( defaults ); + if ( processId ) { + Annotation annotation = buildColumns( element.getColumn(), "id" ); + addIfNotNull( annotationList, annotation ); + annotation = buildGeneratedValue( element.getGeneratedValue() ); + addIfNotNull( annotationList, annotation ); + getTemporal( annotationList, element.getTemporal() ); + //FIXME: fix the priority of xml over java for generator names + annotation = getTableGenerator( element.getTableGenerator(), defaults ); + addIfNotNull( annotationList, annotation ); + annotation = getSequenceGenerator( element.getSequenceGenerator(), defaults ); + addIfNotNull( annotationList, annotation ); + AnnotationDescriptor id = new AnnotationDescriptor( Id.class ); + annotationList.add( AnnotationFactory.create( id ) ); + getAccessType( annotationList, element.getAccess() ); + } + } + if ( elementsForProperty.isEmpty() && defaults.canUseJavaAnnotations() ) { Annotation annotation = getPhysicalAnnotation( Id.class ); if ( annotation != null ) { annotationList.add( annotation ); @@ -1602,11 +1722,26 @@ private boolean isProcessingId(XMLContext.Default defaults) { return correctAccess || ( !isExplicit && hasId ) || ( !isExplicit && propertyIsDefault ); } - private Columns buildColumns(Element element) { - List subelements = element.elements( "column" ); - List columns = new ArrayList<>( subelements.size() ); - for ( Element subelement : subelements ) { - columns.add( getColumn( subelement, false, element ) ); + private Columns buildColumns(JaxbColumn element, String nodeName) { + if ( element == null ) { + return null; + } + List columns = new ArrayList<>( 1 ); + columns.add( getColumn( element, false, nodeName ) ); + if ( columns.size() > 0 ) { + AnnotationDescriptor columnsDescr = new AnnotationDescriptor( Columns.class ); + columnsDescr.setValue( "columns", columns.toArray( new Column[columns.size()] ) ); + return AnnotationFactory.create( columnsDescr ); + } + else { + return null; + } + } + + private Columns buildColumns(List elements, String nodeName) { + List columns = new ArrayList<>( elements.size() ); + for ( JaxbColumn element : elements ) { + columns.add( getColumn( element, false, nodeName ) ); } if ( columns.size() > 0 ) { AnnotationDescriptor columnsDescr = new AnnotationDescriptor( Columns.class ); @@ -1618,27 +1753,14 @@ private Columns buildColumns(Element element) { } } - private GeneratedValue buildGeneratedValue(Element element) { - Element subElement = element != null ? element.element( "generated-value" ) : null; - if ( subElement != null ) { + private GeneratedValue buildGeneratedValue(JaxbGeneratedValue element) { + if ( element != null ) { AnnotationDescriptor ad = new AnnotationDescriptor( GeneratedValue.class ); - String strategy = subElement.attributeValue( "strategy" ); - if ( "TABLE".equalsIgnoreCase( strategy ) ) { - ad.setValue( "strategy", GenerationType.TABLE ); - } - else if ( "SEQUENCE".equalsIgnoreCase( strategy ) ) { - ad.setValue( "strategy", GenerationType.SEQUENCE ); + GenerationType strategy = element.getStrategy(); + if ( strategy != null ) { + ad.setValue( "strategy", strategy ); } - else if ( "IDENTITY".equalsIgnoreCase( strategy ) ) { - ad.setValue( "strategy", GenerationType.IDENTITY ); - } - else if ( "AUTO".equalsIgnoreCase( strategy ) ) { - ad.setValue( "strategy", GenerationType.AUTO ); - } - else if ( StringHelper.isNotEmpty( strategy ) ) { - throw new AnnotationException( "Unknown GenerationType: " + strategy + ". " + SCHEMA_VALIDATION ); - } - copyStringAttribute( ad, subElement, "generator", false ); + copyAttribute( ad, "generator", element.getGenerator(), false ); return AnnotationFactory.create( ad ); } else { @@ -1646,41 +1768,20 @@ else if ( StringHelper.isNotEmpty( strategy ) ) { } } - private void getTemporal(List annotationList, Element element) { - Element subElement = element != null ? element.element( "temporal" ) : null; - if ( subElement != null ) { + private void getTemporal(List annotationList, TemporalType type) { + if ( type != null ) { AnnotationDescriptor ad = new AnnotationDescriptor( Temporal.class ); - String temporal = subElement.getTextTrim(); - if ( "DATE".equalsIgnoreCase( temporal ) ) { - ad.setValue( "value", TemporalType.DATE ); - } - else if ( "TIME".equalsIgnoreCase( temporal ) ) { - ad.setValue( "value", TemporalType.TIME ); - } - else if ( "TIMESTAMP".equalsIgnoreCase( temporal ) ) { - ad.setValue( "value", TemporalType.TIMESTAMP ); - } - else if ( StringHelper.isNotEmpty( temporal ) ) { - throw new AnnotationException( "Unknown TemporalType: " + temporal + ". " + SCHEMA_VALIDATION ); - } + ad.setValue( "value", type ); annotationList.add( AnnotationFactory.create( ad ) ); } } - private void getAccessType(List annotationList, Element element) { + private void getAccessType(List annotationList, AccessType type) { if ( element == null ) { return; } - String access = element.attributeValue( "access" ); - if ( access != null ) { + if ( type != null ) { AnnotationDescriptor ad = new AnnotationDescriptor( Access.class ); - AccessType type; - try { - type = AccessType.valueOf( access ); - } - catch ( IllegalArgumentException e ) { - throw new AnnotationException( access + " is not a valid access type. Check you xml confguration." ); - } if ( ( AccessType.PROPERTY.equals( type ) && this.element instanceof Method ) || ( AccessType.FIELD.equals( type ) && this.element instanceof Field ) ) { @@ -1692,14 +1793,20 @@ private void getAccessType(List annotationList, Element element) { } } + private AssociationOverrides getAssociationOverrides(ManagedType root, XMLContext.Default defaults) { + return root instanceof JaxbEntity + ? getAssociationOverrides( ( (JaxbEntity) root ).getAssociationOverride(), defaults, true ) + : null; + } + /** * @param mergeWithAnnotations Whether to use Java annotations for this * element, if present and not disabled by the XMLContext defaults. * In some contexts (such as an element-collection mapping) merging - * with annotations is never allowed. */ - private AssociationOverrides getAssociationOverrides(Element tree, XMLContext.Default defaults, boolean mergeWithAnnotations) { - List attributes = buildAssociationOverrides( tree, defaults ); + private AssociationOverrides getAssociationOverrides(List elements, XMLContext.Default defaults, + boolean mergeWithAnnotations) { + List attributes = buildAssociationOverrides( elements, defaults ); if ( mergeWithAnnotations && defaults.canUseJavaAnnotations() ) { AssociationOverride annotation = getPhysicalAnnotation( AssociationOverride.class ); addAssociationOverrideIfNeeded( annotation, attributes ); @@ -1720,15 +1827,14 @@ private AssociationOverrides getAssociationOverrides(Element tree, XMLContext.De } } - private List buildAssociationOverrides(Element element, XMLContext.Default defaults) { - List subelements = element == null ? null : element.elements( "association-override" ); + private List buildAssociationOverrides(List elements, XMLContext.Default defaults) { List overrides = new ArrayList<>(); - if ( subelements != null && subelements.size() > 0 ) { - for ( Element current : subelements ) { + if ( elements != null && elements.size() > 0 ) { + for ( JaxbAssociationOverride current : elements ) { AnnotationDescriptor override = new AnnotationDescriptor( AssociationOverride.class ); - copyStringAttribute( override, current, "name", true ); - override.setValue( "joinColumns", getJoinColumns( current, false ) ); - JoinTable joinTable = buildJoinTable( current, defaults ); + copyAttribute( override, "name", current.getName(), true ); + override.setValue( "joinColumns", getJoinColumns( current.getJoinColumn(), false ) ); + JoinTable joinTable = buildJoinTable( current.getJoinTable(), defaults ); if ( joinTable != null ) { override.setValue( "joinTable", joinTable ); } @@ -1738,22 +1844,19 @@ private List buildAssociationOverrides(Element element, XML return overrides; } - private JoinColumn[] getJoinColumns(Element element, boolean isInverse) { - List subelements = element != null ? - element.elements( isInverse ? "inverse-join-column" : "join-column" ) : - null; + private JoinColumn[] getJoinColumns(List subelements, boolean isInverse) { List joinColumns = new ArrayList<>(); if ( subelements != null ) { - for ( Element subelement : subelements ) { + for ( JaxbJoinColumn subelement : subelements ) { AnnotationDescriptor column = new AnnotationDescriptor( JoinColumn.class ); - copyStringAttribute( column, subelement, "name", false ); - copyStringAttribute( column, subelement, "referenced-column-name", false ); - copyBooleanAttribute( column, subelement, "unique" ); - copyBooleanAttribute( column, subelement, "nullable" ); - copyBooleanAttribute( column, subelement, "insertable" ); - copyBooleanAttribute( column, subelement, "updatable" ); - copyStringAttribute( column, subelement, "column-definition", false ); - copyStringAttribute( column, subelement, "table", false ); + copyAttribute( column, "name", subelement.getName(), false ); + copyAttribute( column, "referenced-column-name", subelement.getReferencedColumnName(), false ); + copyAttribute( column, "unique", subelement.isUnique(), false ); + copyAttribute( column, "nullable", subelement.isNullable(), false ); + copyAttribute( column, "insertable", subelement.isInsertable(), false ); + copyAttribute( column, "updatable", subelement.isUpdatable(), false ); + copyAttribute( column, "column-definition", subelement.getColumnDefinition(), false ); + copyAttribute( column, "table", subelement.getTable(), false ); joinColumns.add( AnnotationFactory.create( column ) ); } } @@ -1776,14 +1879,21 @@ private void addAssociationOverrideIfNeeded(AssociationOverride annotation, List } } + private AttributeOverrides getAttributeOverrides(ManagedType root, XMLContext.Default defaults) { + return root instanceof JaxbEntity + ? getAttributeOverrides( ( (JaxbEntity) root ).getAttributeOverride(), defaults, true ) + : null; + } + /** * @param mergeWithAnnotations Whether to use Java annotations for this * element, if present and not disabled by the XMLContext defaults. * In some contexts (such as an association mapping) merging with * annotations is never allowed. */ - private AttributeOverrides getAttributeOverrides(Element tree, XMLContext.Default defaults, boolean mergeWithAnnotations) { - List attributes = buildAttributeOverrides( tree, "attribute-override" ); + private AttributeOverrides getAttributeOverrides(List elements, XMLContext.Default defaults, + boolean mergeWithAnnotations) { + List attributes = buildAttributeOverrides( elements, "attribute-override" ); return mergeAttributeOverrides( defaults, attributes, mergeWithAnnotations ); } @@ -1814,47 +1924,38 @@ private AttributeOverrides mergeAttributeOverrides(XMLContext.Default defaults, } } - private List buildAttributeOverrides(Element element, String nodeName) { - List subelements = element == null ? null : element.elements( nodeName ); - return buildAttributeOverrides( subelements, nodeName ); - } - - private List buildAttributeOverrides(List subelements, String nodeName) { + private List buildAttributeOverrides(List subelements, String nodeName) { List overrides = new ArrayList<>(); if ( subelements != null && subelements.size() > 0 ) { - for ( Element current : subelements ) { - if ( !current.getName().equals( nodeName ) ) { - continue; - } + for ( JaxbAttributeOverride current : subelements ) { AnnotationDescriptor override = new AnnotationDescriptor( AttributeOverride.class ); - copyStringAttribute( override, current, "name", true ); - Element column = current.element( "column" ); - override.setValue( "column", getColumn( column, true, current ) ); + copyAttribute( override, "name", current.getName(), true ); + JaxbColumn column = current.getColumn(); + override.setValue( "column", getColumn( column, true, nodeName ) ); overrides.add( AnnotationFactory.create( override ) ); } } return overrides; } - private Column getColumn(Element element, boolean isMandatory, Element current) { - //Element subelement = element != null ? element.element( "column" ) : null; + private Column getColumn(JaxbColumn element, boolean isMandatory, String nodeName) { if ( element != null ) { AnnotationDescriptor column = new AnnotationDescriptor( Column.class ); - copyStringAttribute( column, element, "name", false ); - copyBooleanAttribute( column, element, "unique" ); - copyBooleanAttribute( column, element, "nullable" ); - copyBooleanAttribute( column, element, "insertable" ); - copyBooleanAttribute( column, element, "updatable" ); - copyStringAttribute( column, element, "column-definition", false ); - copyStringAttribute( column, element, "table", false ); - copyIntegerAttribute( column, element, "length" ); - copyIntegerAttribute( column, element, "precision" ); - copyIntegerAttribute( column, element, "scale" ); + copyAttribute( column, "name", element.getName(), false ); + copyAttribute( column, "unique", element.isUnique(), false ); + copyAttribute( column, "nullable", element.isNullable(), false ); + copyAttribute( column, "insertable", element.isInsertable(), false ); + copyAttribute( column, "updatable", element.isUpdatable(), false ); + copyAttribute( column, "column-definition", element.getColumnDefinition(), false ); + copyAttribute( column, "table", element.getTable(), false ); + copyAttribute( column, "length", element.getLength(), false ); + copyAttribute( column, "precision", element.getPrecision(), false ); + copyAttribute( column, "scale", element.getScale(), false ); return (Column) AnnotationFactory.create( column ); } else { if ( isMandatory ) { - throw new AnnotationException( current.getPath() + ".column is mandatory. " + SCHEMA_VALIDATION ); + throw new AnnotationException( nodeName + ".column is mandatory. " + SCHEMA_VALIDATION ); } return null; } @@ -1876,18 +1977,11 @@ private void addAttributeOverrideIfNeeded(AttributeOverride annotation, List clazz, Element element, XMLContext.Default defaults - ) { - Element subelement = element == null ? null : element.element( annotationToXml.get( clazz ) ); - if ( subelement != null ) { + private Annotation getMarkerAnnotation(Class clazz, JaxbEmptyType element, + XMLContext.Default defaults) { + if ( element != null ) { return AnnotationFactory.create( new AnnotationDescriptor( clazz ) ); } else if ( defaults.canUseJavaAnnotations() ) { @@ -1927,8 +2027,10 @@ else if ( defaults.canUseJavaAnnotations() ) { } } - private SqlResultSetMappings getSqlResultSetMappings(Element tree, XMLContext.Default defaults) { - List results = buildSqlResultsetMappings( tree, defaults, classLoaderAccess ); + private SqlResultSetMappings getSqlResultSetMappings(ManagedType root, XMLContext.Default defaults) { + List results = root instanceof JaxbEntity + ? buildSqlResultsetMappings( ( (JaxbEntity) root ).getSqlResultSetMapping(), defaults, classLoaderAccess ) + : new ArrayList<>(); if ( defaults.canUseJavaAnnotations() ) { SqlResultSetMapping annotation = getPhysicalAnnotation( SqlResultSetMapping.class ); addSqlResultsetMappingIfNeeded( annotation, results ); @@ -1950,26 +2052,18 @@ private SqlResultSetMappings getSqlResultSetMappings(Element tree, XMLContext.De } public static List buildNamedEntityGraph( - Element element, + List elements, XMLContext.Default defaults, ClassLoaderAccess classLoaderAccess) { - if ( element == null ) { - return new ArrayList<>(); - } List namedEntityGraphList = new ArrayList<>(); - List namedEntityGraphElements = element.elements( "named-entity-graph" ); - for ( Element subElement : namedEntityGraphElements ) { + for ( JaxbNamedEntityGraph element : elements ) { AnnotationDescriptor ann = new AnnotationDescriptor( NamedEntityGraph.class ); - copyStringAttribute( ann, subElement, "name", false ); - copyBooleanAttribute( ann, subElement, "include-all-attributes" ); - bindNamedAttributeNodes( subElement, ann ); + copyAttribute( ann, "name", element.getName(), false ); + copyAttribute( ann, "include-all-attributes", element.isIncludeAllAttributes(), false ); + bindNamedAttributeNodes( element.getNamedAttributeNode(), ann ); - List subgraphNodes = subElement.elements( "subgraph" ); - List subclassSubgraphNodes = subElement.elements( "subclass-subgraph" ); - if(!subclassSubgraphNodes.isEmpty()) { - subgraphNodes.addAll( subclassSubgraphNodes ); - } - bindNamedSubgraph( defaults, ann, subgraphNodes, classLoaderAccess ); + bindNamedSubgraph( defaults, ann, "subgraphs", element.getSubgraph(), classLoaderAccess ); + bindNamedSubgraph( defaults, ann, "subclass-subgraph", element.getSubclassSubgraph(), classLoaderAccess ); namedEntityGraphList.add( AnnotationFactory.create( ann ) ); } //TODO @@ -1979,13 +2073,14 @@ public static List buildNamedEntityGraph( private static void bindNamedSubgraph( XMLContext.Default defaults, AnnotationDescriptor ann, - List subgraphNodes, + String annotationAttributeName, + List subgraphNodes, ClassLoaderAccess classLoaderAccess) { List annSubgraphNodes = new ArrayList<>( ); - for(Element subgraphNode : subgraphNodes){ + for(JaxbNamedSubgraph subgraphNode : subgraphNodes){ AnnotationDescriptor annSubgraphNode = new AnnotationDescriptor( NamedSubgraph.class ); - copyStringAttribute( annSubgraphNode, subgraphNode, "name", true ); - String clazzName = subgraphNode.attributeValue( "class" ); + copyAttribute( annSubgraphNode, "name", subgraphNode.getName(), true ); + String clazzName = subgraphNode.getClazz(); Class clazz; try { clazz = classLoaderAccess.classForName( @@ -1996,56 +2091,49 @@ private static void bindNamedSubgraph( throw new AnnotationException( "Unable to find entity-class: " + clazzName, e ); } annSubgraphNode.setValue( "type", clazz ); - bindNamedAttributeNodes(subgraphNode, annSubgraphNode); + bindNamedAttributeNodes(subgraphNode.getNamedAttributeNode(), annSubgraphNode); annSubgraphNodes.add( AnnotationFactory.create( annSubgraphNode ) ); } - ann.setValue( "subgraphs", annSubgraphNodes.toArray( new NamedSubgraph[annSubgraphNodes.size()] ) ); + ann.setValue( annotationAttributeName, annSubgraphNodes.toArray( new NamedSubgraph[annSubgraphNodes.size()] ) ); } - private static void bindNamedAttributeNodes(Element subElement, AnnotationDescriptor ann) { - List namedAttributeNodes = subElement.elements("named-attribute-node"); + private static void bindNamedAttributeNodes(List elements, AnnotationDescriptor ann) { List annNamedAttributeNodes = new ArrayList<>( ); - for(Element namedAttributeNode : namedAttributeNodes){ + for( JaxbNamedAttributeNode element : elements){ AnnotationDescriptor annNamedAttributeNode = new AnnotationDescriptor( NamedAttributeNode.class ); - copyStringAttribute( annNamedAttributeNode, namedAttributeNode, "value", "name", true ); - copyStringAttribute( annNamedAttributeNode, namedAttributeNode, "subgraph", false ); - copyStringAttribute( annNamedAttributeNode, namedAttributeNode, "key-subgraph", false ); + copyAttribute( annNamedAttributeNode, "value", "name", element.getName(),true ); + copyAttribute( annNamedAttributeNode, "subgraph", element.getSubgraph(), false ); + copyAttribute( annNamedAttributeNode, "key-subgraph", element.getKeySubgraph(), false ); annNamedAttributeNodes.add( AnnotationFactory.create( annNamedAttributeNode ) ); } ann.setValue( "attributeNodes", annNamedAttributeNodes.toArray( new NamedAttributeNode[annNamedAttributeNodes.size()] ) ); } public static List buildNamedStoreProcedureQueries( - Element element, + List elements, XMLContext.Default defaults, ClassLoaderAccess classLoaderAccess) { - if ( element == null ) { - return new ArrayList<>(); - } - List namedStoredProcedureElements = element.elements( "named-stored-procedure-query" ); List namedStoredProcedureQueries = new ArrayList<>(); - for ( Object obj : namedStoredProcedureElements ) { - Element subElement = (Element) obj; + for ( JaxbNamedStoredProcedureQuery element : elements ) { AnnotationDescriptor ann = new AnnotationDescriptor( NamedStoredProcedureQuery.class ); - copyStringAttribute( ann, subElement, "name", true ); - copyStringAttribute( ann, subElement, "procedure-name", true ); + copyAttribute( ann, "name", element.getName(), true ); + copyAttribute( ann, "procedure-name", element.getProcedureName(), true ); - List elements = subElement.elements( "parameter" ); List storedProcedureParameters = new ArrayList<>(); - for ( Element parameterElement : elements ) { + for ( JaxbStoredProcedureParameter parameterElement : element.getParameter() ) { AnnotationDescriptor parameterDescriptor = new AnnotationDescriptor( StoredProcedureParameter.class ); - copyStringAttribute( parameterDescriptor, parameterElement, "name", false ); - String modeValue = parameterElement.attributeValue( "mode" ); + copyAttribute( parameterDescriptor, "name", parameterElement.getName(), false ); + ParameterMode modeValue = parameterElement.getMode(); if ( modeValue == null ) { parameterDescriptor.setValue( "mode", ParameterMode.IN ); } else { - parameterDescriptor.setValue( "mode", ParameterMode.valueOf( modeValue.toUpperCase(Locale.ROOT) ) ); + parameterDescriptor.setValue( "mode", modeValue ); } - String clazzName = parameterElement.attributeValue( "class" ); - Class clazz; + String clazzName = parameterElement.getClazz(); + Class clazz; try { clazz = classLoaderAccess.classForName( XMLContext.buildSafeClassName( clazzName, defaults ) @@ -2063,11 +2151,9 @@ public static List buildNamedStoreProcedureQueries( storedProcedureParameters.toArray( new StoredProcedureParameter[storedProcedureParameters.size()] ) ); - elements = subElement.elements( "result-class" ); - List returnClasses = new ArrayList<>(); - for ( Element classElement : elements ) { - String clazzName = classElement.getTextTrim(); - Class clazz; + List> returnClasses = new ArrayList<>(); + for ( String clazzName : element.getResultClass() ) { + Class clazz; try { clazz = classLoaderAccess.classForName( XMLContext.buildSafeClassName( clazzName, defaults ) @@ -2081,14 +2167,8 @@ public static List buildNamedStoreProcedureQueries( ann.setValue( "resultClasses", returnClasses.toArray( new Class[returnClasses.size()] ) ); - elements = subElement.elements( "result-set-mapping" ); - List resultSetMappings = new ArrayList<>(); - for ( Element resultSetMappingElement : elements ) { - resultSetMappings.add( resultSetMappingElement.getTextTrim() ); - } - ann.setValue( "resultSetMappings", resultSetMappings.toArray( new String[resultSetMappings.size()] ) ); - elements = subElement.elements( "hint" ); - buildQueryHints( elements, ann ); + ann.setValue( "resultSetMappings", element.getResultSetMapping().toArray( new String[0] ) ); + buildQueryHints( element.getHint(), ann ); namedStoredProcedureQueries.add( AnnotationFactory.create( ann ) ); } return namedStoredProcedureQueries; @@ -2096,20 +2176,15 @@ public static List buildNamedStoreProcedureQueries( } public static List buildSqlResultsetMappings( - Element element, + List elements, XMLContext.Default defaults, ClassLoaderAccess classLoaderAccess) { final List builtResultSetMappings = new ArrayList<>(); - if ( element == null ) { - return builtResultSetMappings; - } // iterate over each element - for ( Object resultSetMappingElementObject : element.elements( "sql-result-set-mapping" ) ) { - final Element resultSetMappingElement = (Element) resultSetMappingElementObject; - + for ( JaxbSqlResultSetMapping resultSetMappingElement : elements ) { final AnnotationDescriptor resultSetMappingAnnotation = new AnnotationDescriptor( SqlResultSetMapping.class ); - copyStringAttribute( resultSetMappingAnnotation, resultSetMappingElement, "name", true ); + copyAttribute( resultSetMappingAnnotation, "name", resultSetMappingElement.getName(), true ); // iterate over the sub-elements, which should include: // * @@ -2120,48 +2195,24 @@ public static List buildSqlResultsetMappings( List columnResultAnnotations = null; List constructorResultAnnotations = null; - for ( Object resultElementObject : resultSetMappingElement.elements() ) { - final Element resultElement = (Element) resultElementObject; - - if ( "entity-result".equals( resultElement.getName() ) ) { - if ( entityResultAnnotations == null ) { - entityResultAnnotations = new ArrayList<>(); - } - // process the - entityResultAnnotations.add( buildEntityResult( resultElement, defaults, classLoaderAccess ) ); + for ( JaxbEntityResult resultElement : resultSetMappingElement.getEntityResult() ) { + if ( entityResultAnnotations == null ) { + entityResultAnnotations = new ArrayList<>(); } - else if ( "column-result".equals( resultElement.getName() ) ) { - if ( columnResultAnnotations == null ) { - columnResultAnnotations = new ArrayList<>(); - } - columnResultAnnotations.add( buildColumnResult( resultElement, defaults, classLoaderAccess ) ); - } - else if ( "constructor-result".equals( resultElement.getName() ) ) { - if ( constructorResultAnnotations == null ) { - constructorResultAnnotations = new ArrayList<>(); - } - constructorResultAnnotations.add( buildConstructorResult( resultElement, defaults, classLoaderAccess ) ); + // process the + entityResultAnnotations.add( buildEntityResult( resultElement, defaults, classLoaderAccess ) ); + } + for ( JaxbColumnResult resultElement : resultSetMappingElement.getColumnResult() ) { + if ( columnResultAnnotations == null ) { + columnResultAnnotations = new ArrayList<>(); } - else { - // most likely the this code used to handle. I have left the code here, - // but commented it out for now. I'll just log a warning for now. - LOG.debug( "Encountered unrecognized sql-result-set-mapping sub-element : " + resultElement.getName() ); - -// String clazzName = subelement.attributeValue( "result-class" ); -// if ( StringHelper.isNotEmpty( clazzName ) ) { -// Class clazz; -// try { -// clazz = ReflectHelper.classForName( -// XMLContext.buildSafeClassName( clazzName, defaults ), -// JPAOverriddenAnnotationReader.class -// ); -// } -// catch ( ClassNotFoundException e ) { -// throw new AnnotationException( "Unable to find entity-class: " + clazzName, e ); -// } -// ann.setValue( "resultClass", clazz ); -// } + columnResultAnnotations.add( buildColumnResult( resultElement, defaults, classLoaderAccess ) ); + } + for ( JaxbConstructorResult resultElement : resultSetMappingElement.getConstructorResult() ) { + if ( constructorResultAnnotations == null ) { + constructorResultAnnotations = new ArrayList<>(); } + constructorResultAnnotations.add( buildConstructorResult( resultElement, defaults, classLoaderAccess ) ); } if ( entityResultAnnotations != null && !entityResultAnnotations.isEmpty() ) { @@ -2183,10 +2234,6 @@ else if ( "constructor-result".equals( resultElement.getName() ) ) { ); } - - // this was part of the old code too, but could never figure out what it is supposed to do... - // copyStringAttribute( ann, subelement, "result-set-mapping", false ); - builtResultSetMappings.add( AnnotationFactory.create( resultSetMappingAnnotation ) ); } @@ -2194,22 +2241,22 @@ else if ( "constructor-result".equals( resultElement.getName() ) ) { } private static EntityResult buildEntityResult( - Element entityResultElement, + JaxbEntityResult entityResultElement, XMLContext.Default defaults, ClassLoaderAccess classLoaderAccess) { final AnnotationDescriptor entityResultDescriptor = new AnnotationDescriptor( EntityResult.class ); - final Class entityClass = resolveClassReference( entityResultElement.attributeValue( "entity-class" ), defaults, classLoaderAccess ); + final Class entityClass = resolveClassReference( entityResultElement.getEntityClass(), defaults, classLoaderAccess ); entityResultDescriptor.setValue( "entityClass", entityClass ); - copyStringAttribute( entityResultDescriptor, entityResultElement, "discriminator-column", false ); + copyAttribute( entityResultDescriptor, "discriminator-column", entityResultElement.getDiscriminatorColumn(), false ); // process the sub-elements List fieldResultAnnotations = new ArrayList<>(); - for ( Element fieldResult : (List) entityResultElement.elements( "field-result" ) ) { + for ( JaxbFieldResult fieldResult : entityResultElement.getFieldResult() ) { AnnotationDescriptor fieldResultDescriptor = new AnnotationDescriptor( FieldResult.class ); - copyStringAttribute( fieldResultDescriptor, fieldResult, "name", true ); - copyStringAttribute( fieldResultDescriptor, fieldResult, "column", true ); + copyAttribute( fieldResultDescriptor, "name", fieldResult.getName(), true ); + copyAttribute( fieldResultDescriptor, "column", fieldResult.getColumn(), true ); fieldResultAnnotations.add( AnnotationFactory.create( fieldResultDescriptor ) ); } entityResultDescriptor.setValue( @@ -2236,16 +2283,12 @@ private static Class resolveClassReference( } private static ColumnResult buildColumnResult( - Element columnResultElement, + JaxbColumnResult columnResultElement, XMLContext.Default defaults, ClassLoaderAccess classLoaderAccess) { -// AnnotationDescriptor columnResultDescriptor = new AnnotationDescriptor( ColumnResult.class ); -// copyStringAttribute( columnResultDescriptor, columnResultElement, "name", true ); -// return AnnotationFactory.create( columnResultDescriptor ); - AnnotationDescriptor columnResultDescriptor = new AnnotationDescriptor( ColumnResult.class ); - copyStringAttribute( columnResultDescriptor, columnResultElement, "name", true ); - final String columnTypeName = columnResultElement.attributeValue( "class" ); + copyAttribute( columnResultDescriptor, "name", columnResultElement.getName(), true ); + final String columnTypeName = columnResultElement.getClazz(); if ( StringHelper.isNotEmpty( columnTypeName ) ) { columnResultDescriptor.setValue( "type", resolveClassReference( columnTypeName, defaults, classLoaderAccess ) ); } @@ -2253,16 +2296,16 @@ private static ColumnResult buildColumnResult( } private static ConstructorResult buildConstructorResult( - Element constructorResultElement, + JaxbConstructorResult constructorResultElement, XMLContext.Default defaults, ClassLoaderAccess classLoaderAccess) { AnnotationDescriptor constructorResultDescriptor = new AnnotationDescriptor( ConstructorResult.class ); - final Class entityClass = resolveClassReference( constructorResultElement.attributeValue( "target-class" ), defaults, classLoaderAccess ); + final Class entityClass = resolveClassReference( constructorResultElement.getTargetClass(), defaults, classLoaderAccess ); constructorResultDescriptor.setValue( "targetClass", entityClass ); List columnResultAnnotations = new ArrayList<>(); - for ( Element columnResultElement : (List) constructorResultElement.elements( "column" ) ) { + for ( JaxbColumnResult columnResultElement : constructorResultElement.getColumn() ) { columnResultAnnotations.add( buildColumnResult( columnResultElement, defaults, classLoaderAccess ) ); } constructorResultDescriptor.setValue( @@ -2289,9 +2332,11 @@ private void addSqlResultsetMappingIfNeeded(SqlResultSetMapping annotation, List } } - private NamedQueries getNamedQueries(Element tree, XMLContext.Default defaults) { + private NamedQueries getNamedQueries(ManagedType root, XMLContext.Default defaults) { //TODO avoid the Proxy Creation (@NamedQueries) when possible - List queries = (List) buildNamedQueries( tree, false, defaults, classLoaderAccess ); + List queries = root instanceof JaxbEntity + ? buildNamedQueries( ( (JaxbEntity) root ).getNamedQuery(), defaults, classLoaderAccess ) + : new ArrayList<>(); if ( defaults.canUseJavaAnnotations() ) { NamedQuery annotation = getPhysicalAnnotation( NamedQuery.class ); addNamedQueryIfNeeded( annotation, queries ); @@ -2328,8 +2373,10 @@ private void addNamedQueryIfNeeded(NamedQuery annotation, List queri } } - private NamedEntityGraphs getNamedEntityGraphs(Element tree, XMLContext.Default defaults) { - List queries = buildNamedEntityGraph( tree, defaults, classLoaderAccess ); + private NamedEntityGraphs getNamedEntityGraphs(ManagedType root, XMLContext.Default defaults) { + List queries = root instanceof JaxbEntity + ? buildNamedEntityGraph( ( (JaxbEntity) root ).getNamedEntityGraph(), defaults, classLoaderAccess ) + : new ArrayList<>(); if ( defaults.canUseJavaAnnotations() ) { NamedEntityGraph annotation = getPhysicalAnnotation( NamedEntityGraph.class ); addNamedEntityGraphIfNeeded( annotation, queries ); @@ -2367,8 +2414,10 @@ private void addNamedEntityGraphIfNeeded(NamedEntityGraph annotation, List queries = buildNamedStoreProcedureQueries( tree, defaults, classLoaderAccess ); + private NamedStoredProcedureQueries getNamedStoredProcedureQueries(ManagedType root, XMLContext.Default defaults) { + List queries = root instanceof JaxbEntity + ? buildNamedStoreProcedureQueries( ( (JaxbEntity) root ).getNamedStoredProcedureQuery(), defaults, classLoaderAccess ) + : new ArrayList<>(); if ( defaults.canUseJavaAnnotations() ) { NamedStoredProcedureQuery annotation = getPhysicalAnnotation( NamedStoredProcedureQuery.class ); addNamedStoredProcedureQueryIfNeeded( annotation, queries ); @@ -2407,9 +2456,11 @@ private void addNamedStoredProcedureQueryIfNeeded(NamedStoredProcedureQuery anno private NamedNativeQueries getNamedNativeQueries( - Element tree, + ManagedType root, XMLContext.Default defaults) { - List queries = (List) buildNamedQueries( tree, true, defaults, classLoaderAccess ); + List queries = root instanceof JaxbEntity + ? buildNamedNativeQueries( ( (JaxbEntity) root ).getNamedNativeQuery(), defaults, classLoaderAccess ) + : new ArrayList<>(); if ( defaults.canUseJavaAnnotations() ) { NamedNativeQuery annotation = getPhysicalAnnotation( NamedNativeQuery.class ); addNamedNativeQueryIfNeeded( annotation, queries ); @@ -2446,16 +2497,16 @@ private void addNamedNativeQueryIfNeeded(NamedNativeQuery annotation, List elements, AnnotationDescriptor ann){ + private static void buildQueryHints(List elements, AnnotationDescriptor ann){ List queryHints = new ArrayList<>( elements.size() ); - for ( Element hint : elements ) { + for ( JaxbQueryHint hint : elements ) { AnnotationDescriptor hintDescriptor = new AnnotationDescriptor( QueryHint.class ); - String value = hint.attributeValue( "name" ); + String value = hint.getName(); if ( value == null ) { throw new AnnotationException( " without name. " + SCHEMA_VALIDATION ); } hintDescriptor.setValue( "name", value ); - value = hint.attributeValue( "value" ); + value = hint.getValue(); if ( value == null ) { throw new AnnotationException( " without value. " + SCHEMA_VALIDATION ); } @@ -2465,32 +2516,33 @@ private static void buildQueryHints(List elements, AnnotationDescriptor ann.setValue( "hints", queryHints.toArray( new QueryHint[queryHints.size()] ) ); } - public static List buildNamedQueries( - Element element, - boolean isNative, + public static List buildNamedQueries( + List elements, XMLContext.Default defaults, ClassLoaderAccess classLoaderAccess) { - if ( element == null ) { - return new ArrayList(); - } - List namedQueryElementList = isNative ? - element.elements( "named-native-query" ) : - element.elements( "named-query" ); - List namedQueries = new ArrayList(); - for ( Object aNamedQueryElementList : namedQueryElementList ) { - Element subelement = (Element) aNamedQueryElementList; - AnnotationDescriptor ann = new AnnotationDescriptor( - isNative ? NamedNativeQuery.class : NamedQuery.class - ); - copyStringAttribute( ann, subelement, "name", false ); - Element queryElt = subelement.element( "query" ); - if ( queryElt == null ) { - throw new AnnotationException( "No element found." + SCHEMA_VALIDATION ); - } - copyStringElement( queryElt, ann, "query" ); - List elements = subelement.elements( "hint" ); - buildQueryHints( elements, ann ); - String clazzName = subelement.attributeValue( "result-class" ); + List namedQueries = new ArrayList<>(); + for ( JaxbNamedQuery element : elements ) { + AnnotationDescriptor ann = new AnnotationDescriptor( NamedQuery.class ); + copyAttribute( ann, "name", element.getName(), false ); + copyAttribute( ann, "query", element.getQuery(), true ); + buildQueryHints( element.getHint(), ann ); + copyAttribute( ann, "lock-mode", element.getLockMode(), false ); + namedQueries.add( AnnotationFactory.create( ann ) ); + } + return namedQueries; + } + + public static List buildNamedNativeQueries( + List elements, + XMLContext.Default defaults, + ClassLoaderAccess classLoaderAccess) { + List namedQueries = new ArrayList<>(); + for ( JaxbNamedNativeQuery element : elements ) { + AnnotationDescriptor ann = new AnnotationDescriptor( NamedNativeQuery.class ); + copyAttribute( ann, "name", element.getName(), false ); + copyAttribute( ann, "query", element.getQuery(), true ); + buildQueryHints( element.getHint(), ann ); + String clazzName = element.getResultClass(); if ( StringHelper.isNotEmpty( clazzName ) ) { Class clazz; try { @@ -2503,14 +2555,17 @@ public static List buildNamedQueries( } ann.setValue( "resultClass", clazz ); } - copyStringAttribute( ann, subelement, "result-set-mapping", false ); + copyAttribute( ann, "result-set-mapping", element.getResultSetMapping(), false ); namedQueries.add( AnnotationFactory.create( ann ) ); } return namedQueries; } - private TableGenerator getTableGenerator(Element tree, XMLContext.Default defaults) { - Element element = tree != null ? tree.element( annotationToXml.get( TableGenerator.class ) ) : null; + private TableGenerator getTableGenerator(ManagedType root, XMLContext.Default defaults) { + return getTableGenerator( root instanceof JaxbEntity ? ( (JaxbEntity) root ).getTableGenerator() : null, defaults ); + } + + private TableGenerator getTableGenerator(JaxbTableGenerator element, XMLContext.Default defaults) { if ( element != null ) { return buildTableGeneratorAnnotation( element, defaults ); } @@ -2548,18 +2603,18 @@ else if ( defaults.canUseJavaAnnotations() && isPhysicalAnnotationPresent( Table } } - public static TableGenerator buildTableGeneratorAnnotation(Element element, XMLContext.Default defaults) { + public static TableGenerator buildTableGeneratorAnnotation(JaxbTableGenerator element, XMLContext.Default defaults) { AnnotationDescriptor ad = new AnnotationDescriptor( TableGenerator.class ); - copyStringAttribute( ad, element, "name", false ); - copyStringAttribute( ad, element, "table", false ); - copyStringAttribute( ad, element, "catalog", false ); - copyStringAttribute( ad, element, "schema", false ); - copyStringAttribute( ad, element, "pk-column-name", false ); - copyStringAttribute( ad, element, "value-column-name", false ); - copyStringAttribute( ad, element, "pk-column-value", false ); - copyIntegerAttribute( ad, element, "initial-value" ); - copyIntegerAttribute( ad, element, "allocation-size" ); - buildUniqueConstraints( ad, element ); + copyAttribute( ad, "name", element.getName(), false ); + copyAttribute( ad, "table", element.getTable(), false ); + copyAttribute( ad, "catalog", element.getCatalog(), false ); + copyAttribute( ad, "schema", element.getSchema(), false ); + copyAttribute( ad, "pk-column-name", element.getPkColumnName(), false ); + copyAttribute( ad, "value-column-name", element.getValueColumnName(), false ); + copyAttribute( ad, "pk-column-value", element.getPkColumnValue(), false ); + copyAttribute( ad, "initial-value", element.getInitialValue(), false ); + copyAttribute( ad, "allocation-size", element.getAllocationSize(), false ); + buildUniqueConstraints( ad, element.getUniqueConstraint() ); if ( StringHelper.isEmpty( (String) ad.valueOf( "schema" ) ) && StringHelper.isNotEmpty( defaults.getSchema() ) ) { ad.setValue( "schema", defaults.getSchema() ); @@ -2571,8 +2626,12 @@ public static TableGenerator buildTableGeneratorAnnotation(Element element, XMLC return AnnotationFactory.create( ad ); } - private SequenceGenerator getSequenceGenerator(Element tree, XMLContext.Default defaults) { - Element element = tree != null ? tree.element( annotationToXml.get( SequenceGenerator.class ) ) : null; + private SequenceGenerator getSequenceGenerator(ManagedType root, XMLContext.Default defaults) { + return getSequenceGenerator( root instanceof JaxbEntity ? ( (JaxbEntity) root ).getSequenceGenerator() : null, + defaults ); + } + + private SequenceGenerator getSequenceGenerator(JaxbSequenceGenerator element, XMLContext.Default defaults) { if ( element != null ) { return buildSequenceGeneratorAnnotation( element ); } @@ -2584,13 +2643,13 @@ else if ( defaults.canUseJavaAnnotations() ) { } } - public static SequenceGenerator buildSequenceGeneratorAnnotation(Element element) { + public static SequenceGenerator buildSequenceGeneratorAnnotation(JaxbSequenceGenerator element) { if ( element != null ) { AnnotationDescriptor ad = new AnnotationDescriptor( SequenceGenerator.class ); - copyStringAttribute( ad, element, "name", false ); - copyStringAttribute( ad, element, "sequence-name", false ); - copyIntegerAttribute( ad, element, "initial-value" ); - copyIntegerAttribute( ad, element, "allocation-size" ); + copyAttribute( ad, "name", element.getName(), false ); + copyAttribute( ad, "sequence-name", element.getSequenceName(), false ); + copyAttribute( ad, "initial-value", element.getInitialValue(), false ); + copyAttribute( ad, "allocation-size", element.getAllocationSize(), false ); return AnnotationFactory.create( ad ); } else { @@ -2598,32 +2657,17 @@ public static SequenceGenerator buildSequenceGeneratorAnnotation(Element element } } - private DiscriminatorColumn getDiscriminatorColumn(Element tree, XMLContext.Default defaults) { - Element element = tree != null ? tree.element( "discriminator-column" ) : null; + private DiscriminatorColumn getDiscriminatorColumn(ManagedType root, XMLContext.Default defaults) { + JaxbDiscriminatorColumn element = root instanceof JaxbEntity ? ( (JaxbEntity) root ).getDiscriminatorColumn() : null; if ( element != null ) { AnnotationDescriptor ad = new AnnotationDescriptor( DiscriminatorColumn.class ); - copyStringAttribute( ad, element, "name", false ); - copyStringAttribute( ad, element, "column-definition", false ); - String value = element.attributeValue( "discriminator-type" ); - DiscriminatorType type = DiscriminatorType.STRING; - if ( value != null ) { - if ( "STRING".equals( value ) ) { - type = DiscriminatorType.STRING; - } - else if ( "CHAR".equals( value ) ) { - type = DiscriminatorType.CHAR; - } - else if ( "INTEGER".equals( value ) ) { - type = DiscriminatorType.INTEGER; - } - else { - throw new AnnotationException( - "Unknown DiscriminatorType in XML: " + value + " (" + SCHEMA_VALIDATION + ")" - ); - } + copyAttribute( ad, "name", element.getName(), false ); + copyAttribute( ad, "column-definition", element.getColumnDefinition(), false ); + DiscriminatorType type = element.getDiscriminatorType(); + if ( type != null ) { + ad.setValue( "discriminatorType", type ); } - ad.setValue( "discriminatorType", type ); - copyIntegerAttribute( ad, element, "length" ); + copyAttribute( ad, "length", element.getLength(), false ); return AnnotationFactory.create( ad ); } else if ( defaults.canUseJavaAnnotations() ) { @@ -2634,11 +2678,11 @@ else if ( defaults.canUseJavaAnnotations() ) { } } - private DiscriminatorValue getDiscriminatorValue(Element tree, XMLContext.Default defaults) { - Element element = tree != null ? tree.element( "discriminator-value" ) : null; + private DiscriminatorValue getDiscriminatorValue(ManagedType root, XMLContext.Default defaults) { + String element = root instanceof JaxbEntity ? ( (JaxbEntity) root ).getDiscriminatorValue() : null; if ( element != null ) { AnnotationDescriptor ad = new AnnotationDescriptor( DiscriminatorValue.class ); - copyStringElement( element, ad, "value" ); + ad.setValue( "value", element ); return AnnotationFactory.create( ad ); } else if ( defaults.canUseJavaAnnotations() ) { @@ -2649,30 +2693,14 @@ else if ( defaults.canUseJavaAnnotations() ) { } } - private Inheritance getInheritance(Element tree, XMLContext.Default defaults) { - Element element = tree != null ? tree.element( "inheritance" ) : null; + private Inheritance getInheritance(ManagedType root, XMLContext.Default defaults) { + JaxbInheritance element = root instanceof JaxbEntity ? ( (JaxbEntity) root ).getInheritance() : null; if ( element != null ) { AnnotationDescriptor ad = new AnnotationDescriptor( Inheritance.class ); - Attribute attr = element.attribute( "strategy" ); - InheritanceType strategy = InheritanceType.SINGLE_TABLE; - if ( attr != null ) { - String value = attr.getValue(); - if ( "SINGLE_TABLE".equals( value ) ) { - strategy = InheritanceType.SINGLE_TABLE; - } - else if ( "JOINED".equals( value ) ) { - strategy = InheritanceType.JOINED; - } - else if ( "TABLE_PER_CLASS".equals( value ) ) { - strategy = InheritanceType.TABLE_PER_CLASS; - } - else { - throw new AnnotationException( - "Unknown InheritanceType in XML: " + value + " (" + SCHEMA_VALIDATION + ")" - ); - } + InheritanceType strategy = element.getStrategy(); + if ( strategy != null ) { + ad.setValue( "strategy", strategy ); } - ad.setValue( "strategy", strategy ); return AnnotationFactory.create( ad ); } else if ( defaults.canUseJavaAnnotations() ) { @@ -2683,19 +2711,19 @@ else if ( defaults.canUseJavaAnnotations() ) { } } - private IdClass getIdClass(Element tree, XMLContext.Default defaults) { - Element element = tree == null ? null : tree.element( "id-class" ); + private IdClass getIdClass(ManagedType root, XMLContext.Default defaults) { + JaxbIdClass element = root instanceof EntityOrMappedSuperclass ? + ( (EntityOrMappedSuperclass) root ).getIdClass() : null; if ( element != null ) { - Attribute attr = element.attribute( "class" ); - if ( attr != null ) { + String className = element.getClazz(); + if ( className != null ) { AnnotationDescriptor ad = new AnnotationDescriptor( IdClass.class ); - Class clazz; + Class clazz; try { - clazz = classLoaderAccess.classForName( XMLContext.buildSafeClassName( attr.getValue(), defaults ) - ); + clazz = classLoaderAccess.classForName( XMLContext.buildSafeClassName( className, defaults ) ); } catch ( ClassLoadingException e ) { - throw new AnnotationException( "Unable to find id-class: " + attr.getValue(), e ); + throw new AnnotationException( "Unable to find id-class: " + className, e ); } ad.setValue( "value", clazz ); return AnnotationFactory.create( ad ); @@ -2712,14 +2740,20 @@ else if ( defaults.canUseJavaAnnotations() ) { } } + private PrimaryKeyJoinColumns getPrimaryKeyJoinColumns(ManagedType root, XMLContext.Default defaults) { + return root instanceof JaxbEntity + ? getPrimaryKeyJoinColumns( ( (JaxbEntity) root ).getPrimaryKeyJoinColumn(), defaults, true ) + : null; + } + /** * @param mergeWithAnnotations Whether to use Java annotations for this * element, if present and not disabled by the XMLContext defaults. * In some contexts (such as an association mapping) merging with - * annotations is never allowed. */ - private PrimaryKeyJoinColumns getPrimaryKeyJoinColumns(Element element, XMLContext.Default defaults, boolean mergeWithAnnotations) { - PrimaryKeyJoinColumn[] columns = buildPrimaryKeyJoinColumns( element ); + private PrimaryKeyJoinColumns getPrimaryKeyJoinColumns(List elements, + XMLContext.Default defaults, boolean mergeWithAnnotations) { + PrimaryKeyJoinColumn[] columns = buildPrimaryKeyJoinColumns( elements ); if ( mergeWithAnnotations ) { if ( columns.length == 0 && defaults.canUseJavaAnnotations() ) { PrimaryKeyJoinColumn annotation = getPhysicalAnnotation( PrimaryKeyJoinColumn.class ); @@ -2742,14 +2776,15 @@ private PrimaryKeyJoinColumns getPrimaryKeyJoinColumns(Element element, XMLConte } } - private Entity getEntity(Element tree, XMLContext.Default defaults) { - if ( tree == null ) { + private Entity getEntity(ManagedType element, XMLContext.Default defaults) { + if ( element == null ) { return defaults.canUseJavaAnnotations() ? getPhysicalAnnotation( Entity.class ) : null; } else { - if ( "entity".equals( tree.getName() ) ) { + if ( element instanceof JaxbEntity ) { + JaxbEntity entityElement = (JaxbEntity) element; AnnotationDescriptor entity = new AnnotationDescriptor( Entity.class ); - copyStringAttribute( entity, tree, "name", false ); + copyAttribute( entity, "name", entityElement.getName(), false ); if ( defaults.canUseJavaAnnotations() && StringHelper.isEmpty( (String) entity.valueOf( "name" ) ) ) { Entity javaAnn = getPhysicalAnnotation( Entity.class ); @@ -2765,12 +2800,12 @@ private Entity getEntity(Element tree, XMLContext.Default defaults) { } } - private MappedSuperclass getMappedSuperclass(Element tree, XMLContext.Default defaults) { - if ( tree == null ) { + private MappedSuperclass getMappedSuperclass(ManagedType element, XMLContext.Default defaults) { + if ( element == null ) { return defaults.canUseJavaAnnotations() ? getPhysicalAnnotation( MappedSuperclass.class ) : null; } else { - if ( "mapped-superclass".equals( tree.getName() ) ) { + if ( element instanceof JaxbMappedSuperclass ) { AnnotationDescriptor entity = new AnnotationDescriptor( MappedSuperclass.class ); return AnnotationFactory.create( entity ); } @@ -2780,12 +2815,12 @@ private MappedSuperclass getMappedSuperclass(Element tree, XMLContext.Default de } } - private Embeddable getEmbeddable(Element tree, XMLContext.Default defaults) { - if ( tree == null ) { + private Embeddable getEmbeddable(ManagedType element, XMLContext.Default defaults) { + if ( element == null ) { return defaults.canUseJavaAnnotations() ? getPhysicalAnnotation( Embeddable.class ) : null; } else { - if ( "embeddable".equals( tree.getName() ) ) { + if ( element instanceof JaxbEmbeddable ) { AnnotationDescriptor entity = new AnnotationDescriptor( Embeddable.class ); return AnnotationFactory.create( entity ); } @@ -2795,9 +2830,9 @@ private Embeddable getEmbeddable(Element tree, XMLContext.Default defaults) { } } - private Table getTable(Element tree, XMLContext.Default defaults) { - Element subelement = tree == null ? null : tree.element( "table" ); - if ( subelement == null ) { + private Table getTable(ManagedType root, XMLContext.Default defaults) { + JaxbTable element = root instanceof JaxbEntity ? ( (JaxbEntity) root ).getTable() : null; + if ( element == null ) { //no element but might have some default or some annotation if ( StringHelper.isNotEmpty( defaults.getCatalog() ) || StringHelper.isNotEmpty( defaults.getSchema() ) ) { @@ -2832,44 +2867,44 @@ else if ( defaults.canUseJavaAnnotations() ) { else { //ignore java annotation, an element is defined AnnotationDescriptor annotation = new AnnotationDescriptor( Table.class ); - copyStringAttribute( annotation, subelement, "name", false ); - copyStringAttribute( annotation, subelement, "catalog", false ); + copyAttribute( annotation, "name", element.getName(), false ); + copyAttribute( annotation, "catalog", element.getCatalog(), false ); if ( StringHelper.isNotEmpty( defaults.getCatalog() ) && StringHelper.isEmpty( (String) annotation.valueOf( "catalog" ) ) ) { annotation.setValue( "catalog", defaults.getCatalog() ); } - copyStringAttribute( annotation, subelement, "schema", false ); + copyAttribute( annotation, "schema", element.getSchema(), false ); if ( StringHelper.isNotEmpty( defaults.getSchema() ) && StringHelper.isEmpty( (String) annotation.valueOf( "schema" ) ) ) { annotation.setValue( "schema", defaults.getSchema() ); } - buildUniqueConstraints( annotation, subelement ); - buildIndex( annotation, subelement ); + buildUniqueConstraints( annotation, element.getUniqueConstraint() ); + buildIndex( annotation, element.getIndex() ); return AnnotationFactory.create( annotation ); } } - private SecondaryTables getSecondaryTables(Element tree, XMLContext.Default defaults) { - List elements = tree == null ? - new ArrayList<>() : - (List) tree.elements( "secondary-table" ); + private SecondaryTables getSecondaryTables(ManagedType root, XMLContext.Default defaults) { + List elements = root instanceof JaxbEntity ? + ( (JaxbEntity) root ).getSecondaryTable() : Collections.emptyList(); List secondaryTables = new ArrayList<>( 3 ); - for ( Element element : elements ) { + for ( JaxbSecondaryTable element : elements ) { AnnotationDescriptor annotation = new AnnotationDescriptor( SecondaryTable.class ); - copyStringAttribute( annotation, element, "name", false ); - copyStringAttribute( annotation, element, "catalog", false ); + copyAttribute( annotation, "name", element.getName(), false ); + copyAttribute( annotation, "catalog", element.getCatalog(), false ); if ( StringHelper.isNotEmpty( defaults.getCatalog() ) && StringHelper.isEmpty( (String) annotation.valueOf( "catalog" ) ) ) { annotation.setValue( "catalog", defaults.getCatalog() ); } - copyStringAttribute( annotation, element, "schema", false ); + copyAttribute( annotation, "schema", element.getSchema(), false ); if ( StringHelper.isNotEmpty( defaults.getSchema() ) && StringHelper.isEmpty( (String) annotation.valueOf( "schema" ) ) ) { annotation.setValue( "schema", defaults.getSchema() ); } - buildUniqueConstraints( annotation, element ); - buildIndex( annotation, element ); - annotation.setValue( "pkJoinColumns", buildPrimaryKeyJoinColumns( element ) ); + buildUniqueConstraints( annotation, element.getUniqueConstraint() ); + buildIndex( annotation, element.getIndex() ); + annotation.setValue( "pkJoinColumns", + buildPrimaryKeyJoinColumns( element.getPrimaryKeyJoinColumn() ) ); secondaryTables.add( AnnotationFactory.create( annotation ) ); } /* @@ -2924,120 +2959,91 @@ private void overridesDefaultInSecondaryTable( } } } - private static void buildIndex(AnnotationDescriptor annotation, Element element){ - List indexElementList = element.elements( "index" ); - Index[] indexes = new Index[indexElementList.size()]; - for(int i=0;i elements) { + Index[] indexes = new Index[elements.size()]; + int i = 0; + for ( JaxbIndex element : elements ) { AnnotationDescriptor indexAnn = new AnnotationDescriptor( Index.class ); - copyStringAttribute( indexAnn, subelement, "name", false ); - copyStringAttribute( indexAnn, subelement, "column-list", true ); - copyBooleanAttribute( indexAnn, subelement, "unique" ); - indexes[i] = AnnotationFactory.create( indexAnn ); + copyAttribute( indexAnn, "name", element.getName(), false ); + copyAttribute( indexAnn, "column-list", element.getColumnList(), true ); + copyAttribute( indexAnn, "unique", element.isUnique(), false ); + indexes[i++] = AnnotationFactory.create( indexAnn ); } annotation.setValue( "indexes", indexes ); } - private static void buildUniqueConstraints(AnnotationDescriptor annotation, Element element) { - List uniqueConstraintElementList = element.elements( "unique-constraint" ); - UniqueConstraint[] uniqueConstraints = new UniqueConstraint[uniqueConstraintElementList.size()]; - int ucIndex = 0; - Iterator ucIt = uniqueConstraintElementList.listIterator(); - while ( ucIt.hasNext() ) { - Element subelement = (Element) ucIt.next(); - List columnNamesElements = subelement.elements( "column-name" ); - String[] columnNames = new String[columnNamesElements.size()]; - int columnNameIndex = 0; - Iterator it = columnNamesElements.listIterator(); - while ( it.hasNext() ) { - Element columnNameElt = (Element) it.next(); - columnNames[columnNameIndex++] = columnNameElt.getTextTrim(); - } + + private static void buildUniqueConstraints(AnnotationDescriptor annotation, + List elements) { + UniqueConstraint[] uniqueConstraints = new UniqueConstraint[elements.size()]; + int i = 0; + for ( JaxbUniqueConstraint element : elements ) { + String[] columnNames = element.getColumnName().toArray( new String[0] ); AnnotationDescriptor ucAnn = new AnnotationDescriptor( UniqueConstraint.class ); - copyStringAttribute( ucAnn, subelement, "name", false ); + copyAttribute( ucAnn, "name", element.getName(), false ); ucAnn.setValue( "columnNames", columnNames ); - uniqueConstraints[ucIndex++] = AnnotationFactory.create( ucAnn ); + uniqueConstraints[i++] = AnnotationFactory.create( ucAnn ); } annotation.setValue( "uniqueConstraints", uniqueConstraints ); } - private PrimaryKeyJoinColumn[] buildPrimaryKeyJoinColumns(Element element) { - if ( element == null ) { - return new PrimaryKeyJoinColumn[] { }; - } - List pkJoinColumnElementList = element.elements( "primary-key-join-column" ); - PrimaryKeyJoinColumn[] pkJoinColumns = new PrimaryKeyJoinColumn[pkJoinColumnElementList.size()]; - int index = 0; - Iterator pkIt = pkJoinColumnElementList.listIterator(); - while ( pkIt.hasNext() ) { - Element subelement = (Element) pkIt.next(); + private PrimaryKeyJoinColumn[] buildPrimaryKeyJoinColumns(List elements) { + PrimaryKeyJoinColumn[] pkJoinColumns = new PrimaryKeyJoinColumn[elements.size()]; + int i = 0; + for ( JaxbPrimaryKeyJoinColumn element : elements ) { AnnotationDescriptor pkAnn = new AnnotationDescriptor( PrimaryKeyJoinColumn.class ); - copyStringAttribute( pkAnn, subelement, "name", false ); - copyStringAttribute( pkAnn, subelement, "referenced-column-name", false ); - copyStringAttribute( pkAnn, subelement, "column-definition", false ); - pkJoinColumns[index++] = AnnotationFactory.create( pkAnn ); + copyAttribute( pkAnn, "name", element.getName(), false ); + copyAttribute( pkAnn, "referenced-column-name", element.getReferencedColumnName(), false ); + copyAttribute( pkAnn, "column-definition", element.getColumnDefinition(), false ); + pkJoinColumns[i++] = AnnotationFactory.create( pkAnn ); } return pkJoinColumns; } /** - * Copy a string attribute from an XML element to an annotation descriptor. The name of the annotation attribute is + * Copy an attribute from an XML element to an annotation descriptor. The name of the annotation attribute is * computed from the name of the XML attribute by {@link #getJavaAttributeNameFromXMLOne(String)}. * * @param annotation annotation descriptor where to copy to the attribute. - * @param element XML element from where to copy the attribute. * @param attributeName name of the XML attribute to copy. + * @param attributeValue value of the XML attribute to copy. * @param mandatory whether the attribute is mandatory. */ - private static void copyStringAttribute( - final AnnotationDescriptor annotation, final Element element, - final String attributeName, final boolean mandatory) { - copyStringAttribute( + private static void copyAttribute( + final AnnotationDescriptor annotation, + final String attributeName, final Object attributeValue, + final boolean mandatory) { + copyAttribute( annotation, - element, getJavaAttributeNameFromXMLOne( attributeName ), attributeName, + attributeValue, mandatory ); } /** - * Copy a string attribute from an XML element to an annotation descriptor. The name of the annotation attribute is + * Copy an attribute from an XML element to an annotation descriptor. The name of the annotation attribute is * explicitly given. * * @param annotation annotation where to copy to the attribute. - * @param element XML element from where to copy the attribute. * @param annotationAttributeName name of the annotation attribute where to copy. - * @param attributeName name of the XML attribute to copy. + * @param attributeValue value of the XML attribute to copy. * @param mandatory whether the attribute is mandatory. */ - private static void copyStringAttribute( - final AnnotationDescriptor annotation, final Element element, - final String annotationAttributeName, final String attributeName, boolean mandatory) { - String attribute = element.attributeValue( attributeName ); - if ( attribute != null ) { - annotation.setValue( annotationAttributeName, attribute ); + private static void copyAttribute( + final AnnotationDescriptor annotation, + final String annotationAttributeName, final Object attributeName, + final Object attributeValue, + boolean mandatory) { + if ( attributeValue != null ) { + annotation.setValue( annotationAttributeName, attributeValue ); } else { if ( mandatory ) { throw new AnnotationException( - element.getName() + "." + attributeName + " is mandatory in XML overriding. " + SCHEMA_VALIDATION - ); - } - } - } - - private static void copyIntegerAttribute(AnnotationDescriptor annotation, Element element, String attributeName) { - String attribute = element.attributeValue( attributeName ); - if ( attribute != null ) { - String annotationAttributeName = getJavaAttributeNameFromXMLOne( attributeName ); - annotation.setValue( annotationAttributeName, attribute ); - try { - int length = Integer.parseInt( attribute ); - annotation.setValue( annotationAttributeName, length ); - } - catch ( NumberFormatException e ) { - throw new AnnotationException( - element.getPath() + attributeName + " not parseable: " + attribute + " (" + SCHEMA_VALIDATION + ")" + annotationToXml.getOrDefault( annotation.type(), annotation.type().getName() ) + + "." + attributeName + + " is mandatory in XML overriding. " + SCHEMA_VALIDATION ); } } @@ -3056,19 +3062,6 @@ private static String getJavaAttributeNameFromXMLOne(String attributeName) { return annotationAttributeName.toString(); } - private static void copyStringElement(Element element, AnnotationDescriptor ad, String annotationAttribute) { - String discr = element.getTextTrim(); - ad.setValue( annotationAttribute, discr ); - } - - private static void copyBooleanAttribute(AnnotationDescriptor descriptor, Element element, String attribute) { - String attributeValue = element.attributeValue( attribute ); - if ( StringHelper.isNotEmpty( attributeValue ) ) { - String javaAttribute = getJavaAttributeNameFromXMLOne( attribute ); - descriptor.setValue( javaAttribute, Boolean.parseBoolean( attributeValue ) ); - } - } - private T getPhysicalAnnotation(Class annotationType) { return element.getAnnotation( annotationType ); } @@ -3080,4 +3073,5 @@ private boolean isPhysicalAnnotationPresent(Class anno private Annotation[] getPhysicalAnnotations() { return element.getAnnotations(); } + } diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenMetadataProvider.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenMetadataProvider.java index 6c65829d0999..99bf8efd5484 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenMetadataProvider.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenMetadataProvider.java @@ -23,20 +23,19 @@ import org.hibernate.annotations.common.reflection.AnnotationReader; import org.hibernate.annotations.common.reflection.MetadataProvider; import org.hibernate.annotations.common.reflection.java.JavaMetadataProvider; +import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappings; +import org.hibernate.boot.jaxb.mapping.spi.JaxbSequenceGenerator; +import org.hibernate.boot.jaxb.mapping.spi.JaxbTableGenerator; import org.hibernate.boot.jaxb.spi.XmlMappingOptions; import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; import org.hibernate.boot.spi.BootstrapContext; import org.hibernate.boot.spi.ClassLoaderAccess; -import org.dom4j.Element; - /** * MetadataProvider aware of the JPA Deployment descriptor (orm.xml, ...). * * @author Emmanuel Bernard */ -// FIXME HHH-14529 Change this class to use JaxbEntityMappings instead of Document. -// I'm delaying this change in order to keep the commits simpler and easier to review. @SuppressWarnings("unchecked") public final class JPAXMLOverriddenMetadataProvider implements MetadataProvider { @@ -112,28 +111,27 @@ public Map getDefaults() { } } defaults.put( EntityListeners.class, entityListeners ); - for ( Element element : xmlContext.getAllDocuments() ) { - @SuppressWarnings( "unchecked" ) - List elements = element.elements( "sequence-generator" ); + for ( JaxbEntityMappings entityMappings : xmlContext.getAllDocuments() ) { + List jaxbSequenceGenerators = entityMappings.getSequenceGenerator(); List sequenceGenerators = ( List ) defaults.get( SequenceGenerator.class ); if ( sequenceGenerators == null ) { sequenceGenerators = new ArrayList<>(); defaults.put( SequenceGenerator.class, sequenceGenerators ); } - for ( Element subelement : elements ) { - sequenceGenerators.add( JPAXMLOverriddenAnnotationReader.buildSequenceGeneratorAnnotation( subelement ) ); + for ( JaxbSequenceGenerator element : jaxbSequenceGenerators ) { + sequenceGenerators.add( JPAXMLOverriddenAnnotationReader.buildSequenceGeneratorAnnotation( element ) ); } - elements = element.elements( "table-generator" ); + List jaxbTableGenerators = entityMappings.getTableGenerator(); List tableGenerators = ( List ) defaults.get( TableGenerator.class ); if ( tableGenerators == null ) { tableGenerators = new ArrayList<>(); defaults.put( TableGenerator.class, tableGenerators ); } - for ( Element subelement : elements ) { + for ( JaxbTableGenerator element : jaxbTableGenerators ) { tableGenerators.add( JPAXMLOverriddenAnnotationReader.buildTableGeneratorAnnotation( - subelement, xmlDefaults + element, xmlDefaults ) ); } @@ -144,8 +142,7 @@ public Map getDefaults() { defaults.put( NamedQuery.class, namedQueries ); } List currentNamedQueries = JPAXMLOverriddenAnnotationReader.buildNamedQueries( - element, - false, + entityMappings.getNamedQuery(), xmlDefaults, classLoaderAccess ); @@ -156,9 +153,8 @@ public Map getDefaults() { namedNativeQueries = new ArrayList<>(); defaults.put( NamedNativeQuery.class, namedNativeQueries ); } - List currentNamedNativeQueries = JPAXMLOverriddenAnnotationReader.buildNamedQueries( - element, - true, + List currentNamedNativeQueries = JPAXMLOverriddenAnnotationReader.buildNamedNativeQueries( + entityMappings.getNamedNativeQuery(), xmlDefaults, classLoaderAccess ); @@ -172,7 +168,7 @@ public Map getDefaults() { defaults.put( SqlResultSetMapping.class, sqlResultSetMappings ); } List currentSqlResultSetMappings = JPAXMLOverriddenAnnotationReader.buildSqlResultsetMappings( - element, + entityMappings.getSqlResultSetMapping(), xmlDefaults, classLoaderAccess ); @@ -185,7 +181,7 @@ public Map getDefaults() { } List currentNamedStoredProcedureQueries = JPAXMLOverriddenAnnotationReader .buildNamedStoreProcedureQueries( - element, + entityMappings.getNamedStoredProcedureQuery(), xmlDefaults, classLoaderAccess ); diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/PropertyMappingElementCollector.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/PropertyMappingElementCollector.java new file mode 100644 index 000000000000..97bf6b89ea23 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/PropertyMappingElementCollector.java @@ -0,0 +1,214 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.cfg.annotations.reflection.internal; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.function.Function; + +import org.hibernate.boot.jaxb.mapping.spi.AttributesContainer; +import org.hibernate.boot.jaxb.mapping.spi.JaxbAttributes; +import org.hibernate.boot.jaxb.mapping.spi.JaxbBasic; +import org.hibernate.boot.jaxb.mapping.spi.JaxbElementCollection; +import org.hibernate.boot.jaxb.mapping.spi.JaxbEmbedded; +import org.hibernate.boot.jaxb.mapping.spi.JaxbEmbeddedId; +import org.hibernate.boot.jaxb.mapping.spi.JaxbId; +import org.hibernate.boot.jaxb.mapping.spi.JaxbManyToMany; +import org.hibernate.boot.jaxb.mapping.spi.JaxbManyToOne; +import org.hibernate.boot.jaxb.mapping.spi.JaxbOneToMany; +import org.hibernate.boot.jaxb.mapping.spi.JaxbOneToOne; +import org.hibernate.boot.jaxb.mapping.spi.JaxbPostLoad; +import org.hibernate.boot.jaxb.mapping.spi.JaxbPostPersist; +import org.hibernate.boot.jaxb.mapping.spi.JaxbPostRemove; +import org.hibernate.boot.jaxb.mapping.spi.JaxbPostUpdate; +import org.hibernate.boot.jaxb.mapping.spi.JaxbPrePersist; +import org.hibernate.boot.jaxb.mapping.spi.JaxbPreRemove; +import org.hibernate.boot.jaxb.mapping.spi.JaxbPreUpdate; +import org.hibernate.boot.jaxb.mapping.spi.JaxbTransient; +import org.hibernate.boot.jaxb.mapping.spi.JaxbVersion; +import org.hibernate.boot.jaxb.mapping.spi.LifecycleCallback; +import org.hibernate.boot.jaxb.mapping.spi.LifecycleCallbackContainer; +import org.hibernate.boot.jaxb.mapping.spi.PersistentAttribute; + +/** + * Reproduces what we used to do with a {@code List} in {@link JPAXMLOverriddenAnnotationReader}, + * with the following constraints: + *

    + *
  • Preserve type safety
  • + *
  • Only create lists if we actually have elements (most lists should be empty in most cases)
  • + *
+ */ +final class PropertyMappingElementCollector { + static final Function PERSISTENT_ATTRIBUTE_NAME = PersistentAttribute::getName; + static final Function JAXB_TRANSIENT_NAME = JaxbTransient::getName; + static final Function LIFECYCLE_CALLBACK_NAME = LifecycleCallback::getMethodName; + + private final String propertyName; + + private List id; + private List embeddedId; + private List basic; + private List version; + private List manyToOne; + private List oneToMany; + private List oneToOne; + private List manyToMany; + private List elementCollection; + private List embedded; + private List _transient; + + private List prePersist; + private List postPersist; + private List preRemove; + private List postRemove; + private List preUpdate; + private List postUpdate; + private List postLoad; + + PropertyMappingElementCollector(String propertyName) { + this.propertyName = propertyName; + } + + public boolean isEmpty() { + return allNullOrEmpty( id, embeddedId, basic, version, manyToOne, oneToMany, oneToOne, manyToMany, + elementCollection, embedded, _transient, + prePersist, postPersist, preRemove, postRemove, preUpdate, postUpdate, postLoad ); + } + + private boolean allNullOrEmpty(List... lists) { + for ( List list : lists ) { + if ( list != null && !list.isEmpty() ) { + return false; + } + } + return true; + } + + private List defaultToEmpty(List list) { + return list == null ? Collections.emptyList() : list; + } + + public void collectPersistentAttributesIfMatching(AttributesContainer container) { + if ( container instanceof JaxbAttributes ) { + JaxbAttributes jaxbAttributes = (JaxbAttributes) container; + id = collectIfMatching( id, jaxbAttributes.getId(), PERSISTENT_ATTRIBUTE_NAME ); + embeddedId = collectIfMatching( embeddedId, jaxbAttributes.getEmbeddedId(), PERSISTENT_ATTRIBUTE_NAME ); + version = collectIfMatching( version, jaxbAttributes.getVersion(), PERSISTENT_ATTRIBUTE_NAME ); + } + basic = collectIfMatching( basic, container.getBasic(), PERSISTENT_ATTRIBUTE_NAME ); + manyToOne = collectIfMatching( manyToOne, container.getManyToOne(), PERSISTENT_ATTRIBUTE_NAME ); + oneToMany = collectIfMatching( oneToMany, container.getOneToMany(), PERSISTENT_ATTRIBUTE_NAME ); + oneToOne = collectIfMatching( oneToOne, container.getOneToOne(), PERSISTENT_ATTRIBUTE_NAME ); + manyToMany = collectIfMatching( manyToMany, container.getManyToMany(), PERSISTENT_ATTRIBUTE_NAME ); + elementCollection = collectIfMatching( elementCollection, container.getElementCollection(), PERSISTENT_ATTRIBUTE_NAME ); + embedded = collectIfMatching( embedded, container.getEmbedded(), PERSISTENT_ATTRIBUTE_NAME ); + _transient = collectIfMatching( _transient, container.getTransient(), JAXB_TRANSIENT_NAME ); + } + + public void collectLifecycleCallbacksIfMatching(LifecycleCallbackContainer container) { + prePersist = collectIfMatching( prePersist, container.getPrePersist(), LIFECYCLE_CALLBACK_NAME ); + postPersist = collectIfMatching( postPersist, container.getPostPersist(), LIFECYCLE_CALLBACK_NAME ); + preRemove = collectIfMatching( preRemove, container.getPreRemove(), LIFECYCLE_CALLBACK_NAME ); + postRemove = collectIfMatching( postRemove, container.getPostRemove(), LIFECYCLE_CALLBACK_NAME ); + preUpdate = collectIfMatching( preUpdate, container.getPreUpdate(), LIFECYCLE_CALLBACK_NAME ); + postUpdate = collectIfMatching( postUpdate, container.getPostUpdate(), LIFECYCLE_CALLBACK_NAME ); + postLoad = collectIfMatching( postLoad, container.getPostLoad(), LIFECYCLE_CALLBACK_NAME ); + } + + private List collectIfMatching(List collected, List candidates, + Function nameGetter) { + List result = collected; + for ( T candidate : candidates ) { + result = collectIfMatching( result, candidate, nameGetter ); + } + return result; + } + + private List collectIfMatching(List collected, T candidate, Function nameGetter) { + List result = collected; + if ( candidate != null && propertyName.equals( nameGetter.apply( candidate ) ) ) { + if ( result == null ) { + result = new ArrayList<>(); + } + result.add( candidate ); + } + return result; + } + + public List getId() { + return defaultToEmpty( id ); + } + + public List getEmbeddedId() { + return defaultToEmpty( embeddedId ); + } + + public List getBasic() { + return defaultToEmpty( basic ); + } + + public List getVersion() { + return defaultToEmpty( version ); + } + + public List getManyToOne() { + return defaultToEmpty( manyToOne ); + } + + public List getOneToMany() { + return defaultToEmpty( oneToMany ); + } + + public List getOneToOne() { + return defaultToEmpty( oneToOne ); + } + + public List getManyToMany() { + return defaultToEmpty( manyToMany ); + } + + public List getElementCollection() { + return defaultToEmpty( elementCollection ); + } + + public List getEmbedded() { + return defaultToEmpty( embedded ); + } + + public List getTransient() { + return defaultToEmpty( _transient ); + } + + public List getPrePersist() { + return defaultToEmpty( prePersist ); + } + + public List getPostPersist() { + return defaultToEmpty( postPersist ); + } + + public List getPreRemove() { + return defaultToEmpty( preRemove ); + } + + public List getPostRemove() { + return defaultToEmpty( postRemove ); + } + + public List getPreUpdate() { + return defaultToEmpty( preUpdate ); + } + + public List getPostUpdate() { + return defaultToEmpty( postUpdate ); + } + + public List getPostLoad() { + return defaultToEmpty( postLoad ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/XMLContext.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/XMLContext.java index 513fbd6aa87c..f009b708c4cb 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/XMLContext.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/XMLContext.java @@ -16,89 +16,81 @@ import org.hibernate.AnnotationException; import org.hibernate.boot.AttributeConverterInfo; +import org.hibernate.boot.jaxb.mapping.spi.JaxbConverter; +import org.hibernate.boot.jaxb.mapping.spi.JaxbEntity; +import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityListener; +import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityListeners; import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappings; +import org.hibernate.boot.jaxb.mapping.spi.JaxbMappedSuperclass; +import org.hibernate.boot.jaxb.mapping.spi.JaxbPersistenceUnitDefaults; +import org.hibernate.boot.jaxb.mapping.spi.JaxbPersistenceUnitMetadata; +import org.hibernate.boot.jaxb.mapping.spi.ManagedType; import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; import org.hibernate.boot.spi.BootstrapContext; import org.hibernate.boot.spi.ClassLoaderAccess; import org.hibernate.cfg.AttributeConverterDefinition; -import org.hibernate.cfg.NotYetImplementedException; import org.hibernate.cfg.annotations.reflection.AttributeConverterDefinitionCollector; import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.StringHelper; -import org.dom4j.Document; -import org.dom4j.Element; - /** * A helper for consuming orm.xml mappings. * * @author Emmanuel Bernard * @author Brett Meyer */ -// FIXME HHH-14529 Change this class to use JaxbEntityMappings instead of Document. -// I'm delaying this change in order to keep the commits simpler and easier to review. public class XMLContext implements Serializable { private static final CoreMessageLogger LOG = CoreLogging.messageLogger( XMLContext.class ); private final ClassLoaderAccess classLoaderAccess; private Default globalDefaults; - private Map classOverriding = new HashMap<>(); - private Map defaultsOverriding = new HashMap<>(); - private List defaultElements = new ArrayList<>(); - private List defaultEntityListeners = new ArrayList<>(); + private final Map managedTypeOverride = new HashMap<>(); + private final Map entityListenerOverride = new HashMap<>(); + private final Map defaultsOverride = new HashMap<>(); + private final List defaultElements = new ArrayList<>(); + private final List defaultEntityListeners = new ArrayList<>(); private boolean hasContext = false; - XMLContext(ClassLoaderAccess classLoaderAccess) { + /** + * @deprecated Use {@link org.hibernate.cfg.annotations.reflection.XMLContext#XMLContext(BootstrapContext)} instead. + */ + @Deprecated + public XMLContext(ClassLoaderAccess classLoaderAccess) { this.classLoaderAccess = classLoaderAccess; } - // For tests only public XMLContext(BootstrapContext bootstrapContext) { this.classLoaderAccess = bootstrapContext.getClassLoaderAccess(); } /** - * @param entityMappings The xml entity mappings to add - * @return Add an xml document to this context and return the list of added class names. - */ - public List addDocument(JaxbEntityMappings entityMappings) { - throw new NotYetImplementedException("HHH-14529 Implementation in progress"); - } - - /** - * @param doc The xml document to add + * @param entityMappings The xml document to add * @return Add an xml document to this context and return the list of added class names. */ @SuppressWarnings( "unchecked" ) - public List addDocument(Document doc) { + public List addDocument(JaxbEntityMappings entityMappings) { hasContext = true; List addedClasses = new ArrayList<>(); - Element root = doc.getRootElement(); //global defaults - Element metadata = root.element( "persistence-unit-metadata" ); + JaxbPersistenceUnitMetadata metadata = entityMappings.getPersistenceUnitMetadata(); if ( metadata != null ) { if ( globalDefaults == null ) { globalDefaults = new Default(); globalDefaults.setMetadataComplete( - metadata.element( "xml-mapping-metadata-complete" ) != null ? + metadata.getXmlMappingMetadataComplete() != null ? Boolean.TRUE : null ); - Element defaultElement = metadata.element( "persistence-unit-defaults" ); + JaxbPersistenceUnitDefaults defaultElement = metadata.getPersistenceUnitDefaults(); if ( defaultElement != null ) { - Element unitElement = defaultElement.element( "schema" ); - globalDefaults.setSchema( unitElement != null ? unitElement.getTextTrim() : null ); - unitElement = defaultElement.element( "catalog" ); - globalDefaults.setCatalog( unitElement != null ? unitElement.getTextTrim() : null ); - unitElement = defaultElement.element( "access" ); - setAccess( unitElement, globalDefaults ); - unitElement = defaultElement.element( "cascade-persist" ); - globalDefaults.setCascadePersist( unitElement != null ? Boolean.TRUE : null ); - unitElement = defaultElement.element( "delimited-identifiers" ); - globalDefaults.setDelimitedIdentifiers( unitElement != null ? Boolean.TRUE : null ); - defaultEntityListeners.addAll( addEntityListenerClasses( defaultElement, null, addedClasses ) ); + globalDefaults.setSchema( defaultElement.getSchema() ); + globalDefaults.setCatalog( defaultElement.getCatalog() ); + globalDefaults.setAccess( defaultElement.getAccess() ); + globalDefaults.setCascadePersist( defaultElement.getCascadePersist() != null ? Boolean.TRUE : null ); + globalDefaults.setDelimitedIdentifiers( defaultElement.getDelimitedIdentifiers() != null ? Boolean.TRUE : null ); + defaultEntityListeners.addAll( addEntityListenerClasses( defaultElement.getEntityListeners(), null, addedClasses ) ); } } else { @@ -108,92 +100,61 @@ public List addDocument(Document doc) { //entity mapping default Default entityMappingDefault = new Default(); - Element unitElement = root.element( "package" ); - String packageName = unitElement != null ? unitElement.getTextTrim() : null; + String packageName = entityMappings.getPackage(); entityMappingDefault.setPackageName( packageName ); - unitElement = root.element( "schema" ); - entityMappingDefault.setSchema( unitElement != null ? unitElement.getTextTrim() : null ); - unitElement = root.element( "catalog" ); - entityMappingDefault.setCatalog( unitElement != null ? unitElement.getTextTrim() : null ); - unitElement = root.element( "access" ); - setAccess( unitElement, entityMappingDefault ); - defaultElements.add( root ); + entityMappingDefault.setSchema( entityMappings.getSchema() ); + entityMappingDefault.setCatalog( entityMappings.getCatalog() ); + entityMappingDefault.setAccess( entityMappings.getAccess() ); + defaultElements.add( entityMappings ); - setLocalAttributeConverterDefinitions( root.elements( "converter" ) ); + setLocalAttributeConverterDefinitions( entityMappings.getConverter() ); - List entities = root.elements( "entity" ); - addClass( entities, packageName, entityMappingDefault, addedClasses ); + addClass( entityMappings.getEntity(), packageName, entityMappingDefault, addedClasses ); - entities = root.elements( "mapped-superclass" ); - addClass( entities, packageName, entityMappingDefault, addedClasses ); + addClass( entityMappings.getMappedSuperclass(), packageName, entityMappingDefault, addedClasses ); - entities = root.elements( "embeddable" ); - addClass( entities, packageName, entityMappingDefault, addedClasses ); - return addedClasses; - } + addClass( entityMappings.getEmbeddable(), packageName, entityMappingDefault, addedClasses ); - private void setAccess(Element unitElement, Default defaultType) { - if ( unitElement != null ) { - String access = unitElement.getTextTrim(); - setAccess( access, defaultType ); - } - } - - private void setAccess( String access, Default defaultType) { - AccessType type; - if ( access != null ) { - try { - type = AccessType.valueOf( access ); - } - catch ( IllegalArgumentException e ) { - throw new AnnotationException( "Invalid access type " + access + " (check your xml configuration)" ); - } - defaultType.setAccess( type ); - } + return addedClasses; } - private void addClass(List entities, String packageName, Default defaults, List addedClasses) { - for (Element element : entities) { - String className = buildSafeClassName( element.attributeValue( "class" ), packageName ); - if ( classOverriding.containsKey( className ) ) { + private void addClass(List managedTypes, String packageName, Default defaults, List addedClasses) { + for (ManagedType element : managedTypes) { + String className = buildSafeClassName( element.getClazz(), packageName ); + if ( managedTypeOverride.containsKey( className ) ) { //maybe switch it to warn? throw new IllegalStateException( "Duplicate XML entry for " + className ); } addedClasses.add( className ); - classOverriding.put( className, element ); + managedTypeOverride.put( className, element ); Default localDefault = new Default(); localDefault.override( defaults ); - String metadataCompleteString = element.attributeValue( "metadata-complete" ); - if ( metadataCompleteString != null ) { - localDefault.setMetadataComplete( Boolean.parseBoolean( metadataCompleteString ) ); - } - String access = element.attributeValue( "access" ); - setAccess( access, localDefault ); - defaultsOverriding.put( className, localDefault ); + localDefault.setMetadataComplete( element.isMetadataComplete() ); + localDefault.setAccess( element.getAccess() ); + defaultsOverride.put( className, localDefault ); LOG.debugf( "Adding XML overriding information for %s", className ); - addEntityListenerClasses( element, packageName, addedClasses ); + if ( element instanceof JaxbEntity ) { + addEntityListenerClasses( ( (JaxbEntity) element ).getEntityListeners(), packageName, addedClasses ); + } + else if ( element instanceof JaxbMappedSuperclass ) { + addEntityListenerClasses( ( (JaxbMappedSuperclass) element ).getEntityListeners(), packageName, addedClasses ); + } } } - private List addEntityListenerClasses(Element element, String packageName, List addedClasses) { + private List addEntityListenerClasses(JaxbEntityListeners listeners, String packageName, List addedClasses) { List localAddedClasses = new ArrayList<>(); - Element listeners = element.element( "entity-listeners" ); if ( listeners != null ) { - @SuppressWarnings( "unchecked" ) - List elements = listeners.elements( "entity-listener" ); - for (Element listener : elements) { - String listenerClassName = buildSafeClassName( listener.attributeValue( "class" ), packageName ); - if ( classOverriding.containsKey( listenerClassName ) ) { - //maybe switch it to warn? - if ( "entity-listener".equals( classOverriding.get( listenerClassName ).getName() ) ) { - LOG.duplicateListener( listenerClassName ); - continue; - } - throw new IllegalStateException("Duplicate XML entry for " + listenerClassName); + List elements = listeners.getEntityListener(); + for (JaxbEntityListener listener : elements) { + String listenerClassName = buildSafeClassName( listener.getClazz(), packageName ); + if ( entityListenerOverride.containsKey( listenerClassName ) ) { + LOG.duplicateListener( listenerClassName ); + continue; } localAddedClasses.add( listenerClassName ); - classOverriding.put( listenerClassName, listener ); + entityListenerOverride.put( listenerClassName, listener ); } } LOG.debugf( "Adding XML overriding information for listeners: %s", localAddedClasses ); @@ -202,11 +163,10 @@ private List addEntityListenerClasses(Element element, String packageNam } @SuppressWarnings("unchecked") - private void setLocalAttributeConverterDefinitions(List converterElements) { - for ( Element converterElement : converterElements ) { - final String className = converterElement.attributeValue( "class" ); - final String autoApplyAttribute = converterElement.attributeValue( "auto-apply" ); - final boolean autoApply = autoApplyAttribute != null && Boolean.parseBoolean( autoApplyAttribute ); + private void setLocalAttributeConverterDefinitions(List converterElements) { + for ( JaxbConverter converterElement : converterElements ) { + final String className = converterElement.getClazz(); + final boolean autoApply = Boolean.TRUE.equals( converterElement.isAutoApply() ); try { final Class attributeConverterClass = classLoaderAccess.classForName( @@ -232,7 +192,7 @@ public static String buildSafeClassName(String className, String defaultPackageN return className; } - public static String buildSafeClassName(String className, XMLContext.Default defaults) { + public static String buildSafeClassName(String className, Default defaults) { return buildSafeClassName( className, defaults.getPackageName() ); } @@ -240,17 +200,21 @@ public Default getDefault(String className) { Default xmlDefault = new Default(); xmlDefault.override( globalDefaults ); if ( className != null ) { - Default entityMappingOverriding = defaultsOverriding.get( className ); + Default entityMappingOverriding = defaultsOverride.get( className ); xmlDefault.override( entityMappingOverriding ); } return xmlDefault; } - public Element getXMLTree(String className ) { - return classOverriding.get( className ); + public ManagedType getManagedTypeOverride(String className) { + return managedTypeOverride.get( className ); + } + + public JaxbEntityListener getEntityListenerOverride(String className) { + return entityListenerOverride.get( className ); } - public List getAllDocuments() { + public List getAllDocuments() { return defaultElements; } diff --git a/hibernate-core/src/main/xjb/mapping-bindings.xjb b/hibernate-core/src/main/xjb/mapping-bindings.xjb index 1c611dcf0165..3ca2d1a54cf9 100644 --- a/hibernate-core/src/main/xjb/mapping-bindings.xjb +++ b/hibernate-core/src/main/xjb/mapping-bindings.xjb @@ -72,9 +72,9 @@ - + diff --git a/hibernate-core/src/test/java/org/hibernate/internal/util/xml/XMLMappingHelper.java b/hibernate-core/src/test/java/org/hibernate/internal/util/xml/XMLMappingHelper.java new file mode 100644 index 000000000000..11d3628fe415 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/internal/util/xml/XMLMappingHelper.java @@ -0,0 +1,51 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.internal.util.xml; + +import java.io.IOException; +import java.io.InputStream; + +import org.hibernate.boot.jaxb.Origin; +import org.hibernate.boot.jaxb.SourceType; +import org.hibernate.boot.jaxb.internal.MappingBinder; +import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappings; +import org.hibernate.boot.jaxb.spi.Binding; +import org.hibernate.boot.jaxb.spi.XmlMappingOptions; +import org.hibernate.boot.registry.BootstrapServiceRegistry; +import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder; +import org.hibernate.service.spi.ServiceRegistryImplementor; + +import org.hibernate.testing.boot.ClassLoaderServiceTestingImpl; +import org.junit.Assert; + +/** + * A small helper class for parsing XML mappings, to be used in unit tests. + */ +public final class XMLMappingHelper { + private final MappingBinder binder; + + public XMLMappingHelper(XmlMappingOptions xmlMappingOptions) { + binder = new MappingBinder( ClassLoaderServiceTestingImpl.INSTANCE, true, xmlMappingOptions ); + } + + public JaxbEntityMappings readOrmXmlMappings(String name) throws IOException { + try (InputStream is = ClassLoaderServiceTestingImpl.INSTANCE.locateResourceStream( name )) { + return readOrmXmlMappings( is, name ); + } + } + + public JaxbEntityMappings readOrmXmlMappings(InputStream is, String name) { + try { + Assert.assertNotNull( "Resource not found: " + name, is ); + Binding binding = binder.bind( is, new Origin( SourceType.JAR, name ) ); + return (JaxbEntityMappings) binding.getRoot(); + } + catch (RuntimeException e) { + throw new IllegalStateException( "Could not parse orm.xml mapping '" + name + "': " + e.getMessage(), e ); + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/JPAXMLOverriddenAnnotationReaderTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/JPAXMLOverriddenAnnotationReaderTest.java index 7024aad12492..1704cce53e96 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/JPAXMLOverriddenAnnotationReaderTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/JPAXMLOverriddenAnnotationReaderTest.java @@ -9,12 +9,15 @@ import org.dom4j.DocumentException; import org.dom4j.io.SAXReader; import org.hibernate.annotations.Columns; +import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappings; +import org.hibernate.boot.jaxb.spi.XmlMappingOptions; import org.hibernate.cfg.EJB3DTDEntityResolver; import org.hibernate.cfg.annotations.reflection.JPAOverriddenAnnotationReader; import org.hibernate.cfg.annotations.reflection.internal.JPAXMLOverriddenAnnotationReader; import org.hibernate.cfg.annotations.reflection.internal.XMLContext; import org.hibernate.internal.util.xml.ErrorLogger; import org.hibernate.internal.util.xml.XMLHelper; +import org.hibernate.internal.util.xml.XMLMappingHelper; import org.hibernate.testing.boot.BootstrapContextImpl; import org.hibernate.testing.junit4.BaseUnitTestCase; @@ -401,32 +404,16 @@ public void testEntityListeners() throws Exception { assertEquals( OtherLogListener.class.getName(), context.getDefaultEntityListeners().get( 0 ) ); } - private XMLContext buildContext(String ormfile) throws SAXException, DocumentException, IOException { - XMLHelper xmlHelper = new XMLHelper(); - InputStream is = ClassLoaderServiceTestingImpl.INSTANCE.locateResourceStream( ormfile ); - assertNotNull( "ORM.xml not found: " + ormfile, is ); + private XMLContext buildContext(String ormfile) throws IOException { + XMLMappingHelper xmlHelper = new XMLMappingHelper( new XmlMappingOptions() { + @Override + public boolean isPreferJaxb() { + return true; + } + } ); + JaxbEntityMappings mappings = xmlHelper.readOrmXmlMappings( ormfile ); XMLContext context = new XMLContext( BootstrapContextImpl.INSTANCE ); - ErrorLogger errorLogger = new ErrorLogger(); - SAXReader saxReader = xmlHelper.createSAXReader( errorLogger, EJB3DTDEntityResolver.INSTANCE ); - //saxReader.setValidation( false ); - try { - saxReader.setFeature( "http://apache.org/xml/features/validation/schema", true ); - } - catch ( SAXNotSupportedException e ) { - saxReader.setValidation( false ); - } - org.dom4j.Document doc; - try { - doc = saxReader.read( new InputSource( new BufferedInputStream( is ) ) ); - } - finally { - is.close(); - } - if ( errorLogger.hasErrors() ) { - System.out.println( errorLogger.getErrors().get( 0 ) ); - } - assertFalse( errorLogger.hasErrors() ); - context.addDocument( doc ); + context.addDocument( mappings ); return context; } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/XMLContextTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/XMLContextTest.java index fb68e62a4604..39ed92d42f96 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/XMLContextTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/XMLContextTest.java @@ -6,24 +6,14 @@ */ package org.hibernate.test.annotations.reflection; -import java.io.BufferedInputStream; -import java.io.IOException; -import java.io.InputStream; - -import org.dom4j.io.SAXReader; -import org.junit.Assert; -import org.junit.Test; -import org.xml.sax.InputSource; -import org.xml.sax.SAXNotSupportedException; - -import org.hibernate.cfg.EJB3DTDEntityResolver; +import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappings; +import org.hibernate.boot.jaxb.spi.XmlMappingOptions; import org.hibernate.cfg.annotations.reflection.internal.XMLContext; -import org.hibernate.internal.util.xml.ErrorLogger; -import org.hibernate.internal.util.xml.XMLHelper; +import org.hibernate.internal.util.xml.XMLMappingHelper; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.boot.BootstrapContextImpl; -import org.hibernate.testing.boot.ClassLoaderServiceTestingImpl; +import org.junit.Test; /** * Tests the new {@link XMLContext}, @@ -38,36 +28,15 @@ public class XMLContextTest { @Test public void testAll() throws Exception { - final XMLHelper xmlHelper = new XMLHelper(); + XMLMappingHelper xmlHelper = new XMLMappingHelper( new XmlMappingOptions() { + @Override + public boolean isPreferJaxb() { + return true; + } + } ); final XMLContext context = new XMLContext( BootstrapContextImpl.INSTANCE ); - InputStream is = ClassLoaderServiceTestingImpl.INSTANCE.locateResourceStream( - "org/hibernate/test/annotations/reflection/orm.xml" - ); - Assert.assertNotNull( "ORM.xml not found", is ); - - final ErrorLogger errorLogger = new ErrorLogger(); - final SAXReader saxReader = xmlHelper.createSAXReader( errorLogger, EJB3DTDEntityResolver.INSTANCE ); - - try { - saxReader.setFeature( "http://apache.org/xml/features/validation/schema", true ); - } - catch ( SAXNotSupportedException e ) { - saxReader.setValidation( false ); - } - org.dom4j.Document doc; - try { - doc = saxReader.read( new InputSource( new BufferedInputStream( is ) ) ); - } - finally { - try { - is.close(); - } - catch ( IOException ioe ) { - //log.warn( "Could not close input stream", ioe ); - } - } - Assert.assertFalse( errorLogger.hasErrors() ); - context.addDocument( doc ); + JaxbEntityMappings mappings = xmlHelper.readOrmXmlMappings( "org/hibernate/test/annotations/reflection/orm.xml" ); + context.addDocument( mappings ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlTestCase.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlTestCase.java index c4ebbed1d651..ea1d1fee35e0 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlTestCase.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlTestCase.java @@ -10,11 +10,11 @@ import java.lang.annotation.Annotation; import java.lang.reflect.AnnotatedElement; -import org.dom4j.Document; -import org.dom4j.io.SAXReader; - +import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappings; +import org.hibernate.boot.jaxb.spi.XmlMappingOptions; import org.hibernate.cfg.annotations.reflection.internal.JPAXMLOverriddenAnnotationReader; import org.hibernate.cfg.annotations.reflection.internal.XMLContext; +import org.hibernate.internal.util.xml.XMLMappingHelper; import org.hibernate.testing.boot.BootstrapContextImpl; import org.hibernate.testing.junit4.BaseUnitTestCase; @@ -29,8 +29,12 @@ * database is used. Thus, no schema generation or cleanup will be performed. */ public abstract class Ejb3XmlTestCase extends BaseUnitTestCase { + protected JPAXMLOverriddenAnnotationReader reader; + protected Ejb3XmlTestCase() { + } + protected void assertAnnotationPresent(Class annotationType) { assertTrue( "Expected annotation " + annotationType.getSimpleName() + " was not present", @@ -59,17 +63,19 @@ protected AnnotatedElement getAnnotatedElement(Class entityClass, String fiel protected XMLContext getContext(String resourceName) throws Exception { InputStream is = getClass().getResourceAsStream( resourceName ); assertNotNull( "Could not load resource " + resourceName, is ); - return getContext( is ); + return getContext( is, resourceName ); } - protected XMLContext getContext(InputStream is) throws Exception { - XMLContext xmlContext = new XMLContext( BootstrapContextImpl.INSTANCE ); - SAXReader reader = new SAXReader(); - reader.setFeature( "http://apache.org/xml/features/nonvalidating/load-external-dtd", false ); - reader.setFeature( "http://xml.org/sax/features/external-general-entities", false ); - reader.setFeature( "http://xml.org/sax/features/external-parameter-entities", false ); - Document doc = reader.read( is ); - xmlContext.addDocument( doc ); - return xmlContext; + protected XMLContext getContext(InputStream is, String resourceName) throws Exception { + XMLMappingHelper xmlHelper = new XMLMappingHelper( new XmlMappingOptions() { + @Override + public boolean isPreferJaxb() { + return true; + } + } ); + JaxbEntityMappings mappings = xmlHelper.readOrmXmlMappings( is, resourceName ); + XMLContext context = new XMLContext( BootstrapContextImpl.INSTANCE ); + context.addDocument( mappings ); + return context; } } From 2aa2bee255f443ea05508968d58e9acf19d51c8b Mon Sep 17 00:00:00 2001 From: Karel Maesen Date: Thu, 15 Apr 2021 20:02:48 +0200 Subject: [PATCH 104/644] HHH-11490 Fix for UUID mapping conflict * HHH-11490 Fix for UUID mapping conflict * HHH-11490 Custom ValueBinder implementation --- .../postgis/PGGeometryTypeDescriptor.java | 36 ++++++++++++++----- 1 file changed, 28 insertions(+), 8 deletions(-) diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PGGeometryTypeDescriptor.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PGGeometryTypeDescriptor.java index af4ebc86b3c2..d4a589789688 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PGGeometryTypeDescriptor.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PGGeometryTypeDescriptor.java @@ -17,7 +17,6 @@ import org.hibernate.type.descriptor.ValueExtractor; import org.hibernate.type.descriptor.WrapperOptions; import org.hibernate.type.descriptor.java.JavaTypeDescriptor; -import org.hibernate.type.descriptor.sql.BasicBinder; import org.hibernate.type.descriptor.sql.BasicExtractor; import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; @@ -39,12 +38,12 @@ public class PGGeometryTypeDescriptor implements SqlTypeDescriptor { - final private Wkb.Dialect wkbDialect; + private final Wkb.Dialect wkbDialect; // Type descriptor instance using EWKB v1 (postgis versions < 2.2.2) - public static final PGGeometryTypeDescriptor INSTANCE_WKB_1 = new PGGeometryTypeDescriptor( Wkb.Dialect.POSTGIS_EWKB_1); + public static final PGGeometryTypeDescriptor INSTANCE_WKB_1 = new PGGeometryTypeDescriptor( Wkb.Dialect.POSTGIS_EWKB_1 ); // Type descriptor instance using EWKB v2 (postgis versions >= 2.2.2, see: https://trac.osgeo.org/postgis/ticket/3181) - public static final PGGeometryTypeDescriptor INSTANCE_WKB_2 = new PGGeometryTypeDescriptor(Wkb.Dialect.POSTGIS_EWKB_2); + public static final PGGeometryTypeDescriptor INSTANCE_WKB_2 = new PGGeometryTypeDescriptor( Wkb.Dialect.POSTGIS_EWKB_2 ); private PGGeometryTypeDescriptor(Wkb.Dialect dialect) { wkbDialect = dialect; @@ -79,7 +78,7 @@ private static Geometry parseWkt(String pgValue) { @Override public int getSqlType() { - return Types.OTHER; + return 5432; } @Override @@ -89,15 +88,36 @@ public boolean canBeRemapped() { @Override public ValueBinder getBinder(final JavaTypeDescriptor javaTypeDescriptor) { - return new BasicBinder( javaTypeDescriptor, this ) { + return new ValueBinder() { + + @Override + public final void bind(PreparedStatement st, X value, int index, WrapperOptions options) + throws SQLException { + if ( value == null ) { + st.setNull( index, Types.OTHER ); + } + else { + doBind( st, value, index, options ); + } + } + @Override + public final void bind(CallableStatement st, X value, String name, WrapperOptions options) + throws SQLException { + if ( value == null ) { + st.setNull( name, Types.OTHER ); + } + else { + doBind( st, value, name, options ); + } + } + protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) throws SQLException { final PGobject obj = toPGobject( value, options ); st.setObject( index, obj ); } - @Override protected void doBind(CallableStatement st, X value, String name, WrapperOptions options) throws SQLException { final PGobject obj = toPGobject( value, options ); @@ -106,7 +126,7 @@ protected void doBind(CallableStatement st, X value, String name, WrapperOptions private PGobject toPGobject(X value, WrapperOptions options) throws SQLException { final WkbEncoder encoder = Wkb.newEncoder( Wkb.Dialect.POSTGIS_EWKB_1 ); - final Geometry geometry = getJavaDescriptor().unwrap( value, Geometry.class, options ); + final Geometry geometry = javaTypeDescriptor.unwrap( value, Geometry.class, options ); final String hexString = encoder.encode( geometry, ByteOrder.NDR ).toString(); final PGobject obj = new PGobject(); obj.setType( "geometry" ); From 7620e0e3959714dad4e9534051a2db0cdd3b4085 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Mon, 12 Apr 2021 17:14:57 +0200 Subject: [PATCH 105/644] HHH-14549 Add test for issue --- .../LoadUninitializedCollectionTest.java | 232 ++++++++++++++++++ ...QueryExecutionWithFlushModeAlwaysTest.java | 188 ++++++++++++++ 2 files changed, 420 insertions(+) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/LoadUninitializedCollectionTest.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/LoadingLazyCollectionAfterQueryExecutionWithFlushModeAlwaysTest.java diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/LoadUninitializedCollectionTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/LoadUninitializedCollectionTest.java new file mode 100644 index 000000000000..86f0ee7727fd --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/LoadUninitializedCollectionTest.java @@ -0,0 +1,232 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.bytecode.enhancement.lazy.proxy.inlinedirtychecking; + + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import javax.persistence.Query; +import javax.persistence.Table; + +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.cfg.Environment; +import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; +import org.hibernate.testing.bytecode.enhancement.CustomEnhancementContext; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; +import static org.junit.Assert.assertEquals; + +@TestForIssue(jiraKey = "HHH-14549") +@RunWith(BytecodeEnhancerRunner.class) +@CustomEnhancementContext({ DirtyCheckEnhancementContext.class, NoDirtyCheckEnhancementContext.class }) +public class LoadUninitializedCollectionTest extends BaseEntityManagerFunctionalTestCase { + + boolean skipTest; + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + Bank.class, + BankAccount.class, + BankDepartment.class + }; + } + + @Override + protected void addMappings(Map settings) { + String byteCodeProvider = Environment.getProperties().getProperty( AvailableSettings.BYTECODE_PROVIDER ); + if ( byteCodeProvider != null && !Environment.BYTECODE_PROVIDER_NAME_BYTEBUDDY.equals( byteCodeProvider ) ) { + // skip the test if the bytecode provider is Javassist + skipTest = true; + } + } + + + @Before + public void setUp() { + if ( skipTest ) { + return; + } + doInJPA( + this::entityManagerFactory, entityManager -> { + Bank bank = new Bank( 1L, "International" ); + BankAccount bankAccount = new BankAccount( 1L, bank, "1234567890" ); + BankDepartment bankDepartmentA = new BankDepartment( 1L, "A" ); + BankDepartment bankDepartmentB = new BankDepartment( 2L, "B" ); + BankDepartment bankDepartmentC = new BankDepartment( 3L, "C" ); + + bank.addDepartment( bankDepartmentA ); + bank.addDepartment( bankDepartmentB ); + bank.addDepartment( bankDepartmentC ); + + entityManager.persist( bank ); + entityManager.persist( bankAccount ); + entityManager.persist( bankDepartmentA ); + entityManager.persist( bankDepartmentB ); + entityManager.persist( bankDepartmentC ); + } + ); + } + + @Test + public void testLoadAfterNativeQueryExecution() { + if ( skipTest ) { + return; + } + doInJPA( this::entityManagerFactory, entityManager -> { + BankAccount account = entityManager.find( BankAccount.class, 1L ); + + Query nativeQuery = entityManager.createNativeQuery( "SELECT ID FROM BANK" ); + nativeQuery.getResultList(); + + Bank bank = account.getBank(); + List deps = bank.getDepartments(); + + assertEquals( deps.size(), 3 ); + } + ); + } + + @Test + public void testLoadAfterFlush() { + if ( skipTest ) { + return; + } + doInJPA( this::entityManagerFactory, entityManager -> { + BankAccount account = entityManager.find( BankAccount.class, 1L ); + + entityManager.flush(); + + Bank bank = account.getBank(); + List deps = bank.getDepartments(); + + assertEquals( deps.size(), 3 ); + } + ); + } + + @After + public void tearDown() { + if ( skipTest ) { + return; + } + doInJPA( this::entityManagerFactory, entityManager -> { + Bank bank = entityManager.find( Bank.class, 1L ); + bank.getDepartments().forEach( + department -> entityManager.remove( department ) + ); + List accounts = entityManager.createQuery( "from BankAccount" ).getResultList(); + + accounts.forEach( + account -> entityManager.remove( account ) + ); + + entityManager.remove( bank ); + } + ); + } + + + @Entity(name = "Bank") + @Table(name = "BANK") + public static class Bank { + + @Id + @Column(name = "ID") + private Long id; + + private String name; + + public Bank() { + } + + public Bank(Long id, String name) { + this.id = id; + this.name = name; + } + + @OneToMany + private List departments = new ArrayList<>(); + + public List getDepartments() { + return departments; + } + + public void addDepartment(BankDepartment department) { + this.departments.add( department ); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } + + @Entity(name = "BankAccount") + public static class BankAccount { + + @Id + private Long id; + + @ManyToOne(fetch = FetchType.LAZY) + private Bank bank; + + private String serialNumber; + + public BankAccount() { + } + + public BankAccount(Long id, Bank bank, String serialNumber) { + this.id = id; + this.bank = bank; + this.serialNumber = serialNumber; + } + + public Bank getBank() { + return bank; + } + + public String getSerialNumber() { + return serialNumber; + } + } + + @Entity(name = "BankDepartment") + public static class BankDepartment { + + @Id + private Long id; + + private String name; + + public BankDepartment() { + } + + public BankDepartment(Long id, String name) { + this.id = id; + } + } + + +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/LoadingLazyCollectionAfterQueryExecutionWithFlushModeAlwaysTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/LoadingLazyCollectionAfterQueryExecutionWithFlushModeAlwaysTest.java new file mode 100644 index 000000000000..123f672a3109 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/LoadingLazyCollectionAfterQueryExecutionWithFlushModeAlwaysTest.java @@ -0,0 +1,188 @@ +package org.hibernate.test.bytecode.enhancement.lazy.proxy.inlinedirtychecking; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.MappedSuperclass; +import javax.persistence.OneToMany; +import javax.persistence.OneToOne; + +import org.hibernate.FlushMode; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.cfg.Environment; +import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; +import org.hibernate.testing.bytecode.enhancement.CustomEnhancementContext; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +@TestForIssue( jiraKey = "HHH-14549") +@RunWith(BytecodeEnhancerRunner.class) +@CustomEnhancementContext({ DirtyCheckEnhancementContext.class, NoDirtyCheckEnhancementContext.class }) +public class LoadingLazyCollectionAfterQueryExecutionWithFlushModeAlwaysTest + extends BaseEntityManagerFunctionalTestCase { + + boolean skipTest; + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + Customer.class, + ProductOrder.class, + Product.class, + City.class + }; + } + + @Override + protected void addMappings(Map settings) { + String byteCodeProvider = Environment.getProperties().getProperty( AvailableSettings.BYTECODE_PROVIDER ); + settings.put( AvailableSettings.FLUSH_MODE, FlushMode.ALWAYS ); + if ( byteCodeProvider != null && !Environment.BYTECODE_PROVIDER_NAME_BYTEBUDDY.equals( byteCodeProvider ) ) { + // skip the test if the bytecode provider is Javassist + skipTest = true; + } + } + + @Before + public void setUp() { + if ( skipTest ) { + return; + } + doInJPA( + this::entityManagerFactory, entityManager -> { + ProductOrder order = new ProductOrder(); + order.setOrderNumber( "12345" ); + + Customer customer = new Customer(); + customer.setProductOrder( order ); + customer.setName( "Fab" ); + + Product product = new Product(); + product.setName( "gloves" ); + + order.addProduct( product ); + + entityManager.persist( order ); + entityManager.persist( product ); + entityManager.persist( customer ); + } + ); + } + + @Test + public void reproducer_Case1() { + if ( skipTest ) { + return; + } + doInJPA( + this::entityManagerFactory, entityManager -> { + List customers = entityManager.createQuery( "select c from Customer c" ).getResultList(); + assertEquals( 1, customers.size() ); + + Customer customer = customers.get( 0 ); + ProductOrder order = customer.getProductOrder(); + assertNotNull( order ); + + entityManager.createQuery( "select c from City c" ).getResultList(); + + assertEquals( 1, order.getProducts().size() ); + } ); + } + + @MappedSuperclass + public static abstract class Base { + @Id + @GeneratedValue + public Long id; + + public Long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + } + + @Entity(name = "Customer") + public static class Customer extends Base { + + private String name; + + @OneToOne(fetch = FetchType.LAZY) + ProductOrder order; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public ProductOrder getProductOrder() { + return order; + } + + public void setProductOrder(ProductOrder order) { + this.order = order; + } + } + + @Entity(name = "ProductOrder") + public static class ProductOrder extends Base { + + private String orderNumber; + + @OneToMany + private List products = new ArrayList<>(); + + public String getOrderNumber() { + return orderNumber; + } + + public void setOrderNumber(String orderNumber) { + this.orderNumber = orderNumber; + } + + public List getProducts() { + return products; + } + + public void addProduct(Product product) { + products.add( product ); + } + + } + + @Entity(name = "Product") + public static class Product extends Base { + + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } + + @Entity(name = "City") + public static class City extends Base { + private String name; + } +} From 6f75d96a99f2c17edbace5eaedbd95340099dac6 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Mon, 12 Apr 2021 18:03:35 +0200 Subject: [PATCH 106/644] HHH-14549 Collection with default field initializer will always be empty --- .../DefaultFlushEntityEventListener.java | 9 ++++---- .../event/internal/FlushVisitor.java | 5 ++++- .../hibernate/event/internal/WrapVisitor.java | 21 +++++++++++++------ 3 files changed, 24 insertions(+), 11 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultFlushEntityEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultFlushEntityEventListener.java index 21c97adf8109..23e4955d5f5c 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultFlushEntityEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultFlushEntityEventListener.java @@ -22,7 +22,6 @@ import org.hibernate.engine.internal.Versioning; import org.hibernate.engine.spi.EntityEntry; import org.hibernate.engine.spi.EntityKey; -import org.hibernate.engine.spi.ManagedEntity; import org.hibernate.engine.spi.PersistenceContext; import org.hibernate.engine.spi.PersistentAttributeInterceptable; import org.hibernate.engine.spi.PersistentAttributeInterceptor; @@ -40,7 +39,6 @@ import org.hibernate.metadata.ClassMetadata; import org.hibernate.persister.entity.EntityPersister; import org.hibernate.pretty.MessageHelper; -import org.hibernate.proxy.HibernateProxy; import org.hibernate.stat.spi.StatisticsImplementor; import org.hibernate.type.Type; @@ -166,7 +164,8 @@ public void onFlushEntity(FlushEntityEvent event) throws HibernateException { event.setPropertyValues( values ); //TODO: avoid this for non-new instances where mightBeDirty==false - boolean substitute = wrapCollections( session, persister, types, values ); + + boolean substitute = wrapCollections( session, persister, entity, entry.getId(), types, values ); if ( isUpdateNecessary( event, mightBeDirty ) ) { substitute = scheduleUpdate( event ) || substitute; @@ -214,6 +213,8 @@ else if ( !mightBeDirty && loadedState != null ) { private boolean wrapCollections( EventSource session, EntityPersister persister, + Object entity, + Serializable id, Type[] types, Object[] values ) { @@ -227,7 +228,7 @@ private boolean wrapCollections( // don't dirty the container. Also, for versioned data, we // need to wrap before calling searchForDirtyCollections - WrapVisitor visitor = new WrapVisitor( session ); + WrapVisitor visitor = new WrapVisitor( entity, id ,session ); // substitutes into values by side-effect visitor.processEntityPropertyValues( values, types ); return visitor.isSubstitutionRequired(); diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/FlushVisitor.java b/hibernate-core/src/main/java/org/hibernate/event/internal/FlushVisitor.java index 947d3de574f4..85d6bdf22280 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/FlushVisitor.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/FlushVisitor.java @@ -43,9 +43,12 @@ Object processCollection(Object collection, CollectionType type) throws Hibernat else if ( collection == LazyPropertyInitializer.UNFETCHED_PROPERTY ) { coll = (PersistentCollection) type.resolve( collection, session, owner ); } - else { + else if ( collection instanceof PersistentCollection ) { coll = (PersistentCollection) collection; } + else { + return null; + } Collections.processReachableCollection( coll, type, owner, session); } diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/WrapVisitor.java b/hibernate-core/src/main/java/org/hibernate/event/internal/WrapVisitor.java index 49d7b1748fc9..a7e038995699 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/WrapVisitor.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/WrapVisitor.java @@ -11,8 +11,11 @@ import org.hibernate.EntityMode; import org.hibernate.HibernateException; import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer; +import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor; import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.engine.spi.PersistenceContext; +import org.hibernate.engine.spi.PersistentAttributeInterceptable; +import org.hibernate.engine.spi.PersistentAttributeInterceptor; import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.event.spi.EventSource; import org.hibernate.internal.CoreLogging; @@ -31,8 +34,8 @@ @SuppressWarnings("WeakerAccess") public class WrapVisitor extends ProxyVisitor { private static final CoreMessageLogger LOG = CoreLogging.messageLogger( WrapVisitor.class ); - private Object entity; - private Serializable id; + protected Object entity; + protected Serializable id; private boolean substitute; @@ -105,8 +108,17 @@ final Object processArrayOrNewCollection(Object collection, CollectionType colle return null; } else { + if ( entity instanceof PersistentAttributeInterceptable ) { + final PersistentAttributeInterceptor interceptor = ( (PersistentAttributeInterceptable) entity ).$$_hibernate_getInterceptor(); + if ( interceptor instanceof EnhancementAsProxyLazinessInterceptor ) { + if ( !( (EnhancementAsProxyLazinessInterceptor) interceptor ).isInitialized() ) { + return null; + } + } + } + + final PersistentCollection persistentCollection = collectionType.wrap( session, collection ); - PersistentCollection persistentCollection = collectionType.wrap( session, collection ); persistenceContext.addNewCollection( persister, persistentCollection ); if ( LOG.isTraceEnabled() ) { @@ -114,11 +126,8 @@ final Object processArrayOrNewCollection(Object collection, CollectionType colle } return persistentCollection; //Force a substitution! - } - } - } @Override From 6723ed4626db0fa1b04aac66abd4894e018d11e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Mon, 19 Apr 2021 09:47:00 +0200 Subject: [PATCH 107/644] HHH-14529 Fix incorrect attribute name for @NamedEntityGraph in JPAXMLOverriddenAnnotationReader --- .../reflection/internal/JPAXMLOverriddenAnnotationReader.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenAnnotationReader.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenAnnotationReader.java index c91855d43efa..ae848b91305b 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenAnnotationReader.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenAnnotationReader.java @@ -2063,7 +2063,7 @@ public static List buildNamedEntityGraph( bindNamedAttributeNodes( element.getNamedAttributeNode(), ann ); bindNamedSubgraph( defaults, ann, "subgraphs", element.getSubgraph(), classLoaderAccess ); - bindNamedSubgraph( defaults, ann, "subclass-subgraph", element.getSubclassSubgraph(), classLoaderAccess ); + bindNamedSubgraph( defaults, ann, "subclassSubgraphs", element.getSubclassSubgraph(), classLoaderAccess ); namedEntityGraphList.add( AnnotationFactory.create( ann ) ); } //TODO From 5b830f3f5edbb9295fcec4dc8c5a51232f3feb2b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Mon, 19 Apr 2021 09:49:12 +0200 Subject: [PATCH 108/644] HHH-14529 Fix invalid order of elements in orm.xml files used for tests Surprisingly, the XSD does mandate a specific order for some elements, including "entity", "embeddable" and the children of "attributes". It turns out we were allowing a wrong order with the dom4j implementation, but we no longer do with the jaxb implementation. --- .../jpa/test/graphs/named/subgraph/orm.xml | 6 +++--- .../annotations/embeddables/collection/orm.xml | 18 +++++++++--------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/hibernate-core/src/test/resources/org/hibernate/jpa/test/graphs/named/subgraph/orm.xml b/hibernate-core/src/test/resources/org/hibernate/jpa/test/graphs/named/subgraph/orm.xml index c94b207b1aed..507a3e4991ea 100644 --- a/hibernate-core/src/test/resources/org/hibernate/jpa/test/graphs/named/subgraph/orm.xml +++ b/hibernate-core/src/test/resources/org/hibernate/jpa/test/graphs/named/subgraph/orm.xml @@ -35,12 +35,12 @@ - - - + + + diff --git a/hibernate-core/src/test/resources/org/hibernate/test/annotations/embeddables/collection/orm.xml b/hibernate-core/src/test/resources/org/hibernate/test/annotations/embeddables/collection/orm.xml index 36e3e680514f..0c115235b6a9 100644 --- a/hibernate-core/src/test/resources/org/hibernate/test/annotations/embeddables/collection/orm.xml +++ b/hibernate-core/src/test/resources/org/hibernate/test/annotations/embeddables/collection/orm.xml @@ -23,6 +23,15 @@ + + + + + + + + + @@ -34,13 +43,4 @@ - - - - - - - - - \ No newline at end of file From 4f7bb75ec7c7006836ce95c99e195b44c6ef0e62 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Mon, 19 Apr 2021 10:06:29 +0200 Subject: [PATCH 109/644] HHH-14529 Fix access type being ignored when defined at the entity level in orm.xml That's a bug I introduced when I migrated code from dom4j to jaxb. --- .../reflection/internal/XMLContext.java | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/XMLContext.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/XMLContext.java index f009b708c4cb..0192e4dce667 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/XMLContext.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/XMLContext.java @@ -127,11 +127,16 @@ private void addClass(List managedTypes, String packageNa } addedClasses.add( className ); managedTypeOverride.put( className, element ); - Default localDefault = new Default(); - localDefault.override( defaults ); - localDefault.setMetadataComplete( element.isMetadataComplete() ); - localDefault.setAccess( element.getAccess() ); - defaultsOverride.put( className, localDefault ); + Default mergedDefaults = new Default(); + // Apply entity mapping defaults + mergedDefaults.override( defaults ); + // ... then apply entity settings + Default fileDefaults = new Default(); + fileDefaults.setMetadataComplete( element.isMetadataComplete() ); + fileDefaults.setAccess( element.getAccess() ); + mergedDefaults.override( fileDefaults ); + // ... and we get the merged defaults for that entity + defaultsOverride.put( className, mergedDefaults ); LOG.debugf( "Adding XML overriding information for %s", className ); if ( element instanceof JaxbEntity ) { From 194e53a0fb2b90a14e34e8e3a825f671218a55cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Fri, 16 Apr 2021 13:44:46 +0200 Subject: [PATCH 110/644] HHH-14563 Remove legacy tests for DOM4J-based XML mapping --- .../internal/util/xml/XMLHelper.java | 78 -- .../LegacyElementCollectionConverterTest.java | 71 -- ...gacyJPAOverriddenAnnotationReaderTest.java | 485 ------------ .../reflection/LegacyXMLContextTest.java | 73 -- .../LegacyEjb3XmlElementCollectionTest.java | 716 ------------------ .../xml/ejb3/LegacyEjb3XmlManyToManyTest.java | 508 ------------- .../xml/ejb3/LegacyEjb3XmlManyToOneTest.java | 245 ------ .../xml/ejb3/LegacyEjb3XmlOneToManyTest.java | 561 -------------- .../xml/ejb3/LegacyEjb3XmlOneToOneTest.java | 309 -------- .../xml/ejb3/LegacyEjb3XmlTest.java | 148 ---- .../xml/ejb3/LegacyEjb3XmlTestCase.java | 82 -- .../ejb3/LegacyNonExistentOrmVersionTest.java | 42 - .../ejb3/LegacyOrmVersion1SupportedTest.java | 68 -- .../xml/ejb3/LegacyPreParsedOrmXmlTest.java | 58 -- 14 files changed, 3444 deletions(-) delete mode 100644 hibernate-core/src/test/java/org/hibernate/internal/util/xml/XMLHelper.java delete mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/LegacyElementCollectionConverterTest.java delete mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/LegacyJPAOverriddenAnnotationReaderTest.java delete mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/LegacyXMLContextTest.java delete mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlElementCollectionTest.java delete mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlManyToManyTest.java delete mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlManyToOneTest.java delete mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlOneToManyTest.java delete mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlOneToOneTest.java delete mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlTest.java delete mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlTestCase.java delete mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyNonExistentOrmVersionTest.java delete mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyOrmVersion1SupportedTest.java delete mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyPreParsedOrmXmlTest.java diff --git a/hibernate-core/src/test/java/org/hibernate/internal/util/xml/XMLHelper.java b/hibernate-core/src/test/java/org/hibernate/internal/util/xml/XMLHelper.java deleted file mode 100644 index e68f9e567453..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/internal/util/xml/XMLHelper.java +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.internal.util.xml; - -import java.security.AccessController; -import java.security.PrivilegedAction; - -import org.dom4j.DocumentFactory; -import org.dom4j.io.SAXReader; -import org.xml.sax.EntityResolver; - -/** - * Small helper class that lazily loads DOM and SAX reader and keep them for fast use afterwards. - * - * This was part of Hibernate ORM core, but moved into the testsuite helpers to not expose - * access to the dom4j types. It's also used by Hibernate Envers, so we will need two copies - * until Envers is able to remove its reliance on dom4j. - * The rest of Hibernate uses StAX now for XML processing. See {@link org.hibernate.boot.jaxb.internal.stax} - */ -public final class XMLHelper { - private final DocumentFactory documentFactory; - - public XMLHelper() { - PrivilegedAction action = new PrivilegedAction() { - public DocumentFactory run() { - final ClassLoader originalTccl = Thread.currentThread().getContextClassLoader(); - try { - // We need to make sure we get DocumentFactory - // loaded from the same ClassLoader that loads - // Hibernate classes, to make sure we get the - // proper version of DocumentFactory, This class - // is "internal", and should only be used for XML - // files generated by Envers. - - // Using the (Hibernate) ClassLoader that loads - // this Class will avoid collisions in the case - // that DocumentFactory can be loaded from, - // for example, the application ClassLoader. - Thread.currentThread().setContextClassLoader( this.getClass().getClassLoader() ); - return DocumentFactory.getInstance(); - } - finally { - Thread.currentThread().setContextClassLoader( originalTccl ); - } - } - }; - - this.documentFactory = System.getSecurityManager() != null - ? AccessController.doPrivileged( action ) - : action.run(); - } - - public DocumentFactory getDocumentFactory() { - return documentFactory; - } - - public SAXReader createSAXReader(ErrorLogger errorLogger, EntityResolver entityResolver) { - SAXReader saxReader = new SAXReader(); - try { - saxReader.setFeature( "http://apache.org/xml/features/nonvalidating/load-external-dtd", false ); - saxReader.setFeature( "http://xml.org/sax/features/external-general-entities", false ); - saxReader.setFeature( "http://xml.org/sax/features/external-parameter-entities", false ); - } - catch (Exception e) { - throw new RuntimeException( e ); - } - saxReader.setMergeAdjacentText( true ); - saxReader.setValidation( true ); - saxReader.setErrorHandler( errorLogger ); - saxReader.setEntityResolver( entityResolver ); - - return saxReader; - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/LegacyElementCollectionConverterTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/LegacyElementCollectionConverterTest.java deleted file mode 100644 index 70d559357b16..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/LegacyElementCollectionConverterTest.java +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.annotations.reflection; - -import org.hibernate.cfg.annotations.reflection.JPAOverriddenAnnotationReader; - -import org.hibernate.testing.TestForIssue; -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; -import org.junit.Test; - -import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; -import static org.junit.Assert.assertEquals; - -/** - * Tests the legacy {@link JPAOverriddenAnnotationReader}, - * which will be replaced with {@link org.hibernate.cfg.annotations.reflection.internal.JPAXMLOverriddenAnnotationReader}. - * {@link JPAOverriddenAnnotationReader} is still the default implementation, - * but we want to switch to {@link org.hibernate.cfg.annotations.reflection.internal.JPAXMLOverriddenAnnotationReader} - * as soon as it will be practical. - * - * @see JPAXMLOverriddenAnnotationReaderTest - * @deprecated This test will be removed in Hibernate ORM 6, along with the legacy {@link JPAOverriddenAnnotationReader}. - */ -@Deprecated -@TestForIssue( jiraKey = "HHH-11924") -public class LegacyElementCollectionConverterTest extends BaseCoreFunctionalTestCase { - - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] { - Company.class, - }; - } - - @Override - protected String[] getXmlFiles() { - return new String[] { "org/hibernate/test/annotations/reflection/element-collection-converter-orm.xml" }; - } - - - @Test - public void testConverterIsAppliedToElementCollection() { - doInHibernate( this::sessionFactory, session -> { - Company company = new Company(); - company.setId( 1L ); - - Organization org1 = new Organization(); - org1.setOrganizationId( "ACME" ); - - company.getOrganizations().add( org1 ); - - session.persist( company ); - } ); - - doInHibernate( this::sessionFactory, session -> { - String organizationId = (String) session - .createNativeQuery( "select organizations from Company_organizations" ) - .getSingleResult(); - assertEquals( "ORG-ACME", organizationId ); - - Company company = session.find( Company.class, 1L ); - - assertEquals( 1, company.getOrganizations().size() ); - assertEquals( "ACME" , company.getOrganizations().get( 0 ).getOrganizationId()); - } ); - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/LegacyJPAOverriddenAnnotationReaderTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/LegacyJPAOverriddenAnnotationReaderTest.java deleted file mode 100644 index 57561467ccea..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/LegacyJPAOverriddenAnnotationReaderTest.java +++ /dev/null @@ -1,485 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.annotations.reflection; - -import java.io.BufferedInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import javax.persistence.AssociationOverrides; -import javax.persistence.AttributeOverrides; -import javax.persistence.Basic; -import javax.persistence.Column; -import javax.persistence.Converts; -import javax.persistence.DiscriminatorColumn; -import javax.persistence.DiscriminatorValue; -import javax.persistence.ElementCollection; -import javax.persistence.Embedded; -import javax.persistence.EmbeddedId; -import javax.persistence.Entity; -import javax.persistence.EntityListeners; -import javax.persistence.EnumType; -import javax.persistence.Enumerated; -import javax.persistence.ExcludeDefaultListeners; -import javax.persistence.ExcludeSuperclassListeners; -import javax.persistence.FetchType; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.IdClass; -import javax.persistence.Inheritance; -import javax.persistence.InheritanceType; -import javax.persistence.JoinColumns; -import javax.persistence.JoinTable; -import javax.persistence.Lob; -import javax.persistence.ManyToMany; -import javax.persistence.MapKey; -import javax.persistence.MappedSuperclass; -import javax.persistence.NamedNativeQueries; -import javax.persistence.NamedQueries; -import javax.persistence.OneToMany; -import javax.persistence.OneToOne; -import javax.persistence.OrderBy; -import javax.persistence.PostLoad; -import javax.persistence.PostPersist; -import javax.persistence.PrePersist; -import javax.persistence.PrimaryKeyJoinColumn; -import javax.persistence.PrimaryKeyJoinColumns; -import javax.persistence.SecondaryTable; -import javax.persistence.SecondaryTables; -import javax.persistence.SequenceGenerator; -import javax.persistence.SqlResultSetMappings; -import javax.persistence.Table; -import javax.persistence.TableGenerator; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; -import javax.persistence.Transient; -import javax.persistence.Version; - -import org.hibernate.annotations.Columns; -import org.hibernate.cfg.EJB3DTDEntityResolver; -import org.hibernate.cfg.annotations.reflection.JPAOverriddenAnnotationReader; -import org.hibernate.cfg.annotations.reflection.XMLContext; -import org.hibernate.internal.util.xml.ErrorLogger; -import org.hibernate.internal.util.xml.XMLHelper; - -import org.hibernate.testing.TestForIssue; -import org.hibernate.testing.boot.BootstrapContextImpl; -import org.hibernate.testing.boot.ClassLoaderServiceTestingImpl; -import org.hibernate.testing.junit4.BaseUnitTestCase; -import org.junit.Test; - -import org.dom4j.DocumentException; -import org.dom4j.io.SAXReader; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; -import org.xml.sax.SAXNotSupportedException; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertNull; -import static org.junit.Assert.assertTrue; - -/** - * Tests the legacy {@link JPAOverriddenAnnotationReader}, - * which will be replaced with {@link org.hibernate.cfg.annotations.reflection.internal.JPAXMLOverriddenAnnotationReader}. - * {@link JPAOverriddenAnnotationReader} is still the default implementation, - * but we want to switch to {@link org.hibernate.cfg.annotations.reflection.internal.JPAXMLOverriddenAnnotationReader} - * as soon as it will be practical. - * - * @see JPAXMLOverriddenAnnotationReaderTest - * @author Emmanuel Bernard - * @deprecated This test will be removed in Hibernate ORM 6, along with the legacy {@link JPAOverriddenAnnotationReader}. - */ -@Deprecated -public class LegacyJPAOverriddenAnnotationReaderTest extends BaseUnitTestCase { - @Test - public void testMappedSuperclassAnnotations() throws Exception { - XMLContext context = buildContext( - "org/hibernate/test/annotations/reflection/metadata-complete.xml" - ); - JPAOverriddenAnnotationReader reader = new JPAOverriddenAnnotationReader( Organization.class, context, BootstrapContextImpl.INSTANCE ); - assertTrue( reader.isAnnotationPresent( MappedSuperclass.class ) ); - } - - @Test - public void testEntityRelatedAnnotations() throws Exception { - XMLContext context = buildContext( "org/hibernate/test/annotations/reflection/orm.xml" ); - JPAOverriddenAnnotationReader reader = new JPAOverriddenAnnotationReader( Administration.class, context, BootstrapContextImpl.INSTANCE ); - assertNotNull( reader.getAnnotation( Entity.class ) ); - assertEquals( - "Default value in xml entity should not override @Entity.name", "JavaAdministration", - reader.getAnnotation( Entity.class ).name() - ); - 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() ); - assertEquals( - "Proper @Table.uniqueConstraints", 2, - reader.getAnnotation( Table.class ).uniqueConstraints()[0].columnNames().length - ); - String columnName = reader.getAnnotation( Table.class ).uniqueConstraints()[0].columnNames()[0]; - assertTrue( - "Proper @Table.uniqueConstraints", "firstname".equals( columnName ) || "lastname".equals( columnName ) - ); - assertNull( "Both Java and XML used", reader.getAnnotation( SecondaryTable.class ) ); - assertNotNull( "XML does not work", reader.getAnnotation( SecondaryTables.class ) ); - SecondaryTable[] tables = reader.getAnnotation( SecondaryTables.class ).value(); - assertEquals( 1, tables.length ); - assertEquals( "admin2", tables[0].name() ); - assertEquals( "unique constraints ignored", 1, tables[0].uniqueConstraints().length ); - assertEquals( "pk join column ignored", 1, tables[0].pkJoinColumns().length ); - assertEquals( "pk join column ignored", "admin_id", tables[0].pkJoinColumns()[0].name() ); - assertNotNull( "Sequence Overriding not working", reader.getAnnotation( SequenceGenerator.class ) ); - assertEquals( - "wrong sequence name", "seqhilo", reader.getAnnotation( SequenceGenerator.class ).sequenceName() - ); - 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() ); - - reader = new JPAOverriddenAnnotationReader( Match.class, context, BootstrapContextImpl.INSTANCE ); - assertNotNull( reader.getAnnotation( Table.class ) ); - assertEquals( - "Java annotation not taken into account", "matchtable", reader.getAnnotation( Table.class ).name() - ); - 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() ); - assertNotNull( "SecondaryTable swallowed", reader.getAnnotation( SecondaryTables.class ) ); - assertEquals( - "Default schema not taken into account", "myschema", - reader.getAnnotation( SecondaryTables.class ).value()[0].schema() - ); - assertNotNull( reader.getAnnotation( Inheritance.class ) ); - assertEquals( - "inheritance strategy not overriden", InheritanceType.JOINED, - reader.getAnnotation( Inheritance.class ).strategy() - ); - assertNotNull( "NamedQuery not overriden", reader.getAnnotation( NamedQueries.class ) ); - assertEquals( "No deduplication", 3, reader.getAnnotation( NamedQueries.class ).value().length ); - assertEquals( - "deduplication kept the Java version", 1, - reader.getAnnotation( NamedQueries.class ).value()[1].hints().length - ); - assertEquals( - "org.hibernate.timeout", reader.getAnnotation( NamedQueries.class ).value()[1].hints()[0].name() - ); - assertNotNull( "NamedNativeQuery not overriden", reader.getAnnotation( NamedNativeQueries.class ) ); - assertEquals( "No deduplication", 3, reader.getAnnotation( NamedNativeQueries.class ).value().length ); - assertEquals( - "deduplication kept the Java version", 1, - reader.getAnnotation( NamedNativeQueries.class ).value()[1].hints().length - ); - assertEquals( - "org.hibernate.timeout", reader.getAnnotation( NamedNativeQueries.class ).value()[1].hints()[0].name() - ); - assertNotNull( reader.getAnnotation( SqlResultSetMappings.class ) ); - assertEquals( - "competitor1Point", reader.getAnnotation( SqlResultSetMappings.class ).value()[0].columns()[0].name() - ); - assertEquals( - "competitor1Point", - reader.getAnnotation( SqlResultSetMappings.class ).value()[0].entities()[0].fields()[0].column() - ); - assertNotNull( reader.getAnnotation( ExcludeSuperclassListeners.class ) ); - assertNotNull( reader.getAnnotation( ExcludeDefaultListeners.class ) ); - - reader = new JPAOverriddenAnnotationReader( Competition.class, context, BootstrapContextImpl.INSTANCE ); - assertNotNull( reader.getAnnotation( MappedSuperclass.class ) ); - - reader = new JPAOverriddenAnnotationReader( TennisMatch.class, context, BootstrapContextImpl.INSTANCE ); - assertNull( "Mutualize PKJC into PKJCs", reader.getAnnotation( PrimaryKeyJoinColumn.class ) ); - assertNotNull( reader.getAnnotation( PrimaryKeyJoinColumns.class ) ); - assertEquals( - "PrimaryKeyJoinColumn overrden", "id", - reader.getAnnotation( PrimaryKeyJoinColumns.class ).value()[0].name() - ); - assertNotNull( reader.getAnnotation( AttributeOverrides.class ) ); - assertEquals( "Wrong deduplication", 3, reader.getAnnotation( AttributeOverrides.class ).value().length ); - assertEquals( - "Wrong priority (XML vs java annotations)", "fld_net", - reader.getAnnotation( AttributeOverrides.class ).value()[0].column().name() - ); - assertEquals( - "Column mapping", 2, reader.getAnnotation( AttributeOverrides.class ).value()[1].column().scale() - ); - assertEquals( - "Column mapping", true, reader.getAnnotation( AttributeOverrides.class ).value()[1].column().unique() - ); - assertNotNull( reader.getAnnotation( AssociationOverrides.class ) ); - assertEquals( "no XML processing", 1, reader.getAnnotation( AssociationOverrides.class ).value().length ); - assertEquals( - "wrong xml processing", "id", - reader.getAnnotation( AssociationOverrides.class ).value()[0].joinColumns()[0].referencedColumnName() - ); - - - reader = new JPAOverriddenAnnotationReader( SocialSecurityPhysicalAccount.class, context, BootstrapContextImpl.INSTANCE ); - assertNotNull( reader.getAnnotation( IdClass.class ) ); - assertEquals( "id-class not used", SocialSecurityNumber.class, reader.getAnnotation( IdClass.class ).value() ); - assertEquals( - "discriminator-value not used", "Physical", reader.getAnnotation( DiscriminatorValue.class ).value() - ); - assertNotNull( "discriminator-column not used", reader.getAnnotation( DiscriminatorColumn.class ) ); - assertEquals( - "discriminator-column.name default value broken", "DTYPE", - reader.getAnnotation( DiscriminatorColumn.class ).name() - ); - assertEquals( - "discriminator-column.length broken", 34, reader.getAnnotation( DiscriminatorColumn.class ).length() - ); - } - - @Test - public void testEntityRelatedAnnotationsMetadataComplete() throws Exception { - XMLContext context = buildContext( - "org/hibernate/test/annotations/reflection/metadata-complete.xml" - ); - JPAOverriddenAnnotationReader reader = new JPAOverriddenAnnotationReader( Administration.class, context, BootstrapContextImpl.INSTANCE ); - assertNotNull( reader.getAnnotation( Entity.class ) ); - 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() ); - - reader = new JPAOverriddenAnnotationReader( Match.class, context, BootstrapContextImpl.INSTANCE ); - 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() ); - assertNull( "Ignore Java annotation", reader.getAnnotation( SecondaryTable.class ) ); - assertNull( "Ignore Java annotation", reader.getAnnotation( SecondaryTables.class ) ); - assertNull( "Ignore Java annotation", reader.getAnnotation( Inheritance.class ) ); - assertNull( reader.getAnnotation( NamedQueries.class ) ); - assertNull( reader.getAnnotation( NamedNativeQueries.class ) ); - - reader = new JPAOverriddenAnnotationReader( TennisMatch.class, context, BootstrapContextImpl.INSTANCE ); - assertNull( reader.getAnnotation( PrimaryKeyJoinColumn.class ) ); - assertNull( reader.getAnnotation( PrimaryKeyJoinColumns.class ) ); - - reader = new JPAOverriddenAnnotationReader( Competition.class, context, BootstrapContextImpl.INSTANCE ); - assertNull( reader.getAnnotation( MappedSuperclass.class ) ); - - reader = new JPAOverriddenAnnotationReader( SocialSecurityMoralAccount.class, context, BootstrapContextImpl.INSTANCE ); - assertNull( reader.getAnnotation( IdClass.class ) ); - assertNull( reader.getAnnotation( DiscriminatorValue.class ) ); - assertNull( reader.getAnnotation( DiscriminatorColumn.class ) ); - assertNull( reader.getAnnotation( SequenceGenerator.class ) ); - assertNull( reader.getAnnotation( TableGenerator.class ) ); - } - - @Test - public void testIdRelatedAnnotations() throws Exception { - XMLContext context = buildContext( "org/hibernate/test/annotations/reflection/orm.xml" ); - Method method = Administration.class.getDeclaredMethod( "getId" ); - JPAOverriddenAnnotationReader reader = new JPAOverriddenAnnotationReader( method, context, BootstrapContextImpl.INSTANCE ); - assertNull( reader.getAnnotation( Id.class ) ); - assertNull( reader.getAnnotation( Column.class ) ); - Field field = Administration.class.getDeclaredField( "id" ); - reader = new JPAOverriddenAnnotationReader( field, context, BootstrapContextImpl.INSTANCE ); - assertNotNull( reader.getAnnotation( Id.class ) ); - assertNotNull( reader.getAnnotation( GeneratedValue.class ) ); - assertEquals( GenerationType.SEQUENCE, reader.getAnnotation( GeneratedValue.class ).strategy() ); - assertEquals( "generator", reader.getAnnotation( GeneratedValue.class ).generator() ); - assertNotNull( reader.getAnnotation( SequenceGenerator.class ) ); - assertEquals( "seq", reader.getAnnotation( SequenceGenerator.class ).sequenceName() ); - assertNotNull( reader.getAnnotation( Columns.class ) ); - assertEquals( 1, reader.getAnnotation( Columns.class ).columns().length ); - assertEquals( "fld_id", reader.getAnnotation( Columns.class ).columns()[0].name() ); - assertNotNull( reader.getAnnotation( Temporal.class ) ); - assertEquals( TemporalType.DATE, reader.getAnnotation( Temporal.class ).value() ); - - context = buildContext( - "org/hibernate/test/annotations/reflection/metadata-complete.xml" - ); - method = Administration.class.getDeclaredMethod( "getId" ); - reader = new JPAOverriddenAnnotationReader( method, context, BootstrapContextImpl.INSTANCE ); - assertNotNull( - "Default access type when not defined in metadata complete should be property", - reader.getAnnotation( Id.class ) - ); - field = Administration.class.getDeclaredField( "id" ); - reader = new JPAOverriddenAnnotationReader( field, context, BootstrapContextImpl.INSTANCE ); - assertNull( - "Default access type when not defined in metadata complete should be property", - reader.getAnnotation( Id.class ) - ); - - method = BusTrip.class.getDeclaredMethod( "getId" ); - reader = new JPAOverriddenAnnotationReader( method, context, BootstrapContextImpl.INSTANCE ); - assertNull( reader.getAnnotation( EmbeddedId.class ) ); - field = BusTrip.class.getDeclaredField( "id" ); - reader = new JPAOverriddenAnnotationReader( field, context, BootstrapContextImpl.INSTANCE ); - assertNotNull( reader.getAnnotation( EmbeddedId.class ) ); - assertNotNull( reader.getAnnotation( AttributeOverrides.class ) ); - assertEquals( 1, reader.getAnnotation( AttributeOverrides.class ).value().length ); - } - - @Test - public void testBasicRelatedAnnotations() throws Exception { - XMLContext context = buildContext( - "org/hibernate/test/annotations/reflection/metadata-complete.xml" - ); - Field field = BusTrip.class.getDeclaredField( "status" ); - JPAOverriddenAnnotationReader reader = new JPAOverriddenAnnotationReader( field, context, BootstrapContextImpl.INSTANCE ); - assertNotNull( reader.getAnnotation( Enumerated.class ) ); - assertEquals( EnumType.STRING, reader.getAnnotation( Enumerated.class ).value() ); - assertEquals( false, reader.getAnnotation( Basic.class ).optional() ); - field = BusTrip.class.getDeclaredField( "serial" ); - reader = new JPAOverriddenAnnotationReader( field, context, BootstrapContextImpl.INSTANCE ); - assertNotNull( reader.getAnnotation( Lob.class ) ); - assertEquals( "serialbytes", reader.getAnnotation( Columns.class ).columns()[0].name() ); - field = BusTrip.class.getDeclaredField( "terminusTime" ); - reader = new JPAOverriddenAnnotationReader( field, context, BootstrapContextImpl.INSTANCE ); - assertNotNull( reader.getAnnotation( Temporal.class ) ); - assertEquals( TemporalType.TIMESTAMP, reader.getAnnotation( Temporal.class ).value() ); - assertEquals( FetchType.LAZY, reader.getAnnotation( Basic.class ).fetch() ); - - field = BusTripPk.class.getDeclaredField( "busDriver" ); - reader = new JPAOverriddenAnnotationReader( field, context, BootstrapContextImpl.INSTANCE ); - assertNotNull( reader.isAnnotationPresent( Basic.class ) ); - } - - @Test - public void testVersionRelatedAnnotations() throws Exception { - XMLContext context = buildContext( "org/hibernate/test/annotations/reflection/orm.xml" ); - Method method = Administration.class.getDeclaredMethod( "getVersion" ); - JPAOverriddenAnnotationReader reader = new JPAOverriddenAnnotationReader( method, context, BootstrapContextImpl.INSTANCE ); - assertNotNull( reader.getAnnotation( Version.class ) ); - - Field field = Match.class.getDeclaredField( "version" ); - assertNotNull( reader.getAnnotation( Version.class ) ); - } - - @Test - public void testTransientAndEmbeddedRelatedAnnotations() throws Exception { - XMLContext context = buildContext( "org/hibernate/test/annotations/reflection/orm.xml" ); - - Field field = Administration.class.getDeclaredField( "transientField" ); - JPAOverriddenAnnotationReader reader = new JPAOverriddenAnnotationReader( field, context, BootstrapContextImpl.INSTANCE ); - assertNotNull( reader.getAnnotation( Transient.class ) ); - assertNull( reader.getAnnotation( Basic.class ) ); - - field = Match.class.getDeclaredField( "playerASSN" ); - reader = new JPAOverriddenAnnotationReader( field, context, BootstrapContextImpl.INSTANCE ); - assertNotNull( reader.getAnnotation( Embedded.class ) ); - } - - @Test - public void testAssociationRelatedAnnotations() throws Exception { - XMLContext context = buildContext( "org/hibernate/test/annotations/reflection/orm.xml" ); - - Field field = Administration.class.getDeclaredField( "defaultBusTrip" ); - JPAOverriddenAnnotationReader reader = new JPAOverriddenAnnotationReader( field, context, BootstrapContextImpl.INSTANCE ); - assertNotNull( reader.getAnnotation( OneToOne.class ) ); - assertNull( reader.getAnnotation( JoinColumns.class ) ); - assertNotNull( reader.getAnnotation( PrimaryKeyJoinColumns.class ) ); - assertEquals( "pk", reader.getAnnotation( PrimaryKeyJoinColumns.class ).value()[0].name() ); - assertEquals( 5, reader.getAnnotation( OneToOne.class ).cascade().length ); - assertEquals( FetchType.LAZY, reader.getAnnotation( OneToOne.class ).fetch() ); - assertEquals( "test", reader.getAnnotation( OneToOne.class ).mappedBy() ); - - context = buildContext( - "org/hibernate/test/annotations/reflection/metadata-complete.xml" - ); - field = BusTrip.class.getDeclaredField( "players" ); - reader = new JPAOverriddenAnnotationReader( field, context, BootstrapContextImpl.INSTANCE ); - assertNotNull( reader.getAnnotation( OneToMany.class ) ); - assertNotNull( reader.getAnnotation( JoinColumns.class ) ); - assertEquals( 2, reader.getAnnotation( JoinColumns.class ).value().length ); - assertEquals( "driver", reader.getAnnotation( JoinColumns.class ).value()[0].name() ); - assertNotNull( reader.getAnnotation( MapKey.class ) ); - assertEquals( "name", reader.getAnnotation( MapKey.class ).name() ); - - field = BusTrip.class.getDeclaredField( "roads" ); - reader = new JPAOverriddenAnnotationReader( field, context, BootstrapContextImpl.INSTANCE ); - assertNotNull( reader.getAnnotation( ManyToMany.class ) ); - assertNotNull( reader.getAnnotation( JoinTable.class ) ); - assertEquals( "bus_road", reader.getAnnotation( JoinTable.class ).name() ); - assertEquals( 2, reader.getAnnotation( JoinTable.class ).joinColumns().length ); - assertEquals( 1, reader.getAnnotation( JoinTable.class ).inverseJoinColumns().length ); - assertEquals( 2, reader.getAnnotation( JoinTable.class ).uniqueConstraints()[0].columnNames().length ); - assertNotNull( reader.getAnnotation( OrderBy.class ) ); - assertEquals( "maxSpeed", reader.getAnnotation( OrderBy.class ).value() ); - } - - @Test - @TestForIssue(jiraKey = "HHH-11924") - public void testElementCollectionConverter() throws Exception { - XMLContext context = buildContext( "org/hibernate/test/annotations/reflection/orm.xml" ); - - Field field = Company.class.getDeclaredField( "organizations" ); - JPAOverriddenAnnotationReader reader = new JPAOverriddenAnnotationReader( field, context, BootstrapContextImpl.INSTANCE ); - assertNotNull( reader.getAnnotation( ElementCollection.class ) ); - assertNotNull( reader.getAnnotation( Converts.class ) ); - assertNotNull( reader.getAnnotation( Converts.class ).value() ); - assertTrue( reader.getAnnotation( Converts.class ).value().length == 1 ); - assertEquals(OrganizationConverter.class, reader.getAnnotation( Converts.class ).value()[0].converter()); - } - - @Test - public void testEntityListeners() throws Exception { - XMLContext context = buildContext( "org/hibernate/test/annotations/reflection/orm.xml" ); - - Method method = Administration.class.getDeclaredMethod( "calculate" ); - JPAOverriddenAnnotationReader reader = new JPAOverriddenAnnotationReader( method, context, BootstrapContextImpl.INSTANCE ); - assertTrue( reader.isAnnotationPresent( PrePersist.class ) ); - - reader = new JPAOverriddenAnnotationReader( Administration.class, context, BootstrapContextImpl.INSTANCE ); - assertTrue( reader.isAnnotationPresent( EntityListeners.class ) ); - assertEquals( 1, reader.getAnnotation( EntityListeners.class ).value().length ); - assertEquals( LogListener.class, reader.getAnnotation( EntityListeners.class ).value()[0] ); - - method = LogListener.class.getDeclaredMethod( "noLog", Object.class ); - reader = new JPAOverriddenAnnotationReader( method, context, BootstrapContextImpl.INSTANCE ); - assertTrue( reader.isAnnotationPresent( PostLoad.class ) ); - - method = LogListener.class.getDeclaredMethod( "log", Object.class ); - reader = new JPAOverriddenAnnotationReader( method, context, BootstrapContextImpl.INSTANCE ); - assertTrue( reader.isAnnotationPresent( PrePersist.class ) ); - assertFalse( reader.isAnnotationPresent( PostPersist.class ) ); - - assertEquals( 1, context.getDefaultEntityListeners().size() ); - assertEquals( OtherLogListener.class.getName(), context.getDefaultEntityListeners().get( 0 ) ); - } - - private XMLContext buildContext(String ormfile) throws SAXException, DocumentException, IOException { - XMLHelper xmlHelper = new XMLHelper(); - InputStream is = ClassLoaderServiceTestingImpl.INSTANCE.locateResourceStream( ormfile ); - assertNotNull( "ORM.xml not found: " + ormfile, is ); - XMLContext context = new XMLContext( BootstrapContextImpl.INSTANCE ); - ErrorLogger errorLogger = new ErrorLogger(); - SAXReader saxReader = xmlHelper.createSAXReader( errorLogger, EJB3DTDEntityResolver.INSTANCE ); - //saxReader.setValidation( false ); - try { - saxReader.setFeature( "http://apache.org/xml/features/validation/schema", true ); - } - catch ( SAXNotSupportedException e ) { - saxReader.setValidation( false ); - } - org.dom4j.Document doc; - try { - doc = saxReader.read( new InputSource( new BufferedInputStream( is ) ) ); - } - finally { - is.close(); - } - if ( errorLogger.hasErrors() ) { - System.out.println( errorLogger.getErrors().get( 0 ) ); - } - assertFalse( errorLogger.hasErrors() ); - context.addDocument( doc ); - return context; - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/LegacyXMLContextTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/LegacyXMLContextTest.java deleted file mode 100644 index 38ade26b4cae..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/LegacyXMLContextTest.java +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.annotations.reflection; - -import java.io.BufferedInputStream; -import java.io.IOException; -import java.io.InputStream; - -import org.hibernate.cfg.EJB3DTDEntityResolver; -import org.hibernate.cfg.annotations.reflection.XMLContext; -import org.hibernate.internal.util.xml.ErrorLogger; -import org.hibernate.internal.util.xml.XMLHelper; - -import org.hibernate.testing.boot.BootstrapContextImpl; -import org.hibernate.testing.boot.ClassLoaderServiceTestingImpl; -import org.junit.Assert; -import org.junit.Test; - -import org.dom4j.io.SAXReader; -import org.xml.sax.InputSource; -import org.xml.sax.SAXNotSupportedException; - -/** - * Tests the legacy {@link XMLContext}, - * which will be replaced with {@link org.hibernate.cfg.annotations.reflection.internal.XMLContext}. - * {@link XMLContext} is still the default implementation, - * but we want to switch to {@link org.hibernate.cfg.annotations.reflection.internal.XMLContext} - * as soon as it will be practical. - * - * @see XMLContextTest - * @author Emmanuel Bernard - * @deprecated This test will be removed in Hibernate ORM 6, along with the legacy {@link XMLContext}. - */ -public class LegacyXMLContextTest { - @Test - public void testAll() throws Exception { - final XMLHelper xmlHelper = new XMLHelper(); - final XMLContext context = new XMLContext( BootstrapContextImpl.INSTANCE ); - - InputStream is = ClassLoaderServiceTestingImpl.INSTANCE.locateResourceStream( - "org/hibernate/test/annotations/reflection/orm.xml" - ); - Assert.assertNotNull( "ORM.xml not found", is ); - - final ErrorLogger errorLogger = new ErrorLogger(); - final SAXReader saxReader = xmlHelper.createSAXReader( errorLogger, EJB3DTDEntityResolver.INSTANCE ); - - try { - saxReader.setFeature( "http://apache.org/xml/features/validation/schema", true ); - } - catch ( SAXNotSupportedException e ) { - saxReader.setValidation( false ); - } - org.dom4j.Document doc; - try { - doc = saxReader.read( new InputSource( new BufferedInputStream( is ) ) ); - } - finally { - try { - is.close(); - } - catch ( IOException ioe ) { - //log.warn( "Could not close input stream", ioe ); - } - } - Assert.assertFalse( errorLogger.hasErrors() ); - context.addDocument( doc ); - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlElementCollectionTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlElementCollectionTest.java deleted file mode 100644 index 7d46e662bfcd..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlElementCollectionTest.java +++ /dev/null @@ -1,716 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.annotations.xml.ejb3; - -import javax.persistence.Access; -import javax.persistence.AccessType; -import javax.persistence.AssociationOverride; -import javax.persistence.AssociationOverrides; -import javax.persistence.AttributeOverride; -import javax.persistence.AttributeOverrides; -import javax.persistence.CollectionTable; -import javax.persistence.Column; -import javax.persistence.ElementCollection; -import javax.persistence.EnumType; -import javax.persistence.Enumerated; -import javax.persistence.FetchType; -import javax.persistence.JoinColumn; -import javax.persistence.JoinTable; -import javax.persistence.Lob; -import javax.persistence.MapKey; -import javax.persistence.MapKeyClass; -import javax.persistence.MapKeyColumn; -import javax.persistence.MapKeyEnumerated; -import javax.persistence.MapKeyJoinColumn; -import javax.persistence.MapKeyJoinColumns; -import javax.persistence.MapKeyTemporal; -import javax.persistence.OrderBy; -import javax.persistence.OrderColumn; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; -import javax.persistence.UniqueConstraint; - -import org.hibernate.cfg.annotations.reflection.JPAOverriddenAnnotationReader; - -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -/** - * Equivalent to {@link org.hibernate.test.annotations.xml.ejb3.Ejb3XmlElementCollectionTest} - * for the legacy {@link JPAOverriddenAnnotationReader}. - * - * @author Emmanuel Bernard - * @deprecated This test will be removed in Hibernate ORM 6, along with the legacy {@link JPAOverriddenAnnotationReader}. - */ -@Deprecated -public class LegacyEjb3XmlElementCollectionTest extends LegacyEjb3XmlTestCase { - @Test - public void testNoChildren() throws Exception { - reader = getReader( Entity2.class, "field1", "element-collection.orm1.xml" ); - assertAnnotationPresent( ElementCollection.class ); - assertAnnotationNotPresent( OrderBy.class ); - assertAnnotationNotPresent( OrderColumn.class ); - assertAnnotationNotPresent( MapKey.class ); - assertAnnotationNotPresent( MapKeyClass.class ); - assertAnnotationNotPresent( MapKeyTemporal.class ); - assertAnnotationNotPresent( MapKeyEnumerated.class ); - assertAnnotationNotPresent( MapKeyColumn.class ); - assertAnnotationNotPresent( MapKeyJoinColumns.class ); - assertAnnotationNotPresent( MapKeyJoinColumn.class ); - assertAnnotationNotPresent( Column.class ); - assertAnnotationNotPresent( Temporal.class ); - assertAnnotationNotPresent( Enumerated.class ); - assertAnnotationNotPresent( Lob.class ); - assertAnnotationNotPresent( AttributeOverride.class ); - assertAnnotationNotPresent( AttributeOverrides.class ); - assertAnnotationNotPresent( AssociationOverride.class ); - assertAnnotationNotPresent( AssociationOverrides.class ); - assertAnnotationNotPresent( CollectionTable.class ); - assertAnnotationNotPresent( Access.class ); - ElementCollection relAnno = reader.getAnnotation( ElementCollection.class ); - assertEquals( FetchType.LAZY, relAnno.fetch() ); - assertEquals( void.class, relAnno.targetClass() ); - } - - @Test - public void testOrderBy() throws Exception { - reader = getReader( Entity2.class, "field1", "element-collection.orm2.xml" ); - assertAnnotationPresent( ElementCollection.class ); - assertAnnotationPresent( OrderBy.class ); - assertAnnotationNotPresent( OrderColumn.class ); - assertEquals( - "col1 ASC, col2 DESC", reader.getAnnotation( OrderBy.class ) - .value() - ); - } - - @Test - public void testOrderColumnNoAttributes() throws Exception { - reader = getReader( Entity2.class, "field1", "element-collection.orm3.xml" ); - assertAnnotationPresent( ElementCollection.class ); - assertAnnotationNotPresent( OrderBy.class ); - assertAnnotationPresent( OrderColumn.class ); - OrderColumn orderColumnAnno = reader.getAnnotation( OrderColumn.class ); - assertEquals( "", orderColumnAnno.columnDefinition() ); - assertEquals( "", orderColumnAnno.name() ); - assertTrue( orderColumnAnno.insertable() ); - assertTrue( orderColumnAnno.nullable() ); - assertTrue( orderColumnAnno.updatable() ); - } - - @Test - public void testOrderColumnAllAttributes() throws Exception { - reader = getReader( Entity2.class, "field1", "element-collection.orm4.xml" ); - assertAnnotationPresent( ElementCollection.class ); - assertAnnotationNotPresent( OrderBy.class ); - assertAnnotationPresent( OrderColumn.class ); - OrderColumn orderColumnAnno = reader.getAnnotation( OrderColumn.class ); - assertEquals( "int", orderColumnAnno.columnDefinition() ); - assertEquals( "col1", orderColumnAnno.name() ); - assertFalse( orderColumnAnno.insertable() ); - assertFalse( orderColumnAnno.nullable() ); - assertFalse( orderColumnAnno.updatable() ); - } - - @Test - public void testMapKeyNoAttributes() throws Exception { - reader = getReader( Entity3.class, "field1", "element-collection.orm5.xml" ); - assertAnnotationPresent( ElementCollection.class ); - assertAnnotationPresent( MapKey.class ); - assertAnnotationNotPresent( MapKeyClass.class ); - assertAnnotationNotPresent( MapKeyTemporal.class ); - assertAnnotationNotPresent( MapKeyEnumerated.class ); - assertAnnotationNotPresent( MapKeyColumn.class ); - assertAnnotationNotPresent( MapKeyJoinColumns.class ); - assertAnnotationNotPresent( MapKeyJoinColumn.class ); - assertEquals( "", reader.getAnnotation( MapKey.class ).name() ); - } - - @Test - public void testMapKeyAllAttributes() throws Exception { - reader = getReader( Entity3.class, "field1", "element-collection.orm6.xml" ); - assertAnnotationPresent( ElementCollection.class ); - assertAnnotationPresent( MapKey.class ); - assertAnnotationNotPresent( MapKeyClass.class ); - assertAnnotationNotPresent( MapKeyTemporal.class ); - assertAnnotationNotPresent( MapKeyEnumerated.class ); - assertAnnotationNotPresent( MapKeyColumn.class ); - assertAnnotationNotPresent( MapKeyJoinColumns.class ); - assertAnnotationNotPresent( MapKeyJoinColumn.class ); - assertEquals( "field2", reader.getAnnotation( MapKey.class ).name() ); - } - - @Test - public void testMapKeyClass() throws Exception { - reader = getReader( Entity3.class, "field1", "element-collection.orm7.xml" ); - assertAnnotationPresent( ElementCollection.class ); - assertAnnotationNotPresent( MapKey.class ); - assertAnnotationPresent( MapKeyClass.class ); - assertAnnotationNotPresent( MapKeyTemporal.class ); - assertAnnotationNotPresent( MapKeyEnumerated.class ); - assertAnnotationNotPresent( MapKeyColumn.class ); - assertAnnotationNotPresent( MapKeyJoinColumns.class ); - assertAnnotationNotPresent( MapKeyJoinColumn.class ); - assertEquals( - Entity2.class, reader.getAnnotation( MapKeyClass.class ) - .value() - ); - } - - @Test - public void testMapKeyTemporal() throws Exception { - reader = getReader( Entity3.class, "field1", "element-collection.orm8.xml" ); - assertAnnotationPresent( ElementCollection.class ); - assertAnnotationNotPresent( MapKey.class ); - assertAnnotationNotPresent( MapKeyClass.class ); - assertAnnotationPresent( MapKeyTemporal.class ); - assertAnnotationNotPresent( MapKeyEnumerated.class ); - assertAnnotationNotPresent( MapKeyColumn.class ); - assertAnnotationNotPresent( MapKeyJoinColumns.class ); - assertAnnotationNotPresent( MapKeyJoinColumn.class ); - assertEquals( - TemporalType.DATE, reader.getAnnotation( - MapKeyTemporal.class - ).value() - ); - } - - @Test - public void testMapKeyEnumerated() throws Exception { - reader = getReader( Entity3.class, "field1", "element-collection.orm9.xml" ); - assertAnnotationPresent( ElementCollection.class ); - assertAnnotationNotPresent( MapKey.class ); - assertAnnotationNotPresent( MapKeyClass.class ); - assertAnnotationNotPresent( MapKeyTemporal.class ); - assertAnnotationPresent( MapKeyEnumerated.class ); - assertAnnotationNotPresent( MapKeyColumn.class ); - assertAnnotationNotPresent( MapKeyJoinColumns.class ); - assertAnnotationNotPresent( MapKeyJoinColumn.class ); - assertEquals( - EnumType.STRING, reader.getAnnotation( - MapKeyEnumerated.class - ).value() - ); - } - - /** - * When there's a single map key attribute override, we still wrap it with - * an AttributeOverrides annotation. - */ - @Test - public void testSingleMapKeyAttributeOverride() throws Exception { - reader = getReader( Entity3.class, "field1", "element-collection.orm10.xml" ); - assertAnnotationPresent( ElementCollection.class ); - assertAnnotationNotPresent( MapKey.class ); - assertAnnotationNotPresent( MapKeyClass.class ); - assertAnnotationNotPresent( MapKeyTemporal.class ); - assertAnnotationNotPresent( MapKeyEnumerated.class ); - assertAnnotationNotPresent( MapKeyColumn.class ); - assertAnnotationNotPresent( MapKeyJoinColumns.class ); - assertAnnotationNotPresent( MapKeyJoinColumn.class ); - assertAnnotationNotPresent( AttributeOverride.class ); - assertAnnotationPresent( AttributeOverrides.class ); - AttributeOverrides overridesAnno = reader - .getAnnotation( AttributeOverrides.class ); - AttributeOverride[] overrides = overridesAnno.value(); - assertEquals( 1, overrides.length ); - assertEquals( "field1", overrides[0].name() ); - assertEquals( "col1", overrides[0].column().name() ); - } - - @Test - public void testMultipleMapKeyAttributeOverrides() throws Exception { - reader = getReader( Entity3.class, "field1", "element-collection.orm11.xml" ); - assertAnnotationPresent( ElementCollection.class ); - assertAnnotationNotPresent( MapKey.class ); - assertAnnotationNotPresent( MapKeyClass.class ); - assertAnnotationNotPresent( MapKeyTemporal.class ); - assertAnnotationNotPresent( MapKeyEnumerated.class ); - assertAnnotationNotPresent( MapKeyColumn.class ); - assertAnnotationNotPresent( MapKeyJoinColumns.class ); - assertAnnotationNotPresent( MapKeyJoinColumn.class ); - assertAnnotationNotPresent( AttributeOverride.class ); - assertAnnotationPresent( AttributeOverrides.class ); - AttributeOverrides overridesAnno = reader - .getAnnotation( AttributeOverrides.class ); - AttributeOverride[] overrides = overridesAnno.value(); - assertEquals( 2, overrides.length ); - assertEquals( "field1", overrides[0].name() ); - assertEquals( "", overrides[0].column().name() ); - assertFalse( overrides[0].column().unique() ); - assertTrue( overrides[0].column().nullable() ); - assertTrue( overrides[0].column().insertable() ); - assertTrue( overrides[0].column().updatable() ); - assertEquals( "", overrides[0].column().columnDefinition() ); - assertEquals( "", overrides[0].column().table() ); - assertEquals( 255, overrides[0].column().length() ); - assertEquals( 0, overrides[0].column().precision() ); - assertEquals( 0, overrides[0].column().scale() ); - assertEquals( "field2", overrides[1].name() ); - assertEquals( "col1", overrides[1].column().name() ); - assertTrue( overrides[1].column().unique() ); - assertFalse( overrides[1].column().nullable() ); - assertFalse( overrides[1].column().insertable() ); - assertFalse( overrides[1].column().updatable() ); - assertEquals( "int", overrides[1].column().columnDefinition() ); - assertEquals( "table1", overrides[1].column().table() ); - assertEquals( 50, overrides[1].column().length() ); - assertEquals( 2, overrides[1].column().precision() ); - assertEquals( 1, overrides[1].column().scale() ); - } - - @Test - public void testMapKeyColumnNoAttributes() throws Exception { - reader = getReader( Entity3.class, "field1", "element-collection.orm12.xml" ); - assertAnnotationPresent( ElementCollection.class ); - assertAnnotationNotPresent( MapKey.class ); - assertAnnotationNotPresent( MapKeyClass.class ); - assertAnnotationNotPresent( MapKeyTemporal.class ); - assertAnnotationNotPresent( MapKeyEnumerated.class ); - assertAnnotationPresent( MapKeyColumn.class ); - assertAnnotationNotPresent( MapKeyJoinColumns.class ); - assertAnnotationNotPresent( MapKeyJoinColumn.class ); - MapKeyColumn keyColAnno = reader.getAnnotation( MapKeyColumn.class ); - assertEquals( "", keyColAnno.columnDefinition() ); - assertEquals( "", keyColAnno.name() ); - assertEquals( "", keyColAnno.table() ); - assertFalse( keyColAnno.nullable() ); - assertTrue( keyColAnno.insertable() ); - assertFalse( keyColAnno.unique() ); - assertTrue( keyColAnno.updatable() ); - assertEquals( 255, keyColAnno.length() ); - assertEquals( 0, keyColAnno.precision() ); - assertEquals( 0, keyColAnno.scale() ); - } - - @Test - public void testMapKeyColumnAllAttributes() throws Exception { - reader = getReader( Entity3.class, "field1", "element-collection.orm13.xml" ); - assertAnnotationPresent( ElementCollection.class ); - assertAnnotationNotPresent( MapKey.class ); - assertAnnotationNotPresent( MapKeyClass.class ); - assertAnnotationNotPresent( MapKeyTemporal.class ); - assertAnnotationNotPresent( MapKeyEnumerated.class ); - assertAnnotationPresent( MapKeyColumn.class ); - assertAnnotationNotPresent( MapKeyJoinColumns.class ); - assertAnnotationNotPresent( MapKeyJoinColumn.class ); - MapKeyColumn keyColAnno = reader.getAnnotation( MapKeyColumn.class ); - assertEquals( "int", keyColAnno.columnDefinition() ); - assertEquals( "col1", keyColAnno.name() ); - assertEquals( "table1", keyColAnno.table() ); - assertTrue( keyColAnno.nullable() ); - assertFalse( keyColAnno.insertable() ); - assertTrue( keyColAnno.unique() ); - assertFalse( keyColAnno.updatable() ); - assertEquals( 50, keyColAnno.length() ); - assertEquals( 2, keyColAnno.precision() ); - assertEquals( 1, keyColAnno.scale() ); - } - - /** - * When there's a single map key join column, we still wrap it with a - * MapKeyJoinColumns annotation. - */ - @Test - public void testSingleMapKeyJoinColumn() throws Exception { - reader = getReader( Entity3.class, "field1", "element-collection.orm14.xml" ); - assertAnnotationPresent( ElementCollection.class ); - assertAnnotationNotPresent( MapKey.class ); - assertAnnotationNotPresent( MapKeyClass.class ); - assertAnnotationNotPresent( MapKeyTemporal.class ); - assertAnnotationNotPresent( MapKeyEnumerated.class ); - assertAnnotationNotPresent( MapKeyColumn.class ); - assertAnnotationPresent( MapKeyJoinColumns.class ); - assertAnnotationNotPresent( MapKeyJoinColumn.class ); - MapKeyJoinColumns joinColumnsAnno = reader - .getAnnotation( MapKeyJoinColumns.class ); - MapKeyJoinColumn[] joinColumns = joinColumnsAnno.value(); - assertEquals( 1, joinColumns.length ); - assertEquals( "col1", joinColumns[0].name() ); - } - - @Test - public void testMultipleMapKeyJoinColumns() throws Exception { - reader = getReader( Entity3.class, "field1", "element-collection.orm15.xml" ); - assertAnnotationPresent( ElementCollection.class ); - assertAnnotationNotPresent( MapKey.class ); - assertAnnotationNotPresent( MapKeyClass.class ); - assertAnnotationNotPresent( MapKeyTemporal.class ); - assertAnnotationNotPresent( MapKeyEnumerated.class ); - assertAnnotationNotPresent( MapKeyColumn.class ); - assertAnnotationPresent( MapKeyJoinColumns.class ); - assertAnnotationNotPresent( MapKeyJoinColumn.class ); - MapKeyJoinColumns joinColumnsAnno = reader - .getAnnotation( MapKeyJoinColumns.class ); - MapKeyJoinColumn[] joinColumns = joinColumnsAnno.value(); - assertEquals( 2, joinColumns.length ); - assertEquals( "", joinColumns[0].name() ); - assertEquals( "", joinColumns[0].referencedColumnName() ); - assertFalse( joinColumns[0].unique() ); - assertFalse( joinColumns[0].nullable() ); - assertTrue( joinColumns[0].insertable() ); - assertTrue( joinColumns[0].updatable() ); - assertEquals( "", joinColumns[0].columnDefinition() ); - assertEquals( "", joinColumns[0].table() ); - assertEquals( "col1", joinColumns[1].name() ); - assertEquals( "col2", joinColumns[1].referencedColumnName() ); - assertTrue( joinColumns[1].unique() ); - assertTrue( joinColumns[1].nullable() ); - assertFalse( joinColumns[1].insertable() ); - assertFalse( joinColumns[1].updatable() ); - assertEquals( "int", joinColumns[1].columnDefinition() ); - assertEquals( "table1", joinColumns[1].table() ); - } - - @Test - public void testColumnNoAttributes() throws Exception { - reader = getReader( Entity3.class, "field1", "element-collection.orm16.xml" ); - assertAnnotationPresent( ElementCollection.class ); - assertAnnotationPresent( Column.class ); - Column column = reader.getAnnotation( Column.class ); - assertEquals( "", column.name() ); - assertFalse( column.unique() ); - assertTrue( column.nullable() ); - assertTrue( column.insertable() ); - assertTrue( column.updatable() ); - assertEquals( "", column.columnDefinition() ); - assertEquals( "", column.table() ); - assertEquals( 255, column.length() ); - assertEquals( 0, column.precision() ); - assertEquals( 0, column.scale() ); - } - - @Test - public void testColumnAllAttributes() throws Exception { - reader = getReader( Entity3.class, "field1", "element-collection.orm17.xml" ); - assertAnnotationPresent( ElementCollection.class ); - assertAnnotationPresent( Column.class ); - Column column = reader.getAnnotation( Column.class ); - assertEquals( "col1", column.name() ); - assertTrue( column.unique() ); - assertFalse( column.nullable() ); - assertFalse( column.insertable() ); - assertFalse( column.updatable() ); - assertEquals( "int", column.columnDefinition() ); - assertEquals( "table1", column.table() ); - assertEquals( 50, column.length() ); - assertEquals( 2, column.precision() ); - assertEquals( 1, column.scale() ); - } - - @Test - public void testTemporal() throws Exception { - reader = getReader( Entity3.class, "field1", "element-collection.orm18.xml" ); - assertAnnotationPresent( ElementCollection.class ); - assertAnnotationPresent( Temporal.class ); - assertAnnotationNotPresent( Enumerated.class ); - assertAnnotationNotPresent( Lob.class ); - assertEquals( - TemporalType.DATE, reader.getAnnotation( - Temporal.class - ).value() - ); - } - - @Test - public void testEnumerated() throws Exception { - reader = getReader( Entity3.class, "field1", "element-collection.orm19.xml" ); - assertAnnotationPresent( ElementCollection.class ); - assertAnnotationNotPresent( Temporal.class ); - assertAnnotationPresent( Enumerated.class ); - assertAnnotationNotPresent( Lob.class ); - assertEquals( - EnumType.STRING, reader.getAnnotation( - Enumerated.class - ).value() - ); - } - - @Test - public void testLob() throws Exception { - reader = getReader( Entity3.class, "field1", "element-collection.orm20.xml" ); - assertAnnotationPresent( ElementCollection.class ); - assertAnnotationNotPresent( Temporal.class ); - assertAnnotationNotPresent( Enumerated.class ); - assertAnnotationPresent( Lob.class ); - } - - /** - * When there's a single attribute override, we still wrap it with an - * AttributeOverrides annotation. - */ - @Test - public void testSingleAttributeOverride() throws Exception { - reader = getReader( Entity3.class, "field1", "element-collection.orm21.xml" ); - assertAnnotationPresent( ElementCollection.class ); - assertAnnotationNotPresent( AttributeOverride.class ); - assertAnnotationPresent( AttributeOverrides.class ); - AttributeOverrides overridesAnno = reader - .getAnnotation( AttributeOverrides.class ); - AttributeOverride[] overrides = overridesAnno.value(); - assertEquals( 1, overrides.length ); - assertEquals( "field1", overrides[0].name() ); - assertEquals( "col1", overrides[0].column().name() ); - } - - @Test - public void testMultipleAttributeOverrides() throws Exception { - reader = getReader( Entity3.class, "field1", "element-collection.orm22.xml" ); - assertAnnotationPresent( ElementCollection.class ); - assertAnnotationNotPresent( AttributeOverride.class ); - assertAnnotationPresent( AttributeOverrides.class ); - AttributeOverrides overridesAnno = reader - .getAnnotation( AttributeOverrides.class ); - AttributeOverride[] overrides = overridesAnno.value(); - assertEquals( 2, overrides.length ); - assertEquals( "field1", overrides[0].name() ); - assertEquals( "", overrides[0].column().name() ); - assertFalse( overrides[0].column().unique() ); - assertTrue( overrides[0].column().nullable() ); - assertTrue( overrides[0].column().insertable() ); - assertTrue( overrides[0].column().updatable() ); - assertEquals( "", overrides[0].column().columnDefinition() ); - assertEquals( "", overrides[0].column().table() ); - assertEquals( 255, overrides[0].column().length() ); - assertEquals( 0, overrides[0].column().precision() ); - assertEquals( 0, overrides[0].column().scale() ); - assertEquals( "field2", overrides[1].name() ); - assertEquals( "col1", overrides[1].column().name() ); - assertTrue( overrides[1].column().unique() ); - assertFalse( overrides[1].column().nullable() ); - assertFalse( overrides[1].column().insertable() ); - assertFalse( overrides[1].column().updatable() ); - assertEquals( "int", overrides[1].column().columnDefinition() ); - assertEquals( "table1", overrides[1].column().table() ); - assertEquals( 50, overrides[1].column().length() ); - assertEquals( 2, overrides[1].column().precision() ); - assertEquals( 1, overrides[1].column().scale() ); - } - - /** - * Tests that map-key-attribute-override and attribute-override elements - * both end up in the AttributeOverrides annotation. - */ - @Test - public void testMixedAttributeOverrides() throws Exception { - reader = getReader( Entity3.class, "field1", "element-collection.orm23.xml" ); - assertAnnotationPresent( ElementCollection.class ); - assertAnnotationNotPresent( AttributeOverride.class ); - assertAnnotationPresent( AttributeOverrides.class ); - AttributeOverrides overridesAnno = reader - .getAnnotation( AttributeOverrides.class ); - AttributeOverride[] overrides = overridesAnno.value(); - assertEquals( 2, overrides.length ); - assertEquals( "field1", overrides[0].name() ); - assertEquals( "col1", overrides[0].column().name() ); - assertEquals( "field2", overrides[1].name() ); - assertEquals( "col2", overrides[1].column().name() ); - } - - /** - * When there's a single association override, we still wrap it with an - * AssociationOverrides annotation. - */ - @Test - public void testSingleAssociationOverride() throws Exception { - reader = getReader( Entity3.class, "field1", "element-collection.orm24.xml" ); - assertAnnotationPresent( ElementCollection.class ); - assertAnnotationNotPresent( AssociationOverride.class ); - assertAnnotationPresent( AssociationOverrides.class ); - AssociationOverrides overridesAnno = reader.getAnnotation( AssociationOverrides.class ); - AssociationOverride[] overrides = overridesAnno.value(); - assertEquals( 1, overrides.length ); - assertEquals( "association1", overrides[0].name() ); - assertEquals( 0, overrides[0].joinColumns().length ); - assertEquals( "", overrides[0].joinTable().name() ); - } - - @Test - public void testMultipleAssociationOverridesJoinColumns() throws Exception { - reader = getReader( Entity3.class, "field1", "element-collection.orm25.xml" ); - assertAnnotationPresent( ElementCollection.class ); - assertAnnotationNotPresent( AssociationOverride.class ); - assertAnnotationPresent( AssociationOverrides.class ); - AssociationOverrides overridesAnno = reader.getAnnotation( AssociationOverrides.class ); - AssociationOverride[] overrides = overridesAnno.value(); - assertEquals( 2, overrides.length ); - //First, an association using join table - assertEquals( "association1", overrides[0].name() ); - assertEquals( 0, overrides[0].joinColumns().length ); - - JoinTable joinTableAnno = overrides[0].joinTable(); - assertEquals( "catalog1", joinTableAnno.catalog() ); - assertEquals( "table1", joinTableAnno.name() ); - assertEquals( "schema1", joinTableAnno.schema() ); - - //JoinColumns - JoinColumn[] joinColumns = joinTableAnno.joinColumns(); - assertEquals( 2, joinColumns.length ); - assertEquals( "", joinColumns[0].name() ); - assertEquals( "", joinColumns[0].referencedColumnName() ); - assertEquals( "", joinColumns[0].table() ); - assertEquals( "", joinColumns[0].columnDefinition() ); - assertTrue( joinColumns[0].insertable() ); - assertTrue( joinColumns[0].updatable() ); - assertTrue( joinColumns[0].nullable() ); - assertFalse( joinColumns[0].unique() ); - assertEquals( "col1", joinColumns[1].name() ); - assertEquals( "col2", joinColumns[1].referencedColumnName() ); - assertEquals( "table2", joinColumns[1].table() ); - assertEquals( "int", joinColumns[1].columnDefinition() ); - assertFalse( joinColumns[1].insertable() ); - assertFalse( joinColumns[1].updatable() ); - assertFalse( joinColumns[1].nullable() ); - assertTrue( joinColumns[1].unique() ); - - //InverseJoinColumns - JoinColumn[] inverseJoinColumns = joinTableAnno.inverseJoinColumns(); - assertEquals( 2, inverseJoinColumns.length ); - assertEquals( "", inverseJoinColumns[0].name() ); - assertEquals( "", inverseJoinColumns[0].referencedColumnName() ); - assertEquals( "", inverseJoinColumns[0].table() ); - assertEquals( "", inverseJoinColumns[0].columnDefinition() ); - assertTrue( inverseJoinColumns[0].insertable() ); - assertTrue( inverseJoinColumns[0].updatable() ); - assertTrue( inverseJoinColumns[0].nullable() ); - assertFalse( inverseJoinColumns[0].unique() ); - assertEquals( "col3", inverseJoinColumns[1].name() ); - assertEquals( "col4", inverseJoinColumns[1].referencedColumnName() ); - assertEquals( "table3", inverseJoinColumns[1].table() ); - assertEquals( "int", inverseJoinColumns[1].columnDefinition() ); - assertFalse( inverseJoinColumns[1].insertable() ); - assertFalse( inverseJoinColumns[1].updatable() ); - assertFalse( inverseJoinColumns[1].nullable() ); - assertTrue( inverseJoinColumns[1].unique() ); - - //UniqueConstraints - UniqueConstraint[] uniqueConstraints = joinTableAnno - .uniqueConstraints(); - assertEquals( 2, uniqueConstraints.length ); - assertEquals( "", uniqueConstraints[0].name() ); - assertEquals( 1, uniqueConstraints[0].columnNames().length ); - assertEquals( "col5", uniqueConstraints[0].columnNames()[0] ); - assertEquals( "uq1", uniqueConstraints[1].name() ); - assertEquals( 2, uniqueConstraints[1].columnNames().length ); - assertEquals( "col6", uniqueConstraints[1].columnNames()[0] ); - assertEquals( "col7", uniqueConstraints[1].columnNames()[1] ); - - //Second, an association using join columns - assertEquals( "association2", overrides[1].name() ); - - //JoinColumns - joinColumns = overrides[1].joinColumns(); - assertEquals( 2, joinColumns.length ); - assertEquals( "", joinColumns[0].name() ); - assertEquals( "", joinColumns[0].referencedColumnName() ); - assertEquals( "", joinColumns[0].table() ); - assertEquals( "", joinColumns[0].columnDefinition() ); - assertTrue( joinColumns[0].insertable() ); - assertTrue( joinColumns[0].updatable() ); - assertTrue( joinColumns[0].nullable() ); - assertFalse( joinColumns[0].unique() ); - assertEquals( "col8", joinColumns[1].name() ); - assertEquals( "col9", joinColumns[1].referencedColumnName() ); - assertEquals( "table4", joinColumns[1].table() ); - assertEquals( "int", joinColumns[1].columnDefinition() ); - assertFalse( joinColumns[1].insertable() ); - assertFalse( joinColumns[1].updatable() ); - assertFalse( joinColumns[1].nullable() ); - assertTrue( joinColumns[1].unique() ); - } - - @Test - public void testCollectionTableNoChildren() throws Exception { - reader = getReader( Entity3.class, "field1", "element-collection.orm26.xml" ); - assertAnnotationPresent( ElementCollection.class ); - assertAnnotationPresent( CollectionTable.class ); - CollectionTable tableAnno = reader.getAnnotation( CollectionTable.class ); - assertEquals( "", tableAnno.name() ); - assertEquals( "", tableAnno.catalog() ); - assertEquals( "", tableAnno.schema() ); - assertEquals( 0, tableAnno.joinColumns().length ); - assertEquals( 0, tableAnno.uniqueConstraints().length ); - } - - @Test - public void testCollectionTableAllChildren() throws Exception { - reader = getReader( Entity3.class, "field1", "element-collection.orm27.xml" ); - assertAnnotationPresent( ElementCollection.class ); - assertAnnotationPresent( CollectionTable.class ); - CollectionTable tableAnno = reader.getAnnotation( CollectionTable.class ); - assertEquals( "table1", tableAnno.name() ); - assertEquals( "catalog1", tableAnno.catalog() ); - assertEquals( "schema1", tableAnno.schema() ); - - //JoinColumns - JoinColumn[] joinColumns = tableAnno.joinColumns(); - assertEquals( 2, joinColumns.length ); - assertEquals( "", joinColumns[0].name() ); - assertEquals( "", joinColumns[0].referencedColumnName() ); - assertEquals( "", joinColumns[0].table() ); - assertEquals( "", joinColumns[0].columnDefinition() ); - assertTrue( joinColumns[0].insertable() ); - assertTrue( joinColumns[0].updatable() ); - assertTrue( joinColumns[0].nullable() ); - assertFalse( joinColumns[0].unique() ); - assertEquals( "col1", joinColumns[1].name() ); - assertEquals( "col2", joinColumns[1].referencedColumnName() ); - assertEquals( "table2", joinColumns[1].table() ); - assertEquals( "int", joinColumns[1].columnDefinition() ); - assertFalse( joinColumns[1].insertable() ); - assertFalse( joinColumns[1].updatable() ); - assertFalse( joinColumns[1].nullable() ); - assertTrue( joinColumns[1].unique() ); - - //UniqueConstraints - UniqueConstraint[] uniqueConstraints = tableAnno.uniqueConstraints(); - assertEquals( 2, uniqueConstraints.length ); - assertEquals( "", uniqueConstraints[0].name() ); - assertEquals( 1, uniqueConstraints[0].columnNames().length ); - assertEquals( "col3", uniqueConstraints[0].columnNames()[0] ); - assertEquals( "uq1", uniqueConstraints[1].name() ); - assertEquals( 2, uniqueConstraints[1].columnNames().length ); - assertEquals( "col4", uniqueConstraints[1].columnNames()[0] ); - assertEquals( "col5", uniqueConstraints[1].columnNames()[1] ); - } - - @Test - public void testAllAttributes() throws Exception { - reader = getReader( Entity2.class, "field1", "element-collection.orm28.xml" ); - assertAnnotationPresent( ElementCollection.class ); - assertAnnotationNotPresent( OrderBy.class ); - assertAnnotationNotPresent( OrderColumn.class ); - assertAnnotationNotPresent( MapKey.class ); - assertAnnotationNotPresent( MapKeyClass.class ); - assertAnnotationNotPresent( MapKeyTemporal.class ); - assertAnnotationNotPresent( MapKeyEnumerated.class ); - assertAnnotationNotPresent( MapKeyColumn.class ); - assertAnnotationNotPresent( MapKeyJoinColumns.class ); - assertAnnotationNotPresent( MapKeyJoinColumn.class ); - assertAnnotationNotPresent( Column.class ); - assertAnnotationNotPresent( Temporal.class ); - assertAnnotationNotPresent( Enumerated.class ); - assertAnnotationNotPresent( Lob.class ); - assertAnnotationNotPresent( AttributeOverride.class ); - assertAnnotationNotPresent( AttributeOverrides.class ); - assertAnnotationNotPresent( AssociationOverride.class ); - assertAnnotationNotPresent( AssociationOverrides.class ); - assertAnnotationNotPresent( CollectionTable.class ); - assertAnnotationPresent( Access.class ); - ElementCollection relAnno = reader.getAnnotation( ElementCollection.class ); - assertEquals( FetchType.EAGER, relAnno.fetch() ); - assertEquals( Entity3.class, relAnno.targetClass() ); - assertEquals( - AccessType.PROPERTY, reader.getAnnotation( Access.class ) - .value() - ); - } - -} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlManyToManyTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlManyToManyTest.java deleted file mode 100644 index e80c00e08e8d..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlManyToManyTest.java +++ /dev/null @@ -1,508 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.annotations.xml.ejb3; - -import javax.persistence.Access; -import javax.persistence.AccessType; -import javax.persistence.AttributeOverride; -import javax.persistence.AttributeOverrides; -import javax.persistence.CascadeType; -import javax.persistence.EnumType; -import javax.persistence.FetchType; -import javax.persistence.JoinColumn; -import javax.persistence.JoinColumns; -import javax.persistence.JoinTable; -import javax.persistence.ManyToMany; -import javax.persistence.MapKey; -import javax.persistence.MapKeyClass; -import javax.persistence.MapKeyColumn; -import javax.persistence.MapKeyEnumerated; -import javax.persistence.MapKeyJoinColumn; -import javax.persistence.MapKeyJoinColumns; -import javax.persistence.MapKeyTemporal; -import javax.persistence.OrderBy; -import javax.persistence.OrderColumn; -import javax.persistence.TemporalType; -import javax.persistence.UniqueConstraint; - -import org.hibernate.cfg.annotations.reflection.JPAOverriddenAnnotationReader; - -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -/** - * Equivalent to {@link org.hibernate.test.annotations.xml.ejb3.Ejb3XmlManyToManyTest} - * for the legacy {@link JPAOverriddenAnnotationReader}. - * - * @author Emmanuel Bernard - * @deprecated This test will be removed in Hibernate ORM 6, along with the legacy {@link JPAOverriddenAnnotationReader}. - */ -@Deprecated -public class LegacyEjb3XmlManyToManyTest extends LegacyEjb3XmlTestCase { - @Test - public void testNoChildren() throws Exception { - reader = getReader( Entity2.class, "field1", "many-to-many.orm1.xml" ); - assertAnnotationPresent( ManyToMany.class ); - assertAnnotationNotPresent( OrderBy.class ); - assertAnnotationNotPresent( OrderColumn.class ); - assertAnnotationNotPresent( MapKey.class ); - assertAnnotationNotPresent( MapKeyClass.class ); - assertAnnotationNotPresent( MapKeyTemporal.class ); - assertAnnotationNotPresent( MapKeyEnumerated.class ); - assertAnnotationNotPresent( MapKeyColumn.class ); - assertAnnotationNotPresent( MapKeyJoinColumns.class ); - assertAnnotationNotPresent( MapKeyJoinColumn.class ); - assertAnnotationNotPresent( JoinTable.class ); - assertAnnotationNotPresent( Access.class ); - ManyToMany relAnno = reader.getAnnotation( ManyToMany.class ); - assertEquals( 0, relAnno.cascade().length ); - assertEquals( FetchType.LAZY, relAnno.fetch() ); - assertEquals( "", relAnno.mappedBy() ); - assertEquals( void.class, relAnno.targetEntity() ); - } - - @Test - public void testOrderBy() throws Exception { - reader = getReader( Entity2.class, "field1", "many-to-many.orm2.xml" ); - assertAnnotationPresent( ManyToMany.class ); - assertAnnotationPresent( OrderBy.class ); - assertAnnotationNotPresent( OrderColumn.class ); - assertEquals( - "col1 ASC, col2 DESC", reader.getAnnotation( OrderBy.class ) - .value() - ); - } - - @Test - public void testOrderColumnNoAttributes() throws Exception { - reader = getReader( Entity2.class, "field1", "many-to-many.orm3.xml" ); - assertAnnotationPresent( ManyToMany.class ); - assertAnnotationNotPresent( OrderBy.class ); - assertAnnotationPresent( OrderColumn.class ); - OrderColumn orderColumnAnno = reader.getAnnotation( OrderColumn.class ); - assertEquals( "", orderColumnAnno.columnDefinition() ); - assertEquals( "", orderColumnAnno.name() ); - assertTrue( orderColumnAnno.insertable() ); - assertTrue( orderColumnAnno.nullable() ); - assertTrue( orderColumnAnno.updatable() ); - } - - @Test - public void testOrderColumnAllAttributes() throws Exception { - reader = getReader( Entity2.class, "field1", "many-to-many.orm4.xml" ); - assertAnnotationPresent( ManyToMany.class ); - assertAnnotationNotPresent( OrderBy.class ); - assertAnnotationPresent( OrderColumn.class ); - OrderColumn orderColumnAnno = reader.getAnnotation( OrderColumn.class ); - assertEquals( "int", orderColumnAnno.columnDefinition() ); - assertEquals( "col1", orderColumnAnno.name() ); - assertFalse( orderColumnAnno.insertable() ); - assertFalse( orderColumnAnno.nullable() ); - assertFalse( orderColumnAnno.updatable() ); - } - - @Test - public void testMapKeyNoAttributes() throws Exception { - reader = getReader( Entity3.class, "field1", "many-to-many.orm5.xml" ); - assertAnnotationPresent( ManyToMany.class ); - assertAnnotationPresent( MapKey.class ); - assertAnnotationNotPresent( MapKeyClass.class ); - assertAnnotationNotPresent( MapKeyTemporal.class ); - assertAnnotationNotPresent( MapKeyEnumerated.class ); - assertAnnotationNotPresent( MapKeyColumn.class ); - assertAnnotationNotPresent( MapKeyJoinColumns.class ); - assertAnnotationNotPresent( MapKeyJoinColumn.class ); - assertEquals( "", reader.getAnnotation( MapKey.class ).name() ); - } - - @Test - public void testMapKeyAllAttributes() throws Exception { - reader = getReader( Entity3.class, "field1", "many-to-many.orm6.xml" ); - assertAnnotationPresent( ManyToMany.class ); - assertAnnotationPresent( MapKey.class ); - assertAnnotationNotPresent( MapKeyClass.class ); - assertAnnotationNotPresent( MapKeyTemporal.class ); - assertAnnotationNotPresent( MapKeyEnumerated.class ); - assertAnnotationNotPresent( MapKeyColumn.class ); - assertAnnotationNotPresent( MapKeyJoinColumns.class ); - assertAnnotationNotPresent( MapKeyJoinColumn.class ); - assertEquals( "field2", reader.getAnnotation( MapKey.class ).name() ); - } - - @Test - public void testMapKeyClass() throws Exception { - reader = getReader( Entity3.class, "field1", "many-to-many.orm7.xml" ); - assertAnnotationPresent( ManyToMany.class ); - assertAnnotationNotPresent( MapKey.class ); - assertAnnotationPresent( MapKeyClass.class ); - assertAnnotationNotPresent( MapKeyTemporal.class ); - assertAnnotationNotPresent( MapKeyEnumerated.class ); - assertAnnotationNotPresent( MapKeyColumn.class ); - assertAnnotationNotPresent( MapKeyJoinColumns.class ); - assertAnnotationNotPresent( MapKeyJoinColumn.class ); - assertEquals( - Entity2.class, reader.getAnnotation( MapKeyClass.class ) - .value() - ); - } - - @Test - public void testMapKeyTemporal() throws Exception { - reader = getReader( Entity3.class, "field1", "many-to-many.orm8.xml" ); - assertAnnotationPresent( ManyToMany.class ); - assertAnnotationNotPresent( MapKey.class ); - assertAnnotationNotPresent( MapKeyClass.class ); - assertAnnotationPresent( MapKeyTemporal.class ); - assertAnnotationNotPresent( MapKeyEnumerated.class ); - assertAnnotationNotPresent( MapKeyColumn.class ); - assertAnnotationNotPresent( MapKeyJoinColumns.class ); - assertAnnotationNotPresent( MapKeyJoinColumn.class ); - assertEquals( - TemporalType.DATE, reader.getAnnotation( - MapKeyTemporal.class - ).value() - ); - } - - @Test - public void testMapKeyEnumerated() throws Exception { - reader = getReader( Entity3.class, "field1", "many-to-many.orm9.xml" ); - assertAnnotationPresent( ManyToMany.class ); - assertAnnotationNotPresent( MapKey.class ); - assertAnnotationNotPresent( MapKeyClass.class ); - assertAnnotationNotPresent( MapKeyTemporal.class ); - assertAnnotationPresent( MapKeyEnumerated.class ); - assertAnnotationNotPresent( MapKeyColumn.class ); - assertAnnotationNotPresent( MapKeyJoinColumns.class ); - assertAnnotationNotPresent( MapKeyJoinColumn.class ); - assertEquals( - EnumType.STRING, reader.getAnnotation( - MapKeyEnumerated.class - ).value() - ); - } - - /** - * When there's a single map key attribute override, we still wrap it with - * an AttributeOverrides annotation. - */ - @Test - public void testSingleMapKeyAttributeOverride() throws Exception { - reader = getReader( Entity3.class, "field1", "many-to-many.orm10.xml" ); - assertAnnotationPresent( ManyToMany.class ); - assertAnnotationNotPresent( MapKey.class ); - assertAnnotationNotPresent( MapKeyClass.class ); - assertAnnotationNotPresent( MapKeyTemporal.class ); - assertAnnotationNotPresent( MapKeyEnumerated.class ); - assertAnnotationNotPresent( MapKeyColumn.class ); - assertAnnotationNotPresent( MapKeyJoinColumns.class ); - assertAnnotationNotPresent( MapKeyJoinColumn.class ); - assertAnnotationNotPresent( AttributeOverride.class ); - assertAnnotationPresent( AttributeOverrides.class ); - AttributeOverrides overridesAnno = reader - .getAnnotation( AttributeOverrides.class ); - AttributeOverride[] overrides = overridesAnno.value(); - assertEquals( 1, overrides.length ); - assertEquals( "field1", overrides[0].name() ); - assertEquals( "col1", overrides[0].column().name() ); - } - - @Test - public void testMultipleMapKeyAttributeOverrides() throws Exception { - reader = getReader( Entity3.class, "field1", "many-to-many.orm11.xml" ); - assertAnnotationPresent( ManyToMany.class ); - assertAnnotationNotPresent( MapKey.class ); - assertAnnotationNotPresent( MapKeyClass.class ); - assertAnnotationNotPresent( MapKeyTemporal.class ); - assertAnnotationNotPresent( MapKeyEnumerated.class ); - assertAnnotationNotPresent( MapKeyColumn.class ); - assertAnnotationNotPresent( MapKeyJoinColumns.class ); - assertAnnotationNotPresent( MapKeyJoinColumn.class ); - assertAnnotationNotPresent( AttributeOverride.class ); - assertAnnotationPresent( AttributeOverrides.class ); - AttributeOverrides overridesAnno = reader - .getAnnotation( AttributeOverrides.class ); - AttributeOverride[] overrides = overridesAnno.value(); - assertEquals( 2, overrides.length ); - assertEquals( "field1", overrides[0].name() ); - assertEquals( "", overrides[0].column().name() ); - assertFalse( overrides[0].column().unique() ); - assertTrue( overrides[0].column().nullable() ); - assertTrue( overrides[0].column().insertable() ); - assertTrue( overrides[0].column().updatable() ); - assertEquals( "", overrides[0].column().columnDefinition() ); - assertEquals( "", overrides[0].column().table() ); - assertEquals( 255, overrides[0].column().length() ); - assertEquals( 0, overrides[0].column().precision() ); - assertEquals( 0, overrides[0].column().scale() ); - assertEquals( "field2", overrides[1].name() ); - assertEquals( "col1", overrides[1].column().name() ); - assertTrue( overrides[1].column().unique() ); - assertFalse( overrides[1].column().nullable() ); - assertFalse( overrides[1].column().insertable() ); - assertFalse( overrides[1].column().updatable() ); - assertEquals( "int", overrides[1].column().columnDefinition() ); - assertEquals( "table1", overrides[1].column().table() ); - assertEquals( 50, overrides[1].column().length() ); - assertEquals( 2, overrides[1].column().precision() ); - assertEquals( 1, overrides[1].column().scale() ); - } - - @Test - public void testMapKeyColumnNoAttributes() throws Exception { - reader = getReader( Entity3.class, "field1", "many-to-many.orm12.xml" ); - assertAnnotationPresent( ManyToMany.class ); - assertAnnotationNotPresent( MapKey.class ); - assertAnnotationNotPresent( MapKeyClass.class ); - assertAnnotationNotPresent( MapKeyTemporal.class ); - assertAnnotationNotPresent( MapKeyEnumerated.class ); - assertAnnotationPresent( MapKeyColumn.class ); - assertAnnotationNotPresent( MapKeyJoinColumns.class ); - assertAnnotationNotPresent( MapKeyJoinColumn.class ); - MapKeyColumn keyColAnno = reader.getAnnotation( MapKeyColumn.class ); - assertEquals( "", keyColAnno.columnDefinition() ); - assertEquals( "", keyColAnno.name() ); - assertEquals( "", keyColAnno.table() ); - assertFalse( keyColAnno.nullable() ); - assertTrue( keyColAnno.insertable() ); - assertFalse( keyColAnno.unique() ); - assertTrue( keyColAnno.updatable() ); - assertEquals( 255, keyColAnno.length() ); - assertEquals( 0, keyColAnno.precision() ); - assertEquals( 0, keyColAnno.scale() ); - } - - @Test - public void testMapKeyColumnAllAttributes() throws Exception { - reader = getReader( Entity3.class, "field1", "many-to-many.orm13.xml" ); - assertAnnotationPresent( ManyToMany.class ); - assertAnnotationNotPresent( MapKey.class ); - assertAnnotationNotPresent( MapKeyClass.class ); - assertAnnotationNotPresent( MapKeyTemporal.class ); - assertAnnotationNotPresent( MapKeyEnumerated.class ); - assertAnnotationPresent( MapKeyColumn.class ); - assertAnnotationNotPresent( MapKeyJoinColumns.class ); - assertAnnotationNotPresent( MapKeyJoinColumn.class ); - MapKeyColumn keyColAnno = reader.getAnnotation( MapKeyColumn.class ); - assertEquals( "int", keyColAnno.columnDefinition() ); - assertEquals( "col1", keyColAnno.name() ); - assertEquals( "table1", keyColAnno.table() ); - assertTrue( keyColAnno.nullable() ); - assertFalse( keyColAnno.insertable() ); - assertTrue( keyColAnno.unique() ); - assertFalse( keyColAnno.updatable() ); - assertEquals( 50, keyColAnno.length() ); - assertEquals( 2, keyColAnno.precision() ); - assertEquals( 1, keyColAnno.scale() ); - } - - /** - * When there's a single map key join column, we still wrap it with a - * MapKeyJoinColumns annotation. - */ - @Test - public void testSingleMapKeyJoinColumn() throws Exception { - reader = getReader( Entity3.class, "field1", "many-to-many.orm14.xml" ); - assertAnnotationPresent( ManyToMany.class ); - assertAnnotationNotPresent( MapKey.class ); - assertAnnotationNotPresent( MapKeyClass.class ); - assertAnnotationNotPresent( MapKeyTemporal.class ); - assertAnnotationNotPresent( MapKeyEnumerated.class ); - assertAnnotationNotPresent( MapKeyColumn.class ); - assertAnnotationPresent( MapKeyJoinColumns.class ); - assertAnnotationNotPresent( MapKeyJoinColumn.class ); - MapKeyJoinColumns joinColumnsAnno = reader - .getAnnotation( MapKeyJoinColumns.class ); - MapKeyJoinColumn[] joinColumns = joinColumnsAnno.value(); - assertEquals( 1, joinColumns.length ); - assertEquals( "col1", joinColumns[0].name() ); - } - - @Test - public void testMultipleMapKeyJoinColumns() throws Exception { - reader = getReader( Entity3.class, "field1", "many-to-many.orm15.xml" ); - assertAnnotationPresent( ManyToMany.class ); - assertAnnotationNotPresent( MapKey.class ); - assertAnnotationNotPresent( MapKeyClass.class ); - assertAnnotationNotPresent( MapKeyTemporal.class ); - assertAnnotationNotPresent( MapKeyEnumerated.class ); - assertAnnotationNotPresent( MapKeyColumn.class ); - assertAnnotationPresent( MapKeyJoinColumns.class ); - assertAnnotationNotPresent( MapKeyJoinColumn.class ); - MapKeyJoinColumns joinColumnsAnno = reader - .getAnnotation( MapKeyJoinColumns.class ); - MapKeyJoinColumn[] joinColumns = joinColumnsAnno.value(); - assertEquals( 2, joinColumns.length ); - assertEquals( "", joinColumns[0].name() ); - assertEquals( "", joinColumns[0].referencedColumnName() ); - assertFalse( joinColumns[0].unique() ); - assertFalse( joinColumns[0].nullable() ); - assertTrue( joinColumns[0].insertable() ); - assertTrue( joinColumns[0].updatable() ); - assertEquals( "", joinColumns[0].columnDefinition() ); - assertEquals( "", joinColumns[0].table() ); - assertEquals( "col1", joinColumns[1].name() ); - assertEquals( "col2", joinColumns[1].referencedColumnName() ); - assertTrue( joinColumns[1].unique() ); - assertTrue( joinColumns[1].nullable() ); - assertFalse( joinColumns[1].insertable() ); - assertFalse( joinColumns[1].updatable() ); - assertEquals( "int", joinColumns[1].columnDefinition() ); - assertEquals( "table1", joinColumns[1].table() ); - } - - @Test - public void testJoinTableNoChildren() throws Exception { - reader = getReader( Entity2.class, "field1", "many-to-many.orm16.xml" ); - assertAnnotationPresent( ManyToMany.class ); - assertAnnotationPresent( JoinTable.class ); - assertAnnotationNotPresent( JoinColumns.class ); - assertAnnotationNotPresent( JoinColumn.class ); - JoinTable joinTableAnno = reader.getAnnotation( JoinTable.class ); - assertEquals( "", joinTableAnno.catalog() ); - assertEquals( "", joinTableAnno.name() ); - assertEquals( "", joinTableAnno.schema() ); - assertEquals( 0, joinTableAnno.joinColumns().length ); - assertEquals( 0, joinTableAnno.inverseJoinColumns().length ); - assertEquals( 0, joinTableAnno.uniqueConstraints().length ); - } - - @Test - public void testJoinTableAllChildren() throws Exception { - reader = getReader( Entity2.class, "field1", "many-to-many.orm17.xml" ); - assertAnnotationPresent( ManyToMany.class ); - assertAnnotationPresent( JoinTable.class ); - assertAnnotationNotPresent( JoinColumns.class ); - assertAnnotationNotPresent( JoinColumn.class ); - JoinTable joinTableAnno = reader.getAnnotation( JoinTable.class ); - assertEquals( "cat1", joinTableAnno.catalog() ); - assertEquals( "table1", joinTableAnno.name() ); - assertEquals( "schema1", joinTableAnno.schema() ); - - // JoinColumns - JoinColumn[] joinColumns = joinTableAnno.joinColumns(); - assertEquals( 2, joinColumns.length ); - assertEquals( "", joinColumns[0].name() ); - assertEquals( "", joinColumns[0].referencedColumnName() ); - assertEquals( "", joinColumns[0].table() ); - assertEquals( "", joinColumns[0].columnDefinition() ); - assertTrue( joinColumns[0].insertable() ); - assertTrue( joinColumns[0].updatable() ); - assertTrue( joinColumns[0].nullable() ); - assertFalse( joinColumns[0].unique() ); - assertEquals( "col1", joinColumns[1].name() ); - assertEquals( "col2", joinColumns[1].referencedColumnName() ); - assertEquals( "table2", joinColumns[1].table() ); - assertEquals( "int", joinColumns[1].columnDefinition() ); - assertFalse( joinColumns[1].insertable() ); - assertFalse( joinColumns[1].updatable() ); - assertFalse( joinColumns[1].nullable() ); - assertTrue( joinColumns[1].unique() ); - - // InverseJoinColumns - JoinColumn[] inverseJoinColumns = joinTableAnno.inverseJoinColumns(); - assertEquals( 2, inverseJoinColumns.length ); - assertEquals( "", inverseJoinColumns[0].name() ); - assertEquals( "", inverseJoinColumns[0].referencedColumnName() ); - assertEquals( "", inverseJoinColumns[0].table() ); - assertEquals( "", inverseJoinColumns[0].columnDefinition() ); - assertTrue( inverseJoinColumns[0].insertable() ); - assertTrue( inverseJoinColumns[0].updatable() ); - assertTrue( inverseJoinColumns[0].nullable() ); - assertFalse( inverseJoinColumns[0].unique() ); - assertEquals( "col3", inverseJoinColumns[1].name() ); - assertEquals( "col4", inverseJoinColumns[1].referencedColumnName() ); - assertEquals( "table3", inverseJoinColumns[1].table() ); - assertEquals( "int", inverseJoinColumns[1].columnDefinition() ); - assertFalse( inverseJoinColumns[1].insertable() ); - assertFalse( inverseJoinColumns[1].updatable() ); - assertFalse( inverseJoinColumns[1].nullable() ); - assertTrue( inverseJoinColumns[1].unique() ); - - // UniqueConstraints - UniqueConstraint[] uniqueConstraints = joinTableAnno - .uniqueConstraints(); - assertEquals( 2, uniqueConstraints.length ); - assertEquals( "", uniqueConstraints[0].name() ); - assertEquals( 1, uniqueConstraints[0].columnNames().length ); - assertEquals( "col5", uniqueConstraints[0].columnNames()[0] ); - assertEquals( "uq1", uniqueConstraints[1].name() ); - assertEquals( 2, uniqueConstraints[1].columnNames().length ); - assertEquals( "col6", uniqueConstraints[1].columnNames()[0] ); - assertEquals( "col7", uniqueConstraints[1].columnNames()[1] ); - } - - @Test - public void testCascadeAll() throws Exception { - reader = getReader( Entity2.class, "field1", "many-to-many.orm18.xml" ); - assertAnnotationPresent( ManyToMany.class ); - ManyToMany relAnno = reader.getAnnotation( ManyToMany.class ); - assertEquals( 1, relAnno.cascade().length ); - assertEquals( CascadeType.ALL, relAnno.cascade()[0] ); - } - - @Test - public void testCascadeSomeWithDefaultPersist() throws Exception { - reader = getReader( Entity2.class, "field1", "many-to-many.orm19.xml" ); - assertAnnotationPresent( ManyToMany.class ); - ManyToMany relAnno = reader.getAnnotation( ManyToMany.class ); - assertEquals( 4, relAnno.cascade().length ); - assertEquals( CascadeType.REMOVE, relAnno.cascade()[0] ); - assertEquals( CascadeType.REFRESH, relAnno.cascade()[1] ); - assertEquals( CascadeType.DETACH, relAnno.cascade()[2] ); - assertEquals( CascadeType.PERSIST, relAnno.cascade()[3] ); - } - - /** - * Make sure that it doesn't break the handler when {@link CascadeType#ALL} - * is specified in addition to a default cascade-persist or individual - * cascade settings. - */ - @Test - public void testCascadeAllPlusMore() throws Exception { - reader = getReader( Entity2.class, "field1", "many-to-many.orm20.xml" ); - assertAnnotationPresent( ManyToMany.class ); - ManyToMany relAnno = reader.getAnnotation( ManyToMany.class ); - assertEquals( 6, relAnno.cascade().length ); - assertEquals( CascadeType.ALL, relAnno.cascade()[0] ); - assertEquals( CascadeType.PERSIST, relAnno.cascade()[1] ); - assertEquals( CascadeType.MERGE, relAnno.cascade()[2] ); - assertEquals( CascadeType.REMOVE, relAnno.cascade()[3] ); - assertEquals( CascadeType.REFRESH, relAnno.cascade()[4] ); - assertEquals( CascadeType.DETACH, relAnno.cascade()[5] ); - } - - @Test - public void testAllAttributes() throws Exception { - reader = getReader( Entity2.class, "field1", "many-to-many.orm21.xml" ); - assertAnnotationPresent( ManyToMany.class ); - assertAnnotationNotPresent( OrderBy.class ); - assertAnnotationNotPresent( OrderColumn.class ); - assertAnnotationNotPresent( MapKey.class ); - assertAnnotationNotPresent( MapKeyClass.class ); - assertAnnotationNotPresent( MapKeyTemporal.class ); - assertAnnotationNotPresent( MapKeyEnumerated.class ); - assertAnnotationNotPresent( MapKeyColumn.class ); - assertAnnotationNotPresent( MapKeyJoinColumns.class ); - assertAnnotationNotPresent( MapKeyJoinColumn.class ); - assertAnnotationNotPresent( JoinTable.class ); - assertAnnotationPresent( Access.class ); - ManyToMany relAnno = reader.getAnnotation( ManyToMany.class ); - assertEquals( 0, relAnno.cascade().length ); - assertEquals( FetchType.EAGER, relAnno.fetch() ); - assertEquals( "field2", relAnno.mappedBy() ); - assertEquals( Entity3.class, relAnno.targetEntity() ); - assertEquals( - AccessType.PROPERTY, reader.getAnnotation( Access.class ) - .value() - ); - } - -} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlManyToOneTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlManyToOneTest.java deleted file mode 100644 index e665be4f2ef4..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlManyToOneTest.java +++ /dev/null @@ -1,245 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.annotations.xml.ejb3; - -import javax.persistence.Access; -import javax.persistence.AccessType; -import javax.persistence.CascadeType; -import javax.persistence.FetchType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.JoinColumns; -import javax.persistence.JoinTable; -import javax.persistence.ManyToOne; -import javax.persistence.MapsId; -import javax.persistence.UniqueConstraint; - -import org.hibernate.cfg.annotations.reflection.JPAOverriddenAnnotationReader; - -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -/** - * Equivalent to {@link org.hibernate.test.annotations.xml.ejb3.Ejb3XmlManyToOneTest} - * for the legacy {@link JPAOverriddenAnnotationReader}. - * - * @author Emmanuel Bernard - * @deprecated This test will be removed in Hibernate ORM 6, along with the legacy {@link JPAOverriddenAnnotationReader}. - */ -@Deprecated -public class LegacyEjb3XmlManyToOneTest extends LegacyEjb3XmlTestCase { - @Test - public void testNoJoins() throws Exception { - reader = getReader( Entity1.class, "field1", "many-to-one.orm1.xml" ); - assertAnnotationPresent( ManyToOne.class ); - assertAnnotationNotPresent( JoinColumn.class ); - assertAnnotationNotPresent( JoinColumns.class ); - assertAnnotationNotPresent( JoinTable.class ); - assertAnnotationNotPresent( Id.class ); - assertAnnotationNotPresent( MapsId.class ); - assertAnnotationNotPresent( Access.class ); - ManyToOne relAnno = reader.getAnnotation( ManyToOne.class ); - assertEquals( 0, relAnno.cascade().length ); - assertEquals( FetchType.EAGER, relAnno.fetch() ); - assertTrue( relAnno.optional() ); - assertEquals( void.class, relAnno.targetEntity() ); - } - - /** - * When there's a single join column, we still wrap it with a JoinColumns - * annotation. - */ - @Test - public void testSingleJoinColumn() throws Exception { - reader = getReader( Entity1.class, "field1", "many-to-one.orm2.xml" ); - assertAnnotationPresent( ManyToOne.class ); - assertAnnotationNotPresent( JoinColumn.class ); - assertAnnotationPresent( JoinColumns.class ); - assertAnnotationNotPresent( JoinTable.class ); - JoinColumns joinColumnsAnno = reader.getAnnotation( JoinColumns.class ); - JoinColumn[] joinColumns = joinColumnsAnno.value(); - assertEquals( 1, joinColumns.length ); - assertEquals( "col1", joinColumns[0].name() ); - assertEquals( "col2", joinColumns[0].referencedColumnName() ); - assertEquals( "table1", joinColumns[0].table() ); - } - - @Test - public void testMultipleJoinColumns() throws Exception { - reader = getReader( Entity1.class, "field1", "many-to-one.orm3.xml" ); - assertAnnotationPresent( ManyToOne.class ); - assertAnnotationNotPresent( JoinColumn.class ); - assertAnnotationPresent( JoinColumns.class ); - assertAnnotationNotPresent( JoinTable.class ); - JoinColumns joinColumnsAnno = reader.getAnnotation( JoinColumns.class ); - JoinColumn[] joinColumns = joinColumnsAnno.value(); - assertEquals( 2, joinColumns.length ); - assertEquals( "", joinColumns[0].name() ); - assertEquals( "", joinColumns[0].referencedColumnName() ); - assertEquals( "", joinColumns[0].table() ); - assertEquals( "", joinColumns[0].columnDefinition() ); - assertTrue( joinColumns[0].insertable() ); - assertTrue( joinColumns[0].updatable() ); - assertTrue( joinColumns[0].nullable() ); - assertFalse( joinColumns[0].unique() ); - assertEquals( "col1", joinColumns[1].name() ); - assertEquals( "col2", joinColumns[1].referencedColumnName() ); - assertEquals( "table1", joinColumns[1].table() ); - assertEquals( "int", joinColumns[1].columnDefinition() ); - assertFalse( joinColumns[1].insertable() ); - assertFalse( joinColumns[1].updatable() ); - assertFalse( joinColumns[1].nullable() ); - assertTrue( joinColumns[1].unique() ); - } - - @Test - public void testJoinTableNoChildren() throws Exception { - reader = getReader( Entity1.class, "field1", "many-to-one.orm4.xml" ); - assertAnnotationPresent( ManyToOne.class ); - assertAnnotationNotPresent( JoinColumn.class ); - assertAnnotationNotPresent( JoinColumns.class ); - assertAnnotationPresent( JoinTable.class ); - JoinTable joinTableAnno = reader.getAnnotation( JoinTable.class ); - assertEquals( "", joinTableAnno.catalog() ); - assertEquals( "", joinTableAnno.name() ); - assertEquals( "", joinTableAnno.schema() ); - assertEquals( 0, joinTableAnno.joinColumns().length ); - assertEquals( 0, joinTableAnno.inverseJoinColumns().length ); - assertEquals( 0, joinTableAnno.uniqueConstraints().length ); - } - - @Test - public void testJoinTableAllChildren() throws Exception { - reader = getReader( Entity1.class, "field1", "many-to-one.orm5.xml" ); - assertAnnotationPresent( ManyToOne.class ); - assertAnnotationNotPresent( JoinColumn.class ); - assertAnnotationNotPresent( JoinColumns.class ); - assertAnnotationPresent( JoinTable.class ); - JoinTable joinTableAnno = reader.getAnnotation( JoinTable.class ); - assertEquals( "cat1", joinTableAnno.catalog() ); - assertEquals( "table1", joinTableAnno.name() ); - assertEquals( "schema1", joinTableAnno.schema() ); - - // JoinColumns - JoinColumn[] joinColumns = joinTableAnno.joinColumns(); - assertEquals( 2, joinColumns.length ); - assertEquals( "", joinColumns[0].name() ); - assertEquals( "", joinColumns[0].referencedColumnName() ); - assertEquals( "", joinColumns[0].table() ); - assertEquals( "", joinColumns[0].columnDefinition() ); - assertTrue( joinColumns[0].insertable() ); - assertTrue( joinColumns[0].updatable() ); - assertTrue( joinColumns[0].nullable() ); - assertFalse( joinColumns[0].unique() ); - assertEquals( "col1", joinColumns[1].name() ); - assertEquals( "col2", joinColumns[1].referencedColumnName() ); - assertEquals( "table2", joinColumns[1].table() ); - assertEquals( "int", joinColumns[1].columnDefinition() ); - assertFalse( joinColumns[1].insertable() ); - assertFalse( joinColumns[1].updatable() ); - assertFalse( joinColumns[1].nullable() ); - assertTrue( joinColumns[1].unique() ); - - // InverseJoinColumns - JoinColumn[] inverseJoinColumns = joinTableAnno.inverseJoinColumns(); - assertEquals( 2, inverseJoinColumns.length ); - assertEquals( "", inverseJoinColumns[0].name() ); - assertEquals( "", inverseJoinColumns[0].referencedColumnName() ); - assertEquals( "", inverseJoinColumns[0].table() ); - assertEquals( "", inverseJoinColumns[0].columnDefinition() ); - assertTrue( inverseJoinColumns[0].insertable() ); - assertTrue( inverseJoinColumns[0].updatable() ); - assertTrue( inverseJoinColumns[0].nullable() ); - assertFalse( inverseJoinColumns[0].unique() ); - assertEquals( "col3", inverseJoinColumns[1].name() ); - assertEquals( "col4", inverseJoinColumns[1].referencedColumnName() ); - assertEquals( "table3", inverseJoinColumns[1].table() ); - assertEquals( "int", inverseJoinColumns[1].columnDefinition() ); - assertFalse( inverseJoinColumns[1].insertable() ); - assertFalse( inverseJoinColumns[1].updatable() ); - assertFalse( inverseJoinColumns[1].nullable() ); - assertTrue( inverseJoinColumns[1].unique() ); - - // UniqueConstraints - UniqueConstraint[] uniqueConstraints = joinTableAnno - .uniqueConstraints(); - assertEquals( 2, uniqueConstraints.length ); - assertEquals( "", uniqueConstraints[0].name() ); - assertEquals( 1, uniqueConstraints[0].columnNames().length ); - assertEquals( "col5", uniqueConstraints[0].columnNames()[0] ); - assertEquals( "uq1", uniqueConstraints[1].name() ); - assertEquals( 2, uniqueConstraints[1].columnNames().length ); - assertEquals( "col6", uniqueConstraints[1].columnNames()[0] ); - assertEquals( "col7", uniqueConstraints[1].columnNames()[1] ); - } - - @Test - public void testAllAttributes() throws Exception { - reader = getReader( Entity1.class, "field1", "many-to-one.orm6.xml" ); - assertAnnotationPresent( ManyToOne.class ); - assertAnnotationNotPresent( JoinColumn.class ); - assertAnnotationNotPresent( JoinColumns.class ); - assertAnnotationNotPresent( JoinTable.class ); - assertAnnotationPresent( Id.class ); - assertAnnotationPresent( MapsId.class ); - assertAnnotationPresent( Access.class ); - ManyToOne relAnno = reader.getAnnotation( ManyToOne.class ); - assertEquals( 0, relAnno.cascade().length ); - assertEquals( FetchType.LAZY, relAnno.fetch() ); - assertFalse( relAnno.optional() ); - assertEquals( Entity3.class, relAnno.targetEntity() ); - assertEquals( "col1", reader.getAnnotation( MapsId.class ).value() ); - assertEquals( - AccessType.PROPERTY, reader.getAnnotation( Access.class ) - .value() - ); - } - - @Test - public void testCascadeAll() throws Exception { - reader = getReader( Entity1.class, "field1", "many-to-one.orm7.xml" ); - assertAnnotationPresent( ManyToOne.class ); - ManyToOne relAnno = reader.getAnnotation( ManyToOne.class ); - assertEquals( 1, relAnno.cascade().length ); - assertEquals( CascadeType.ALL, relAnno.cascade()[0] ); - } - - @Test - public void testCascadeSomeWithDefaultPersist() throws Exception { - reader = getReader( Entity1.class, "field1", "many-to-one.orm8.xml" ); - assertAnnotationPresent( ManyToOne.class ); - ManyToOne relAnno = reader.getAnnotation( ManyToOne.class ); - assertEquals( 4, relAnno.cascade().length ); - assertEquals( CascadeType.REMOVE, relAnno.cascade()[0] ); - assertEquals( CascadeType.REFRESH, relAnno.cascade()[1] ); - assertEquals( CascadeType.DETACH, relAnno.cascade()[2] ); - assertEquals( CascadeType.PERSIST, relAnno.cascade()[3] ); - } - - /** - * Make sure that it doesn't break the handler when {@link CascadeType#ALL} - * is specified in addition to a default cascade-persist or individual - * cascade settings. - */ - @Test - public void testCascadeAllPlusMore() throws Exception { - reader = getReader( Entity1.class, "field1", "many-to-one.orm9.xml" ); - assertAnnotationPresent( ManyToOne.class ); - ManyToOne relAnno = reader.getAnnotation( ManyToOne.class ); - assertEquals( 6, relAnno.cascade().length ); - assertEquals( CascadeType.ALL, relAnno.cascade()[0] ); - assertEquals( CascadeType.PERSIST, relAnno.cascade()[1] ); - assertEquals( CascadeType.MERGE, relAnno.cascade()[2] ); - assertEquals( CascadeType.REMOVE, relAnno.cascade()[3] ); - assertEquals( CascadeType.REFRESH, relAnno.cascade()[4] ); - assertEquals( CascadeType.DETACH, relAnno.cascade()[5] ); - } - -} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlOneToManyTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlOneToManyTest.java deleted file mode 100644 index b531fabecf21..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlOneToManyTest.java +++ /dev/null @@ -1,561 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.annotations.xml.ejb3; - -import javax.persistence.Access; -import javax.persistence.AccessType; -import javax.persistence.AttributeOverride; -import javax.persistence.AttributeOverrides; -import javax.persistence.CascadeType; -import javax.persistence.EnumType; -import javax.persistence.FetchType; -import javax.persistence.JoinColumn; -import javax.persistence.JoinColumns; -import javax.persistence.JoinTable; -import javax.persistence.MapKey; -import javax.persistence.MapKeyClass; -import javax.persistence.MapKeyColumn; -import javax.persistence.MapKeyEnumerated; -import javax.persistence.MapKeyJoinColumn; -import javax.persistence.MapKeyJoinColumns; -import javax.persistence.MapKeyTemporal; -import javax.persistence.OneToMany; -import javax.persistence.OrderBy; -import javax.persistence.OrderColumn; -import javax.persistence.TemporalType; -import javax.persistence.UniqueConstraint; - -import org.hibernate.cfg.annotations.reflection.JPAOverriddenAnnotationReader; - -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -/** - * Equivalent to {@link org.hibernate.test.annotations.xml.ejb3.Ejb3XmlOneToManyTest} - * for the legacy {@link JPAOverriddenAnnotationReader}. - * - * @author Emmanuel Bernard - * @deprecated This test will be removed in Hibernate ORM 6, along with the legacy {@link JPAOverriddenAnnotationReader}. - */ -@Deprecated -public class LegacyEjb3XmlOneToManyTest extends LegacyEjb3XmlTestCase { - @Test - public void testNoChildren() throws Exception { - reader = getReader( Entity2.class, "field1", "one-to-many.orm1.xml" ); - assertAnnotationPresent( OneToMany.class ); - assertAnnotationNotPresent( OrderBy.class ); - assertAnnotationNotPresent( OrderColumn.class ); - assertAnnotationNotPresent( MapKey.class ); - assertAnnotationNotPresent( MapKeyClass.class ); - assertAnnotationNotPresent( MapKeyTemporal.class ); - assertAnnotationNotPresent( MapKeyEnumerated.class ); - assertAnnotationNotPresent( MapKeyColumn.class ); - assertAnnotationNotPresent( MapKeyJoinColumns.class ); - assertAnnotationNotPresent( MapKeyJoinColumn.class ); - assertAnnotationNotPresent( JoinTable.class ); - assertAnnotationNotPresent( JoinColumns.class ); - assertAnnotationNotPresent( JoinColumn.class ); - assertAnnotationNotPresent( Access.class ); - OneToMany relAnno = reader.getAnnotation( OneToMany.class ); - assertEquals( 0, relAnno.cascade().length ); - assertEquals( FetchType.LAZY, relAnno.fetch() ); - assertEquals( "", relAnno.mappedBy() ); - assertFalse( relAnno.orphanRemoval() ); - assertEquals( void.class, relAnno.targetEntity() ); - } - - @Test - public void testOrderBy() throws Exception { - reader = getReader( Entity2.class, "field1", "one-to-many.orm2.xml" ); - assertAnnotationPresent( OneToMany.class ); - assertAnnotationPresent( OrderBy.class ); - assertAnnotationNotPresent( OrderColumn.class ); - assertEquals( - "col1 ASC, col2 DESC", reader.getAnnotation( OrderBy.class ) - .value() - ); - } - - @Test - public void testOrderColumnNoAttributes() throws Exception { - reader = getReader( Entity2.class, "field1", "one-to-many.orm3.xml" ); - assertAnnotationPresent( OneToMany.class ); - assertAnnotationNotPresent( OrderBy.class ); - assertAnnotationPresent( OrderColumn.class ); - OrderColumn orderColumnAnno = reader.getAnnotation( OrderColumn.class ); - assertEquals( "", orderColumnAnno.columnDefinition() ); - assertEquals( "", orderColumnAnno.name() ); - assertTrue( orderColumnAnno.insertable() ); - assertTrue( orderColumnAnno.nullable() ); - assertTrue( orderColumnAnno.updatable() ); - } - - @Test - public void testOrderColumnAllAttributes() throws Exception { - reader = getReader( Entity2.class, "field1", "one-to-many.orm4.xml" ); - assertAnnotationPresent( OneToMany.class ); - assertAnnotationNotPresent( OrderBy.class ); - assertAnnotationPresent( OrderColumn.class ); - OrderColumn orderColumnAnno = reader.getAnnotation( OrderColumn.class ); - assertEquals( "int", orderColumnAnno.columnDefinition() ); - assertEquals( "col1", orderColumnAnno.name() ); - assertFalse( orderColumnAnno.insertable() ); - assertFalse( orderColumnAnno.nullable() ); - assertFalse( orderColumnAnno.updatable() ); - } - - @Test - public void testMapKeyNoAttributes() throws Exception { - reader = getReader( Entity3.class, "field1", "one-to-many.orm5.xml" ); - assertAnnotationPresent( OneToMany.class ); - assertAnnotationPresent( MapKey.class ); - assertAnnotationNotPresent( MapKeyClass.class ); - assertAnnotationNotPresent( MapKeyTemporal.class ); - assertAnnotationNotPresent( MapKeyEnumerated.class ); - assertAnnotationNotPresent( MapKeyColumn.class ); - assertAnnotationNotPresent( MapKeyJoinColumns.class ); - assertAnnotationNotPresent( MapKeyJoinColumn.class ); - assertEquals( "", reader.getAnnotation( MapKey.class ).name() ); - } - - @Test - public void testMapKeyAllAttributes() throws Exception { - reader = getReader( Entity3.class, "field1", "one-to-many.orm6.xml" ); - assertAnnotationPresent( OneToMany.class ); - assertAnnotationPresent( MapKey.class ); - assertAnnotationNotPresent( MapKeyClass.class ); - assertAnnotationNotPresent( MapKeyTemporal.class ); - assertAnnotationNotPresent( MapKeyEnumerated.class ); - assertAnnotationNotPresent( MapKeyColumn.class ); - assertAnnotationNotPresent( MapKeyJoinColumns.class ); - assertAnnotationNotPresent( MapKeyJoinColumn.class ); - assertEquals( "field2", reader.getAnnotation( MapKey.class ).name() ); - } - - @Test - public void testMapKeyClass() throws Exception { - reader = getReader( Entity3.class, "field1", "one-to-many.orm7.xml" ); - assertAnnotationPresent( OneToMany.class ); - assertAnnotationNotPresent( MapKey.class ); - assertAnnotationPresent( MapKeyClass.class ); - assertAnnotationNotPresent( MapKeyTemporal.class ); - assertAnnotationNotPresent( MapKeyEnumerated.class ); - assertAnnotationNotPresent( MapKeyColumn.class ); - assertAnnotationNotPresent( MapKeyJoinColumns.class ); - assertAnnotationNotPresent( MapKeyJoinColumn.class ); - assertEquals( - Entity2.class, reader.getAnnotation( MapKeyClass.class ) - .value() - ); - } - - @Test - public void testMapKeyTemporal() throws Exception { - reader = getReader( Entity3.class, "field1", "one-to-many.orm8.xml" ); - assertAnnotationPresent( OneToMany.class ); - assertAnnotationNotPresent( MapKey.class ); - assertAnnotationNotPresent( MapKeyClass.class ); - assertAnnotationPresent( MapKeyTemporal.class ); - assertAnnotationNotPresent( MapKeyEnumerated.class ); - assertAnnotationNotPresent( MapKeyColumn.class ); - assertAnnotationNotPresent( MapKeyJoinColumns.class ); - assertAnnotationNotPresent( MapKeyJoinColumn.class ); - assertEquals( - TemporalType.DATE, reader.getAnnotation( - MapKeyTemporal.class - ).value() - ); - } - - @Test - public void testMapKeyEnumerated() throws Exception { - reader = getReader( Entity3.class, "field1", "one-to-many.orm9.xml" ); - assertAnnotationPresent( OneToMany.class ); - assertAnnotationNotPresent( MapKey.class ); - assertAnnotationNotPresent( MapKeyClass.class ); - assertAnnotationNotPresent( MapKeyTemporal.class ); - assertAnnotationPresent( MapKeyEnumerated.class ); - assertAnnotationNotPresent( MapKeyColumn.class ); - assertAnnotationNotPresent( MapKeyJoinColumns.class ); - assertAnnotationNotPresent( MapKeyJoinColumn.class ); - assertEquals( - EnumType.STRING, reader.getAnnotation( - MapKeyEnumerated.class - ).value() - ); - } - - /** - * When there's a single map key attribute override, we still wrap it with - * an AttributeOverrides annotation. - */ - @Test - public void testSingleMapKeyAttributeOverride() throws Exception { - reader = getReader( Entity3.class, "field1", "one-to-many.orm10.xml" ); - assertAnnotationPresent( OneToMany.class ); - assertAnnotationNotPresent( MapKey.class ); - assertAnnotationNotPresent( MapKeyClass.class ); - assertAnnotationNotPresent( MapKeyTemporal.class ); - assertAnnotationNotPresent( MapKeyEnumerated.class ); - assertAnnotationNotPresent( MapKeyColumn.class ); - assertAnnotationNotPresent( MapKeyJoinColumns.class ); - assertAnnotationNotPresent( MapKeyJoinColumn.class ); - assertAnnotationNotPresent( AttributeOverride.class ); - assertAnnotationPresent( AttributeOverrides.class ); - AttributeOverrides overridesAnno = reader - .getAnnotation( AttributeOverrides.class ); - AttributeOverride[] overrides = overridesAnno.value(); - assertEquals( 1, overrides.length ); - assertEquals( "field1", overrides[0].name() ); - assertEquals( "col1", overrides[0].column().name() ); - } - - @Test - public void testMultipleMapKeyAttributeOverrides() throws Exception { - reader = getReader( Entity3.class, "field1", "one-to-many.orm11.xml" ); - assertAnnotationPresent( OneToMany.class ); - assertAnnotationNotPresent( MapKey.class ); - assertAnnotationNotPresent( MapKeyClass.class ); - assertAnnotationNotPresent( MapKeyTemporal.class ); - assertAnnotationNotPresent( MapKeyEnumerated.class ); - assertAnnotationNotPresent( MapKeyColumn.class ); - assertAnnotationNotPresent( MapKeyJoinColumns.class ); - assertAnnotationNotPresent( MapKeyJoinColumn.class ); - assertAnnotationNotPresent( AttributeOverride.class ); - assertAnnotationPresent( AttributeOverrides.class ); - AttributeOverrides overridesAnno = reader - .getAnnotation( AttributeOverrides.class ); - AttributeOverride[] overrides = overridesAnno.value(); - assertEquals( 2, overrides.length ); - assertEquals( "field1", overrides[0].name() ); - assertEquals( "", overrides[0].column().name() ); - assertFalse( overrides[0].column().unique() ); - assertTrue( overrides[0].column().nullable() ); - assertTrue( overrides[0].column().insertable() ); - assertTrue( overrides[0].column().updatable() ); - assertEquals( "", overrides[0].column().columnDefinition() ); - assertEquals( "", overrides[0].column().table() ); - assertEquals( 255, overrides[0].column().length() ); - assertEquals( 0, overrides[0].column().precision() ); - assertEquals( 0, overrides[0].column().scale() ); - assertEquals( "field2", overrides[1].name() ); - assertEquals( "col1", overrides[1].column().name() ); - assertTrue( overrides[1].column().unique() ); - assertFalse( overrides[1].column().nullable() ); - assertFalse( overrides[1].column().insertable() ); - assertFalse( overrides[1].column().updatable() ); - assertEquals( "int", overrides[1].column().columnDefinition() ); - assertEquals( "table1", overrides[1].column().table() ); - assertEquals( 50, overrides[1].column().length() ); - assertEquals( 2, overrides[1].column().precision() ); - assertEquals( 1, overrides[1].column().scale() ); - } - - @Test - public void testMapKeyColumnNoAttributes() throws Exception { - reader = getReader( Entity3.class, "field1", "one-to-many.orm12.xml" ); - assertAnnotationPresent( OneToMany.class ); - assertAnnotationNotPresent( MapKey.class ); - assertAnnotationNotPresent( MapKeyClass.class ); - assertAnnotationNotPresent( MapKeyTemporal.class ); - assertAnnotationNotPresent( MapKeyEnumerated.class ); - assertAnnotationPresent( MapKeyColumn.class ); - assertAnnotationNotPresent( MapKeyJoinColumns.class ); - assertAnnotationNotPresent( MapKeyJoinColumn.class ); - MapKeyColumn keyColAnno = reader.getAnnotation( MapKeyColumn.class ); - assertEquals( "", keyColAnno.columnDefinition() ); - assertEquals( "", keyColAnno.name() ); - assertEquals( "", keyColAnno.table() ); - assertFalse( keyColAnno.nullable() ); - assertTrue( keyColAnno.insertable() ); - assertFalse( keyColAnno.unique() ); - assertTrue( keyColAnno.updatable() ); - assertEquals( 255, keyColAnno.length() ); - assertEquals( 0, keyColAnno.precision() ); - assertEquals( 0, keyColAnno.scale() ); - } - - @Test - public void testMapKeyColumnAllAttributes() throws Exception { - reader = getReader( Entity3.class, "field1", "one-to-many.orm13.xml" ); - assertAnnotationPresent( OneToMany.class ); - assertAnnotationNotPresent( MapKey.class ); - assertAnnotationNotPresent( MapKeyClass.class ); - assertAnnotationNotPresent( MapKeyTemporal.class ); - assertAnnotationNotPresent( MapKeyEnumerated.class ); - assertAnnotationPresent( MapKeyColumn.class ); - assertAnnotationNotPresent( MapKeyJoinColumns.class ); - assertAnnotationNotPresent( MapKeyJoinColumn.class ); - MapKeyColumn keyColAnno = reader.getAnnotation( MapKeyColumn.class ); - assertEquals( "int", keyColAnno.columnDefinition() ); - assertEquals( "col1", keyColAnno.name() ); - assertEquals( "table1", keyColAnno.table() ); - assertTrue( keyColAnno.nullable() ); - assertFalse( keyColAnno.insertable() ); - assertTrue( keyColAnno.unique() ); - assertFalse( keyColAnno.updatable() ); - assertEquals( 50, keyColAnno.length() ); - assertEquals( 2, keyColAnno.precision() ); - assertEquals( 1, keyColAnno.scale() ); - } - - /** - * When there's a single map key join column, we still wrap it with a - * MapKeyJoinColumns annotation. - */ - @Test - public void testSingleMapKeyJoinColumn() throws Exception { - reader = getReader( Entity3.class, "field1", "one-to-many.orm14.xml" ); - assertAnnotationPresent( OneToMany.class ); - assertAnnotationNotPresent( MapKey.class ); - assertAnnotationNotPresent( MapKeyClass.class ); - assertAnnotationNotPresent( MapKeyTemporal.class ); - assertAnnotationNotPresent( MapKeyEnumerated.class ); - assertAnnotationNotPresent( MapKeyColumn.class ); - assertAnnotationPresent( MapKeyJoinColumns.class ); - assertAnnotationNotPresent( MapKeyJoinColumn.class ); - MapKeyJoinColumns joinColumnsAnno = reader - .getAnnotation( MapKeyJoinColumns.class ); - MapKeyJoinColumn[] joinColumns = joinColumnsAnno.value(); - assertEquals( 1, joinColumns.length ); - assertEquals( "col1", joinColumns[0].name() ); - } - - @Test - public void testMultipleMapKeyJoinColumns() throws Exception { - reader = getReader( Entity3.class, "field1", "one-to-many.orm15.xml" ); - assertAnnotationPresent( OneToMany.class ); - assertAnnotationNotPresent( MapKey.class ); - assertAnnotationNotPresent( MapKeyClass.class ); - assertAnnotationNotPresent( MapKeyTemporal.class ); - assertAnnotationNotPresent( MapKeyEnumerated.class ); - assertAnnotationNotPresent( MapKeyColumn.class ); - assertAnnotationPresent( MapKeyJoinColumns.class ); - assertAnnotationNotPresent( MapKeyJoinColumn.class ); - MapKeyJoinColumns joinColumnsAnno = reader - .getAnnotation( MapKeyJoinColumns.class ); - MapKeyJoinColumn[] joinColumns = joinColumnsAnno.value(); - assertEquals( 2, joinColumns.length ); - assertEquals( "", joinColumns[0].name() ); - assertEquals( "", joinColumns[0].referencedColumnName() ); - assertFalse( joinColumns[0].unique() ); - assertFalse( joinColumns[0].nullable() ); - assertTrue( joinColumns[0].insertable() ); - assertTrue( joinColumns[0].updatable() ); - assertEquals( "", joinColumns[0].columnDefinition() ); - assertEquals( "", joinColumns[0].table() ); - assertEquals( "col1", joinColumns[1].name() ); - assertEquals( "col2", joinColumns[1].referencedColumnName() ); - assertTrue( joinColumns[1].unique() ); - assertTrue( joinColumns[1].nullable() ); - assertFalse( joinColumns[1].insertable() ); - assertFalse( joinColumns[1].updatable() ); - assertEquals( "int", joinColumns[1].columnDefinition() ); - assertEquals( "table1", joinColumns[1].table() ); - } - - @Test - public void testJoinTableNoChildren() throws Exception { - reader = getReader( Entity2.class, "field1", "one-to-many.orm16.xml" ); - assertAnnotationPresent( OneToMany.class ); - assertAnnotationPresent( JoinTable.class ); - assertAnnotationNotPresent( JoinColumns.class ); - assertAnnotationNotPresent( JoinColumn.class ); - JoinTable joinTableAnno = reader.getAnnotation( JoinTable.class ); - assertEquals( "", joinTableAnno.catalog() ); - assertEquals( "", joinTableAnno.name() ); - assertEquals( "", joinTableAnno.schema() ); - assertEquals( 0, joinTableAnno.joinColumns().length ); - assertEquals( 0, joinTableAnno.inverseJoinColumns().length ); - assertEquals( 0, joinTableAnno.uniqueConstraints().length ); - } - - @Test - public void testJoinTableAllChildren() throws Exception { - reader = getReader( Entity2.class, "field1", "one-to-many.orm17.xml" ); - assertAnnotationPresent( OneToMany.class ); - assertAnnotationPresent( JoinTable.class ); - assertAnnotationNotPresent( JoinColumns.class ); - assertAnnotationNotPresent( JoinColumn.class ); - JoinTable joinTableAnno = reader.getAnnotation( JoinTable.class ); - assertEquals( "cat1", joinTableAnno.catalog() ); - assertEquals( "table1", joinTableAnno.name() ); - assertEquals( "schema1", joinTableAnno.schema() ); - - // JoinColumns - JoinColumn[] joinColumns = joinTableAnno.joinColumns(); - assertEquals( 2, joinColumns.length ); - assertEquals( "", joinColumns[0].name() ); - assertEquals( "", joinColumns[0].referencedColumnName() ); - assertEquals( "", joinColumns[0].table() ); - assertEquals( "", joinColumns[0].columnDefinition() ); - assertTrue( joinColumns[0].insertable() ); - assertTrue( joinColumns[0].updatable() ); - assertTrue( joinColumns[0].nullable() ); - assertFalse( joinColumns[0].unique() ); - assertEquals( "col1", joinColumns[1].name() ); - assertEquals( "col2", joinColumns[1].referencedColumnName() ); - assertEquals( "table2", joinColumns[1].table() ); - assertEquals( "int", joinColumns[1].columnDefinition() ); - assertFalse( joinColumns[1].insertable() ); - assertFalse( joinColumns[1].updatable() ); - assertFalse( joinColumns[1].nullable() ); - assertTrue( joinColumns[1].unique() ); - - // InverseJoinColumns - JoinColumn[] inverseJoinColumns = joinTableAnno.inverseJoinColumns(); - assertEquals( 2, inverseJoinColumns.length ); - assertEquals( "", inverseJoinColumns[0].name() ); - assertEquals( "", inverseJoinColumns[0].referencedColumnName() ); - assertEquals( "", inverseJoinColumns[0].table() ); - assertEquals( "", inverseJoinColumns[0].columnDefinition() ); - assertTrue( inverseJoinColumns[0].insertable() ); - assertTrue( inverseJoinColumns[0].updatable() ); - assertTrue( inverseJoinColumns[0].nullable() ); - assertFalse( inverseJoinColumns[0].unique() ); - assertEquals( "col3", inverseJoinColumns[1].name() ); - assertEquals( "col4", inverseJoinColumns[1].referencedColumnName() ); - assertEquals( "table3", inverseJoinColumns[1].table() ); - assertEquals( "int", inverseJoinColumns[1].columnDefinition() ); - assertFalse( inverseJoinColumns[1].insertable() ); - assertFalse( inverseJoinColumns[1].updatable() ); - assertFalse( inverseJoinColumns[1].nullable() ); - assertTrue( inverseJoinColumns[1].unique() ); - - // UniqueConstraints - UniqueConstraint[] uniqueConstraints = joinTableAnno - .uniqueConstraints(); - assertEquals( 2, uniqueConstraints.length ); - assertEquals( "", uniqueConstraints[0].name() ); - assertEquals( 1, uniqueConstraints[0].columnNames().length ); - assertEquals( "col5", uniqueConstraints[0].columnNames()[0] ); - assertEquals( "uq1", uniqueConstraints[1].name() ); - assertEquals( 2, uniqueConstraints[1].columnNames().length ); - assertEquals( "col6", uniqueConstraints[1].columnNames()[0] ); - assertEquals( "col7", uniqueConstraints[1].columnNames()[1] ); - } - - /** - * When there's a single join column, we still wrap it with a JoinColumns - * annotation. - */ - @Test - public void testSingleJoinColumn() throws Exception { - reader = getReader( Entity2.class, "field1", "one-to-many.orm18.xml" ); - assertAnnotationPresent( OneToMany.class ); - assertAnnotationNotPresent( JoinColumn.class ); - assertAnnotationPresent( JoinColumns.class ); - assertAnnotationNotPresent( JoinTable.class ); - JoinColumns joinColumnsAnno = reader.getAnnotation( JoinColumns.class ); - JoinColumn[] joinColumns = joinColumnsAnno.value(); - assertEquals( 1, joinColumns.length ); - assertEquals( "col1", joinColumns[0].name() ); - assertEquals( "col2", joinColumns[0].referencedColumnName() ); - assertEquals( "table1", joinColumns[0].table() ); - } - - @Test - public void testMultipleJoinColumns() throws Exception { - reader = getReader( Entity2.class, "field1", "one-to-many.orm19.xml" ); - assertAnnotationPresent( OneToMany.class ); - assertAnnotationNotPresent( JoinColumn.class ); - assertAnnotationPresent( JoinColumns.class ); - assertAnnotationNotPresent( JoinTable.class ); - JoinColumns joinColumnsAnno = reader.getAnnotation( JoinColumns.class ); - JoinColumn[] joinColumns = joinColumnsAnno.value(); - assertEquals( 2, joinColumns.length ); - assertEquals( "", joinColumns[0].name() ); - assertEquals( "", joinColumns[0].referencedColumnName() ); - assertEquals( "", joinColumns[0].table() ); - assertEquals( "", joinColumns[0].columnDefinition() ); - assertTrue( joinColumns[0].insertable() ); - assertTrue( joinColumns[0].updatable() ); - assertTrue( joinColumns[0].nullable() ); - assertFalse( joinColumns[0].unique() ); - assertEquals( "col1", joinColumns[1].name() ); - assertEquals( "col2", joinColumns[1].referencedColumnName() ); - assertEquals( "table1", joinColumns[1].table() ); - assertEquals( "int", joinColumns[1].columnDefinition() ); - assertFalse( joinColumns[1].insertable() ); - assertFalse( joinColumns[1].updatable() ); - assertFalse( joinColumns[1].nullable() ); - assertTrue( joinColumns[1].unique() ); - } - - @Test - public void testCascadeAll() throws Exception { - reader = getReader( Entity2.class, "field1", "one-to-many.orm20.xml" ); - assertAnnotationPresent( OneToMany.class ); - OneToMany relAnno = reader.getAnnotation( OneToMany.class ); - assertEquals( 1, relAnno.cascade().length ); - assertEquals( CascadeType.ALL, relAnno.cascade()[0] ); - } - - @Test - public void testCascadeSomeWithDefaultPersist() throws Exception { - reader = getReader( Entity2.class, "field1", "one-to-many.orm21.xml" ); - assertAnnotationPresent( OneToMany.class ); - OneToMany relAnno = reader.getAnnotation( OneToMany.class ); - assertEquals( 4, relAnno.cascade().length ); - assertEquals( CascadeType.REMOVE, relAnno.cascade()[0] ); - assertEquals( CascadeType.REFRESH, relAnno.cascade()[1] ); - assertEquals( CascadeType.DETACH, relAnno.cascade()[2] ); - assertEquals( CascadeType.PERSIST, relAnno.cascade()[3] ); - } - - /** - * Make sure that it doesn't break the handler when {@link CascadeType#ALL} - * is specified in addition to a default cascade-persist or individual - * cascade settings. - */ - @Test - public void testCascadeAllPlusMore() throws Exception { - reader = getReader( Entity2.class, "field1", "one-to-many.orm22.xml" ); - assertAnnotationPresent( OneToMany.class ); - OneToMany relAnno = reader.getAnnotation( OneToMany.class ); - assertEquals( 6, relAnno.cascade().length ); - assertEquals( CascadeType.ALL, relAnno.cascade()[0] ); - assertEquals( CascadeType.PERSIST, relAnno.cascade()[1] ); - assertEquals( CascadeType.MERGE, relAnno.cascade()[2] ); - assertEquals( CascadeType.REMOVE, relAnno.cascade()[3] ); - assertEquals( CascadeType.REFRESH, relAnno.cascade()[4] ); - assertEquals( CascadeType.DETACH, relAnno.cascade()[5] ); - } - - @Test - public void testAllAttributes() throws Exception { - reader = getReader( Entity2.class, "field1", "one-to-many.orm23.xml" ); - assertAnnotationPresent( OneToMany.class ); - assertAnnotationNotPresent( OrderBy.class ); - assertAnnotationNotPresent( OrderColumn.class ); - assertAnnotationNotPresent( MapKey.class ); - assertAnnotationNotPresent( MapKeyClass.class ); - assertAnnotationNotPresent( MapKeyTemporal.class ); - assertAnnotationNotPresent( MapKeyEnumerated.class ); - assertAnnotationNotPresent( MapKeyColumn.class ); - assertAnnotationNotPresent( MapKeyJoinColumns.class ); - assertAnnotationNotPresent( MapKeyJoinColumn.class ); - assertAnnotationNotPresent( JoinTable.class ); - assertAnnotationNotPresent( JoinColumns.class ); - assertAnnotationNotPresent( JoinColumn.class ); - assertAnnotationPresent( Access.class ); - OneToMany relAnno = reader.getAnnotation( OneToMany.class ); - assertEquals( 0, relAnno.cascade().length ); - assertEquals( FetchType.EAGER, relAnno.fetch() ); - assertEquals( "field2", relAnno.mappedBy() ); - assertTrue( relAnno.orphanRemoval() ); - assertEquals( Entity3.class, relAnno.targetEntity() ); - assertEquals( - AccessType.PROPERTY, reader.getAnnotation( Access.class ) - .value() - ); - } - -} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlOneToOneTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlOneToOneTest.java deleted file mode 100644 index 45c5e5e8448b..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlOneToOneTest.java +++ /dev/null @@ -1,309 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.annotations.xml.ejb3; - -import javax.persistence.Access; -import javax.persistence.AccessType; -import javax.persistence.CascadeType; -import javax.persistence.FetchType; -import javax.persistence.Id; -import javax.persistence.JoinColumn; -import javax.persistence.JoinColumns; -import javax.persistence.JoinTable; -import javax.persistence.MapsId; -import javax.persistence.OneToOne; -import javax.persistence.PrimaryKeyJoinColumn; -import javax.persistence.PrimaryKeyJoinColumns; -import javax.persistence.UniqueConstraint; - -import org.hibernate.cfg.annotations.reflection.JPAOverriddenAnnotationReader; - -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -/** - * Equivalent to {@link org.hibernate.test.annotations.xml.ejb3.Ejb3XmlOneToOneTest} - * for the legacy {@link JPAOverriddenAnnotationReader}. - * - * @author Emmanuel Bernard - * @deprecated This test will be removed in Hibernate ORM 6, along with the legacy {@link JPAOverriddenAnnotationReader}. - */ -@Deprecated -public class LegacyEjb3XmlOneToOneTest extends LegacyEjb3XmlTestCase { - @Test - public void testNoChildren() throws Exception { - reader = getReader( Entity1.class, "field1", "one-to-one.orm1.xml" ); - assertAnnotationPresent( OneToOne.class ); - assertAnnotationNotPresent( MapsId.class ); - assertAnnotationNotPresent( Id.class ); - assertAnnotationNotPresent( PrimaryKeyJoinColumn.class ); - assertAnnotationNotPresent( PrimaryKeyJoinColumns.class ); - assertAnnotationNotPresent( JoinColumns.class ); - assertAnnotationNotPresent( JoinColumn.class ); - assertAnnotationNotPresent( JoinTable.class ); - assertAnnotationNotPresent( Access.class ); - OneToOne relAnno = reader.getAnnotation( OneToOne.class ); - assertEquals( 0, relAnno.cascade().length ); - assertEquals( FetchType.EAGER, relAnno.fetch() ); - assertEquals( "", relAnno.mappedBy() ); - assertTrue( relAnno.optional() ); - assertFalse( relAnno.orphanRemoval() ); - assertEquals( void.class, relAnno.targetEntity() ); - } - - /** - * When there's a single primary key join column, we still wrap it with - * a PrimaryKeyJoinColumns annotation. - */ - @Test - public void testSinglePrimaryKeyJoinColumn() throws Exception { - reader = getReader( Entity1.class, "field1", "one-to-one.orm2.xml" ); - assertAnnotationPresent( OneToOne.class ); - assertAnnotationNotPresent( PrimaryKeyJoinColumn.class ); - assertAnnotationPresent( PrimaryKeyJoinColumns.class ); - PrimaryKeyJoinColumns joinColumnsAnno = - reader.getAnnotation( PrimaryKeyJoinColumns.class ); - assertAnnotationNotPresent( JoinColumns.class ); - assertAnnotationNotPresent( JoinColumn.class ); - assertAnnotationNotPresent( JoinTable.class ); - PrimaryKeyJoinColumn[] joinColumns = joinColumnsAnno.value(); - assertEquals( 1, joinColumns.length ); - assertEquals( "col1", joinColumns[0].name() ); - assertEquals( "col2", joinColumns[0].referencedColumnName() ); - assertEquals( "int", joinColumns[0].columnDefinition() ); - } - - @Test - public void testMultiplePrimaryKeyJoinColumn() throws Exception { - reader = getReader( Entity1.class, "field1", "one-to-one.orm3.xml" ); - assertAnnotationPresent( OneToOne.class ); - assertAnnotationNotPresent( PrimaryKeyJoinColumn.class ); - assertAnnotationPresent( PrimaryKeyJoinColumns.class ); - assertAnnotationNotPresent( JoinColumns.class ); - assertAnnotationNotPresent( JoinColumn.class ); - assertAnnotationNotPresent( JoinTable.class ); - PrimaryKeyJoinColumns joinColumnsAnno = - reader.getAnnotation( PrimaryKeyJoinColumns.class ); - PrimaryKeyJoinColumn[] joinColumns = joinColumnsAnno.value(); - assertEquals( 2, joinColumns.length ); - assertEquals( "", joinColumns[0].name() ); - assertEquals( "", joinColumns[0].referencedColumnName() ); - assertEquals( "", joinColumns[0].columnDefinition() ); - assertEquals( "col1", joinColumns[1].name() ); - assertEquals( "col2", joinColumns[1].referencedColumnName() ); - assertEquals( "int", joinColumns[1].columnDefinition() ); - } - - /** - * When there's a single join column, we still wrap it with a JoinColumns - * annotation. - */ - @Test - public void testSingleJoinColumn() throws Exception { - reader = getReader( Entity1.class, "field1", "one-to-one.orm4.xml" ); - assertAnnotationPresent( OneToOne.class ); - assertAnnotationNotPresent( PrimaryKeyJoinColumn.class ); - assertAnnotationNotPresent( PrimaryKeyJoinColumns.class ); - assertAnnotationPresent( JoinColumns.class ); - assertAnnotationNotPresent( JoinColumn.class ); - assertAnnotationNotPresent( JoinTable.class ); - JoinColumns joinColumnsAnno = reader.getAnnotation( JoinColumns.class ); - JoinColumn[] joinColumns = joinColumnsAnno.value(); - assertEquals( 1, joinColumns.length ); - assertEquals( "col1", joinColumns[0].name() ); - assertEquals( "col2", joinColumns[0].referencedColumnName() ); - assertEquals( "table1", joinColumns[0].table() ); - } - - @Test - public void testMultipleJoinColumns() throws Exception { - reader = getReader( Entity1.class, "field1", "one-to-one.orm5.xml" ); - assertAnnotationPresent( OneToOne.class ); - assertAnnotationNotPresent( PrimaryKeyJoinColumn.class ); - assertAnnotationNotPresent( PrimaryKeyJoinColumns.class ); - assertAnnotationNotPresent( JoinColumn.class ); - assertAnnotationPresent( JoinColumns.class ); - assertAnnotationNotPresent( JoinTable.class ); - JoinColumns joinColumnsAnno = reader.getAnnotation( JoinColumns.class ); - JoinColumn[] joinColumns = joinColumnsAnno.value(); - assertEquals( 2, joinColumns.length ); - assertEquals( "", joinColumns[0].name() ); - assertEquals( "", joinColumns[0].referencedColumnName() ); - assertEquals( "", joinColumns[0].table() ); - assertEquals( "", joinColumns[0].columnDefinition() ); - assertTrue( joinColumns[0].insertable() ); - assertTrue( joinColumns[0].updatable() ); - assertTrue( joinColumns[0].nullable() ); - assertFalse( joinColumns[0].unique() ); - assertEquals( "col1", joinColumns[1].name() ); - assertEquals( "col2", joinColumns[1].referencedColumnName() ); - assertEquals( "table1", joinColumns[1].table() ); - assertEquals( "int", joinColumns[1].columnDefinition() ); - assertFalse( joinColumns[1].insertable() ); - assertFalse( joinColumns[1].updatable() ); - assertFalse( joinColumns[1].nullable() ); - assertTrue( joinColumns[1].unique() ); - } - - @Test - public void testJoinTableNoChildren() throws Exception { - reader = getReader( Entity1.class, "field1", "one-to-one.orm6.xml" ); - assertAnnotationPresent( OneToOne.class ); - assertAnnotationNotPresent( PrimaryKeyJoinColumn.class ); - assertAnnotationNotPresent( PrimaryKeyJoinColumns.class ); - assertAnnotationPresent( JoinTable.class ); - assertAnnotationNotPresent( JoinColumns.class ); - assertAnnotationNotPresent( JoinColumn.class ); - JoinTable joinTableAnno = reader.getAnnotation( JoinTable.class ); - assertEquals( "", joinTableAnno.catalog() ); - assertEquals( "", joinTableAnno.name() ); - assertEquals( "", joinTableAnno.schema() ); - assertEquals( 0, joinTableAnno.joinColumns().length ); - assertEquals( 0, joinTableAnno.inverseJoinColumns().length ); - assertEquals( 0, joinTableAnno.uniqueConstraints().length ); - } - - @Test - public void testJoinTableAllChildren() throws Exception { - reader = getReader( Entity1.class, "field1", "one-to-one.orm7.xml" ); - assertAnnotationPresent( OneToOne.class ); - assertAnnotationNotPresent( PrimaryKeyJoinColumn.class ); - assertAnnotationNotPresent( PrimaryKeyJoinColumns.class ); - assertAnnotationPresent( JoinTable.class ); - assertAnnotationNotPresent( JoinColumns.class ); - assertAnnotationNotPresent( JoinColumn.class ); - JoinTable joinTableAnno = reader.getAnnotation( JoinTable.class ); - assertEquals( "cat1", joinTableAnno.catalog() ); - assertEquals( "table1", joinTableAnno.name() ); - assertEquals( "schema1", joinTableAnno.schema() ); - - // JoinColumns - JoinColumn[] joinColumns = joinTableAnno.joinColumns(); - assertEquals( 2, joinColumns.length ); - assertEquals( "", joinColumns[0].name() ); - assertEquals( "", joinColumns[0].referencedColumnName() ); - assertEquals( "", joinColumns[0].table() ); - assertEquals( "", joinColumns[0].columnDefinition() ); - assertTrue( joinColumns[0].insertable() ); - assertTrue( joinColumns[0].updatable() ); - assertTrue( joinColumns[0].nullable() ); - assertFalse( joinColumns[0].unique() ); - assertEquals( "col1", joinColumns[1].name() ); - assertEquals( "col2", joinColumns[1].referencedColumnName() ); - assertEquals( "table2", joinColumns[1].table() ); - assertEquals( "int", joinColumns[1].columnDefinition() ); - assertFalse( joinColumns[1].insertable() ); - assertFalse( joinColumns[1].updatable() ); - assertFalse( joinColumns[1].nullable() ); - assertTrue( joinColumns[1].unique() ); - - // InverseJoinColumns - JoinColumn[] inverseJoinColumns = joinTableAnno.inverseJoinColumns(); - assertEquals( 2, inverseJoinColumns.length ); - assertEquals( "", inverseJoinColumns[0].name() ); - assertEquals( "", inverseJoinColumns[0].referencedColumnName() ); - assertEquals( "", inverseJoinColumns[0].table() ); - assertEquals( "", inverseJoinColumns[0].columnDefinition() ); - assertTrue( inverseJoinColumns[0].insertable() ); - assertTrue( inverseJoinColumns[0].updatable() ); - assertTrue( inverseJoinColumns[0].nullable() ); - assertFalse( inverseJoinColumns[0].unique() ); - assertEquals( "col3", inverseJoinColumns[1].name() ); - assertEquals( "col4", inverseJoinColumns[1].referencedColumnName() ); - assertEquals( "table3", inverseJoinColumns[1].table() ); - assertEquals( "int", inverseJoinColumns[1].columnDefinition() ); - assertFalse( inverseJoinColumns[1].insertable() ); - assertFalse( inverseJoinColumns[1].updatable() ); - assertFalse( inverseJoinColumns[1].nullable() ); - assertTrue( inverseJoinColumns[1].unique() ); - - // UniqueConstraints - UniqueConstraint[] uniqueConstraints = joinTableAnno - .uniqueConstraints(); - assertEquals( 2, uniqueConstraints.length ); - assertEquals( "", uniqueConstraints[0].name() ); - assertEquals( 1, uniqueConstraints[0].columnNames().length ); - assertEquals( "col5", uniqueConstraints[0].columnNames()[0] ); - assertEquals( "uq1", uniqueConstraints[1].name() ); - assertEquals( 2, uniqueConstraints[1].columnNames().length ); - assertEquals( "col6", uniqueConstraints[1].columnNames()[0] ); - assertEquals( "col7", uniqueConstraints[1].columnNames()[1] ); - } - - @Test - public void testCascadeAll() throws Exception { - reader = getReader( Entity1.class, "field1", "one-to-one.orm8.xml" ); - assertAnnotationPresent( OneToOne.class ); - OneToOne relAnno = reader.getAnnotation( OneToOne.class ); - assertEquals( 1, relAnno.cascade().length ); - assertEquals( CascadeType.ALL, relAnno.cascade()[0] ); - } - - @Test - public void testCascadeSomeWithDefaultPersist() throws Exception { - reader = getReader( Entity1.class, "field1", "one-to-one.orm9.xml" ); - assertAnnotationPresent( OneToOne.class ); - OneToOne relAnno = reader.getAnnotation( OneToOne.class ); - assertEquals( 4, relAnno.cascade().length ); - assertEquals( CascadeType.REMOVE, relAnno.cascade()[0] ); - assertEquals( CascadeType.REFRESH, relAnno.cascade()[1] ); - assertEquals( CascadeType.DETACH, relAnno.cascade()[2] ); - assertEquals( CascadeType.PERSIST, relAnno.cascade()[3] ); - } - - /** - * Make sure that it doesn't break the handler when {@link CascadeType#ALL} - * is specified in addition to a default cascade-persist or individual - * cascade settings. - */ - @Test - public void testCascadeAllPlusMore() throws Exception { - reader = getReader( Entity1.class, "field1", "one-to-one.orm10.xml" ); - assertAnnotationPresent( OneToOne.class ); - OneToOne relAnno = reader.getAnnotation( OneToOne.class ); - assertEquals( 6, relAnno.cascade().length ); - assertEquals( CascadeType.ALL, relAnno.cascade()[0] ); - assertEquals( CascadeType.PERSIST, relAnno.cascade()[1] ); - assertEquals( CascadeType.MERGE, relAnno.cascade()[2] ); - assertEquals( CascadeType.REMOVE, relAnno.cascade()[3] ); - assertEquals( CascadeType.REFRESH, relAnno.cascade()[4] ); - assertEquals( CascadeType.DETACH, relAnno.cascade()[5] ); - } - - @Test - public void testAllAttributes() throws Exception { - reader = getReader( Entity1.class, "field1", "one-to-one.orm11.xml" ); - assertAnnotationPresent( OneToOne.class ); - assertAnnotationPresent( MapsId.class ); - assertAnnotationPresent( Id.class ); - assertAnnotationNotPresent( PrimaryKeyJoinColumn.class ); - assertAnnotationNotPresent( PrimaryKeyJoinColumns.class ); - assertAnnotationNotPresent( JoinColumns.class ); - assertAnnotationNotPresent( JoinColumn.class ); - assertAnnotationNotPresent( JoinTable.class ); - assertAnnotationPresent( Access.class ); - OneToOne relAnno = reader.getAnnotation( OneToOne.class ); - assertEquals( 0, relAnno.cascade().length ); - assertEquals( FetchType.LAZY, relAnno.fetch() ); - assertEquals( "field2", relAnno.mappedBy() ); - assertFalse( relAnno.optional() ); - assertTrue( relAnno.orphanRemoval() ); - assertEquals( Entity3.class, relAnno.targetEntity() ); - assertEquals( - AccessType.PROPERTY, reader.getAnnotation( Access.class ) - .value() - ); - assertEquals( - "field3", reader.getAnnotation( MapsId.class ) - .value() - ); - } - -} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlTest.java deleted file mode 100644 index dae470e238c8..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlTest.java +++ /dev/null @@ -1,148 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.annotations.xml.ejb3; - -import java.util.Date; -import java.util.List; - -import org.hibernate.Session; -import org.hibernate.SessionFactory; -import org.hibernate.Transaction; -import org.hibernate.cfg.annotations.reflection.JPAOverriddenAnnotationReader; -import org.hibernate.dialect.CockroachDB192Dialect; -import org.hibernate.dialect.PostgreSQL81Dialect; -import org.hibernate.dialect.PostgreSQLDialect; -import org.hibernate.dialect.TeradataDialect; -import org.hibernate.persister.collection.BasicCollectionPersister; - -import org.hibernate.testing.SkipForDialect; -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; -import org.junit.Test; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertNotNull; - -/** - * Equivalent to {@link org.hibernate.test.annotations.xml.ejb3.Ejb3XmlTest} - * for the legacy {@link JPAOverriddenAnnotationReader}. - * - * @author Emmanuel Bernard - * @deprecated This test will be removed in Hibernate ORM 6, along with the legacy {@link JPAOverriddenAnnotationReader}. - */ -@Deprecated -public class LegacyEjb3XmlTest extends BaseCoreFunctionalTestCase { - @Test - @SkipForDialect(value = {PostgreSQL81Dialect.class, PostgreSQLDialect.class, CockroachDB192Dialect.class}, - comment = "postgresql jdbc driver does not implement the setQueryTimeout method") - @SkipForDialect(value = TeradataDialect.class, - jiraKey = "HHH-8190", - comment = "uses Teradata reserved word - year") - public void testEjb3Xml() throws Exception { - Session s = openSession(); - Transaction tx = s.beginTransaction(); - CarModel model = new CarModel(); - model.setYear( new Date() ); - Manufacturer manufacturer = new Manufacturer(); - //s.persist( manufacturer ); - model.setManufacturer( manufacturer ); - manufacturer.getModels().add( model ); - s.persist( model ); - s.flush(); - s.clear(); - - model.setYear( new Date() ); - manufacturer = (Manufacturer) s.get( Manufacturer.class, manufacturer.getId() ); - @SuppressWarnings("unchecked") - List cars = s.getNamedQuery( "allModelsPerManufacturer" ) - .setParameter( "manufacturer", manufacturer ) - .list(); - assertEquals( 1, cars.size() ); - for ( Model car : cars ) { - assertNotNull( car.getManufacturer() ); - s.delete( manufacturer ); - s.delete( car ); - } - tx.rollback(); - s.close(); - } - - @Test - public void testXMLEntityHandled() throws Exception { - Session s = openSession(); - s.getTransaction().begin(); - Lighter l = new Lighter(); - l.name = "Blue"; - l.power = "400F"; - s.persist( l ); - s.flush(); - s.getTransaction().rollback(); - s.close(); - } - - @Test - public void testXmlDefaultOverriding() throws Exception { - Session s = openSession(); - Transaction tx = s.beginTransaction(); - Manufacturer manufacturer = new Manufacturer(); - s.persist( manufacturer ); - s.flush(); - s.clear(); - - assertEquals( 1, s.getNamedQuery( "manufacturer.findAll" ).list().size() ); - tx.rollback(); - s.close(); - } - - @Test - @SuppressWarnings("unchecked") - public void testMapXMLSupport() throws Exception { - Session s = openSession(); - SessionFactory sf = s.getSessionFactory(); - Transaction tx = s.beginTransaction(); - - // Verify that we can persist an object with a couple Map mappings - VicePresident vpSales = new VicePresident(); - vpSales.name = "Dwight"; - Company company = new Company(); - company.conferenceRoomExtensions.put( "8932", "x1234" ); - company.organization.put( "sales", vpSales ); - s.persist( company ); - s.flush(); - s.clear(); - - // For the element-collection, check that the orm.xml entries are honored. - // This includes: map-key-column/column/collection-table/join-column - BasicCollectionPersister confRoomMeta = (BasicCollectionPersister) sf.getCollectionMetadata( Company.class.getName() + ".conferenceRoomExtensions" ); - assertEquals( "company_id", confRoomMeta.getKeyColumnNames()[0] ); - assertEquals( "phone_extension", confRoomMeta.getElementColumnNames()[0] ); - assertEquals( "room_number", confRoomMeta.getIndexColumnNames()[0] ); - assertEquals( "phone_extension_lookup", confRoomMeta.getTableName() ); - tx.rollback(); - s.close(); - } - - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] { - CarModel.class, - Manufacturer.class, - Model.class, - Light.class - //Lighter.class xml only entuty - }; - } - - @Override - protected String[] getXmlFiles() { - return new String[] { - "org/hibernate/test/annotations/xml/ejb3/orm.xml", - "org/hibernate/test/annotations/xml/ejb3/orm2.xml", - "org/hibernate/test/annotations/xml/ejb3/orm3.xml", - "org/hibernate/test/annotations/xml/ejb3/orm4.xml" - }; - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlTestCase.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlTestCase.java deleted file mode 100644 index e22dfea26ea4..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyEjb3XmlTestCase.java +++ /dev/null @@ -1,82 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.annotations.xml.ejb3; - -import java.io.InputStream; -import java.lang.annotation.Annotation; -import java.lang.reflect.AnnotatedElement; - -import org.hibernate.cfg.annotations.reflection.JPAOverriddenAnnotationReader; -import org.hibernate.cfg.annotations.reflection.XMLContext; - -import org.hibernate.testing.boot.BootstrapContextImpl; -import org.hibernate.testing.junit4.BaseUnitTestCase; - -import org.dom4j.Document; -import org.dom4j.io.SAXReader; - -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertNotNull; -import static org.junit.Assert.assertTrue; - -/** - * Test superclass to provide utility methods for testing the mapping of JPA - * XML to JPA annotations. The configuration is built within each test, and no - * database is used. Thus, no schema generation or cleanup will be performed. - *

- * Equivalent to {@link org.hibernate.test.annotations.xml.ejb3.Ejb3XmlTest} - * for the legacy {@link JPAOverriddenAnnotationReader}. - * - * @author Emmanuel Bernard - * @deprecated This test will be removed in Hibernate ORM 6, along with the legacy {@link JPAOverriddenAnnotationReader}. - */ -@Deprecated -abstract class LegacyEjb3XmlTestCase extends BaseUnitTestCase { - protected JPAOverriddenAnnotationReader reader; - - protected void assertAnnotationPresent(Class annotationType) { - assertTrue( - "Expected annotation " + annotationType.getSimpleName() + " was not present", - reader.isAnnotationPresent( annotationType ) - ); - } - - protected void assertAnnotationNotPresent(Class annotationType) { - assertFalse( - "Unexpected annotation " + annotationType.getSimpleName() + " was present", - reader.isAnnotationPresent( annotationType ) - ); - } - - protected JPAOverriddenAnnotationReader getReader(Class entityClass, String fieldName, String ormResourceName) - throws Exception { - AnnotatedElement el = getAnnotatedElement( entityClass, fieldName ); - XMLContext xmlContext = getContext( ormResourceName ); - return new JPAOverriddenAnnotationReader( el, xmlContext, BootstrapContextImpl.INSTANCE ); - } - - protected AnnotatedElement getAnnotatedElement(Class entityClass, String fieldName) throws Exception { - return entityClass.getDeclaredField( fieldName ); - } - - protected XMLContext getContext(String resourceName) throws Exception { - InputStream is = getClass().getResourceAsStream( resourceName ); - assertNotNull( "Could not load resource " + resourceName, is ); - return getContext( is ); - } - - protected XMLContext getContext(InputStream is) throws Exception { - XMLContext xmlContext = new XMLContext( BootstrapContextImpl.INSTANCE ); - SAXReader reader = new SAXReader(); - reader.setFeature( "http://apache.org/xml/features/nonvalidating/load-external-dtd", false ); - reader.setFeature( "http://xml.org/sax/features/external-general-entities", false ); - reader.setFeature( "http://xml.org/sax/features/external-parameter-entities", false ); - Document doc = reader.read( is ); - xmlContext.addDocument( doc ); - return xmlContext; - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyNonExistentOrmVersionTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyNonExistentOrmVersionTest.java deleted file mode 100644 index 74509b879ca3..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyNonExistentOrmVersionTest.java +++ /dev/null @@ -1,42 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.annotations.xml.ejb3; - -import org.hibernate.InvalidMappingException; -import org.hibernate.boot.MetadataSources; -import org.hibernate.cfg.annotations.reflection.JPAOverriddenAnnotationReader; -import org.hibernate.internal.util.xml.UnsupportedOrmXsdVersionException; - -import org.hibernate.testing.TestForIssue; -import org.hibernate.testing.junit4.BaseUnitTestCase; -import org.junit.Test; - -import static org.junit.Assert.fail; - -/** - * Equivalent to {@link org.hibernate.test.annotations.xml.ejb3.NonExistentOrmVersionTest} - * for the legacy {@link JPAOverriddenAnnotationReader}. - * - * @author Emmanuel Bernard - * @deprecated This test will be removed in Hibernate ORM 6, along with the legacy {@link JPAOverriddenAnnotationReader}. - */ -@TestForIssue(jiraKey = "HHH-6271") -public class LegacyNonExistentOrmVersionTest extends BaseUnitTestCase { - @Test - public void testNonExistentOrmVersion() { - try { - new MetadataSources() - .addResource( "org/hibernate/test/annotations/xml/ejb3/orm5.xml" ) - .buildMetadata(); - fail( "Expecting failure due to unsupported xsd version" ); - } - catch ( InvalidMappingException expected ) { - } - catch ( UnsupportedOrmXsdVersionException expected ) { - } - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyOrmVersion1SupportedTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyOrmVersion1SupportedTest.java deleted file mode 100644 index 763b79f605d2..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyOrmVersion1SupportedTest.java +++ /dev/null @@ -1,68 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.annotations.xml.ejb3; - -import org.hibernate.Session; -import org.hibernate.Transaction; -import org.hibernate.cfg.annotations.reflection.JPAOverriddenAnnotationReader; -import org.hibernate.internal.CoreMessageLogger; -import org.hibernate.internal.util.xml.ErrorLogger; - -import org.hibernate.testing.TestForIssue; -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; -import org.hibernate.testing.logger.LoggerInspectionRule; -import org.hibernate.testing.logger.Triggerable; -import org.junit.Rule; -import org.junit.Test; - -import org.jboss.logging.Logger; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; - -/** - * Equivalent to {@link org.hibernate.test.annotations.xml.ejb3.OrmVersion1SupportedTest} - * for the legacy {@link JPAOverriddenAnnotationReader}. - * - * @author Emmanuel Bernard - * @deprecated This test will be removed in Hibernate ORM 6, along with the legacy {@link JPAOverriddenAnnotationReader}. - */ -@TestForIssue(jiraKey = "HHH-6271") -public class LegacyOrmVersion1SupportedTest extends BaseCoreFunctionalTestCase { - - @Rule - public LoggerInspectionRule logInspection = new LoggerInspectionRule( - Logger.getMessageLogger( - CoreMessageLogger.class, - ErrorLogger.class.getName() - ) - ); - - @Test - public void testOrm1Support() { - Triggerable triggerable = logInspection.watchForLogMessages( "HHH00196" ); - - Session s = openSession(); - Transaction tx = s.beginTransaction(); - Light light = new Light(); - light.name = "the light at the end of the tunnel"; - s.persist( light ); - s.flush(); - s.clear(); - - assertEquals( 1, s.getNamedQuery( "find.the.light" ).list().size() ); - tx.rollback(); - s.close(); - - assertFalse( triggerable.wasTriggered() ); - } - - @Override - protected String[] getXmlFiles() { - return new String[] { "org/hibernate/test/annotations/xml/ejb3/orm2.xml" }; - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyPreParsedOrmXmlTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyPreParsedOrmXmlTest.java deleted file mode 100644 index 9d3e4654b210..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/LegacyPreParsedOrmXmlTest.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.annotations.xml.ejb3; - -import java.io.IOException; -import java.io.InputStream; -import java.io.UncheckedIOException; - -import org.hibernate.boot.jaxb.spi.Binding; -import org.hibernate.cfg.Configuration; -import org.hibernate.cfg.annotations.reflection.JPAOverriddenAnnotationReader; - -import org.hibernate.testing.TestForIssue; -import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; -import org.hibernate.test.annotations.xml.ejb3.PreParsedOrmXmlTest.NonAnnotatedEntity; -import org.junit.Test; - -import static org.assertj.core.api.Assertions.assertThat; - -/** - * Equivalent to {@link org.hibernate.test.annotations.xml.ejb3.PreParsedOrmXmlTest} - * for the legacy {@link JPAOverriddenAnnotationReader}. - * - * @author Emmanuel Bernard - * @deprecated This test will be removed in Hibernate ORM 6, along with the legacy {@link JPAOverriddenAnnotationReader}. - */ -@TestForIssue(jiraKey = "HHH-14530") -public class LegacyPreParsedOrmXmlTest extends BaseCoreFunctionalTestCase { - - @Override - protected void addMappings(Configuration configuration) { - super.addMappings( configuration ); - try (InputStream xmlStream = Thread.currentThread().getContextClassLoader() - .getResourceAsStream( "org/hibernate/test/annotations/xml/ejb3/pre-parsed-orm.xml" )) { - Binding parsed = configuration.getXmlMappingBinderAccess().bind( xmlStream ); - configuration.addXmlMapping( parsed ); - } - catch (IOException e) { - throw new UncheckedIOException( e ); - } - } - - @Test - public void testPreParsedOrmXml() { - // Just check that the entity can be persisted, which means the mapping file was taken into account - NonAnnotatedEntity persistedEntity = new NonAnnotatedEntity( "someName" ); - inTransaction( s -> s.persist( persistedEntity ) ); - inTransaction( s -> { - NonAnnotatedEntity retrievedEntity = s.find( NonAnnotatedEntity.class, persistedEntity.getId() ); - assertThat( retrievedEntity ).extracting( NonAnnotatedEntity::getName ) - .isEqualTo( persistedEntity.getName() ); - } ); - } -} From 6f5f6b32c3a158633309c187b7172dab0a744767 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Fri, 16 Apr 2021 13:55:00 +0200 Subject: [PATCH 111/644] HHH-14563 Remove DOM4J-based XML mapping Use JAXB-based XML mapping everywhere. --- .../boot/internal/BootstrapContextImpl.java | 9 +- .../boot/jaxb/internal/MappingBinder.java | 56 +- .../boot/jaxb/spi/XmlMappingOptions.java | 11 - .../process/spi/MetadataBuildingProcess.java | 2 +- ...AnnotationMetadataSourceProcessorImpl.java | 43 +- .../boot/spi/XmlMappingBinderAccess.java | 4 +- .../reflection/JPAMetadataProvider.java | 239 -- .../JPAOverriddenAnnotationReader.java | 3091 ----------------- .../annotations/reflection/XMLContext.java | 363 -- .../reflection/internal/XMLContext.java | 2 +- .../internal/util/xml/XMLMappingHelper.java | 4 +- ...ngOptionsStrategyRegistrationProvider.java | 66 - .../ElementCollectionConverterTest.java | 2 - .../JPAXMLOverriddenAnnotationReaderTest.java | 27 +- .../reflection/XMLContextTest.java | 14 +- .../annotations/xml/ejb3/Ejb3XmlTest.java | 2 - .../annotations/xml/ejb3/Ejb3XmlTestCase.java | 8 +- .../xml/ejb3/NonExistentOrmVersionTest.java | 2 - .../xml/ejb3/OrmVersion1SupportedTest.java | 2 - .../xml/ejb3/PreParsedOrmXmlTest.java | 2 - ...stry.selector.StrategyRegistrationProvider | 1 - 21 files changed, 25 insertions(+), 3925 deletions(-) delete mode 100644 hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/JPAMetadataProvider.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/JPAOverriddenAnnotationReader.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/XMLContext.java delete mode 100644 hibernate-core/src/test/java/org/hibernate/internal/util/xml/XmlMappingOptionsStrategyRegistrationProvider.java delete mode 100644 hibernate-core/src/test/resources/META-INF/services/org.hibernate.boot.registry.selector.StrategyRegistrationProvider diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/BootstrapContextImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/BootstrapContextImpl.java index 6f05fafad590..e231f7d53ed4 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/BootstrapContextImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/BootstrapContextImpl.java @@ -30,7 +30,6 @@ import org.hibernate.boot.spi.ClassLoaderAccess; import org.hibernate.boot.spi.MetadataBuildingOptions; import org.hibernate.cfg.AvailableSettings; -import org.hibernate.cfg.annotations.reflection.JPAMetadataProvider; import org.hibernate.cfg.annotations.reflection.internal.JPAXMLOverriddenMetadataProvider; import org.hibernate.dialect.function.SQLFunction; import org.hibernate.engine.config.spi.ConfigurationService; @@ -310,13 +309,7 @@ public void addCacheRegionDefinition(CacheRegionDefinition cacheRegionDefinition private JavaReflectionManager generateHcannReflectionManager() { final JavaReflectionManager reflectionManager = new JavaReflectionManager(); - if ( metadataBuildingOptions.getXmlMappingOptions().isPreferJaxb() ) { - reflectionManager.setMetadataProvider( new JPAXMLOverriddenMetadataProvider( this ) ); - } - else { - // Legacy implementation based on DOM4J, for backwards compatibility. - reflectionManager.setMetadataProvider( new JPAMetadataProvider( this ) ); - } + reflectionManager.setMetadataProvider( new JPAXMLOverriddenMetadataProvider( this ) ); return reflectionManager; } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/MappingBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/MappingBinder.java index ba0049988b75..84cd9ef7f51a 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/MappingBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/MappingBinder.java @@ -10,11 +10,8 @@ import javax.xml.bind.JAXBException; import javax.xml.stream.XMLEventFactory; import javax.xml.stream.XMLEventReader; -import javax.xml.stream.XMLStreamException; import javax.xml.stream.events.StartElement; -import javax.xml.stream.events.XMLEvent; -import org.hibernate.boot.MappingException; import org.hibernate.boot.UnsupportedOrmXsdVersionException; import org.hibernate.boot.jaxb.Origin; import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmHibernateMapping; @@ -29,10 +26,6 @@ import org.jboss.logging.Logger; -import org.dom4j.Document; -import org.dom4j.Node; -import org.dom4j.io.STAXEventReader; - /** * @author Steve Ebersole */ @@ -41,14 +34,11 @@ public class MappingBinder extends AbstractBinder { private final XMLEventFactory xmlEventFactory = XMLEventFactory.newInstance(); - private final XmlMappingOptions options; - private JAXBContext hbmJaxbContext; private JAXBContext entityMappingsJaxbContext; - public MappingBinder(ClassLoaderService classLoaderService, boolean validateXml, XmlMappingOptions options) { + public MappingBinder(ClassLoaderService classLoaderService, boolean validateXml) { super( classLoaderService, validateXml ); - this.options = options; } @Override @@ -66,19 +56,11 @@ protected Binding doBind( } else { try { - if ( options.isPreferJaxb() ) { - log.debugf( "Performing JAXB binding of orm.xml document : %s", origin.toString() ); + log.debugf( "Performing JAXB binding of orm.xml document : %s", origin.toString() ); - XMLEventReader reader = new JpaOrmXmlEventReader( staxEventReader, xmlEventFactory ); - JaxbEntityMappings bindingRoot = jaxb( reader, MappingXsdSupport.INSTANCE.latestJpaDescriptor().getSchema(), entityMappingsJaxbContext(), origin ); - return new Binding<>( bindingRoot, origin ); - } - else { - log.debugf( "Performing DOM4J binding of orm.xml document : %s", origin.toString() ); - - final XMLEventReader reader = new JpaOrmXmlEventReader( staxEventReader, xmlEventFactory ); - return new Binding<>( toDom4jDocument( reader, origin ), origin ); - } + XMLEventReader reader = new JpaOrmXmlEventReader( staxEventReader, xmlEventFactory ); + JaxbEntityMappings bindingRoot = jaxb( reader, MappingXsdSupport.INSTANCE.latestJpaDescriptor().getSchema(), entityMappingsJaxbContext(), origin ); + return new Binding<>( bindingRoot, origin ); } catch (JpaOrmXmlEventReader.BadVersionException e) { throw new UnsupportedOrmXsdVersionException( e.getRequestedVersion(), origin ); @@ -109,32 +91,4 @@ private JAXBContext entityMappingsJaxbContext() { } return entityMappingsJaxbContext; } - - private Document toDom4jDocument(XMLEventReader jpaOrmXmlEventReader, Origin origin) { - // todo : do we need to build a DocumentFactory instance for use here? - // historically we did that to set TCCL since, iirc, dom4j uses TCCL - org.dom4j.io.STAXEventReader staxToDom4jReader = new STAXEventReader() { - @Override - public Node readNode(XMLEventReader reader) throws XMLStreamException { - // dom4j's reader misses handling of XML comments. So if the document we - // are trying to read has comments this process will blow up. So we - // override that to add that support as best we can - XMLEvent event = reader.peek(); - if ( javax.xml.stream.events.Comment.class.isInstance( event ) ) { - return super.readComment( reader ); - } - return super.readNode( reader ); - } - }; - try { - return staxToDom4jReader.readDocument( jpaOrmXmlEventReader ); - } - catch (XMLStreamException e) { - throw new MappingException( - "An error occurred transforming orm.xml document from StAX to dom4j representation ", - e, - origin - ); - } - } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/spi/XmlMappingOptions.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/spi/XmlMappingOptions.java index 5247ef82ccc0..af5b02d066da 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/spi/XmlMappingOptions.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/spi/XmlMappingOptions.java @@ -72,15 +72,4 @@ default boolean isEnabled() { return true; } - /** - * Whether to prefer JAXB implementations for XML parsing, - * or to rely on legacy behavior (JAXB for hbm.xml, DOM4J for orm.xml and Envers). - *

- * This option will be removed in a future major version (probably ORM 6.0) - * where JAXB will always be used. - */ - default boolean isPreferJaxb() { - return false; - } - } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/process/spi/MetadataBuildingProcess.java b/hibernate-core/src/main/java/org/hibernate/boot/model/process/spi/MetadataBuildingProcess.java index 1457f3c12923..bef1390faf89 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/process/spi/MetadataBuildingProcess.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/process/spi/MetadataBuildingProcess.java @@ -294,7 +294,7 @@ public void finishUp() { final EntityHierarchyBuilder hierarchyBuilder = new EntityHierarchyBuilder(); // final MappingBinder mappingBinder = new MappingBinder( true ); // We need to disable validation here. It seems Envers is not producing valid (according to schema) XML - final MappingBinder mappingBinder = new MappingBinder( classLoaderService, false, xmlMappingOptions ); + final MappingBinder mappingBinder = new MappingBinder( classLoaderService, false ); for ( AdditionalJaxbMappingProducer producer : producers ) { log.tracef( "Calling AdditionalJaxbMappingProducer : %s", producer ); Collection additionalMappings = producer.produceAdditionalMappings( diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/annotations/AnnotationMetadataSourceProcessorImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/annotations/AnnotationMetadataSourceProcessorImpl.java index f336e4551cf2..68d8d225a6ce 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/annotations/AnnotationMetadataSourceProcessorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/annotations/AnnotationMetadataSourceProcessorImpl.java @@ -35,7 +35,6 @@ import org.hibernate.cfg.AnnotationBinder; import org.hibernate.cfg.InheritanceState; import org.hibernate.cfg.annotations.reflection.AttributeConverterDefinitionCollector; -import org.hibernate.cfg.annotations.reflection.JPAMetadataProvider; import org.hibernate.cfg.annotations.reflection.internal.JPAXMLOverriddenMetadataProvider; import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.collections.CollectionHelper; @@ -43,8 +42,6 @@ import org.jboss.jandex.IndexView; import org.jboss.logging.Logger; -import org.dom4j.Document; - /** * @author Steve Ebersole */ @@ -84,39 +81,21 @@ public AnnotationMetadataSourceProcessorImpl( if ( xmlMappingOptions.isEnabled() ) { // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Ewww. This is temporary until we migrate to Jandex + StAX for annotation binding - if ( xmlMappingOptions.isPreferJaxb() ) { - final JPAXMLOverriddenMetadataProvider jpaMetadataProvider = (JPAXMLOverriddenMetadataProvider) ( (MetadataProviderInjector) reflectionManager ) - .getMetadataProvider(); - for ( Binding xmlBinding : managedResources.getXmlMappingBindings() ) { - Object root = xmlBinding.getRoot(); - if ( !(root instanceof JaxbEntityMappings) ) { - continue; - } - JaxbEntityMappings entityMappings = (JaxbEntityMappings) xmlBinding.getRoot(); - - final List classNames = jpaMetadataProvider.getXMLContext().addDocument( entityMappings ); - for ( String className : classNames ) { - xClasses.add( toXClass( className, reflectionManager, classLoaderService ) ); - } + final JPAXMLOverriddenMetadataProvider jpaMetadataProvider = (JPAXMLOverriddenMetadataProvider) ( (MetadataProviderInjector) reflectionManager ) + .getMetadataProvider(); + for ( Binding xmlBinding : managedResources.getXmlMappingBindings() ) { + Object root = xmlBinding.getRoot(); + if ( !(root instanceof JaxbEntityMappings) ) { + continue; } - jpaMetadataProvider.getXMLContext().applyDiscoveredAttributeConverters( attributeConverterManager ); - } - else { - final JPAMetadataProvider jpaMetadataProvider = (JPAMetadataProvider) ( (MetadataProviderInjector) reflectionManager ) - .getMetadataProvider(); - for ( Binding xmlBinding : managedResources.getXmlMappingBindings() ) { - if ( !org.dom4j.Document.class.isInstance( xmlBinding.getRoot() ) ) { - continue; - } - org.dom4j.Document dom4jDocument = (Document) xmlBinding.getRoot(); + JaxbEntityMappings entityMappings = (JaxbEntityMappings) xmlBinding.getRoot(); - final List classNames = jpaMetadataProvider.getXMLContext().addDocument( dom4jDocument ); - for ( String className : classNames ) { - xClasses.add( toXClass( className, reflectionManager, classLoaderService ) ); - } + final List classNames = jpaMetadataProvider.getXMLContext().addDocument( entityMappings ); + for ( String className : classNames ) { + xClasses.add( toXClass( className, reflectionManager, classLoaderService ) ); } - jpaMetadataProvider.getXMLContext().applyDiscoveredAttributeConverters( attributeConverterManager ); } + jpaMetadataProvider.getXMLContext().applyDiscoveredAttributeConverters( attributeConverterManager ); // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/XmlMappingBinderAccess.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/XmlMappingBinderAccess.java index fa7014840b71..80c825b42811 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/spi/XmlMappingBinderAccess.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/XmlMappingBinderAccess.java @@ -41,12 +41,10 @@ public class XmlMappingBinderAccess { public XmlMappingBinderAccess(ServiceRegistry serviceRegistry) { this.classLoaderService = serviceRegistry.getService( ClassLoaderService.class ); - XmlMappingOptions xmlMappingOptions = XmlMappingOptions.get( serviceRegistry ); - // NOTE : The boolean here indicates whether or not to perform validation as we load XML documents. // Should we expose this setting? Disabling would speed up JAXP and JAXB at runtime, but potentially // at the cost of less obvious errors when a document is not valid. - this.mappingBinder = new MappingBinder( classLoaderService, true, xmlMappingOptions ); + this.mappingBinder = new MappingBinder( classLoaderService, true ); } public MappingBinder getMappingBinder() { diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/JPAMetadataProvider.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/JPAMetadataProvider.java deleted file mode 100644 index 5579a01c79f0..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/JPAMetadataProvider.java +++ /dev/null @@ -1,239 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.cfg.annotations.reflection; - -import java.lang.reflect.AnnotatedElement; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import javax.persistence.EntityListeners; -import javax.persistence.NamedNativeQuery; -import javax.persistence.NamedQuery; -import javax.persistence.NamedStoredProcedureQuery; -import javax.persistence.SequenceGenerator; -import javax.persistence.SqlResultSetMapping; -import javax.persistence.TableGenerator; - -import org.hibernate.annotations.common.reflection.AnnotationReader; -import org.hibernate.annotations.common.reflection.MetadataProvider; -import org.hibernate.annotations.common.reflection.java.JavaMetadataProvider; -import org.hibernate.boot.internal.ClassLoaderAccessImpl; -import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; -import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; -import org.hibernate.boot.spi.BootstrapContext; -import org.hibernate.boot.spi.ClassLoaderAccess; -import org.hibernate.boot.spi.ClassLoaderAccessDelegateImpl; -import org.hibernate.boot.spi.MetadataBuildingOptions; -import org.hibernate.cfg.annotations.reflection.internal.JPAXMLOverriddenMetadataProvider; - -import org.dom4j.Element; - -/** - * MetadataProvider aware of the JPA Deployment descriptor - * - * @author Emmanuel Bernard - * - * @deprecated This class is not API: do not use it from application code. - * This class will be removed in Hibernate ORM 6.0. - * For implementation code, use {@link JPAXMLOverriddenMetadataProvider} - * instead. - */ -@Deprecated -@SuppressWarnings("unchecked") -public final class JPAMetadataProvider implements MetadataProvider { - - private static final MetadataProvider STATELESS_BASE_DELEGATE = new JavaMetadataProvider(); - - private final ClassLoaderAccess classLoaderAccess; - private final XMLContext xmlContext; - - /** - * We allow fully disabling XML sources so to improve the efficiency of - * the boot process for those not using it. - */ - private final boolean xmlMappingEnabled; - - private Map defaults; - private Map cache; - - /** - * @deprecated Use {@link JPAMetadataProvider#JPAMetadataProvider(BootstrapContext)} instead. - */ - @Deprecated - public JPAMetadataProvider(final MetadataBuildingOptions metadataBuildingOptions) { - this( new ClassLoaderAccessDelegateImpl() { - ClassLoaderAccess delegate; - - @Override - protected ClassLoaderAccess getDelegate() { - if ( delegate == null ) { - delegate = new ClassLoaderAccessImpl( - metadataBuildingOptions.getTempClassLoader(), - metadataBuildingOptions.getServiceRegistry().getService( ClassLoaderService.class ) - ); - } - return delegate; - } - }, - metadataBuildingOptions.getXmlMappingOptions().isEnabled() ); - } - - public JPAMetadataProvider(BootstrapContext bootstrapContext) { - this( bootstrapContext.getClassLoaderAccess(), - bootstrapContext.getMetadataBuildingOptions().getXmlMappingOptions().isEnabled() ); - } - - JPAMetadataProvider(ClassLoaderAccess classLoaderAccess, boolean xmlMetadataEnabled) { - this.classLoaderAccess = classLoaderAccess; - this.xmlContext = new XMLContext( classLoaderAccess ); - this.xmlMappingEnabled = xmlMetadataEnabled; - } - - //all of the above can be safely rebuilt from XMLContext: only XMLContext this object is serialized - @Override - public AnnotationReader getAnnotationReader(AnnotatedElement annotatedElement) { - if ( cache == null ) { - cache = new HashMap<>(50 ); - } - AnnotationReader reader = cache.get( annotatedElement ); - if (reader == null) { - if ( xmlContext.hasContext() ) { - reader = new JPAOverriddenAnnotationReader( annotatedElement, xmlContext, classLoaderAccess ); - } - else { - reader = STATELESS_BASE_DELEGATE.getAnnotationReader( annotatedElement ); - } - cache.put( annotatedElement, reader ); - } - return reader; - } - - @Override - public void reset() { - //It's better to remove the HashMap, as it could grow rather large: - //when doing a clear() the internal buckets array is not scaled down. - this.cache = null; - } - - @Override - public Map getDefaults() { - if ( xmlMappingEnabled == false ) { - return Collections.emptyMap(); - } - else { - if ( defaults == null ) { - defaults = new HashMap<>(); - XMLContext.Default xmlDefaults = xmlContext.getDefault( null ); - - defaults.put( "schema", xmlDefaults.getSchema() ); - defaults.put( "catalog", xmlDefaults.getCatalog() ); - defaults.put( "delimited-identifier", xmlDefaults.getDelimitedIdentifier() ); - defaults.put( "cascade-persist", xmlDefaults.getCascadePersist() ); - List entityListeners = new ArrayList(); - for ( String className : xmlContext.getDefaultEntityListeners() ) { - try { - entityListeners.add( classLoaderAccess.classForName( className ) ); - } - catch ( ClassLoadingException e ) { - throw new IllegalStateException( "Default entity listener class not found: " + className ); - } - } - defaults.put( EntityListeners.class, entityListeners ); - for ( Element element : xmlContext.getAllDocuments() ) { - @SuppressWarnings( "unchecked" ) - List elements = element.elements( "sequence-generator" ); - List sequenceGenerators = ( List ) defaults.get( SequenceGenerator.class ); - if ( sequenceGenerators == null ) { - sequenceGenerators = new ArrayList<>(); - defaults.put( SequenceGenerator.class, sequenceGenerators ); - } - for ( Element subelement : elements ) { - sequenceGenerators.add( JPAOverriddenAnnotationReader - .buildSequenceGeneratorAnnotation( subelement ) ); - } - - elements = element.elements( "table-generator" ); - List tableGenerators = ( List ) defaults.get( TableGenerator.class ); - if ( tableGenerators == null ) { - tableGenerators = new ArrayList<>(); - defaults.put( TableGenerator.class, tableGenerators ); - } - for ( Element subelement : elements ) { - tableGenerators.add( - JPAOverriddenAnnotationReader.buildTableGeneratorAnnotation( - subelement, xmlDefaults - ) - ); - } - - List namedQueries = ( List ) defaults.get( NamedQuery.class ); - if ( namedQueries == null ) { - namedQueries = new ArrayList<>(); - defaults.put( NamedQuery.class, namedQueries ); - } - List currentNamedQueries = JPAOverriddenAnnotationReader - .buildNamedQueries( - element, - false, - xmlDefaults, - classLoaderAccess - ); - namedQueries.addAll( currentNamedQueries ); - - List namedNativeQueries = ( List ) defaults.get( NamedNativeQuery.class ); - if ( namedNativeQueries == null ) { - namedNativeQueries = new ArrayList<>(); - defaults.put( NamedNativeQuery.class, namedNativeQueries ); - } - List currentNamedNativeQueries = JPAOverriddenAnnotationReader - .buildNamedQueries( - element, - true, - xmlDefaults, - classLoaderAccess - ); - namedNativeQueries.addAll( currentNamedNativeQueries ); - - List sqlResultSetMappings = ( List ) defaults.get( - SqlResultSetMapping.class - ); - if ( sqlResultSetMappings == null ) { - sqlResultSetMappings = new ArrayList<>(); - defaults.put( SqlResultSetMapping.class, sqlResultSetMappings ); - } - List currentSqlResultSetMappings = JPAOverriddenAnnotationReader - .buildSqlResultsetMappings( - element, - xmlDefaults, - classLoaderAccess - ); - sqlResultSetMappings.addAll( currentSqlResultSetMappings ); - - List namedStoredProcedureQueries = (List)defaults.get( NamedStoredProcedureQuery.class ); - if(namedStoredProcedureQueries==null){ - namedStoredProcedureQueries = new ArrayList<>( ); - defaults.put( NamedStoredProcedureQuery.class, namedStoredProcedureQueries ); - } - List currentNamedStoredProcedureQueries = JPAOverriddenAnnotationReader - .buildNamedStoreProcedureQueries( - element, - xmlDefaults, - classLoaderAccess - ); - namedStoredProcedureQueries.addAll( currentNamedStoredProcedureQueries ); - } - } - return defaults; - } - } - - public XMLContext getXMLContext() { - return xmlContext; - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/JPAOverriddenAnnotationReader.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/JPAOverriddenAnnotationReader.java deleted file mode 100644 index 895da45b37df..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/JPAOverriddenAnnotationReader.java +++ /dev/null @@ -1,3091 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.cfg.annotations.reflection; - -import java.beans.Introspector; -import java.lang.annotation.Annotation; -import java.lang.reflect.AccessibleObject; -import java.lang.reflect.AnnotatedElement; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Set; -import javax.persistence.Access; -import javax.persistence.AccessType; -import javax.persistence.AssociationOverride; -import javax.persistence.AssociationOverrides; -import javax.persistence.AttributeOverride; -import javax.persistence.AttributeOverrides; -import javax.persistence.Basic; -import javax.persistence.Cacheable; -import javax.persistence.CascadeType; -import javax.persistence.CollectionTable; -import javax.persistence.Column; -import javax.persistence.ColumnResult; -import javax.persistence.ConstructorResult; -import javax.persistence.Convert; -import javax.persistence.Converts; -import javax.persistence.DiscriminatorColumn; -import javax.persistence.DiscriminatorType; -import javax.persistence.DiscriminatorValue; -import javax.persistence.ElementCollection; -import javax.persistence.Embeddable; -import javax.persistence.Embedded; -import javax.persistence.EmbeddedId; -import javax.persistence.Entity; -import javax.persistence.EntityListeners; -import javax.persistence.EntityResult; -import javax.persistence.EnumType; -import javax.persistence.Enumerated; -import javax.persistence.ExcludeDefaultListeners; -import javax.persistence.ExcludeSuperclassListeners; -import javax.persistence.FetchType; -import javax.persistence.FieldResult; -import javax.persistence.ForeignKey; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.IdClass; -import javax.persistence.Index; -import javax.persistence.Inheritance; -import javax.persistence.InheritanceType; -import javax.persistence.JoinColumn; -import javax.persistence.JoinColumns; -import javax.persistence.JoinTable; -import javax.persistence.Lob; -import javax.persistence.ManyToMany; -import javax.persistence.ManyToOne; -import javax.persistence.MapKey; -import javax.persistence.MapKeyClass; -import javax.persistence.MapKeyColumn; -import javax.persistence.MapKeyEnumerated; -import javax.persistence.MapKeyJoinColumn; -import javax.persistence.MapKeyJoinColumns; -import javax.persistence.MapKeyTemporal; -import javax.persistence.MappedSuperclass; -import javax.persistence.MapsId; -import javax.persistence.NamedAttributeNode; -import javax.persistence.NamedEntityGraph; -import javax.persistence.NamedEntityGraphs; -import javax.persistence.NamedNativeQueries; -import javax.persistence.NamedNativeQuery; -import javax.persistence.NamedQueries; -import javax.persistence.NamedQuery; -import javax.persistence.NamedStoredProcedureQueries; -import javax.persistence.NamedStoredProcedureQuery; -import javax.persistence.NamedSubgraph; -import javax.persistence.OneToMany; -import javax.persistence.OneToOne; -import javax.persistence.OrderBy; -import javax.persistence.OrderColumn; -import javax.persistence.ParameterMode; -import javax.persistence.PostLoad; -import javax.persistence.PostPersist; -import javax.persistence.PostRemove; -import javax.persistence.PostUpdate; -import javax.persistence.PrePersist; -import javax.persistence.PreRemove; -import javax.persistence.PreUpdate; -import javax.persistence.PrimaryKeyJoinColumn; -import javax.persistence.PrimaryKeyJoinColumns; -import javax.persistence.QueryHint; -import javax.persistence.SecondaryTable; -import javax.persistence.SecondaryTables; -import javax.persistence.SequenceGenerator; -import javax.persistence.SqlResultSetMapping; -import javax.persistence.SqlResultSetMappings; -import javax.persistence.StoredProcedureParameter; -import javax.persistence.Table; -import javax.persistence.TableGenerator; -import javax.persistence.Temporal; -import javax.persistence.TemporalType; -import javax.persistence.Transient; -import javax.persistence.UniqueConstraint; -import javax.persistence.Version; - -import org.hibernate.AnnotationException; -import org.hibernate.annotations.Any; -import org.hibernate.annotations.Cascade; -import org.hibernate.annotations.Columns; -import org.hibernate.annotations.ManyToAny; -import org.hibernate.annotations.common.annotationfactory.AnnotationDescriptor; -import org.hibernate.annotations.common.annotationfactory.AnnotationFactory; -import org.hibernate.annotations.common.reflection.AnnotationReader; -import org.hibernate.annotations.common.reflection.ReflectionUtil; -import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; -import org.hibernate.boot.spi.BootstrapContext; -import org.hibernate.boot.spi.ClassLoaderAccess; -import org.hibernate.cfg.annotations.reflection.internal.JPAXMLOverriddenAnnotationReader; -import org.hibernate.internal.CoreLogging; -import org.hibernate.internal.CoreMessageLogger; -import org.hibernate.internal.util.StringHelper; - -import org.dom4j.Attribute; -import org.dom4j.Element; - -/** - * Encapsulates the overriding of Java annotations from an EJB 3.0 descriptor. - * - * @author Paolo Perrotta - * @author Davide Marchignoli - * @author Emmanuel Bernard - * @author Hardy Ferentschik - * - * @deprecated This class is not API: do not use it from application code. - * This class will be removed in Hibernate ORM 6.0. - * For implementation code, use {@link JPAXMLOverriddenAnnotationReader} - * instead. - */ -@Deprecated -@SuppressWarnings("unchecked") -public class JPAOverriddenAnnotationReader implements AnnotationReader { - private static final CoreMessageLogger LOG = CoreLogging.messageLogger( JPAOverriddenAnnotationReader.class ); - - private static final String SCHEMA_VALIDATION = "Activate schema validation for more information"; - private static final String WORD_SEPARATOR = "-"; - - private enum PropertyType { - PROPERTY, - FIELD, - METHOD - } - - private static final Map annotationToXml; - - static { - annotationToXml = new HashMap<>(); - annotationToXml.put( Entity.class, "entity" ); - annotationToXml.put( MappedSuperclass.class, "mapped-superclass" ); - annotationToXml.put( Embeddable.class, "embeddable" ); - annotationToXml.put( Table.class, "table" ); - annotationToXml.put( SecondaryTable.class, "secondary-table" ); - annotationToXml.put( SecondaryTables.class, "secondary-table" ); - annotationToXml.put( PrimaryKeyJoinColumn.class, "primary-key-join-column" ); - annotationToXml.put( PrimaryKeyJoinColumns.class, "primary-key-join-column" ); - annotationToXml.put( IdClass.class, "id-class" ); - annotationToXml.put( Inheritance.class, "inheritance" ); - annotationToXml.put( DiscriminatorValue.class, "discriminator-value" ); - annotationToXml.put( DiscriminatorColumn.class, "discriminator-column" ); - annotationToXml.put( SequenceGenerator.class, "sequence-generator" ); - annotationToXml.put( TableGenerator.class, "table-generator" ); - annotationToXml.put( NamedEntityGraph.class, "named-entity-graph" ); - annotationToXml.put( NamedEntityGraphs.class, "named-entity-graph" ); - annotationToXml.put( NamedQuery.class, "named-query" ); - annotationToXml.put( NamedQueries.class, "named-query" ); - annotationToXml.put( NamedNativeQuery.class, "named-native-query" ); - annotationToXml.put( NamedNativeQueries.class, "named-native-query" ); - annotationToXml.put( NamedStoredProcedureQuery.class, "named-stored-procedure-query" ); - annotationToXml.put( NamedStoredProcedureQueries.class, "named-stored-procedure-query" ); - annotationToXml.put( SqlResultSetMapping.class, "sql-result-set-mapping" ); - annotationToXml.put( SqlResultSetMappings.class, "sql-result-set-mapping" ); - annotationToXml.put( ExcludeDefaultListeners.class, "exclude-default-listeners" ); - annotationToXml.put( ExcludeSuperclassListeners.class, "exclude-superclass-listeners" ); - annotationToXml.put( AccessType.class, "access" ); - annotationToXml.put( AttributeOverride.class, "attribute-override" ); - annotationToXml.put( AttributeOverrides.class, "attribute-override" ); - annotationToXml.put( AttributeOverride.class, "association-override" ); - annotationToXml.put( AttributeOverrides.class, "association-override" ); - annotationToXml.put( AttributeOverride.class, "map-key-attribute-override" ); - annotationToXml.put( AttributeOverrides.class, "map-key-attribute-override" ); - annotationToXml.put( Id.class, "id" ); - annotationToXml.put( EmbeddedId.class, "embedded-id" ); - annotationToXml.put( GeneratedValue.class, "generated-value" ); - annotationToXml.put( Column.class, "column" ); - annotationToXml.put( Columns.class, "column" ); - annotationToXml.put( Temporal.class, "temporal" ); - annotationToXml.put( Lob.class, "lob" ); - annotationToXml.put( Enumerated.class, "enumerated" ); - annotationToXml.put( Version.class, "version" ); - annotationToXml.put( Transient.class, "transient" ); - annotationToXml.put( Basic.class, "basic" ); - annotationToXml.put( Embedded.class, "embedded" ); - annotationToXml.put( ManyToOne.class, "many-to-one" ); - annotationToXml.put( OneToOne.class, "one-to-one" ); - annotationToXml.put( OneToMany.class, "one-to-many" ); - annotationToXml.put( ManyToMany.class, "many-to-many" ); - annotationToXml.put( Any.class, "any" ); - annotationToXml.put( ManyToAny.class, "many-to-any" ); - annotationToXml.put( JoinTable.class, "join-table" ); - annotationToXml.put( JoinColumn.class, "join-column" ); - annotationToXml.put( JoinColumns.class, "join-column" ); - annotationToXml.put( MapKey.class, "map-key" ); - annotationToXml.put( OrderBy.class, "order-by" ); - annotationToXml.put( EntityListeners.class, "entity-listeners" ); - annotationToXml.put( PrePersist.class, "pre-persist" ); - annotationToXml.put( PreRemove.class, "pre-remove" ); - annotationToXml.put( PreUpdate.class, "pre-update" ); - annotationToXml.put( PostPersist.class, "post-persist" ); - annotationToXml.put( PostRemove.class, "post-remove" ); - annotationToXml.put( PostUpdate.class, "post-update" ); - annotationToXml.put( PostLoad.class, "post-load" ); - annotationToXml.put( CollectionTable.class, "collection-table" ); - annotationToXml.put( MapKeyClass.class, "map-key-class" ); - annotationToXml.put( MapKeyTemporal.class, "map-key-temporal" ); - annotationToXml.put( MapKeyEnumerated.class, "map-key-enumerated" ); - annotationToXml.put( MapKeyColumn.class, "map-key-column" ); - annotationToXml.put( MapKeyJoinColumn.class, "map-key-join-column" ); - annotationToXml.put( MapKeyJoinColumns.class, "map-key-join-column" ); - annotationToXml.put( OrderColumn.class, "order-column" ); - annotationToXml.put( Cacheable.class, "cacheable" ); - annotationToXml.put( Index.class, "index" ); - annotationToXml.put( ForeignKey.class, "foreign-key" ); - annotationToXml.put( Convert.class, "convert" ); - annotationToXml.put( Converts.class, "convert" ); - annotationToXml.put( ConstructorResult.class, "constructor-result" ); - } - - private final XMLContext xmlContext; - private final ClassLoaderAccess classLoaderAccess; - private final AnnotatedElement element; - private final String className; - private final String propertyName; - private final PropertyType propertyType; - private transient Annotation[] annotations; - private transient Map annotationsMap; - private transient List elementsForProperty; - private AccessibleObject mirroredAttribute; - - /** - * @deprecated Use {@link #JPAOverriddenAnnotationReader(AnnotatedElement, XMLContext, BootstrapContext)} instead. - */ - public JPAOverriddenAnnotationReader( - AnnotatedElement el, - XMLContext xmlContext, - ClassLoaderAccess classLoaderAccess) { - this.element = el; - this.xmlContext = xmlContext; - this.classLoaderAccess = classLoaderAccess; - - if ( el instanceof Class ) { - Class clazz = (Class) el; - className = clazz.getName(); - propertyName = null; - propertyType = null; - } - else if ( el instanceof Field ) { - Field field = (Field) el; - className = field.getDeclaringClass().getName(); - propertyName = field.getName(); - propertyType = PropertyType.FIELD; - String expectedGetter = "get" + Character.toUpperCase( propertyName.charAt( 0 ) ) + propertyName.substring( - 1 - ); - try { - mirroredAttribute = field.getDeclaringClass().getDeclaredMethod( expectedGetter ); - } - catch ( NoSuchMethodException e ) { - //no method - } - } - else if ( el instanceof Method ) { - Method method = (Method) el; - className = method.getDeclaringClass().getName(); - String methodName = method.getName(); - - // YUCK! The null here is the 'boundType', we'd rather get the TypeEnvironment() - if ( ReflectionUtil.isProperty( method, null, PersistentAttributeFilter.INSTANCE ) ) { - if ( methodName.startsWith( "get" ) ) { - propertyName = Introspector.decapitalize( methodName.substring( "get".length() ) ); - } - else if ( methodName.startsWith( "is" ) ) { - propertyName = Introspector.decapitalize( methodName.substring( "is".length() ) ); - } - else { - throw new RuntimeException( "Method " + methodName + " is not a property getter" ); - } - propertyType = PropertyType.PROPERTY; - try { - mirroredAttribute = method.getDeclaringClass().getDeclaredField( propertyName ); - } - catch ( NoSuchFieldException e ) { - //no method - } - } - else { - propertyName = methodName; - propertyType = PropertyType.METHOD; - } - } - else { - className = null; - propertyName = null; - propertyType = null; - } - } - - public JPAOverriddenAnnotationReader( - AnnotatedElement el, - XMLContext xmlContext, - BootstrapContext bootstrapContext) { - this( el, xmlContext, bootstrapContext.getClassLoaderAccess() ); - } - - - public T getAnnotation(Class annotationType) { - initAnnotations(); - return (T) annotationsMap.get( annotationType ); - } - - public boolean isAnnotationPresent(Class annotationType) { - initAnnotations(); - return annotationsMap.containsKey( annotationType ); - } - - public Annotation[] getAnnotations() { - initAnnotations(); - return annotations; - } - - /* - * The idea is to create annotation proxies for the xml configuration elements. Using this proxy annotations together - * with the {@link JPAMetadataProvider} allows to handle xml configuration the same way as annotation configuration. - */ - private void initAnnotations() { - if ( annotations == null ) { - XMLContext.Default defaults = xmlContext.getDefault( className ); - if ( className != null && propertyName == null ) { - //is a class - Element tree = xmlContext.getXMLTree( className ); - Annotation[] annotations = getPhysicalAnnotations(); - List annotationList = new ArrayList<>( annotations.length + 5 ); - annotationsMap = new HashMap<>( annotations.length + 5 ); - for ( Annotation annotation : annotations ) { - if ( !annotationToXml.containsKey( annotation.annotationType() ) ) { - //unknown annotations are left over - annotationList.add( annotation ); - } - } - addIfNotNull( annotationList, getEntity( tree, defaults ) ); - addIfNotNull( annotationList, getMappedSuperclass( tree, defaults ) ); - addIfNotNull( annotationList, getEmbeddable( tree, defaults ) ); - addIfNotNull( annotationList, getTable( tree, defaults ) ); - addIfNotNull( annotationList, getSecondaryTables( tree, defaults ) ); - addIfNotNull( annotationList, getPrimaryKeyJoinColumns( tree, defaults, true ) ); - addIfNotNull( annotationList, getIdClass( tree, defaults ) ); - addIfNotNull( annotationList, getCacheable( tree, defaults ) ); - addIfNotNull( annotationList, getInheritance( tree, defaults ) ); - addIfNotNull( annotationList, getDiscriminatorValue( tree, defaults ) ); - addIfNotNull( annotationList, getDiscriminatorColumn( tree, defaults ) ); - addIfNotNull( annotationList, getSequenceGenerator( tree, defaults ) ); - addIfNotNull( annotationList, getTableGenerator( tree, defaults ) ); - addIfNotNull( annotationList, getNamedQueries( tree, defaults ) ); - addIfNotNull( annotationList, getNamedNativeQueries( tree, defaults ) ); - addIfNotNull( annotationList, getNamedStoredProcedureQueries( tree, defaults ) ); - addIfNotNull( annotationList, getNamedEntityGraphs( tree, defaults ) ); - addIfNotNull( annotationList, getSqlResultSetMappings( tree, defaults ) ); - addIfNotNull( annotationList, getExcludeDefaultListeners( tree, defaults ) ); - addIfNotNull( annotationList, getExcludeSuperclassListeners( tree, defaults ) ); - addIfNotNull( annotationList, getAccessType( tree, defaults ) ); - addIfNotNull( annotationList, getAttributeOverrides( tree, defaults, true ) ); - addIfNotNull( annotationList, getAssociationOverrides( tree, defaults, true ) ); - addIfNotNull( annotationList, getEntityListeners( tree, defaults ) ); - addIfNotNull( annotationList, getConverts( tree, defaults ) ); - - this.annotations = annotationList.toArray( new Annotation[annotationList.size()] ); - for ( Annotation ann : this.annotations ) { - annotationsMap.put( ann.annotationType(), ann ); - } - checkForOrphanProperties( tree ); - } - else if ( className != null ) { //&& propertyName != null ) { //always true but less confusing - Element tree = xmlContext.getXMLTree( className ); - Annotation[] annotations = getPhysicalAnnotations(); - List annotationList = new ArrayList<>( annotations.length + 5 ); - annotationsMap = new HashMap<>( annotations.length + 5 ); - for ( Annotation annotation : annotations ) { - if ( !annotationToXml.containsKey( annotation.annotationType() ) ) { - //unknown annotations are left over - annotationList.add( annotation ); - } - } - preCalculateElementsForProperty( tree ); - Transient transientAnn = getTransient( defaults ); - if ( transientAnn != null ) { - annotationList.add( transientAnn ); - } - else { - if ( defaults.canUseJavaAnnotations() ) { - Annotation annotation = getPhysicalAnnotation( Access.class ); - addIfNotNull( annotationList, annotation ); - } - getId( annotationList, defaults ); - getEmbeddedId( annotationList, defaults ); - getEmbedded( annotationList, defaults ); - getBasic( annotationList, defaults ); - getVersion( annotationList, defaults ); - getAssociation( ManyToOne.class, annotationList, defaults ); - getAssociation( OneToOne.class, annotationList, defaults ); - getAssociation( OneToMany.class, annotationList, defaults ); - getAssociation( ManyToMany.class, annotationList, defaults ); - getAssociation( Any.class, annotationList, defaults ); - getAssociation( ManyToAny.class, annotationList, defaults ); - getElementCollection( annotationList, defaults ); - addIfNotNull( annotationList, getSequenceGenerator( elementsForProperty, defaults ) ); - addIfNotNull( annotationList, getTableGenerator( elementsForProperty, defaults ) ); - addIfNotNull( annotationList, getConvertsForAttribute( elementsForProperty, defaults ) ); - } - processEventAnnotations( annotationList, defaults ); - //FIXME use annotationsMap rather than annotationList this will be faster since the annotation type is usually known at put() time - this.annotations = annotationList.toArray( new Annotation[annotationList.size()] ); - for ( Annotation ann : this.annotations ) { - annotationsMap.put( ann.annotationType(), ann ); - } - } - else { - this.annotations = getPhysicalAnnotations(); - annotationsMap = new HashMap<>( annotations.length + 5 ); - for ( Annotation ann : this.annotations ) { - annotationsMap.put( ann.annotationType(), ann ); - } - } - } - } - - private Annotation getConvertsForAttribute(List elementsForProperty, XMLContext.Default defaults) { - // NOTE : we use a map here to make sure that an xml and annotation referring to the same attribute - // properly overrides. Very sparse map, yes, but easy setup. - // todo : revisit this - // although bear in mind that this code is no longer used in 5.0... - - final Map convertAnnotationsMap = new HashMap<>(); - - for ( Element element : elementsForProperty ) { - final boolean isBasic = "basic".equals( element.getName() ); - final boolean isEmbedded = "embedded".equals( element.getName() ); - final boolean isElementCollection = "element-collection".equals(element.getName()); - - final boolean canHaveConverts = isBasic || isEmbedded || isElementCollection; - - if ( !canHaveConverts ) { - continue; - } - - final String attributeNamePrefix = isBasic ? null : propertyName; - applyXmlDefinedConverts( element, defaults, attributeNamePrefix, convertAnnotationsMap ); - } - - // NOTE : per section 12.2.3.16 of the spec is additive, although only if "metadata-complete" is not - // specified in the XML - - if ( defaults.canUseJavaAnnotations() ) { - // todo : note sure how to best handle attributeNamePrefix here - applyPhysicalConvertAnnotations( propertyName, convertAnnotationsMap ); - } - - if ( !convertAnnotationsMap.isEmpty() ) { - final AnnotationDescriptor groupingDescriptor = new AnnotationDescriptor( Converts.class ); - groupingDescriptor.setValue( "value", convertAnnotationsMap.values().toArray( new Convert[convertAnnotationsMap.size()]) ); - return AnnotationFactory.create( groupingDescriptor ); - } - - return null; - } - - private Converts getConverts(Element tree, XMLContext.Default defaults) { - // NOTE : we use a map here to make sure that an xml and annotation referring to the same attribute - // properly overrides. Bit sparse, but easy... - final Map convertAnnotationsMap = new HashMap<>(); - - if ( tree != null ) { - applyXmlDefinedConverts( tree, defaults, null, convertAnnotationsMap ); - } - - // NOTE : per section 12.2.3.16 of the spec is additive, although only if "metadata-complete" is not - // specified in the XML - - if ( defaults.canUseJavaAnnotations() ) { - applyPhysicalConvertAnnotations( null, convertAnnotationsMap ); - } - - if ( !convertAnnotationsMap.isEmpty() ) { - final AnnotationDescriptor groupingDescriptor = new AnnotationDescriptor( Converts.class ); - groupingDescriptor.setValue( "value", convertAnnotationsMap.values().toArray( new Convert[convertAnnotationsMap.size()]) ); - return AnnotationFactory.create( groupingDescriptor ); - } - - return null; - } - - private void applyXmlDefinedConverts( - Element containingElement, - XMLContext.Default defaults, - String attributeNamePrefix, - Map convertAnnotationsMap) { - final List convertElements = containingElement.elements( "convert" ); - for ( Element convertElement : convertElements ) { - final AnnotationDescriptor convertAnnotationDescriptor = new AnnotationDescriptor( Convert.class ); - copyStringAttribute( convertAnnotationDescriptor, convertElement, "attribute-name", false ); - copyBooleanAttribute( convertAnnotationDescriptor, convertElement, "disable-conversion" ); - - final Attribute converterClassAttr = convertElement.attribute( "converter" ); - if ( converterClassAttr != null ) { - final String converterClassName = XMLContext.buildSafeClassName( - converterClassAttr.getValue(), - defaults - ); - try { - final Class converterClass = classLoaderAccess.classForName( converterClassName ); - convertAnnotationDescriptor.setValue( "converter", converterClass ); - } - catch (ClassLoadingException e) { - throw new AnnotationException( "Unable to find specified converter class id-class: " + converterClassName, e ); - } - } - final Convert convertAnnotation = AnnotationFactory.create( convertAnnotationDescriptor ); - final String qualifiedAttributeName = qualifyConverterAttributeName( - attributeNamePrefix, - convertAnnotation.attributeName() - ); - convertAnnotationsMap.put( qualifiedAttributeName, convertAnnotation ); - } - - } - - private String qualifyConverterAttributeName(String attributeNamePrefix, String specifiedAttributeName) { - String qualifiedAttributeName; - if ( StringHelper.isNotEmpty( specifiedAttributeName ) ) { - if ( StringHelper.isNotEmpty( attributeNamePrefix ) ) { - qualifiedAttributeName = attributeNamePrefix + '.' + specifiedAttributeName; - } - else { - qualifiedAttributeName = specifiedAttributeName; - } - } - else { - qualifiedAttributeName = ""; - } - return qualifiedAttributeName; - } - - private void applyPhysicalConvertAnnotations( - String attributeNamePrefix, - Map convertAnnotationsMap) { - final Convert physicalAnnotation = getPhysicalAnnotation( Convert.class ); - if ( physicalAnnotation != null ) { - // only add if no XML element named a converter for this attribute - final String qualifiedAttributeName = qualifyConverterAttributeName( attributeNamePrefix, physicalAnnotation.attributeName() ); - if ( ! convertAnnotationsMap.containsKey( qualifiedAttributeName ) ) { - convertAnnotationsMap.put( qualifiedAttributeName, physicalAnnotation ); - } - } - final Converts physicalGroupingAnnotation = getPhysicalAnnotation( Converts.class ); - if ( physicalGroupingAnnotation != null ) { - for ( Convert convertAnnotation : physicalGroupingAnnotation.value() ) { - // again, only add if no XML element named a converter for this attribute - final String qualifiedAttributeName = qualifyConverterAttributeName( attributeNamePrefix, convertAnnotation.attributeName() ); - if ( ! convertAnnotationsMap.containsKey( qualifiedAttributeName ) ) { - convertAnnotationsMap.put( qualifiedAttributeName, convertAnnotation ); - } - } - } - } - - private void checkForOrphanProperties(Element tree) { - Class clazz; - try { - clazz = classLoaderAccess.classForName( className ); - } - catch ( ClassLoadingException e ) { - return; //a primitive type most likely - } - Element element = tree != null ? tree.element( "attributes" ) : null; - //put entity.attributes elements - if ( element != null ) { - //precompute the list of properties - //TODO is it really useful... - Set properties = new HashSet<>(); - for ( Field field : clazz.getFields() ) { - properties.add( field.getName() ); - } - for ( Method method : clazz.getMethods() ) { - String name = method.getName(); - if ( name.startsWith( "get" ) ) { - properties.add( Introspector.decapitalize( name.substring( "get".length() ) ) ); - } - else if ( name.startsWith( "is" ) ) { - properties.add( Introspector.decapitalize( name.substring( "is".length() ) ) ); - } - } - for ( Element subelement : (List) element.elements() ) { - String propertyName = subelement.attributeValue( "name" ); - if ( !properties.contains( propertyName ) ) { - LOG.propertyNotFound( StringHelper.qualify( className, propertyName ) ); - } - } - } - } - - /** - * Adds {@code annotation} to the list (only if it's not null) and then returns it. - * - * @param annotationList The list of annotations. - * @param annotation The annotation to add to the list. - * - * @return The annotation which was added to the list or {@code null}. - */ - private Annotation addIfNotNull(List annotationList, Annotation annotation) { - if ( annotation != null ) { - annotationList.add( annotation ); - } - return annotation; - } - - //TODO mutualize the next 2 methods - private Annotation getTableGenerator(List elementsForProperty, XMLContext.Default defaults) { - for ( Element element : elementsForProperty ) { - Element subelement = element != null ? element.element( annotationToXml.get( TableGenerator.class ) ) : null; - if ( subelement != null ) { - return buildTableGeneratorAnnotation( subelement, defaults ); - } - } - if ( elementsForProperty.size() == 0 && defaults.canUseJavaAnnotations() ) { - return getPhysicalAnnotation( TableGenerator.class ); - } - else { - return null; - } - } - - private Annotation getSequenceGenerator(List elementsForProperty, XMLContext.Default defaults) { - for ( Element element : elementsForProperty ) { - Element subelement = element != null ? element.element( annotationToXml.get( SequenceGenerator.class ) ) : null; - if ( subelement != null ) { - return buildSequenceGeneratorAnnotation( subelement ); - } - } - if ( elementsForProperty.size() == 0 && defaults.canUseJavaAnnotations() ) { - return getPhysicalAnnotation( SequenceGenerator.class ); - } - else { - return null; - } - } - - private void processEventAnnotations(List annotationList, XMLContext.Default defaults) { - boolean eventElement = false; - for ( Element element : elementsForProperty ) { - String elementName = element.getName(); - if ( "pre-persist".equals( elementName ) ) { - AnnotationDescriptor ad = new AnnotationDescriptor( PrePersist.class ); - annotationList.add( AnnotationFactory.create( ad ) ); - eventElement = true; - } - else if ( "pre-remove".equals( elementName ) ) { - AnnotationDescriptor ad = new AnnotationDescriptor( PreRemove.class ); - annotationList.add( AnnotationFactory.create( ad ) ); - eventElement = true; - } - else if ( "pre-update".equals( elementName ) ) { - AnnotationDescriptor ad = new AnnotationDescriptor( PreUpdate.class ); - annotationList.add( AnnotationFactory.create( ad ) ); - eventElement = true; - } - else if ( "post-persist".equals( elementName ) ) { - AnnotationDescriptor ad = new AnnotationDescriptor( PostPersist.class ); - annotationList.add( AnnotationFactory.create( ad ) ); - eventElement = true; - } - else if ( "post-remove".equals( elementName ) ) { - AnnotationDescriptor ad = new AnnotationDescriptor( PostRemove.class ); - annotationList.add( AnnotationFactory.create( ad ) ); - eventElement = true; - } - else if ( "post-update".equals( elementName ) ) { - AnnotationDescriptor ad = new AnnotationDescriptor( PostUpdate.class ); - annotationList.add( AnnotationFactory.create( ad ) ); - eventElement = true; - } - else if ( "post-load".equals( elementName ) ) { - AnnotationDescriptor ad = new AnnotationDescriptor( PostLoad.class ); - annotationList.add( AnnotationFactory.create( ad ) ); - eventElement = true; - } - } - if ( !eventElement && defaults.canUseJavaAnnotations() ) { - Annotation ann = getPhysicalAnnotation( PrePersist.class ); - addIfNotNull( annotationList, ann ); - ann = getPhysicalAnnotation( PreRemove.class ); - addIfNotNull( annotationList, ann ); - ann = getPhysicalAnnotation( PreUpdate.class ); - addIfNotNull( annotationList, ann ); - ann = getPhysicalAnnotation( PostPersist.class ); - addIfNotNull( annotationList, ann ); - ann = getPhysicalAnnotation( PostRemove.class ); - addIfNotNull( annotationList, ann ); - ann = getPhysicalAnnotation( PostUpdate.class ); - addIfNotNull( annotationList, ann ); - ann = getPhysicalAnnotation( PostLoad.class ); - addIfNotNull( annotationList, ann ); - } - } - - private EntityListeners getEntityListeners(Element tree, XMLContext.Default defaults) { - Element element = tree != null ? tree.element( "entity-listeners" ) : null; - if ( element != null ) { - List entityListenerClasses = new ArrayList<>(); - for ( Element subelement : (List) element.elements( "entity-listener" ) ) { - String className = subelement.attributeValue( "class" ); - try { - entityListenerClasses.add( - classLoaderAccess.classForName( - XMLContext.buildSafeClassName( className, defaults ) - ) - ); - } - catch ( ClassLoadingException e ) { - throw new AnnotationException( - "Unable to find " + element.getPath() + ".class: " + className, e - ); - } - } - AnnotationDescriptor ad = new AnnotationDescriptor( EntityListeners.class ); - ad.setValue( "value", entityListenerClasses.toArray( new Class[entityListenerClasses.size()] ) ); - return AnnotationFactory.create( ad ); - } - else if ( defaults.canUseJavaAnnotations() ) { - return getPhysicalAnnotation( EntityListeners.class ); - } - else { - return null; - } - } - - private JoinTable overridesDefaultsInJoinTable(Annotation annotation, XMLContext.Default defaults) { - //no element but might have some default or some annotation - boolean defaultToJoinTable = !( isPhysicalAnnotationPresent( JoinColumn.class ) - || isPhysicalAnnotationPresent( JoinColumns.class ) ); - final Class annotationClass = annotation.annotationType(); - defaultToJoinTable = defaultToJoinTable && - ( ( annotationClass == ManyToMany.class && StringHelper.isEmpty( ( (ManyToMany) annotation ).mappedBy() ) ) - || ( annotationClass == OneToMany.class && StringHelper.isEmpty( ( (OneToMany) annotation ).mappedBy() ) ) - || ( annotationClass == ElementCollection.class ) - ); - final Class annotationType = JoinTable.class; - if ( defaultToJoinTable - && ( StringHelper.isNotEmpty( defaults.getCatalog() ) - || StringHelper.isNotEmpty( defaults.getSchema() ) ) ) { - AnnotationDescriptor ad = new AnnotationDescriptor( annotationType ); - if ( defaults.canUseJavaAnnotations() ) { - JoinTable table = getPhysicalAnnotation( annotationType ); - if ( table != null ) { - ad.setValue( "name", table.name() ); - ad.setValue( "schema", table.schema() ); - ad.setValue( "catalog", table.catalog() ); - ad.setValue( "uniqueConstraints", table.uniqueConstraints() ); - ad.setValue( "joinColumns", table.joinColumns() ); - ad.setValue( "inverseJoinColumns", table.inverseJoinColumns() ); - } - } - if ( StringHelper.isEmpty( (String) ad.valueOf( "schema" ) ) - && StringHelper.isNotEmpty( defaults.getSchema() ) ) { - ad.setValue( "schema", defaults.getSchema() ); - } - if ( StringHelper.isEmpty( (String) ad.valueOf( "catalog" ) ) - && StringHelper.isNotEmpty( defaults.getCatalog() ) ) { - ad.setValue( "catalog", defaults.getCatalog() ); - } - return AnnotationFactory.create( ad ); - } - else if ( defaults.canUseJavaAnnotations() ) { - return getPhysicalAnnotation( annotationType ); - } - else { - return null; - } - } - - private Annotation overridesDefaultCascadePersist(Annotation annotation, XMLContext.Default defaults) { - if ( Boolean.TRUE.equals( defaults.getCascadePersist() ) ) { - final Class annotationType = annotation.annotationType(); - - if ( annotationType == ManyToOne.class ) { - ManyToOne manyToOne = (ManyToOne) annotation; - List cascades = new ArrayList<>( Arrays.asList( manyToOne.cascade() ) ); - if ( !cascades.contains( CascadeType.ALL ) && !cascades.contains( CascadeType.PERSIST ) ) { - cascades.add( CascadeType.PERSIST ); - } - else { - return annotation; - } - - AnnotationDescriptor ad = new AnnotationDescriptor( annotationType ); - ad.setValue( "cascade", cascades.toArray( new CascadeType[] {} ) ); - ad.setValue( "targetEntity", manyToOne.targetEntity() ); - ad.setValue( "fetch", manyToOne.fetch() ); - ad.setValue( "optional", manyToOne.optional() ); - - return AnnotationFactory.create( ad ); - } - else if ( annotationType == OneToOne.class ) { - OneToOne oneToOne = (OneToOne) annotation; - List cascades = new ArrayList<>( Arrays.asList( oneToOne.cascade() ) ); - if ( !cascades.contains( CascadeType.ALL ) && !cascades.contains( CascadeType.PERSIST ) ) { - cascades.add( CascadeType.PERSIST ); - } - else { - return annotation; - } - - AnnotationDescriptor ad = new AnnotationDescriptor( annotationType ); - ad.setValue( "cascade", cascades.toArray( new CascadeType[] {} ) ); - ad.setValue( "targetEntity", oneToOne.targetEntity() ); - ad.setValue( "fetch", oneToOne.fetch() ); - ad.setValue( "optional", oneToOne.optional() ); - ad.setValue( "mappedBy", oneToOne.mappedBy() ); - ad.setValue( "orphanRemoval", oneToOne.orphanRemoval() ); - - return AnnotationFactory.create( ad ); - } - } - return annotation; - } - - private void getJoinTable(List annotationList, Element tree, XMLContext.Default defaults) { - addIfNotNull( annotationList, buildJoinTable( tree, defaults ) ); - } - - /* - * no partial overriding possible - */ - private JoinTable buildJoinTable(Element tree, XMLContext.Default defaults) { - Element subelement = tree == null ? null : tree.element( "join-table" ); - final Class annotationType = JoinTable.class; - if ( subelement == null ) { - return null; - } - //ignore java annotation, an element is defined - AnnotationDescriptor annotation = new AnnotationDescriptor( annotationType ); - copyStringAttribute( annotation, subelement, "name", false ); - copyStringAttribute( annotation, subelement, "catalog", false ); - if ( StringHelper.isNotEmpty( defaults.getCatalog() ) - && StringHelper.isEmpty( (String) annotation.valueOf( "catalog" ) ) ) { - annotation.setValue( "catalog", defaults.getCatalog() ); - } - copyStringAttribute( annotation, subelement, "schema", false ); - if ( StringHelper.isNotEmpty( defaults.getSchema() ) - && StringHelper.isEmpty( (String) annotation.valueOf( "schema" ) ) ) { - annotation.setValue( "schema", defaults.getSchema() ); - } - buildUniqueConstraints( annotation, subelement ); - buildIndex( annotation, subelement ); - annotation.setValue( "joinColumns", getJoinColumns( subelement, false ) ); - annotation.setValue( "inverseJoinColumns", getJoinColumns( subelement, true ) ); - return AnnotationFactory.create( annotation ); - } - - /** - * As per section 12.2 of the JPA 2.0 specification, the association - * subelements (many-to-one, one-to-many, one-to-one, many-to-many, - * element-collection) completely override the mapping for the specified - * field or property. Thus, any methods which might in some contexts merge - * with annotations must not do so in this context. - * - * @see #getElementCollection(List, XMLContext.Default) - */ - private void getAssociation( - Class annotationType, List annotationList, XMLContext.Default defaults - ) { - String xmlName = annotationToXml.get( annotationType ); - for ( Element element : elementsForProperty ) { - if ( xmlName.equals( element.getName() ) ) { - AnnotationDescriptor ad = new AnnotationDescriptor( annotationType ); - addTargetClass( element, ad, "target-entity", defaults ); - getFetchType( ad, element ); - getCascades( ad, element, defaults ); - getJoinTable( annotationList, element, defaults ); - buildJoinColumns( annotationList, element ); - Annotation annotation = getPrimaryKeyJoinColumns( element, defaults, false ); - addIfNotNull( annotationList, annotation ); - copyBooleanAttribute( ad, element, "optional" ); - copyBooleanAttribute( ad, element, "orphan-removal" ); - copyStringAttribute( ad, element, "mapped-by", false ); - getOrderBy( annotationList, element ); - getMapKey( annotationList, element ); - getMapKeyClass( annotationList, element, defaults ); - getMapKeyColumn( annotationList, element ); - getOrderColumn( annotationList, element ); - getMapKeyTemporal( annotationList, element ); - getMapKeyEnumerated( annotationList, element ); - annotation = getMapKeyAttributeOverrides( element, defaults ); - addIfNotNull( annotationList, annotation ); - buildMapKeyJoinColumns( annotationList, element ); - getAssociationId( annotationList, element ); - getMapsId( annotationList, element ); - annotationList.add( AnnotationFactory.create( ad ) ); - getAccessType( annotationList, element ); - } - } - if ( elementsForProperty.size() == 0 && defaults.canUseJavaAnnotations() ) { - Annotation annotation = getPhysicalAnnotation( annotationType ); - if ( annotation != null ) { - annotation = overridesDefaultCascadePersist( annotation, defaults ); - annotationList.add( annotation ); - annotation = overridesDefaultsInJoinTable( annotation, defaults ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( JoinColumn.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( JoinColumns.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( PrimaryKeyJoinColumn.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( PrimaryKeyJoinColumns.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( MapKey.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( OrderBy.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( AttributeOverride.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( AttributeOverrides.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( AssociationOverride.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( AssociationOverrides.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( Lob.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( Enumerated.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( Temporal.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( Column.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( Columns.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( MapKeyClass.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( MapKeyTemporal.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( MapKeyEnumerated.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( MapKeyColumn.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( MapKeyJoinColumn.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( MapKeyJoinColumns.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( OrderColumn.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( Cascade.class ); - addIfNotNull( annotationList, annotation ); - } - else if ( isPhysicalAnnotationPresent( ElementCollection.class ) ) { //JPA2 - annotation = overridesDefaultsInJoinTable( getPhysicalAnnotation( ElementCollection.class ), defaults ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( MapKey.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( OrderBy.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( AttributeOverride.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( AttributeOverrides.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( AssociationOverride.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( AssociationOverrides.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( Lob.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( Enumerated.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( Temporal.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( Column.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( OrderColumn.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( MapKeyClass.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( MapKeyTemporal.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( MapKeyEnumerated.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( MapKeyColumn.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( MapKeyJoinColumn.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( MapKeyJoinColumns.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( CollectionTable.class ); - addIfNotNull( annotationList, annotation ); - } - } - } - - private void buildMapKeyJoinColumns(List annotationList, Element element) { - MapKeyJoinColumn[] joinColumns = getMapKeyJoinColumns( element ); - if ( joinColumns.length > 0 ) { - AnnotationDescriptor ad = new AnnotationDescriptor( MapKeyJoinColumns.class ); - ad.setValue( "value", joinColumns ); - annotationList.add( AnnotationFactory.create( ad ) ); - } - } - - private MapKeyJoinColumn[] getMapKeyJoinColumns(Element element) { - List subelements = element != null ? element.elements( "map-key-join-column" ) : null; - List joinColumns = new ArrayList<>(); - if ( subelements != null ) { - for ( Element subelement : subelements ) { - AnnotationDescriptor column = new AnnotationDescriptor( MapKeyJoinColumn.class ); - copyStringAttribute( column, subelement, "name", false ); - copyStringAttribute( column, subelement, "referenced-column-name", false ); - copyBooleanAttribute( column, subelement, "unique" ); - copyBooleanAttribute( column, subelement, "nullable" ); - copyBooleanAttribute( column, subelement, "insertable" ); - copyBooleanAttribute( column, subelement, "updatable" ); - copyStringAttribute( column, subelement, "column-definition", false ); - copyStringAttribute( column, subelement, "table", false ); - joinColumns.add( AnnotationFactory.create( column ) ); - } - } - return joinColumns.toArray( new MapKeyJoinColumn[joinColumns.size()] ); - } - - private AttributeOverrides getMapKeyAttributeOverrides(Element tree, XMLContext.Default defaults) { - List attributes = buildAttributeOverrides( tree, "map-key-attribute-override" ); - return mergeAttributeOverrides( defaults, attributes, false ); - } - - private Cacheable getCacheable(Element element, XMLContext.Default defaults){ - if ( element != null ) { - String attValue = element.attributeValue( "cacheable" ); - if ( attValue != null ) { - AnnotationDescriptor ad = new AnnotationDescriptor( Cacheable.class ); - ad.setValue( "value", Boolean.valueOf( attValue ) ); - return AnnotationFactory.create( ad ); - } - } - if ( defaults.canUseJavaAnnotations() ) { - return getPhysicalAnnotation( Cacheable.class ); - } - else { - return null; - } - } - /** - * Adds a @MapKeyEnumerated annotation to the specified annotationList if the specified element - * contains a map-key-enumerated sub-element. This should only be the case for - * element-collection, many-to-many, or one-to-many associations. - */ - private void getMapKeyEnumerated(List annotationList, Element element) { - Element subelement = element != null ? element.element( "map-key-enumerated" ) : null; - if ( subelement != null ) { - AnnotationDescriptor ad = new AnnotationDescriptor( MapKeyEnumerated.class ); - EnumType value = EnumType.valueOf( subelement.getTextTrim() ); - ad.setValue( "value", value ); - annotationList.add( AnnotationFactory.create( ad ) ); - } - } - - /** - * Adds a @MapKeyTemporal annotation to the specified annotationList if the specified element - * contains a map-key-temporal sub-element. This should only be the case for element-collection, - * many-to-many, or one-to-many associations. - */ - private void getMapKeyTemporal(List annotationList, Element element) { - Element subelement = element != null ? element.element( "map-key-temporal" ) : null; - if ( subelement != null ) { - AnnotationDescriptor ad = new AnnotationDescriptor( MapKeyTemporal.class ); - TemporalType value = TemporalType.valueOf( subelement.getTextTrim() ); - ad.setValue( "value", value ); - annotationList.add( AnnotationFactory.create( ad ) ); - } - } - - /** - * Adds an @OrderColumn annotation to the specified annotationList if the specified element - * contains an order-column sub-element. This should only be the case for element-collection, - * many-to-many, or one-to-many associations. - */ - private void getOrderColumn(List annotationList, Element element) { - Element subelement = element != null ? element.element( "order-column" ) : null; - if ( subelement != null ) { - AnnotationDescriptor ad = new AnnotationDescriptor( OrderColumn.class ); - copyStringAttribute( ad, subelement, "name", false ); - copyBooleanAttribute( ad, subelement, "nullable" ); - copyBooleanAttribute( ad, subelement, "insertable" ); - copyBooleanAttribute( ad, subelement, "updatable" ); - copyStringAttribute( ad, subelement, "column-definition", false ); - annotationList.add( AnnotationFactory.create( ad ) ); - } - } - - /** - * Adds a @MapsId annotation to the specified annotationList if the specified element has the - * maps-id attribute set. This should only be the case for many-to-one or one-to-one - * associations. - */ - private void getMapsId(List annotationList, Element element) { - String attrVal = element.attributeValue( "maps-id" ); - if ( attrVal != null ) { - AnnotationDescriptor ad = new AnnotationDescriptor( MapsId.class ); - ad.setValue( "value", attrVal ); - annotationList.add( AnnotationFactory.create( ad ) ); - } - } - - /** - * Adds an @Id annotation to the specified annotationList if the specified element has the id - * attribute set to true. This should only be the case for many-to-one or one-to-one - * associations. - */ - private void getAssociationId(List annotationList, Element element) { - String attrVal = element.attributeValue( "id" ); - if ( "true".equals( attrVal ) ) { - AnnotationDescriptor ad = new AnnotationDescriptor( Id.class ); - annotationList.add( AnnotationFactory.create( ad ) ); - } - } - - private void addTargetClass(Element element, AnnotationDescriptor ad, String nodeName, XMLContext.Default defaults) { - String className = element.attributeValue( nodeName ); - if ( className != null ) { - Class clazz; - try { - clazz = classLoaderAccess.classForName( XMLContext.buildSafeClassName( className, defaults ) ); - } - catch ( ClassLoadingException e ) { - throw new AnnotationException( - "Unable to find " + element.getPath() + " " + nodeName + ": " + className, e - ); - } - ad.setValue( getJavaAttributeNameFromXMLOne( nodeName ), clazz ); - } - } - - /** - * As per sections 12.2.3.23.9, 12.2.4.8.9 and 12.2.5.3.6 of the JPA 2.0 - * specification, the element-collection subelement completely overrides the - * mapping for the specified field or property. Thus, any methods which - * might in some contexts merge with annotations must not do so in this - * context. - */ - private void getElementCollection(List annotationList, XMLContext.Default defaults) { - for ( Element element : elementsForProperty ) { - if ( "element-collection".equals( element.getName() ) ) { - AnnotationDescriptor ad = new AnnotationDescriptor( ElementCollection.class ); - addTargetClass( element, ad, "target-class", defaults ); - getFetchType( ad, element ); - getOrderBy( annotationList, element ); - getOrderColumn( annotationList, element ); - getMapKey( annotationList, element ); - getMapKeyClass( annotationList, element, defaults ); - getMapKeyTemporal( annotationList, element ); - getMapKeyEnumerated( annotationList, element ); - getMapKeyColumn( annotationList, element ); - buildMapKeyJoinColumns( annotationList, element ); - Annotation annotation = getColumn( element.element( "column" ), false, element ); - addIfNotNull( annotationList, annotation ); - getTemporal( annotationList, element ); - getEnumerated( annotationList, element ); - getLob( annotationList, element ); - //Both map-key-attribute-overrides and attribute-overrides - //translate into AttributeOverride annotations, which need - //need to be wrapped in the same AttributeOverrides annotation. - List attributes = new ArrayList<>(); - attributes.addAll( buildAttributeOverrides( element, "map-key-attribute-override" ) ); - attributes.addAll( buildAttributeOverrides( element, "attribute-override" ) ); - annotation = mergeAttributeOverrides( defaults, attributes, false ); - addIfNotNull( annotationList, annotation ); - annotation = getAssociationOverrides( element, defaults, false ); - addIfNotNull( annotationList, annotation ); - getCollectionTable( annotationList, element, defaults ); - annotationList.add( AnnotationFactory.create( ad ) ); - getAccessType( annotationList, element ); - } - } - } - - private void getOrderBy(List annotationList, Element element) { - Element subelement = element != null ? element.element( "order-by" ) : null; - if ( subelement != null ) { - AnnotationDescriptor ad = new AnnotationDescriptor( OrderBy.class ); - copyStringElement( subelement, ad, "value" ); - annotationList.add( AnnotationFactory.create( ad ) ); - } - } - - private void getMapKey(List annotationList, Element element) { - Element subelement = element != null ? element.element( "map-key" ) : null; - if ( subelement != null ) { - AnnotationDescriptor ad = new AnnotationDescriptor( MapKey.class ); - copyStringAttribute( ad, subelement, "name", false ); - annotationList.add( AnnotationFactory.create( ad ) ); - } - } - - private void getMapKeyColumn(List annotationList, Element element) { - Element subelement = element != null ? element.element( "map-key-column" ) : null; - if ( subelement != null ) { - AnnotationDescriptor ad = new AnnotationDescriptor( MapKeyColumn.class ); - copyStringAttribute( ad, subelement, "name", false ); - copyBooleanAttribute( ad, subelement, "unique" ); - copyBooleanAttribute( ad, subelement, "nullable" ); - copyBooleanAttribute( ad, subelement, "insertable" ); - copyBooleanAttribute( ad, subelement, "updatable" ); - copyStringAttribute( ad, subelement, "column-definition", false ); - copyStringAttribute( ad, subelement, "table", false ); - copyIntegerAttribute( ad, subelement, "length" ); - copyIntegerAttribute( ad, subelement, "precision" ); - copyIntegerAttribute( ad, subelement, "scale" ); - annotationList.add( AnnotationFactory.create( ad ) ); - } - } - - private void getMapKeyClass(List annotationList, Element element, XMLContext.Default defaults) { - String nodeName = "map-key-class"; - Element subelement = element != null ? element.element( nodeName ) : null; - if ( subelement != null ) { - String mapKeyClassName = subelement.attributeValue( "class" ); - AnnotationDescriptor ad = new AnnotationDescriptor( MapKeyClass.class ); - if ( StringHelper.isNotEmpty( mapKeyClassName ) ) { - Class clazz; - try { - clazz = classLoaderAccess.classForName( - XMLContext.buildSafeClassName( mapKeyClassName, defaults ) - ); - } - catch ( ClassLoadingException e ) { - throw new AnnotationException( - "Unable to find " + element.getPath() + " " + nodeName + ": " + mapKeyClassName, e - ); - } - ad.setValue( "value", clazz ); - } - annotationList.add( AnnotationFactory.create( ad ) ); - } - } - - private void getCollectionTable(List annotationList, Element element, XMLContext.Default defaults) { - Element subelement = element != null ? element.element( "collection-table" ) : null; - if ( subelement != null ) { - AnnotationDescriptor annotation = new AnnotationDescriptor( CollectionTable.class ); - copyStringAttribute( annotation, subelement, "name", false ); - copyStringAttribute( annotation, subelement, "catalog", false ); - if ( StringHelper.isNotEmpty( defaults.getCatalog() ) - && StringHelper.isEmpty( (String) annotation.valueOf( "catalog" ) ) ) { - annotation.setValue( "catalog", defaults.getCatalog() ); - } - copyStringAttribute( annotation, subelement, "schema", false ); - if ( StringHelper.isNotEmpty( defaults.getSchema() ) - && StringHelper.isEmpty( (String) annotation.valueOf( "schema" ) ) ) { - annotation.setValue( "schema", defaults.getSchema() ); - } - JoinColumn[] joinColumns = getJoinColumns( subelement, false ); - if ( joinColumns.length > 0 ) { - annotation.setValue( "joinColumns", joinColumns ); - } - buildUniqueConstraints( annotation, subelement ); - buildIndex( annotation, subelement ); - annotationList.add( AnnotationFactory.create( annotation ) ); - } - } - - private void buildJoinColumns(List annotationList, Element element) { - JoinColumn[] joinColumns = getJoinColumns( element, false ); - if ( joinColumns.length > 0 ) { - AnnotationDescriptor ad = new AnnotationDescriptor( JoinColumns.class ); - ad.setValue( "value", joinColumns ); - annotationList.add( AnnotationFactory.create( ad ) ); - } - } - - private void getCascades(AnnotationDescriptor ad, Element element, XMLContext.Default defaults) { - List elements = element != null ? element.elements( "cascade" ) : new ArrayList<>( 0 ); - List cascades = new ArrayList<>(); - for ( Element subelement : elements ) { - if ( subelement.element( "cascade-all" ) != null ) { - cascades.add( CascadeType.ALL ); - } - if ( subelement.element( "cascade-persist" ) != null ) { - cascades.add( CascadeType.PERSIST ); - } - if ( subelement.element( "cascade-merge" ) != null ) { - cascades.add( CascadeType.MERGE ); - } - if ( subelement.element( "cascade-remove" ) != null ) { - cascades.add( CascadeType.REMOVE ); - } - if ( subelement.element( "cascade-refresh" ) != null ) { - cascades.add( CascadeType.REFRESH ); - } - if ( subelement.element( "cascade-detach" ) != null ) { - cascades.add( CascadeType.DETACH ); - } - } - if ( Boolean.TRUE.equals( defaults.getCascadePersist() ) - && !cascades.contains( CascadeType.ALL ) && !cascades.contains( CascadeType.PERSIST ) ) { - cascades.add( CascadeType.PERSIST ); - } - if ( cascades.size() > 0 ) { - ad.setValue( "cascade", cascades.toArray( new CascadeType[cascades.size()] ) ); - } - } - - private void getEmbedded(List annotationList, XMLContext.Default defaults) { - for ( Element element : elementsForProperty ) { - if ( "embedded".equals( element.getName() ) ) { - AnnotationDescriptor ad = new AnnotationDescriptor( Embedded.class ); - annotationList.add( AnnotationFactory.create( ad ) ); - Annotation annotation = getAttributeOverrides( element, defaults, false ); - addIfNotNull( annotationList, annotation ); - annotation = getAssociationOverrides( element, defaults, false ); - addIfNotNull( annotationList, annotation ); - getAccessType( annotationList, element ); - } - } - if ( elementsForProperty.size() == 0 && defaults.canUseJavaAnnotations() ) { - Annotation annotation = getPhysicalAnnotation( Embedded.class ); - if ( annotation != null ) { - annotationList.add( annotation ); - annotation = getPhysicalAnnotation( AttributeOverride.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( AttributeOverrides.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( AssociationOverride.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( AssociationOverrides.class ); - addIfNotNull( annotationList, annotation ); - } - } - } - - private Transient getTransient(XMLContext.Default defaults) { - for ( Element element : elementsForProperty ) { - if ( "transient".equals( element.getName() ) ) { - AnnotationDescriptor ad = new AnnotationDescriptor( Transient.class ); - return AnnotationFactory.create( ad ); - } - } - if ( elementsForProperty.size() == 0 && defaults.canUseJavaAnnotations() ) { - return getPhysicalAnnotation( Transient.class ); - } - else { - return null; - } - } - - private void getVersion(List annotationList, XMLContext.Default defaults) { - for ( Element element : elementsForProperty ) { - if ( "version".equals( element.getName() ) ) { - Annotation annotation = buildColumns( element ); - addIfNotNull( annotationList, annotation ); - getTemporal( annotationList, element ); - AnnotationDescriptor basic = new AnnotationDescriptor( Version.class ); - annotationList.add( AnnotationFactory.create( basic ) ); - getAccessType( annotationList, element ); - } - } - if ( elementsForProperty.size() == 0 && defaults.canUseJavaAnnotations() ) { - //we have nothing, so Java annotations might occur - Annotation annotation = getPhysicalAnnotation( Version.class ); - if ( annotation != null ) { - annotationList.add( annotation ); - annotation = getPhysicalAnnotation( Column.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( Columns.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( Temporal.class ); - addIfNotNull( annotationList, annotation ); - } - } - } - - private void getBasic(List annotationList, XMLContext.Default defaults) { - for ( Element element : elementsForProperty ) { - if ( "basic".equals( element.getName() ) ) { - Annotation annotation = buildColumns( element ); - addIfNotNull( annotationList, annotation ); - getAccessType( annotationList, element ); - getTemporal( annotationList, element ); - getLob( annotationList, element ); - getEnumerated( annotationList, element ); - AnnotationDescriptor basic = new AnnotationDescriptor( Basic.class ); - getFetchType( basic, element ); - copyBooleanAttribute( basic, element, "optional" ); - annotationList.add( AnnotationFactory.create( basic ) ); - } - } - if ( elementsForProperty.size() == 0 && defaults.canUseJavaAnnotations() ) { - //no annotation presence constraint, basic is the default - Annotation annotation = getPhysicalAnnotation( Basic.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( Lob.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( Enumerated.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( Temporal.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( Column.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( Columns.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( AttributeOverride.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( AttributeOverrides.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( AssociationOverride.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( AssociationOverrides.class ); - addIfNotNull( annotationList, annotation ); - } - } - - private void getEnumerated(List annotationList, Element element) { - Element subElement = element != null ? element.element( "enumerated" ) : null; - if ( subElement != null ) { - AnnotationDescriptor ad = new AnnotationDescriptor( Enumerated.class ); - String enumerated = subElement.getTextTrim(); - if ( "ORDINAL".equalsIgnoreCase( enumerated ) ) { - ad.setValue( "value", EnumType.ORDINAL ); - } - else if ( "STRING".equalsIgnoreCase( enumerated ) ) { - ad.setValue( "value", EnumType.STRING ); - } - else if ( StringHelper.isNotEmpty( enumerated ) ) { - throw new AnnotationException( "Unknown EnumType: " + enumerated + ". " + SCHEMA_VALIDATION ); - } - annotationList.add( AnnotationFactory.create( ad ) ); - } - } - - private void getLob(List annotationList, Element element) { - Element subElement = element != null ? element.element( "lob" ) : null; - if ( subElement != null ) { - annotationList.add( AnnotationFactory.create( new AnnotationDescriptor( Lob.class ) ) ); - } - } - - private void getFetchType(AnnotationDescriptor descriptor, Element element) { - String fetchString = element != null ? element.attributeValue( "fetch" ) : null; - if ( fetchString != null ) { - if ( "eager".equalsIgnoreCase( fetchString ) ) { - descriptor.setValue( "fetch", FetchType.EAGER ); - } - else if ( "lazy".equalsIgnoreCase( fetchString ) ) { - descriptor.setValue( "fetch", FetchType.LAZY ); - } - } - } - - private void getEmbeddedId(List annotationList, XMLContext.Default defaults) { - for ( Element element : elementsForProperty ) { - if ( "embedded-id".equals( element.getName() ) ) { - if ( isProcessingId( defaults ) ) { - Annotation annotation = getAttributeOverrides( element, defaults, false ); - addIfNotNull( annotationList, annotation ); - annotation = getAssociationOverrides( element, defaults, false ); - addIfNotNull( annotationList, annotation ); - AnnotationDescriptor ad = new AnnotationDescriptor( EmbeddedId.class ); - annotationList.add( AnnotationFactory.create( ad ) ); - getAccessType( annotationList, element ); - } - } - } - if ( elementsForProperty.size() == 0 && defaults.canUseJavaAnnotations() ) { - Annotation annotation = getPhysicalAnnotation( EmbeddedId.class ); - if ( annotation != null ) { - annotationList.add( annotation ); - annotation = getPhysicalAnnotation( Column.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( Columns.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( GeneratedValue.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( Temporal.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( TableGenerator.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( SequenceGenerator.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( AttributeOverride.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( AttributeOverrides.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( AssociationOverride.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( AssociationOverrides.class ); - addIfNotNull( annotationList, annotation ); - } - } - } - - private void preCalculateElementsForProperty(Element tree) { - elementsForProperty = new ArrayList<>(); - Element element = tree != null ? tree.element( "attributes" ) : null; - //put entity.attributes elements - if ( element != null ) { - for ( Element subelement : (List) element.elements() ) { - if ( propertyName.equals( subelement.attributeValue( "name" ) ) ) { - elementsForProperty.add( subelement ); - } - } - } - //add pre-* etc from entity and pure entity listener classes - if ( tree != null ) { - for ( Element subelement : (List) tree.elements() ) { - if ( propertyName.equals( subelement.attributeValue( "method-name" ) ) ) { - elementsForProperty.add( subelement ); - } - } - } - } - - private void getId(List annotationList, XMLContext.Default defaults) { - for ( Element element : elementsForProperty ) { - if ( "id".equals( element.getName() ) ) { - boolean processId = isProcessingId( defaults ); - if ( processId ) { - Annotation annotation = buildColumns( element ); - addIfNotNull( annotationList, annotation ); - annotation = buildGeneratedValue( element ); - addIfNotNull( annotationList, annotation ); - getTemporal( annotationList, element ); - //FIXME: fix the priority of xml over java for generator names - annotation = getTableGenerator( element, defaults ); - addIfNotNull( annotationList, annotation ); - annotation = getSequenceGenerator( element, defaults ); - addIfNotNull( annotationList, annotation ); - AnnotationDescriptor id = new AnnotationDescriptor( Id.class ); - annotationList.add( AnnotationFactory.create( id ) ); - getAccessType( annotationList, element ); - } - } - } - if ( elementsForProperty.size() == 0 && defaults.canUseJavaAnnotations() ) { - Annotation annotation = getPhysicalAnnotation( Id.class ); - if ( annotation != null ) { - annotationList.add( annotation ); - annotation = getPhysicalAnnotation( Column.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( Columns.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( GeneratedValue.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( Temporal.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( TableGenerator.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( SequenceGenerator.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( AttributeOverride.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( AttributeOverrides.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( AssociationOverride.class ); - addIfNotNull( annotationList, annotation ); - annotation = getPhysicalAnnotation( AssociationOverrides.class ); - addIfNotNull( annotationList, annotation ); - } - } - } - - private boolean isProcessingId(XMLContext.Default defaults) { - boolean isExplicit = defaults.getAccess() != null; - boolean correctAccess = - ( PropertyType.PROPERTY.equals( propertyType ) && AccessType.PROPERTY.equals( defaults.getAccess() ) ) - || ( PropertyType.FIELD.equals( propertyType ) && AccessType.FIELD - .equals( defaults.getAccess() ) ); - boolean hasId = defaults.canUseJavaAnnotations() - && ( isPhysicalAnnotationPresent( Id.class ) || isPhysicalAnnotationPresent( EmbeddedId.class ) ); - //if ( properAccessOnMetadataComplete || properOverridingOnMetadataNonComplete ) { - boolean mirrorAttributeIsId = defaults.canUseJavaAnnotations() && - ( mirroredAttribute != null && - ( mirroredAttribute.isAnnotationPresent( Id.class ) - || mirroredAttribute.isAnnotationPresent( EmbeddedId.class ) ) ); - boolean propertyIsDefault = PropertyType.PROPERTY.equals( propertyType ) - && !mirrorAttributeIsId; - return correctAccess || ( !isExplicit && hasId ) || ( !isExplicit && propertyIsDefault ); - } - - private Columns buildColumns(Element element) { - List subelements = element.elements( "column" ); - List columns = new ArrayList<>( subelements.size() ); - for ( Element subelement : subelements ) { - columns.add( getColumn( subelement, false, element ) ); - } - if ( columns.size() > 0 ) { - AnnotationDescriptor columnsDescr = new AnnotationDescriptor( Columns.class ); - columnsDescr.setValue( "columns", columns.toArray( new Column[columns.size()] ) ); - return AnnotationFactory.create( columnsDescr ); - } - else { - return null; - } - } - - private GeneratedValue buildGeneratedValue(Element element) { - Element subElement = element != null ? element.element( "generated-value" ) : null; - if ( subElement != null ) { - AnnotationDescriptor ad = new AnnotationDescriptor( GeneratedValue.class ); - String strategy = subElement.attributeValue( "strategy" ); - if ( "TABLE".equalsIgnoreCase( strategy ) ) { - ad.setValue( "strategy", GenerationType.TABLE ); - } - else if ( "SEQUENCE".equalsIgnoreCase( strategy ) ) { - ad.setValue( "strategy", GenerationType.SEQUENCE ); - } - else if ( "IDENTITY".equalsIgnoreCase( strategy ) ) { - ad.setValue( "strategy", GenerationType.IDENTITY ); - } - else if ( "AUTO".equalsIgnoreCase( strategy ) ) { - ad.setValue( "strategy", GenerationType.AUTO ); - } - else if ( StringHelper.isNotEmpty( strategy ) ) { - throw new AnnotationException( "Unknown GenerationType: " + strategy + ". " + SCHEMA_VALIDATION ); - } - copyStringAttribute( ad, subElement, "generator", false ); - return AnnotationFactory.create( ad ); - } - else { - return null; - } - } - - private void getTemporal(List annotationList, Element element) { - Element subElement = element != null ? element.element( "temporal" ) : null; - if ( subElement != null ) { - AnnotationDescriptor ad = new AnnotationDescriptor( Temporal.class ); - String temporal = subElement.getTextTrim(); - if ( "DATE".equalsIgnoreCase( temporal ) ) { - ad.setValue( "value", TemporalType.DATE ); - } - else if ( "TIME".equalsIgnoreCase( temporal ) ) { - ad.setValue( "value", TemporalType.TIME ); - } - else if ( "TIMESTAMP".equalsIgnoreCase( temporal ) ) { - ad.setValue( "value", TemporalType.TIMESTAMP ); - } - else if ( StringHelper.isNotEmpty( temporal ) ) { - throw new AnnotationException( "Unknown TemporalType: " + temporal + ". " + SCHEMA_VALIDATION ); - } - annotationList.add( AnnotationFactory.create( ad ) ); - } - } - - private void getAccessType(List annotationList, Element element) { - if ( element == null ) { - return; - } - String access = element.attributeValue( "access" ); - if ( access != null ) { - AnnotationDescriptor ad = new AnnotationDescriptor( Access.class ); - AccessType type; - try { - type = AccessType.valueOf( access ); - } - catch ( IllegalArgumentException e ) { - throw new AnnotationException( access + " is not a valid access type. Check you xml confguration." ); - } - - if ( ( AccessType.PROPERTY.equals( type ) && this.element instanceof Method ) || - ( AccessType.FIELD.equals( type ) && this.element instanceof Field ) ) { - return; - } - - ad.setValue( "value", type ); - annotationList.add( AnnotationFactory.create( ad ) ); - } - } - - /** - * @param mergeWithAnnotations Whether to use Java annotations for this - * element, if present and not disabled by the XMLContext defaults. - * In some contexts (such as an element-collection mapping) merging - * with annotations is never allowed. - */ - private AssociationOverrides getAssociationOverrides(Element tree, XMLContext.Default defaults, boolean mergeWithAnnotations) { - List attributes = buildAssociationOverrides( tree, defaults ); - if ( mergeWithAnnotations && defaults.canUseJavaAnnotations() ) { - AssociationOverride annotation = getPhysicalAnnotation( AssociationOverride.class ); - addAssociationOverrideIfNeeded( annotation, attributes ); - AssociationOverrides annotations = getPhysicalAnnotation( AssociationOverrides.class ); - if ( annotations != null ) { - for ( AssociationOverride current : annotations.value() ) { - addAssociationOverrideIfNeeded( current, attributes ); - } - } - } - if ( attributes.size() > 0 ) { - AnnotationDescriptor ad = new AnnotationDescriptor( AssociationOverrides.class ); - ad.setValue( "value", attributes.toArray( new AssociationOverride[attributes.size()] ) ); - return AnnotationFactory.create( ad ); - } - else { - return null; - } - } - - private List buildAssociationOverrides(Element element, XMLContext.Default defaults) { - List subelements = element == null ? null : element.elements( "association-override" ); - List overrides = new ArrayList<>(); - if ( subelements != null && subelements.size() > 0 ) { - for ( Element current : subelements ) { - AnnotationDescriptor override = new AnnotationDescriptor( AssociationOverride.class ); - copyStringAttribute( override, current, "name", true ); - override.setValue( "joinColumns", getJoinColumns( current, false ) ); - JoinTable joinTable = buildJoinTable( current, defaults ); - if ( joinTable != null ) { - override.setValue( "joinTable", joinTable ); - } - overrides.add( AnnotationFactory.create( override ) ); - } - } - return overrides; - } - - private JoinColumn[] getJoinColumns(Element element, boolean isInverse) { - List subelements = element != null ? - element.elements( isInverse ? "inverse-join-column" : "join-column" ) : - null; - List joinColumns = new ArrayList<>(); - if ( subelements != null ) { - for ( Element subelement : subelements ) { - AnnotationDescriptor column = new AnnotationDescriptor( JoinColumn.class ); - copyStringAttribute( column, subelement, "name", false ); - copyStringAttribute( column, subelement, "referenced-column-name", false ); - copyBooleanAttribute( column, subelement, "unique" ); - copyBooleanAttribute( column, subelement, "nullable" ); - copyBooleanAttribute( column, subelement, "insertable" ); - copyBooleanAttribute( column, subelement, "updatable" ); - copyStringAttribute( column, subelement, "column-definition", false ); - copyStringAttribute( column, subelement, "table", false ); - joinColumns.add( AnnotationFactory.create( column ) ); - } - } - return joinColumns.toArray( new JoinColumn[joinColumns.size()] ); - } - - private void addAssociationOverrideIfNeeded(AssociationOverride annotation, List overrides) { - if ( annotation != null ) { - String overrideName = annotation.name(); - boolean present = false; - for ( AssociationOverride current : overrides ) { - if ( current.name().equals( overrideName ) ) { - present = true; - break; - } - } - if ( !present ) { - overrides.add( annotation ); - } - } - } - - /** - * @param mergeWithAnnotations Whether to use Java annotations for this - * element, if present and not disabled by the XMLContext defaults. - * In some contexts (such as an association mapping) merging with - * annotations is never allowed. - */ - private AttributeOverrides getAttributeOverrides(Element tree, XMLContext.Default defaults, boolean mergeWithAnnotations) { - List attributes = buildAttributeOverrides( tree, "attribute-override" ); - return mergeAttributeOverrides( defaults, attributes, mergeWithAnnotations ); - } - - /** - * @param mergeWithAnnotations Whether to use Java annotations for this - * element, if present and not disabled by the XMLContext defaults. - * In some contexts (such as an association mapping) merging with - * annotations is never allowed. - */ - private AttributeOverrides mergeAttributeOverrides(XMLContext.Default defaults, List attributes, boolean mergeWithAnnotations) { - if ( mergeWithAnnotations && defaults.canUseJavaAnnotations() ) { - AttributeOverride annotation = getPhysicalAnnotation( AttributeOverride.class ); - addAttributeOverrideIfNeeded( annotation, attributes ); - AttributeOverrides annotations = getPhysicalAnnotation( AttributeOverrides.class ); - if ( annotations != null ) { - for ( AttributeOverride current : annotations.value() ) { - addAttributeOverrideIfNeeded( current, attributes ); - } - } - } - if ( attributes.size() > 0 ) { - AnnotationDescriptor ad = new AnnotationDescriptor( AttributeOverrides.class ); - ad.setValue( "value", attributes.toArray( new AttributeOverride[attributes.size()] ) ); - return AnnotationFactory.create( ad ); - } - else { - return null; - } - } - - private List buildAttributeOverrides(Element element, String nodeName) { - List subelements = element == null ? null : element.elements( nodeName ); - return buildAttributeOverrides( subelements, nodeName ); - } - - private List buildAttributeOverrides(List subelements, String nodeName) { - List overrides = new ArrayList<>(); - if ( subelements != null && subelements.size() > 0 ) { - for ( Element current : subelements ) { - if ( !current.getName().equals( nodeName ) ) { - continue; - } - AnnotationDescriptor override = new AnnotationDescriptor( AttributeOverride.class ); - copyStringAttribute( override, current, "name", true ); - Element column = current.element( "column" ); - override.setValue( "column", getColumn( column, true, current ) ); - overrides.add( AnnotationFactory.create( override ) ); - } - } - return overrides; - } - - private Column getColumn(Element element, boolean isMandatory, Element current) { - //Element subelement = element != null ? element.element( "column" ) : null; - if ( element != null ) { - AnnotationDescriptor column = new AnnotationDescriptor( Column.class ); - copyStringAttribute( column, element, "name", false ); - copyBooleanAttribute( column, element, "unique" ); - copyBooleanAttribute( column, element, "nullable" ); - copyBooleanAttribute( column, element, "insertable" ); - copyBooleanAttribute( column, element, "updatable" ); - copyStringAttribute( column, element, "column-definition", false ); - copyStringAttribute( column, element, "table", false ); - copyIntegerAttribute( column, element, "length" ); - copyIntegerAttribute( column, element, "precision" ); - copyIntegerAttribute( column, element, "scale" ); - return (Column) AnnotationFactory.create( column ); - } - else { - if ( isMandatory ) { - throw new AnnotationException( current.getPath() + ".column is mandatory. " + SCHEMA_VALIDATION ); - } - return null; - } - } - - private void addAttributeOverrideIfNeeded(AttributeOverride annotation, List overrides) { - if ( annotation != null ) { - String overrideName = annotation.name(); - boolean present = false; - for ( AttributeOverride current : overrides ) { - if ( current.name().equals( overrideName ) ) { - present = true; - break; - } - } - if ( !present ) { - overrides.add( annotation ); - } - } - } - - private Access getAccessType(Element tree, XMLContext.Default defaults) { - String access = tree == null ? null : tree.attributeValue( "access" ); - if ( access != null ) { - AnnotationDescriptor ad = new AnnotationDescriptor( Access.class ); - AccessType type; - try { - type = AccessType.valueOf( access ); - } - catch ( IllegalArgumentException e ) { - throw new AnnotationException( access + " is not a valid access type. Check you xml confguration." ); - } - ad.setValue( "value", type ); - return AnnotationFactory.create( ad ); - } - else if ( defaults.canUseJavaAnnotations() && isPhysicalAnnotationPresent( Access.class ) ) { - return getPhysicalAnnotation( Access.class ); - } - else if ( defaults.getAccess() != null ) { - AnnotationDescriptor ad = new AnnotationDescriptor( Access.class ); - ad.setValue( "value", defaults.getAccess() ); - return AnnotationFactory.create( ad ); - } - else { - return null; - } - } - - private ExcludeSuperclassListeners getExcludeSuperclassListeners(Element tree, XMLContext.Default defaults) { - return (ExcludeSuperclassListeners) getMarkerAnnotation( ExcludeSuperclassListeners.class, tree, defaults ); - } - - private ExcludeDefaultListeners getExcludeDefaultListeners(Element tree, XMLContext.Default defaults) { - return (ExcludeDefaultListeners) getMarkerAnnotation( ExcludeDefaultListeners.class, tree, defaults ); - } - - private Annotation getMarkerAnnotation( - Class clazz, Element element, XMLContext.Default defaults - ) { - Element subelement = element == null ? null : element.element( annotationToXml.get( clazz ) ); - if ( subelement != null ) { - return AnnotationFactory.create( new AnnotationDescriptor( clazz ) ); - } - else if ( defaults.canUseJavaAnnotations() ) { - //TODO wonder whether it should be excluded so that user can undone it - return getPhysicalAnnotation( clazz ); - } - else { - return null; - } - } - - private SqlResultSetMappings getSqlResultSetMappings(Element tree, XMLContext.Default defaults) { - List results = buildSqlResultsetMappings( tree, defaults, classLoaderAccess ); - if ( defaults.canUseJavaAnnotations() ) { - SqlResultSetMapping annotation = getPhysicalAnnotation( SqlResultSetMapping.class ); - addSqlResultsetMappingIfNeeded( annotation, results ); - SqlResultSetMappings annotations = getPhysicalAnnotation( SqlResultSetMappings.class ); - if ( annotations != null ) { - for ( SqlResultSetMapping current : annotations.value() ) { - addSqlResultsetMappingIfNeeded( current, results ); - } - } - } - if ( results.size() > 0 ) { - AnnotationDescriptor ad = new AnnotationDescriptor( SqlResultSetMappings.class ); - ad.setValue( "value", results.toArray( new SqlResultSetMapping[results.size()] ) ); - return AnnotationFactory.create( ad ); - } - else { - return null; - } - } - - public static List buildNamedEntityGraph( - Element element, - XMLContext.Default defaults, - ClassLoaderAccess classLoaderAccess) { - if ( element == null ) { - return new ArrayList<>(); - } - List namedEntityGraphList = new ArrayList<>(); - List namedEntityGraphElements = element.elements( "named-entity-graph" ); - for ( Element subElement : namedEntityGraphElements ) { - AnnotationDescriptor ann = new AnnotationDescriptor( NamedEntityGraph.class ); - copyStringAttribute( ann, subElement, "name", false ); - copyBooleanAttribute( ann, subElement, "include-all-attributes" ); - bindNamedAttributeNodes( subElement, ann ); - - List subgraphNodes = subElement.elements( "subgraph" ); - List subclassSubgraphNodes = subElement.elements( "subclass-subgraph" ); - if(!subclassSubgraphNodes.isEmpty()) { - subgraphNodes.addAll( subclassSubgraphNodes ); - } - bindNamedSubgraph( defaults, ann, subgraphNodes, classLoaderAccess ); - namedEntityGraphList.add( AnnotationFactory.create( ann ) ); - } - //TODO - return namedEntityGraphList; - } - - private static void bindNamedSubgraph( - XMLContext.Default defaults, - AnnotationDescriptor ann, - List subgraphNodes, - ClassLoaderAccess classLoaderAccess) { - List annSubgraphNodes = new ArrayList<>( ); - for(Element subgraphNode : subgraphNodes){ - AnnotationDescriptor annSubgraphNode = new AnnotationDescriptor( NamedSubgraph.class ); - copyStringAttribute( annSubgraphNode, subgraphNode, "name", true ); - String clazzName = subgraphNode.attributeValue( "class" ); - Class clazz; - try { - clazz = classLoaderAccess.classForName( - XMLContext.buildSafeClassName( clazzName, defaults ) - ); - } - catch ( ClassLoadingException e ) { - throw new AnnotationException( "Unable to find entity-class: " + clazzName, e ); - } - annSubgraphNode.setValue( "type", clazz ); - bindNamedAttributeNodes(subgraphNode, annSubgraphNode); - annSubgraphNodes.add( AnnotationFactory.create( annSubgraphNode ) ); - } - - ann.setValue( "subgraphs", annSubgraphNodes.toArray( new NamedSubgraph[annSubgraphNodes.size()] ) ); - } - - private static void bindNamedAttributeNodes(Element subElement, AnnotationDescriptor ann) { - List namedAttributeNodes = subElement.elements("named-attribute-node"); - List annNamedAttributeNodes = new ArrayList<>( ); - for(Element namedAttributeNode : namedAttributeNodes){ - AnnotationDescriptor annNamedAttributeNode = new AnnotationDescriptor( NamedAttributeNode.class ); - copyStringAttribute( annNamedAttributeNode, namedAttributeNode, "value", "name", true ); - copyStringAttribute( annNamedAttributeNode, namedAttributeNode, "subgraph", false ); - copyStringAttribute( annNamedAttributeNode, namedAttributeNode, "key-subgraph", false ); - annNamedAttributeNodes.add( AnnotationFactory.create( annNamedAttributeNode ) ); - } - ann.setValue( "attributeNodes", annNamedAttributeNodes.toArray( new NamedAttributeNode[annNamedAttributeNodes.size()] ) ); - } - - public static List buildNamedStoreProcedureQueries( - Element element, - XMLContext.Default defaults, - ClassLoaderAccess classLoaderAccess) { - if ( element == null ) { - return new ArrayList<>(); - } - List namedStoredProcedureElements = element.elements( "named-stored-procedure-query" ); - List namedStoredProcedureQueries = new ArrayList<>(); - for ( Object obj : namedStoredProcedureElements ) { - Element subElement = (Element) obj; - AnnotationDescriptor ann = new AnnotationDescriptor( NamedStoredProcedureQuery.class ); - copyStringAttribute( ann, subElement, "name", true ); - copyStringAttribute( ann, subElement, "procedure-name", true ); - - List elements = subElement.elements( "parameter" ); - List storedProcedureParameters = new ArrayList<>(); - - for ( Element parameterElement : elements ) { - AnnotationDescriptor parameterDescriptor = new AnnotationDescriptor( StoredProcedureParameter.class ); - copyStringAttribute( parameterDescriptor, parameterElement, "name", false ); - String modeValue = parameterElement.attributeValue( "mode" ); - if ( modeValue == null ) { - parameterDescriptor.setValue( "mode", ParameterMode.IN ); - } - else { - parameterDescriptor.setValue( "mode", ParameterMode.valueOf( modeValue.toUpperCase(Locale.ROOT) ) ); - } - String clazzName = parameterElement.attributeValue( "class" ); - Class clazz; - try { - clazz = classLoaderAccess.classForName( - XMLContext.buildSafeClassName( clazzName, defaults ) - ); - } - catch ( ClassLoadingException e ) { - throw new AnnotationException( "Unable to find entity-class: " + clazzName, e ); - } - parameterDescriptor.setValue( "type", clazz ); - storedProcedureParameters.add( AnnotationFactory.create( parameterDescriptor ) ); - } - - ann.setValue( - "parameters", - storedProcedureParameters.toArray( new StoredProcedureParameter[storedProcedureParameters.size()] ) - ); - - elements = subElement.elements( "result-class" ); - List returnClasses = new ArrayList<>(); - for ( Element classElement : elements ) { - String clazzName = classElement.getTextTrim(); - Class clazz; - try { - clazz = classLoaderAccess.classForName( - XMLContext.buildSafeClassName( clazzName, defaults ) - ); - } - catch ( ClassLoadingException e ) { - throw new AnnotationException( "Unable to find entity-class: " + clazzName, e ); - } - returnClasses.add( clazz ); - } - ann.setValue( "resultClasses", returnClasses.toArray( new Class[returnClasses.size()] ) ); - - - elements = subElement.elements( "result-set-mapping" ); - List resultSetMappings = new ArrayList<>(); - for ( Element resultSetMappingElement : elements ) { - resultSetMappings.add( resultSetMappingElement.getTextTrim() ); - } - ann.setValue( "resultSetMappings", resultSetMappings.toArray( new String[resultSetMappings.size()] ) ); - elements = subElement.elements( "hint" ); - buildQueryHints( elements, ann ); - namedStoredProcedureQueries.add( AnnotationFactory.create( ann ) ); - } - return namedStoredProcedureQueries; - - } - - public static List buildSqlResultsetMappings( - Element element, - XMLContext.Default defaults, - ClassLoaderAccess classLoaderAccess) { - final List builtResultSetMappings = new ArrayList<>(); - if ( element == null ) { - return builtResultSetMappings; - } - - // iterate over each element - for ( Object resultSetMappingElementObject : element.elements( "sql-result-set-mapping" ) ) { - final Element resultSetMappingElement = (Element) resultSetMappingElementObject; - - final AnnotationDescriptor resultSetMappingAnnotation = new AnnotationDescriptor( SqlResultSetMapping.class ); - copyStringAttribute( resultSetMappingAnnotation, resultSetMappingElement, "name", true ); - - // iterate over the sub-elements, which should include: - // * - // * - // * - - List entityResultAnnotations = null; - List columnResultAnnotations = null; - List constructorResultAnnotations = null; - - for ( Object resultElementObject : resultSetMappingElement.elements() ) { - final Element resultElement = (Element) resultElementObject; - - if ( "entity-result".equals( resultElement.getName() ) ) { - if ( entityResultAnnotations == null ) { - entityResultAnnotations = new ArrayList<>(); - } - // process the - entityResultAnnotations.add( buildEntityResult( resultElement, defaults, classLoaderAccess ) ); - } - else if ( "column-result".equals( resultElement.getName() ) ) { - if ( columnResultAnnotations == null ) { - columnResultAnnotations = new ArrayList<>(); - } - columnResultAnnotations.add( buildColumnResult( resultElement, defaults, classLoaderAccess ) ); - } - else if ( "constructor-result".equals( resultElement.getName() ) ) { - if ( constructorResultAnnotations == null ) { - constructorResultAnnotations = new ArrayList<>(); - } - constructorResultAnnotations.add( buildConstructorResult( resultElement, defaults, classLoaderAccess ) ); - } - else { - // most likely the this code used to handle. I have left the code here, - // but commented it out for now. I'll just log a warning for now. - LOG.debug( "Encountered unrecognized sql-result-set-mapping sub-element : " + resultElement.getName() ); - -// String clazzName = subelement.attributeValue( "result-class" ); -// if ( StringHelper.isNotEmpty( clazzName ) ) { -// Class clazz; -// try { -// clazz = ReflectHelper.classForName( -// XMLContext.buildSafeClassName( clazzName, defaults ), -// JPAOverriddenAnnotationReader.class -// ); -// } -// catch ( ClassNotFoundException e ) { -// throw new AnnotationException( "Unable to find entity-class: " + clazzName, e ); -// } -// ann.setValue( "resultClass", clazz ); -// } - } - } - - if ( entityResultAnnotations != null && !entityResultAnnotations.isEmpty() ) { - resultSetMappingAnnotation.setValue( - "entities", - entityResultAnnotations.toArray( new EntityResult[entityResultAnnotations.size()] ) - ); - } - if ( columnResultAnnotations != null && !columnResultAnnotations.isEmpty() ) { - resultSetMappingAnnotation.setValue( - "columns", - columnResultAnnotations.toArray( new ColumnResult[columnResultAnnotations.size()] ) - ); - } - if ( constructorResultAnnotations != null && !constructorResultAnnotations.isEmpty() ) { - resultSetMappingAnnotation.setValue( - "classes", - constructorResultAnnotations.toArray( new ConstructorResult[constructorResultAnnotations.size()] ) - ); - } - - - // this was part of the old code too, but could never figure out what it is supposed to do... - // copyStringAttribute( ann, subelement, "result-set-mapping", false ); - - builtResultSetMappings.add( AnnotationFactory.create( resultSetMappingAnnotation ) ); - } - - return builtResultSetMappings; - } - - private static EntityResult buildEntityResult( - Element entityResultElement, - XMLContext.Default defaults, - ClassLoaderAccess classLoaderAccess) { - final AnnotationDescriptor entityResultDescriptor = new AnnotationDescriptor( EntityResult.class ); - - final Class entityClass = resolveClassReference( entityResultElement.attributeValue( "entity-class" ), defaults, classLoaderAccess ); - entityResultDescriptor.setValue( "entityClass", entityClass ); - - copyStringAttribute( entityResultDescriptor, entityResultElement, "discriminator-column", false ); - - // process the sub-elements - List fieldResultAnnotations = new ArrayList<>(); - for ( Element fieldResult : (List) entityResultElement.elements( "field-result" ) ) { - AnnotationDescriptor fieldResultDescriptor = new AnnotationDescriptor( FieldResult.class ); - copyStringAttribute( fieldResultDescriptor, fieldResult, "name", true ); - copyStringAttribute( fieldResultDescriptor, fieldResult, "column", true ); - fieldResultAnnotations.add( AnnotationFactory.create( fieldResultDescriptor ) ); - } - entityResultDescriptor.setValue( - "fields", fieldResultAnnotations.toArray( new FieldResult[fieldResultAnnotations.size()] ) - ); - return AnnotationFactory.create( entityResultDescriptor ); - } - - private static Class resolveClassReference( - String className, - XMLContext.Default defaults, - ClassLoaderAccess classLoaderAccess) { - if ( className == null ) { - throw new AnnotationException( " without entity-class. " + SCHEMA_VALIDATION ); - } - try { - return classLoaderAccess.classForName( - XMLContext.buildSafeClassName( className, defaults ) - ); - } - catch ( ClassLoadingException e ) { - throw new AnnotationException( "Unable to find specified class: " + className, e ); - } - } - - private static ColumnResult buildColumnResult( - Element columnResultElement, - XMLContext.Default defaults, - ClassLoaderAccess classLoaderAccess) { -// AnnotationDescriptor columnResultDescriptor = new AnnotationDescriptor( ColumnResult.class ); -// copyStringAttribute( columnResultDescriptor, columnResultElement, "name", true ); -// return AnnotationFactory.create( columnResultDescriptor ); - - AnnotationDescriptor columnResultDescriptor = new AnnotationDescriptor( ColumnResult.class ); - copyStringAttribute( columnResultDescriptor, columnResultElement, "name", true ); - final String columnTypeName = columnResultElement.attributeValue( "class" ); - if ( StringHelper.isNotEmpty( columnTypeName ) ) { - columnResultDescriptor.setValue( "type", resolveClassReference( columnTypeName, defaults, classLoaderAccess ) ); - } - return AnnotationFactory.create( columnResultDescriptor ); - } - - private static ConstructorResult buildConstructorResult( - Element constructorResultElement, - XMLContext.Default defaults, - ClassLoaderAccess classLoaderAccess) { - AnnotationDescriptor constructorResultDescriptor = new AnnotationDescriptor( ConstructorResult.class ); - - final Class entityClass = resolveClassReference( constructorResultElement.attributeValue( "target-class" ), defaults, classLoaderAccess ); - constructorResultDescriptor.setValue( "targetClass", entityClass ); - - List columnResultAnnotations = new ArrayList<>(); - for ( Element columnResultElement : (List) constructorResultElement.elements( "column" ) ) { - columnResultAnnotations.add( buildColumnResult( columnResultElement, defaults, classLoaderAccess ) ); - } - constructorResultDescriptor.setValue( - "columns", - columnResultAnnotations.toArray( new ColumnResult[ columnResultAnnotations.size() ] ) - ); - - return AnnotationFactory.create( constructorResultDescriptor ); - } - - private void addSqlResultsetMappingIfNeeded(SqlResultSetMapping annotation, List resultsets) { - if ( annotation != null ) { - String resultsetName = annotation.name(); - boolean present = false; - for ( SqlResultSetMapping current : resultsets ) { - if ( current.name().equals( resultsetName ) ) { - present = true; - break; - } - } - if ( !present ) { - resultsets.add( annotation ); - } - } - } - - private NamedQueries getNamedQueries(Element tree, XMLContext.Default defaults) { - //TODO avoid the Proxy Creation (@NamedQueries) when possible - List queries = (List) buildNamedQueries( tree, false, defaults, classLoaderAccess ); - if ( defaults.canUseJavaAnnotations() ) { - NamedQuery annotation = getPhysicalAnnotation( NamedQuery.class ); - addNamedQueryIfNeeded( annotation, queries ); - NamedQueries annotations = getPhysicalAnnotation( NamedQueries.class ); - if ( annotations != null ) { - for ( NamedQuery current : annotations.value() ) { - addNamedQueryIfNeeded( current, queries ); - } - } - } - if ( queries.size() > 0 ) { - AnnotationDescriptor ad = new AnnotationDescriptor( NamedQueries.class ); - ad.setValue( "value", queries.toArray( new NamedQuery[queries.size()] ) ); - return AnnotationFactory.create( ad ); - } - else { - return null; - } - } - - private void addNamedQueryIfNeeded(NamedQuery annotation, List queries) { - if ( annotation != null ) { - String queryName = annotation.name(); - boolean present = false; - for ( NamedQuery current : queries ) { - if ( current.name().equals( queryName ) ) { - present = true; - break; - } - } - if ( !present ) { - queries.add( annotation ); - } - } - } - - private NamedEntityGraphs getNamedEntityGraphs(Element tree, XMLContext.Default defaults) { - List queries = buildNamedEntityGraph( tree, defaults, classLoaderAccess ); - if ( defaults.canUseJavaAnnotations() ) { - NamedEntityGraph annotation = getPhysicalAnnotation( NamedEntityGraph.class ); - addNamedEntityGraphIfNeeded( annotation, queries ); - NamedEntityGraphs annotations = getPhysicalAnnotation( NamedEntityGraphs.class ); - if ( annotations != null ) { - for ( NamedEntityGraph current : annotations.value() ) { - addNamedEntityGraphIfNeeded( current, queries ); - } - } - } - if ( queries.size() > 0 ) { - AnnotationDescriptor ad = new AnnotationDescriptor( NamedEntityGraphs.class ); - ad.setValue( "value", queries.toArray( new NamedEntityGraph[queries.size()] ) ); - return AnnotationFactory.create( ad ); - } - else { - return null; - } - } - - private void addNamedEntityGraphIfNeeded(NamedEntityGraph annotation, List queries) { - if ( annotation != null ) { - String queryName = annotation.name(); - boolean present = false; - for ( NamedEntityGraph current : queries ) { - if ( current.name().equals( queryName ) ) { - present = true; - break; - } - } - if ( !present ) { - queries.add( annotation ); - } - } - - } - - private NamedStoredProcedureQueries getNamedStoredProcedureQueries(Element tree, XMLContext.Default defaults) { - List queries = buildNamedStoreProcedureQueries( tree, defaults, classLoaderAccess ); - if ( defaults.canUseJavaAnnotations() ) { - NamedStoredProcedureQuery annotation = getPhysicalAnnotation( NamedStoredProcedureQuery.class ); - addNamedStoredProcedureQueryIfNeeded( annotation, queries ); - NamedStoredProcedureQueries annotations = getPhysicalAnnotation( NamedStoredProcedureQueries.class ); - if ( annotations != null ) { - for ( NamedStoredProcedureQuery current : annotations.value() ) { - addNamedStoredProcedureQueryIfNeeded( current, queries ); - } - } - } - if ( queries.size() > 0 ) { - AnnotationDescriptor ad = new AnnotationDescriptor( NamedStoredProcedureQueries.class ); - ad.setValue( "value", queries.toArray( new NamedStoredProcedureQuery[queries.size()] ) ); - return AnnotationFactory.create( ad ); - } - else { - return null; - } - } - - private void addNamedStoredProcedureQueryIfNeeded(NamedStoredProcedureQuery annotation, List queries) { - if ( annotation != null ) { - String queryName = annotation.name(); - boolean present = false; - for ( NamedStoredProcedureQuery current : queries ) { - if ( current.name().equals( queryName ) ) { - present = true; - break; - } - } - if ( !present ) { - queries.add( annotation ); - } - } - } - - - private NamedNativeQueries getNamedNativeQueries( - Element tree, - XMLContext.Default defaults) { - List queries = (List) buildNamedQueries( tree, true, defaults, classLoaderAccess ); - if ( defaults.canUseJavaAnnotations() ) { - NamedNativeQuery annotation = getPhysicalAnnotation( NamedNativeQuery.class ); - addNamedNativeQueryIfNeeded( annotation, queries ); - NamedNativeQueries annotations = getPhysicalAnnotation( NamedNativeQueries.class ); - if ( annotations != null ) { - for ( NamedNativeQuery current : annotations.value() ) { - addNamedNativeQueryIfNeeded( current, queries ); - } - } - } - if ( queries.size() > 0 ) { - AnnotationDescriptor ad = new AnnotationDescriptor( NamedNativeQueries.class ); - ad.setValue( "value", queries.toArray( new NamedNativeQuery[queries.size()] ) ); - return AnnotationFactory.create( ad ); - } - else { - return null; - } - } - - private void addNamedNativeQueryIfNeeded(NamedNativeQuery annotation, List queries) { - if ( annotation != null ) { - String queryName = annotation.name(); - boolean present = false; - for ( NamedNativeQuery current : queries ) { - if ( current.name().equals( queryName ) ) { - present = true; - break; - } - } - if ( !present ) { - queries.add( annotation ); - } - } - } - - private static void buildQueryHints(List elements, AnnotationDescriptor ann){ - List queryHints = new ArrayList<>( elements.size() ); - for ( Element hint : elements ) { - AnnotationDescriptor hintDescriptor = new AnnotationDescriptor( QueryHint.class ); - String value = hint.attributeValue( "name" ); - if ( value == null ) { - throw new AnnotationException( " without name. " + SCHEMA_VALIDATION ); - } - hintDescriptor.setValue( "name", value ); - value = hint.attributeValue( "value" ); - if ( value == null ) { - throw new AnnotationException( " without value. " + SCHEMA_VALIDATION ); - } - hintDescriptor.setValue( "value", value ); - queryHints.add( AnnotationFactory.create( hintDescriptor ) ); - } - ann.setValue( "hints", queryHints.toArray( new QueryHint[queryHints.size()] ) ); - } - - public static List buildNamedQueries( - Element element, - boolean isNative, - XMLContext.Default defaults, - ClassLoaderAccess classLoaderAccess) { - if ( element == null ) { - return new ArrayList(); - } - List namedQueryElementList = isNative ? - element.elements( "named-native-query" ) : - element.elements( "named-query" ); - List namedQueries = new ArrayList(); - for ( Object aNamedQueryElementList : namedQueryElementList ) { - Element subelement = (Element) aNamedQueryElementList; - AnnotationDescriptor ann = new AnnotationDescriptor( - isNative ? NamedNativeQuery.class : NamedQuery.class - ); - copyStringAttribute( ann, subelement, "name", false ); - Element queryElt = subelement.element( "query" ); - if ( queryElt == null ) { - throw new AnnotationException( "No element found." + SCHEMA_VALIDATION ); - } - copyStringElement( queryElt, ann, "query" ); - List elements = subelement.elements( "hint" ); - buildQueryHints( elements, ann ); - String clazzName = subelement.attributeValue( "result-class" ); - if ( StringHelper.isNotEmpty( clazzName ) ) { - Class clazz; - try { - clazz = classLoaderAccess.classForName( - XMLContext.buildSafeClassName( clazzName, defaults ) - ); - } - catch (ClassLoadingException e) { - throw new AnnotationException( "Unable to find entity-class: " + clazzName, e ); - } - ann.setValue( "resultClass", clazz ); - } - copyStringAttribute( ann, subelement, "result-set-mapping", false ); - namedQueries.add( AnnotationFactory.create( ann ) ); - } - return namedQueries; - } - - private TableGenerator getTableGenerator(Element tree, XMLContext.Default defaults) { - Element element = tree != null ? tree.element( annotationToXml.get( TableGenerator.class ) ) : null; - if ( element != null ) { - return buildTableGeneratorAnnotation( element, defaults ); - } - else if ( defaults.canUseJavaAnnotations() && isPhysicalAnnotationPresent( TableGenerator.class ) ) { - TableGenerator tableAnn = getPhysicalAnnotation( TableGenerator.class ); - if ( StringHelper.isNotEmpty( defaults.getSchema() ) - || StringHelper.isNotEmpty( defaults.getCatalog() ) ) { - AnnotationDescriptor annotation = new AnnotationDescriptor( TableGenerator.class ); - annotation.setValue( "name", tableAnn.name() ); - annotation.setValue( "table", tableAnn.table() ); - annotation.setValue( "catalog", tableAnn.table() ); - if ( StringHelper.isEmpty( (String) annotation.valueOf( "catalog" ) ) - && StringHelper.isNotEmpty( defaults.getCatalog() ) ) { - annotation.setValue( "catalog", defaults.getCatalog() ); - } - annotation.setValue( "schema", tableAnn.table() ); - if ( StringHelper.isEmpty( (String) annotation.valueOf( "schema" ) ) - && StringHelper.isNotEmpty( defaults.getSchema() ) ) { - annotation.setValue( "catalog", defaults.getSchema() ); - } - annotation.setValue( "pkColumnName", tableAnn.pkColumnName() ); - annotation.setValue( "valueColumnName", tableAnn.valueColumnName() ); - annotation.setValue( "pkColumnValue", tableAnn.pkColumnValue() ); - annotation.setValue( "initialValue", tableAnn.initialValue() ); - annotation.setValue( "allocationSize", tableAnn.allocationSize() ); - annotation.setValue( "uniqueConstraints", tableAnn.uniqueConstraints() ); - return AnnotationFactory.create( annotation ); - } - else { - return tableAnn; - } - } - else { - return null; - } - } - - public static TableGenerator buildTableGeneratorAnnotation(Element element, XMLContext.Default defaults) { - AnnotationDescriptor ad = new AnnotationDescriptor( TableGenerator.class ); - copyStringAttribute( ad, element, "name", false ); - copyStringAttribute( ad, element, "table", false ); - copyStringAttribute( ad, element, "catalog", false ); - copyStringAttribute( ad, element, "schema", false ); - copyStringAttribute( ad, element, "pk-column-name", false ); - copyStringAttribute( ad, element, "value-column-name", false ); - copyStringAttribute( ad, element, "pk-column-value", false ); - copyIntegerAttribute( ad, element, "initial-value" ); - copyIntegerAttribute( ad, element, "allocation-size" ); - buildUniqueConstraints( ad, element ); - if ( StringHelper.isEmpty( (String) ad.valueOf( "schema" ) ) - && StringHelper.isNotEmpty( defaults.getSchema() ) ) { - ad.setValue( "schema", defaults.getSchema() ); - } - if ( StringHelper.isEmpty( (String) ad.valueOf( "catalog" ) ) - && StringHelper.isNotEmpty( defaults.getCatalog() ) ) { - ad.setValue( "catalog", defaults.getCatalog() ); - } - return AnnotationFactory.create( ad ); - } - - private SequenceGenerator getSequenceGenerator(Element tree, XMLContext.Default defaults) { - Element element = tree != null ? tree.element( annotationToXml.get( SequenceGenerator.class ) ) : null; - if ( element != null ) { - return buildSequenceGeneratorAnnotation( element ); - } - else if ( defaults.canUseJavaAnnotations() ) { - return getPhysicalAnnotation( SequenceGenerator.class ); - } - else { - return null; - } - } - - public static SequenceGenerator buildSequenceGeneratorAnnotation(Element element) { - if ( element != null ) { - AnnotationDescriptor ad = new AnnotationDescriptor( SequenceGenerator.class ); - copyStringAttribute( ad, element, "name", false ); - copyStringAttribute( ad, element, "sequence-name", false ); - copyIntegerAttribute( ad, element, "initial-value" ); - copyIntegerAttribute( ad, element, "allocation-size" ); - return AnnotationFactory.create( ad ); - } - else { - return null; - } - } - - private DiscriminatorColumn getDiscriminatorColumn(Element tree, XMLContext.Default defaults) { - Element element = tree != null ? tree.element( "discriminator-column" ) : null; - if ( element != null ) { - AnnotationDescriptor ad = new AnnotationDescriptor( DiscriminatorColumn.class ); - copyStringAttribute( ad, element, "name", false ); - copyStringAttribute( ad, element, "column-definition", false ); - String value = element.attributeValue( "discriminator-type" ); - DiscriminatorType type = DiscriminatorType.STRING; - if ( value != null ) { - if ( "STRING".equals( value ) ) { - type = DiscriminatorType.STRING; - } - else if ( "CHAR".equals( value ) ) { - type = DiscriminatorType.CHAR; - } - else if ( "INTEGER".equals( value ) ) { - type = DiscriminatorType.INTEGER; - } - else { - throw new AnnotationException( - "Unknown DiscriminatorType in XML: " + value + " (" + SCHEMA_VALIDATION + ")" - ); - } - } - ad.setValue( "discriminatorType", type ); - copyIntegerAttribute( ad, element, "length" ); - return AnnotationFactory.create( ad ); - } - else if ( defaults.canUseJavaAnnotations() ) { - return getPhysicalAnnotation( DiscriminatorColumn.class ); - } - else { - return null; - } - } - - private DiscriminatorValue getDiscriminatorValue(Element tree, XMLContext.Default defaults) { - Element element = tree != null ? tree.element( "discriminator-value" ) : null; - if ( element != null ) { - AnnotationDescriptor ad = new AnnotationDescriptor( DiscriminatorValue.class ); - copyStringElement( element, ad, "value" ); - return AnnotationFactory.create( ad ); - } - else if ( defaults.canUseJavaAnnotations() ) { - return getPhysicalAnnotation( DiscriminatorValue.class ); - } - else { - return null; - } - } - - private Inheritance getInheritance(Element tree, XMLContext.Default defaults) { - Element element = tree != null ? tree.element( "inheritance" ) : null; - if ( element != null ) { - AnnotationDescriptor ad = new AnnotationDescriptor( Inheritance.class ); - Attribute attr = element.attribute( "strategy" ); - InheritanceType strategy = InheritanceType.SINGLE_TABLE; - if ( attr != null ) { - String value = attr.getValue(); - if ( "SINGLE_TABLE".equals( value ) ) { - strategy = InheritanceType.SINGLE_TABLE; - } - else if ( "JOINED".equals( value ) ) { - strategy = InheritanceType.JOINED; - } - else if ( "TABLE_PER_CLASS".equals( value ) ) { - strategy = InheritanceType.TABLE_PER_CLASS; - } - else { - throw new AnnotationException( - "Unknown InheritanceType in XML: " + value + " (" + SCHEMA_VALIDATION + ")" - ); - } - } - ad.setValue( "strategy", strategy ); - return AnnotationFactory.create( ad ); - } - else if ( defaults.canUseJavaAnnotations() ) { - return getPhysicalAnnotation( Inheritance.class ); - } - else { - return null; - } - } - - private IdClass getIdClass(Element tree, XMLContext.Default defaults) { - Element element = tree == null ? null : tree.element( "id-class" ); - if ( element != null ) { - Attribute attr = element.attribute( "class" ); - if ( attr != null ) { - AnnotationDescriptor ad = new AnnotationDescriptor( IdClass.class ); - Class clazz; - try { - clazz = classLoaderAccess.classForName( XMLContext - .buildSafeClassName( attr.getValue(), defaults ) - ); - } - catch ( ClassLoadingException e ) { - throw new AnnotationException( "Unable to find id-class: " + attr.getValue(), e ); - } - ad.setValue( "value", clazz ); - return AnnotationFactory.create( ad ); - } - else { - throw new AnnotationException( "id-class without class. " + SCHEMA_VALIDATION ); - } - } - else if ( defaults.canUseJavaAnnotations() ) { - return getPhysicalAnnotation( IdClass.class ); - } - else { - return null; - } - } - - /** - * @param mergeWithAnnotations Whether to use Java annotations for this - * element, if present and not disabled by the XMLContext defaults. - * In some contexts (such as an association mapping) merging with - * annotations is never allowed. - */ - private PrimaryKeyJoinColumns getPrimaryKeyJoinColumns(Element element, XMLContext.Default defaults, boolean mergeWithAnnotations) { - PrimaryKeyJoinColumn[] columns = buildPrimaryKeyJoinColumns( element ); - if ( mergeWithAnnotations ) { - if ( columns.length == 0 && defaults.canUseJavaAnnotations() ) { - PrimaryKeyJoinColumn annotation = getPhysicalAnnotation( PrimaryKeyJoinColumn.class ); - if ( annotation != null ) { - columns = new PrimaryKeyJoinColumn[] { annotation }; - } - else { - PrimaryKeyJoinColumns annotations = getPhysicalAnnotation( PrimaryKeyJoinColumns.class ); - columns = annotations != null ? annotations.value() : columns; - } - } - } - if ( columns.length > 0 ) { - AnnotationDescriptor ad = new AnnotationDescriptor( PrimaryKeyJoinColumns.class ); - ad.setValue( "value", columns ); - return AnnotationFactory.create( ad ); - } - else { - return null; - } - } - - private Entity getEntity(Element tree, XMLContext.Default defaults) { - if ( tree == null ) { - return defaults.canUseJavaAnnotations() ? getPhysicalAnnotation( Entity.class ) : null; - } - else { - if ( "entity".equals( tree.getName() ) ) { - AnnotationDescriptor entity = new AnnotationDescriptor( Entity.class ); - copyStringAttribute( entity, tree, "name", false ); - if ( defaults.canUseJavaAnnotations() - && StringHelper.isEmpty( (String) entity.valueOf( "name" ) ) ) { - Entity javaAnn = getPhysicalAnnotation( Entity.class ); - if ( javaAnn != null ) { - entity.setValue( "name", javaAnn.name() ); - } - } - return AnnotationFactory.create( entity ); - } - else { - return null; //this is not an entity - } - } - } - - private MappedSuperclass getMappedSuperclass(Element tree, XMLContext.Default defaults) { - if ( tree == null ) { - return defaults.canUseJavaAnnotations() ? getPhysicalAnnotation( MappedSuperclass.class ) : null; - } - else { - if ( "mapped-superclass".equals( tree.getName() ) ) { - AnnotationDescriptor entity = new AnnotationDescriptor( MappedSuperclass.class ); - return AnnotationFactory.create( entity ); - } - else { - return null; //this is not an entity - } - } - } - - private Embeddable getEmbeddable(Element tree, XMLContext.Default defaults) { - if ( tree == null ) { - return defaults.canUseJavaAnnotations() ? getPhysicalAnnotation( Embeddable.class ) : null; - } - else { - if ( "embeddable".equals( tree.getName() ) ) { - AnnotationDescriptor entity = new AnnotationDescriptor( Embeddable.class ); - return AnnotationFactory.create( entity ); - } - else { - return null; //this is not an entity - } - } - } - - private Table getTable(Element tree, XMLContext.Default defaults) { - Element subelement = tree == null ? null : tree.element( "table" ); - if ( subelement == null ) { - //no element but might have some default or some annotation - if ( StringHelper.isNotEmpty( defaults.getCatalog() ) - || StringHelper.isNotEmpty( defaults.getSchema() ) ) { - AnnotationDescriptor annotation = new AnnotationDescriptor( Table.class ); - if ( defaults.canUseJavaAnnotations() ) { - Table table = getPhysicalAnnotation( Table.class ); - if ( table != null ) { - annotation.setValue( "name", table.name() ); - annotation.setValue( "schema", table.schema() ); - annotation.setValue( "catalog", table.catalog() ); - annotation.setValue( "uniqueConstraints", table.uniqueConstraints() ); - annotation.setValue( "indexes", table.indexes() ); - } - } - if ( StringHelper.isEmpty( (String) annotation.valueOf( "schema" ) ) - && StringHelper.isNotEmpty( defaults.getSchema() ) ) { - annotation.setValue( "schema", defaults.getSchema() ); - } - if ( StringHelper.isEmpty( (String) annotation.valueOf( "catalog" ) ) - && StringHelper.isNotEmpty( defaults.getCatalog() ) ) { - annotation.setValue( "catalog", defaults.getCatalog() ); - } - return AnnotationFactory.create( annotation ); - } - else if ( defaults.canUseJavaAnnotations() ) { - return getPhysicalAnnotation( Table.class ); - } - else { - return null; - } - } - else { - //ignore java annotation, an element is defined - AnnotationDescriptor annotation = new AnnotationDescriptor( Table.class ); - copyStringAttribute( annotation, subelement, "name", false ); - copyStringAttribute( annotation, subelement, "catalog", false ); - if ( StringHelper.isNotEmpty( defaults.getCatalog() ) - && StringHelper.isEmpty( (String) annotation.valueOf( "catalog" ) ) ) { - annotation.setValue( "catalog", defaults.getCatalog() ); - } - copyStringAttribute( annotation, subelement, "schema", false ); - if ( StringHelper.isNotEmpty( defaults.getSchema() ) - && StringHelper.isEmpty( (String) annotation.valueOf( "schema" ) ) ) { - annotation.setValue( "schema", defaults.getSchema() ); - } - buildUniqueConstraints( annotation, subelement ); - buildIndex( annotation, subelement ); - return AnnotationFactory.create( annotation ); - } - } - - private SecondaryTables getSecondaryTables(Element tree, XMLContext.Default defaults) { - List elements = tree == null ? - new ArrayList<>() : - (List) tree.elements( "secondary-table" ); - List secondaryTables = new ArrayList<>( 3 ); - for ( Element element : elements ) { - AnnotationDescriptor annotation = new AnnotationDescriptor( SecondaryTable.class ); - copyStringAttribute( annotation, element, "name", false ); - copyStringAttribute( annotation, element, "catalog", false ); - if ( StringHelper.isNotEmpty( defaults.getCatalog() ) - && StringHelper.isEmpty( (String) annotation.valueOf( "catalog" ) ) ) { - annotation.setValue( "catalog", defaults.getCatalog() ); - } - copyStringAttribute( annotation, element, "schema", false ); - if ( StringHelper.isNotEmpty( defaults.getSchema() ) - && StringHelper.isEmpty( (String) annotation.valueOf( "schema" ) ) ) { - annotation.setValue( "schema", defaults.getSchema() ); - } - buildUniqueConstraints( annotation, element ); - buildIndex( annotation, element ); - annotation.setValue( "pkJoinColumns", buildPrimaryKeyJoinColumns( element ) ); - secondaryTables.add( AnnotationFactory.create( annotation ) ); - } - /* - * You can't have both secondary tables in XML and Java, - * since there would be no way to "remove" a secondary table - */ - if ( secondaryTables.size() == 0 && defaults.canUseJavaAnnotations() ) { - SecondaryTable secTableAnn = getPhysicalAnnotation( SecondaryTable.class ); - overridesDefaultInSecondaryTable( secTableAnn, defaults, secondaryTables ); - SecondaryTables secTablesAnn = getPhysicalAnnotation( SecondaryTables.class ); - if ( secTablesAnn != null ) { - for ( SecondaryTable table : secTablesAnn.value() ) { - overridesDefaultInSecondaryTable( table, defaults, secondaryTables ); - } - } - } - if ( secondaryTables.size() > 0 ) { - AnnotationDescriptor descriptor = new AnnotationDescriptor( SecondaryTables.class ); - descriptor.setValue( "value", secondaryTables.toArray( new SecondaryTable[secondaryTables.size()] ) ); - return AnnotationFactory.create( descriptor ); - } - else { - return null; - } - } - - private void overridesDefaultInSecondaryTable( - SecondaryTable secTableAnn, XMLContext.Default defaults, List secondaryTables - ) { - if ( secTableAnn != null ) { - //handle default values - if ( StringHelper.isNotEmpty( defaults.getCatalog() ) - || StringHelper.isNotEmpty( defaults.getSchema() ) ) { - AnnotationDescriptor annotation = new AnnotationDescriptor( SecondaryTable.class ); - annotation.setValue( "name", secTableAnn.name() ); - annotation.setValue( "schema", secTableAnn.schema() ); - annotation.setValue( "catalog", secTableAnn.catalog() ); - annotation.setValue( "uniqueConstraints", secTableAnn.uniqueConstraints() ); - annotation.setValue( "pkJoinColumns", secTableAnn.pkJoinColumns() ); - if ( StringHelper.isEmpty( (String) annotation.valueOf( "schema" ) ) - && StringHelper.isNotEmpty( defaults.getSchema() ) ) { - annotation.setValue( "schema", defaults.getSchema() ); - } - if ( StringHelper.isEmpty( (String) annotation.valueOf( "catalog" ) ) - && StringHelper.isNotEmpty( defaults.getCatalog() ) ) { - annotation.setValue( "catalog", defaults.getCatalog() ); - } - secondaryTables.add( AnnotationFactory.create( annotation ) ); - } - else { - secondaryTables.add( secTableAnn ); - } - } - } - private static void buildIndex(AnnotationDescriptor annotation, Element element){ - List indexElementList = element.elements( "index" ); - Index[] indexes = new Index[indexElementList.size()]; - for(int i=0;i columnNamesElements = subelement.elements( "column-name" ); - String[] columnNames = new String[columnNamesElements.size()]; - int columnNameIndex = 0; - Iterator it = columnNamesElements.listIterator(); - while ( it.hasNext() ) { - Element columnNameElt = (Element) it.next(); - columnNames[columnNameIndex++] = columnNameElt.getTextTrim(); - } - AnnotationDescriptor ucAnn = new AnnotationDescriptor( UniqueConstraint.class ); - copyStringAttribute( ucAnn, subelement, "name", false ); - ucAnn.setValue( "columnNames", columnNames ); - uniqueConstraints[ucIndex++] = AnnotationFactory.create( ucAnn ); - } - annotation.setValue( "uniqueConstraints", uniqueConstraints ); - } - - private PrimaryKeyJoinColumn[] buildPrimaryKeyJoinColumns(Element element) { - if ( element == null ) { - return new PrimaryKeyJoinColumn[] { }; - } - List pkJoinColumnElementList = element.elements( "primary-key-join-column" ); - PrimaryKeyJoinColumn[] pkJoinColumns = new PrimaryKeyJoinColumn[pkJoinColumnElementList.size()]; - int index = 0; - Iterator pkIt = pkJoinColumnElementList.listIterator(); - while ( pkIt.hasNext() ) { - Element subelement = (Element) pkIt.next(); - AnnotationDescriptor pkAnn = new AnnotationDescriptor( PrimaryKeyJoinColumn.class ); - copyStringAttribute( pkAnn, subelement, "name", false ); - copyStringAttribute( pkAnn, subelement, "referenced-column-name", false ); - copyStringAttribute( pkAnn, subelement, "column-definition", false ); - pkJoinColumns[index++] = AnnotationFactory.create( pkAnn ); - } - return pkJoinColumns; - } - - /** - * Copy a string attribute from an XML element to an annotation descriptor. The name of the annotation attribute is - * computed from the name of the XML attribute by {@link #getJavaAttributeNameFromXMLOne(String)}. - * - * @param annotation annotation descriptor where to copy to the attribute. - * @param element XML element from where to copy the attribute. - * @param attributeName name of the XML attribute to copy. - * @param mandatory whether the attribute is mandatory. - */ - private static void copyStringAttribute( - final AnnotationDescriptor annotation, final Element element, - final String attributeName, final boolean mandatory) { - copyStringAttribute( - annotation, - element, - getJavaAttributeNameFromXMLOne( attributeName ), - attributeName, - mandatory - ); - } - - /** - * Copy a string attribute from an XML element to an annotation descriptor. The name of the annotation attribute is - * explicitly given. - * - * @param annotation annotation where to copy to the attribute. - * @param element XML element from where to copy the attribute. - * @param annotationAttributeName name of the annotation attribute where to copy. - * @param attributeName name of the XML attribute to copy. - * @param mandatory whether the attribute is mandatory. - */ - private static void copyStringAttribute( - final AnnotationDescriptor annotation, final Element element, - final String annotationAttributeName, final String attributeName, boolean mandatory) { - String attribute = element.attributeValue( attributeName ); - if ( attribute != null ) { - annotation.setValue( annotationAttributeName, attribute ); - } - else { - if ( mandatory ) { - throw new AnnotationException( - element.getName() + "." + attributeName + " is mandatory in XML overriding. " + SCHEMA_VALIDATION - ); - } - } - } - - private static void copyIntegerAttribute(AnnotationDescriptor annotation, Element element, String attributeName) { - String attribute = element.attributeValue( attributeName ); - if ( attribute != null ) { - String annotationAttributeName = getJavaAttributeNameFromXMLOne( attributeName ); - annotation.setValue( annotationAttributeName, attribute ); - try { - int length = Integer.parseInt( attribute ); - annotation.setValue( annotationAttributeName, length ); - } - catch ( NumberFormatException e ) { - throw new AnnotationException( - element.getPath() + attributeName + " not parseable: " + attribute + " (" + SCHEMA_VALIDATION + ")" - ); - } - } - } - - private static String getJavaAttributeNameFromXMLOne(String attributeName) { - StringBuilder annotationAttributeName = new StringBuilder( attributeName ); - int index = annotationAttributeName.indexOf( WORD_SEPARATOR ); - while ( index != -1 ) { - annotationAttributeName.deleteCharAt( index ); - annotationAttributeName.setCharAt( - index, Character.toUpperCase( annotationAttributeName.charAt( index ) ) - ); - index = annotationAttributeName.indexOf( WORD_SEPARATOR ); - } - return annotationAttributeName.toString(); - } - - private static void copyStringElement(Element element, AnnotationDescriptor ad, String annotationAttribute) { - String discr = element.getTextTrim(); - ad.setValue( annotationAttribute, discr ); - } - - private static void copyBooleanAttribute(AnnotationDescriptor descriptor, Element element, String attribute) { - String attributeValue = element.attributeValue( attribute ); - if ( StringHelper.isNotEmpty( attributeValue ) ) { - String javaAttribute = getJavaAttributeNameFromXMLOne( attribute ); - descriptor.setValue( javaAttribute, Boolean.parseBoolean( attributeValue ) ); - } - } - - private T getPhysicalAnnotation(Class annotationType) { - return element.getAnnotation( annotationType ); - } - - private boolean isPhysicalAnnotationPresent(Class annotationType) { - return element.isAnnotationPresent( annotationType ); - } - - private Annotation[] getPhysicalAnnotations() { - return element.getAnnotations(); - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/XMLContext.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/XMLContext.java deleted file mode 100644 index 9cde55fea7c0..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/XMLContext.java +++ /dev/null @@ -1,363 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.cfg.annotations.reflection; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import javax.persistence.AccessType; -import javax.persistence.AttributeConverter; - -import org.hibernate.AnnotationException; -import org.hibernate.boot.AttributeConverterInfo; -import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; -import org.hibernate.boot.spi.BootstrapContext; -import org.hibernate.boot.spi.ClassLoaderAccess; -import org.hibernate.cfg.AttributeConverterDefinition; -import org.hibernate.internal.CoreLogging; -import org.hibernate.internal.CoreMessageLogger; -import org.hibernate.internal.util.StringHelper; - -import org.dom4j.Document; -import org.dom4j.Element; - -/** - * A helper for consuming orm.xml mappings. - * - * @author Emmanuel Bernard - * @author Brett Meyer - * - * @deprecated This class is not API: do not use it from application code. - * This class will be removed in Hibernate ORM 6.0. - * For implementation code, use {@link org.hibernate.cfg.annotations.reflection.internal.XMLContext} instead. - */ -@Deprecated -public class XMLContext implements Serializable { - private static final CoreMessageLogger LOG = CoreLogging.messageLogger( XMLContext.class ); - - private final ClassLoaderAccess classLoaderAccess; - - private Default globalDefaults; - private Map classOverriding = new HashMap<>(); - private Map defaultsOverriding = new HashMap<>(); - private List defaultElements = new ArrayList<>(); - private List defaultEntityListeners = new ArrayList<>(); - private boolean hasContext = false; - - /** - * @deprecated Use {@link XMLContext#XMLContext(BootstrapContext)} instead. - */ - @Deprecated - public XMLContext(ClassLoaderAccess classLoaderAccess) { - this.classLoaderAccess = classLoaderAccess; - } - - public XMLContext(BootstrapContext bootstrapContext) { - this.classLoaderAccess = bootstrapContext.getClassLoaderAccess(); - } - - /** - * @param doc The xml document to add - * @return Add an xml document to this context and return the list of added class names. - */ - @SuppressWarnings( "unchecked" ) - public List addDocument(Document doc) { - hasContext = true; - List addedClasses = new ArrayList<>(); - Element root = doc.getRootElement(); - //global defaults - Element metadata = root.element( "persistence-unit-metadata" ); - if ( metadata != null ) { - if ( globalDefaults == null ) { - globalDefaults = new Default(); - globalDefaults.setMetadataComplete( - metadata.element( "xml-mapping-metadata-complete" ) != null ? - Boolean.TRUE : - null - ); - Element defaultElement = metadata.element( "persistence-unit-defaults" ); - if ( defaultElement != null ) { - Element unitElement = defaultElement.element( "schema" ); - globalDefaults.setSchema( unitElement != null ? unitElement.getTextTrim() : null ); - unitElement = defaultElement.element( "catalog" ); - globalDefaults.setCatalog( unitElement != null ? unitElement.getTextTrim() : null ); - unitElement = defaultElement.element( "access" ); - setAccess( unitElement, globalDefaults ); - unitElement = defaultElement.element( "cascade-persist" ); - globalDefaults.setCascadePersist( unitElement != null ? Boolean.TRUE : null ); - unitElement = defaultElement.element( "delimited-identifiers" ); - globalDefaults.setDelimitedIdentifiers( unitElement != null ? Boolean.TRUE : null ); - defaultEntityListeners.addAll( addEntityListenerClasses( defaultElement, null, addedClasses ) ); - } - } - else { - LOG.duplicateMetadata(); - } - } - - //entity mapping default - Default entityMappingDefault = new Default(); - Element unitElement = root.element( "package" ); - String packageName = unitElement != null ? unitElement.getTextTrim() : null; - entityMappingDefault.setPackageName( packageName ); - unitElement = root.element( "schema" ); - entityMappingDefault.setSchema( unitElement != null ? unitElement.getTextTrim() : null ); - unitElement = root.element( "catalog" ); - entityMappingDefault.setCatalog( unitElement != null ? unitElement.getTextTrim() : null ); - unitElement = root.element( "access" ); - setAccess( unitElement, entityMappingDefault ); - defaultElements.add( root ); - - setLocalAttributeConverterDefinitions( root.elements( "converter" ) ); - - List entities = root.elements( "entity" ); - addClass( entities, packageName, entityMappingDefault, addedClasses ); - - entities = root.elements( "mapped-superclass" ); - addClass( entities, packageName, entityMappingDefault, addedClasses ); - - entities = root.elements( "embeddable" ); - addClass( entities, packageName, entityMappingDefault, addedClasses ); - return addedClasses; - } - - private void setAccess(Element unitElement, Default defaultType) { - if ( unitElement != null ) { - String access = unitElement.getTextTrim(); - setAccess( access, defaultType ); - } - } - - private void setAccess( String access, Default defaultType) { - AccessType type; - if ( access != null ) { - try { - type = AccessType.valueOf( access ); - } - catch ( IllegalArgumentException e ) { - throw new AnnotationException( "Invalid access type " + access + " (check your xml configuration)" ); - } - defaultType.setAccess( type ); - } - } - - private void addClass(List entities, String packageName, Default defaults, List addedClasses) { - for (Element element : entities) { - String className = buildSafeClassName( element.attributeValue( "class" ), packageName ); - if ( classOverriding.containsKey( className ) ) { - //maybe switch it to warn? - throw new IllegalStateException( "Duplicate XML entry for " + className ); - } - addedClasses.add( className ); - classOverriding.put( className, element ); - Default localDefault = new Default(); - localDefault.override( defaults ); - String metadataCompleteString = element.attributeValue( "metadata-complete" ); - if ( metadataCompleteString != null ) { - localDefault.setMetadataComplete( Boolean.parseBoolean( metadataCompleteString ) ); - } - String access = element.attributeValue( "access" ); - setAccess( access, localDefault ); - defaultsOverriding.put( className, localDefault ); - - LOG.debugf( "Adding XML overriding information for %s", className ); - addEntityListenerClasses( element, packageName, addedClasses ); - } - } - - private List addEntityListenerClasses(Element element, String packageName, List addedClasses) { - List localAddedClasses = new ArrayList<>(); - Element listeners = element.element( "entity-listeners" ); - if ( listeners != null ) { - @SuppressWarnings( "unchecked" ) - List elements = listeners.elements( "entity-listener" ); - for (Element listener : elements) { - String listenerClassName = buildSafeClassName( listener.attributeValue( "class" ), packageName ); - if ( classOverriding.containsKey( listenerClassName ) ) { - //maybe switch it to warn? - if ( "entity-listener".equals( classOverriding.get( listenerClassName ).getName() ) ) { - LOG.duplicateListener( listenerClassName ); - continue; - } - throw new IllegalStateException("Duplicate XML entry for " + listenerClassName); - } - localAddedClasses.add( listenerClassName ); - classOverriding.put( listenerClassName, listener ); - } - } - LOG.debugf( "Adding XML overriding information for listeners: %s", localAddedClasses ); - addedClasses.addAll( localAddedClasses ); - return localAddedClasses; - } - - @SuppressWarnings("unchecked") - private void setLocalAttributeConverterDefinitions(List converterElements) { - for ( Element converterElement : converterElements ) { - final String className = converterElement.attributeValue( "class" ); - final String autoApplyAttribute = converterElement.attributeValue( "auto-apply" ); - final boolean autoApply = autoApplyAttribute != null && Boolean.parseBoolean( autoApplyAttribute ); - - try { - final Class attributeConverterClass = classLoaderAccess.classForName( - className - ); - attributeConverterInfoList.add( - new AttributeConverterDefinition( attributeConverterClass.newInstance(), autoApply ) - ); - } - catch (ClassLoadingException e) { - throw new AnnotationException( "Unable to locate specified AttributeConverter implementation class : " + className, e ); - } - catch (Exception e) { - throw new AnnotationException( "Unable to instantiate specified AttributeConverter implementation class : " + className, e ); - } - } - } - - public static String buildSafeClassName(String className, String defaultPackageName) { - if ( className.indexOf( '.' ) < 0 && StringHelper.isNotEmpty( defaultPackageName ) ) { - className = StringHelper.qualify( defaultPackageName, className ); - } - return className; - } - - public static String buildSafeClassName(String className, Default defaults) { - return buildSafeClassName( className, defaults.getPackageName() ); - } - - public Default getDefault(String className) { - Default xmlDefault = new Default(); - xmlDefault.override( globalDefaults ); - if ( className != null ) { - Default entityMappingOverriding = defaultsOverriding.get( className ); - xmlDefault.override( entityMappingOverriding ); - } - return xmlDefault; - } - - public Element getXMLTree(String className ) { - return classOverriding.get( className ); - } - - public List getAllDocuments() { - return defaultElements; - } - - public boolean hasContext() { - return hasContext; - } - - private List attributeConverterInfoList = new ArrayList<>(); - - public void applyDiscoveredAttributeConverters(AttributeConverterDefinitionCollector collector) { - for ( AttributeConverterInfo info : attributeConverterInfoList ) { - collector.addAttributeConverter( info ); - } - attributeConverterInfoList.clear(); - } - - public static class Default implements Serializable { - private AccessType access; - private String packageName; - private String schema; - private String catalog; - private Boolean metadataComplete; - private Boolean cascadePersist; - private Boolean delimitedIdentifier; - - public AccessType getAccess() { - return access; - } - - protected void setAccess(AccessType access) { - this.access = access; - } - - public String getCatalog() { - return catalog; - } - - protected void setCatalog(String catalog) { - this.catalog = catalog; - } - - public String getPackageName() { - return packageName; - } - - protected void setPackageName(String packageName) { - this.packageName = packageName; - } - - public String getSchema() { - return schema; - } - - protected void setSchema(String schema) { - this.schema = schema; - } - - public Boolean getMetadataComplete() { - return metadataComplete; - } - - public boolean canUseJavaAnnotations() { - return metadataComplete == null || !metadataComplete; - } - - protected void setMetadataComplete(Boolean metadataComplete) { - this.metadataComplete = metadataComplete; - } - - public Boolean getCascadePersist() { - return cascadePersist; - } - - void setCascadePersist(Boolean cascadePersist) { - this.cascadePersist = cascadePersist; - } - - public void override(Default globalDefault) { - if ( globalDefault != null ) { - if ( globalDefault.getAccess() != null ) { - access = globalDefault.getAccess(); - } - 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(); - } - if ( globalDefault.getMetadataComplete() != null ) { - metadataComplete = globalDefault.getMetadataComplete(); - } - //TODO fix that in stone if cascade-persist is set already? - if ( globalDefault.getCascadePersist() != null ) cascadePersist = globalDefault.getCascadePersist(); - } - } - - public void setDelimitedIdentifiers(Boolean delimitedIdentifier) { - this.delimitedIdentifier = delimitedIdentifier; - } - - public Boolean getDelimitedIdentifier() { - return delimitedIdentifier; - } - } - - public List getDefaultEntityListeners() { - return defaultEntityListeners; - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/XMLContext.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/XMLContext.java index 0192e4dce667..32e5aac98223 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/XMLContext.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/XMLContext.java @@ -54,7 +54,7 @@ public class XMLContext implements Serializable { private boolean hasContext = false; /** - * @deprecated Use {@link org.hibernate.cfg.annotations.reflection.XMLContext#XMLContext(BootstrapContext)} instead. + * @deprecated Use {@link #XMLContext(BootstrapContext)} instead. */ @Deprecated public XMLContext(ClassLoaderAccess classLoaderAccess) { diff --git a/hibernate-core/src/test/java/org/hibernate/internal/util/xml/XMLMappingHelper.java b/hibernate-core/src/test/java/org/hibernate/internal/util/xml/XMLMappingHelper.java index 11d3628fe415..2e1d5601b16f 100644 --- a/hibernate-core/src/test/java/org/hibernate/internal/util/xml/XMLMappingHelper.java +++ b/hibernate-core/src/test/java/org/hibernate/internal/util/xml/XMLMappingHelper.java @@ -28,8 +28,8 @@ public final class XMLMappingHelper { private final MappingBinder binder; - public XMLMappingHelper(XmlMappingOptions xmlMappingOptions) { - binder = new MappingBinder( ClassLoaderServiceTestingImpl.INSTANCE, true, xmlMappingOptions ); + public XMLMappingHelper() { + binder = new MappingBinder( ClassLoaderServiceTestingImpl.INSTANCE, true ); } public JaxbEntityMappings readOrmXmlMappings(String name) throws IOException { diff --git a/hibernate-core/src/test/java/org/hibernate/internal/util/xml/XmlMappingOptionsStrategyRegistrationProvider.java b/hibernate-core/src/test/java/org/hibernate/internal/util/xml/XmlMappingOptionsStrategyRegistrationProvider.java deleted file mode 100644 index 97c6a617ce42..000000000000 --- a/hibernate-core/src/test/java/org/hibernate/internal/util/xml/XmlMappingOptionsStrategyRegistrationProvider.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later - * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html - */ -package org.hibernate.internal.util.xml; - -import java.util.Collections; - -import org.hibernate.boot.jaxb.spi.XmlMappingOptions; -import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder; -import org.hibernate.boot.registry.selector.SimpleStrategyRegistrationImpl; -import org.hibernate.boot.registry.selector.StrategyRegistration; -import org.hibernate.boot.registry.selector.StrategyRegistrationProvider; - -import org.jboss.logging.Logger; - -/** - * A strategy registration provider that allows running the whole test suite with different XML mapping options. - *

- * By default, this provider does nothing. - * In some CI jobs, we set the system property {@value STRATEGY_PROPERTY_KEY} - * to re-run the whole test suite using JAXB for orm.xml parsing instead of dom4j. - */ -public class XmlMappingOptionsStrategyRegistrationProvider implements StrategyRegistrationProvider { - - protected final Logger log = Logger.getLogger( getClass() ); - - private static final String STRATEGY_PROPERTY_KEY = "testing.mapping.xml.strategy"; - - public static void applyJaxbStrategy(BootstrapServiceRegistryBuilder builder) { - builder.applyStrategySelector( XmlMappingOptions.class, XmlMappingOptions.DEFAULT_NAME, - PreferJaxbXmlMappingOptions.class - ); - } - - @Override - public Iterable getStrategyRegistrations() { - switch ( getStrategyFromSystemProperties() ) { - case "jaxb": - log.warn( "Overriding the default configuration because of a test system property:" - + " will favor jaxb when parsing XML mapping." ); - return Collections.singleton( - new SimpleStrategyRegistrationImpl<>( XmlMappingOptions.class, - PreferJaxbXmlMappingOptions.class, - XmlMappingOptions.DEFAULT_NAME ) - ); - case "default": - default: - return Collections.emptyList(); - } - } - - private static String getStrategyFromSystemProperties() { - String strategy = System.getProperty( STRATEGY_PROPERTY_KEY ); - return strategy == null || strategy.isEmpty() ? "default" : strategy; - } - - public static class PreferJaxbXmlMappingOptions implements XmlMappingOptions { - @Override - public boolean isPreferJaxb() { - return true; - } - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/ElementCollectionConverterTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/ElementCollectionConverterTest.java index e0357054dd3c..3c86b8b860c6 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/ElementCollectionConverterTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/ElementCollectionConverterTest.java @@ -7,7 +7,6 @@ package org.hibernate.test.annotations.reflection; import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder; -import org.hibernate.internal.util.xml.XmlMappingOptionsStrategyRegistrationProvider; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; @@ -22,7 +21,6 @@ public class ElementCollectionConverterTest extends BaseCoreFunctionalTestCase { @Override protected void prepareBootstrapRegistryBuilder(BootstrapServiceRegistryBuilder builder) { super.prepareBootstrapRegistryBuilder( builder ); - XmlMappingOptionsStrategyRegistrationProvider.applyJaxbStrategy( builder ); } @Override diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/JPAXMLOverriddenAnnotationReaderTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/JPAXMLOverriddenAnnotationReaderTest.java index 1704cce53e96..8eaec9352f65 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/JPAXMLOverriddenAnnotationReaderTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/JPAXMLOverriddenAnnotationReaderTest.java @@ -6,45 +6,25 @@ */ package org.hibernate.test.annotations.reflection; -import org.dom4j.DocumentException; -import org.dom4j.io.SAXReader; import org.hibernate.annotations.Columns; import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappings; -import org.hibernate.boot.jaxb.spi.XmlMappingOptions; -import org.hibernate.cfg.EJB3DTDEntityResolver; -import org.hibernate.cfg.annotations.reflection.JPAOverriddenAnnotationReader; import org.hibernate.cfg.annotations.reflection.internal.JPAXMLOverriddenAnnotationReader; import org.hibernate.cfg.annotations.reflection.internal.XMLContext; -import org.hibernate.internal.util.xml.ErrorLogger; -import org.hibernate.internal.util.xml.XMLHelper; import org.hibernate.internal.util.xml.XMLMappingHelper; import org.hibernate.testing.boot.BootstrapContextImpl; import org.hibernate.testing.junit4.BaseUnitTestCase; import org.hibernate.testing.TestForIssue; -import org.hibernate.testing.boot.ClassLoaderServiceTestingImpl; import org.junit.Test; -import org.xml.sax.InputSource; -import org.xml.sax.SAXException; -import org.xml.sax.SAXNotSupportedException; import javax.persistence.*; -import java.io.BufferedInputStream; import java.io.IOException; -import java.io.InputStream; import java.lang.reflect.Field; import java.lang.reflect.Method; import static org.junit.Assert.*; /** - * Tests the new {@link JPAXMLOverriddenAnnotationReader}, - * which will be replacing {@link JPAOverriddenAnnotationReader}. - * {@link JPAOverriddenAnnotationReader} is still the default implementation, - * but we want to switch to {@link JPAXMLOverriddenAnnotationReader} - * as soon as it will be practical. - * - * @see LegacyJPAOverriddenAnnotationReaderTest * @author Emmanuel Bernard */ @TestForIssue(jiraKey = "HHH-14529") @@ -405,12 +385,7 @@ public void testEntityListeners() throws Exception { } private XMLContext buildContext(String ormfile) throws IOException { - XMLMappingHelper xmlHelper = new XMLMappingHelper( new XmlMappingOptions() { - @Override - public boolean isPreferJaxb() { - return true; - } - } ); + XMLMappingHelper xmlHelper = new XMLMappingHelper(); JaxbEntityMappings mappings = xmlHelper.readOrmXmlMappings( ormfile ); XMLContext context = new XMLContext( BootstrapContextImpl.INSTANCE ); context.addDocument( mappings ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/XMLContextTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/XMLContextTest.java index 39ed92d42f96..22f6e4dbb6f4 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/XMLContextTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/XMLContextTest.java @@ -7,7 +7,6 @@ package org.hibernate.test.annotations.reflection; import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappings; -import org.hibernate.boot.jaxb.spi.XmlMappingOptions; import org.hibernate.cfg.annotations.reflection.internal.XMLContext; import org.hibernate.internal.util.xml.XMLMappingHelper; @@ -16,24 +15,13 @@ import org.junit.Test; /** - * Tests the new {@link XMLContext}, - * which will be replacing {@link org.hibernate.cfg.annotations.reflection.XMLContext}. - * {@link org.hibernate.cfg.annotations.reflection.XMLContext} is still the default implementation, - * but we want to switch to {@link XMLContext} - * as soon as it will be practical. - * * @author Emmanuel Bernard */ @TestForIssue(jiraKey = "HHH-14529") public class XMLContextTest { @Test public void testAll() throws Exception { - XMLMappingHelper xmlHelper = new XMLMappingHelper( new XmlMappingOptions() { - @Override - public boolean isPreferJaxb() { - return true; - } - } ); + XMLMappingHelper xmlHelper = new XMLMappingHelper(); final XMLContext context = new XMLContext( BootstrapContextImpl.INSTANCE ); JaxbEntityMappings mappings = xmlHelper.readOrmXmlMappings( "org/hibernate/test/annotations/reflection/orm.xml" ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlTest.java index 96335a4d416d..c0f8fd1cc08c 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlTest.java @@ -17,7 +17,6 @@ import org.hibernate.dialect.PostgreSQL81Dialect; import org.hibernate.dialect.PostgreSQLDialect; import org.hibernate.dialect.TeradataDialect; -import org.hibernate.internal.util.xml.XmlMappingOptionsStrategyRegistrationProvider; import org.hibernate.persister.collection.BasicCollectionPersister; import org.hibernate.testing.SkipForDialect; @@ -37,7 +36,6 @@ public class Ejb3XmlTest extends BaseCoreFunctionalTestCase { @Override protected void prepareBootstrapRegistryBuilder(BootstrapServiceRegistryBuilder builder) { super.prepareBootstrapRegistryBuilder( builder ); - XmlMappingOptionsStrategyRegistrationProvider.applyJaxbStrategy( builder ); } @Test diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlTestCase.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlTestCase.java index ea1d1fee35e0..b5b18a78150c 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlTestCase.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlTestCase.java @@ -11,7 +11,6 @@ import java.lang.reflect.AnnotatedElement; import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappings; -import org.hibernate.boot.jaxb.spi.XmlMappingOptions; import org.hibernate.cfg.annotations.reflection.internal.JPAXMLOverriddenAnnotationReader; import org.hibernate.cfg.annotations.reflection.internal.XMLContext; import org.hibernate.internal.util.xml.XMLMappingHelper; @@ -67,12 +66,7 @@ protected XMLContext getContext(String resourceName) throws Exception { } protected XMLContext getContext(InputStream is, String resourceName) throws Exception { - XMLMappingHelper xmlHelper = new XMLMappingHelper( new XmlMappingOptions() { - @Override - public boolean isPreferJaxb() { - return true; - } - } ); + XMLMappingHelper xmlHelper = new XMLMappingHelper(); JaxbEntityMappings mappings = xmlHelper.readOrmXmlMappings( is, resourceName ); XMLContext context = new XMLContext( BootstrapContextImpl.INSTANCE ); context.addDocument( mappings ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/NonExistentOrmVersionTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/NonExistentOrmVersionTest.java index 13a8535ca90a..adc2b3d6fbe2 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/NonExistentOrmVersionTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/NonExistentOrmVersionTest.java @@ -10,7 +10,6 @@ import org.hibernate.boot.MetadataSources; import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder; import org.hibernate.internal.util.xml.UnsupportedOrmXsdVersionException; -import org.hibernate.internal.util.xml.XmlMappingOptionsStrategyRegistrationProvider; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.junit4.BaseUnitTestCase; @@ -24,7 +23,6 @@ public class NonExistentOrmVersionTest extends BaseUnitTestCase { public void testNonExistentOrmVersion() { try { BootstrapServiceRegistryBuilder builder = new BootstrapServiceRegistryBuilder(); - XmlMappingOptionsStrategyRegistrationProvider.applyJaxbStrategy( builder ); new MetadataSources( builder.build() ) .addResource( "org/hibernate/test/annotations/xml/ejb3/orm5.xml" ) .buildMetadata(); diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/OrmVersion1SupportedTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/OrmVersion1SupportedTest.java index ef227c81ae6d..92571730db76 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/OrmVersion1SupportedTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/OrmVersion1SupportedTest.java @@ -11,7 +11,6 @@ import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.xml.ErrorLogger; -import org.hibernate.internal.util.xml.XmlMappingOptionsStrategyRegistrationProvider; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; @@ -31,7 +30,6 @@ public class OrmVersion1SupportedTest extends BaseCoreFunctionalTestCase { @Override protected void prepareBootstrapRegistryBuilder(BootstrapServiceRegistryBuilder builder) { super.prepareBootstrapRegistryBuilder( builder ); - XmlMappingOptionsStrategyRegistrationProvider.applyJaxbStrategy( builder ); } @Rule diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/PreParsedOrmXmlTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/PreParsedOrmXmlTest.java index 057c4ede5d60..a2c8faf9e074 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/PreParsedOrmXmlTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/PreParsedOrmXmlTest.java @@ -13,7 +13,6 @@ import org.hibernate.boot.jaxb.spi.Binding; import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder; import org.hibernate.cfg.Configuration; -import org.hibernate.internal.util.xml.XmlMappingOptionsStrategyRegistrationProvider; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; @@ -27,7 +26,6 @@ public class PreParsedOrmXmlTest extends BaseCoreFunctionalTestCase { @Override protected void prepareBootstrapRegistryBuilder(BootstrapServiceRegistryBuilder builder) { super.prepareBootstrapRegistryBuilder( builder ); - XmlMappingOptionsStrategyRegistrationProvider.applyJaxbStrategy( builder ); } @Override diff --git a/hibernate-core/src/test/resources/META-INF/services/org.hibernate.boot.registry.selector.StrategyRegistrationProvider b/hibernate-core/src/test/resources/META-INF/services/org.hibernate.boot.registry.selector.StrategyRegistrationProvider deleted file mode 100644 index 98148e1689bf..000000000000 --- a/hibernate-core/src/test/resources/META-INF/services/org.hibernate.boot.registry.selector.StrategyRegistrationProvider +++ /dev/null @@ -1 +0,0 @@ -org.hibernate.internal.util.xml.XmlMappingOptionsStrategyRegistrationProvider \ No newline at end of file From b076216e841d00470281e198bef1fccc35be34a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Fri, 16 Apr 2021 14:27:27 +0200 Subject: [PATCH 112/644] HHH-14563 Remove XmlMappingOptions We don't need that anymore: XML mapping is either enabled or disabled, there are no other options. So a boolean will do. --- .../boot/internal/MetadataBuilderImpl.java | 13 ++-- .../internal/DefaultXmlMappingOptions.java | 12 --- .../boot/jaxb/internal/MappingBinder.java | 1 - .../boot/jaxb/spi/XmlMappingOptions.java | 75 ------------------- .../process/spi/MetadataBuildingProcess.java | 20 +++-- ...AnnotationMetadataSourceProcessorImpl.java | 4 +- .../internal/StrategySelectorBuilder.java | 4 - ...ractDelegatingMetadataBuildingOptions.java | 5 +- .../boot/spi/MetadataBuildingOptions.java | 5 +- .../boot/spi/XmlMappingBinderAccess.java | 4 - .../JPAXMLOverriddenMetadataProvider.java | 7 +- .../internal/util/xml/XMLMappingHelper.java | 4 - .../AdditionalJaxbMappingProducerImpl.java | 5 +- 13 files changed, 30 insertions(+), 129 deletions(-) delete mode 100644 hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/DefaultXmlMappingOptions.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/boot/jaxb/spi/XmlMappingOptions.java diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/MetadataBuilderImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/MetadataBuilderImpl.java index 0b0195d2d97c..5c96508086f8 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/MetadataBuilderImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/MetadataBuilderImpl.java @@ -30,7 +30,6 @@ import org.hibernate.boot.cfgxml.spi.CfgXmlAccessService; import org.hibernate.boot.cfgxml.spi.LoadedConfig; import org.hibernate.boot.cfgxml.spi.MappingReference; -import org.hibernate.boot.jaxb.spi.XmlMappingOptions; import org.hibernate.boot.model.IdGeneratorStrategyInterpreter; import org.hibernate.boot.model.TypeContributions; import org.hibernate.boot.model.TypeContributor; @@ -623,7 +622,7 @@ public static class MetadataBuildingOptionsImpl private IdGeneratorInterpreterImpl idGenerationTypeInterpreter = new IdGeneratorInterpreterImpl(); private String schemaCharset; - private final XmlMappingOptions xmlMappingOptions; + private final boolean xmlMappingEnabled; public MetadataBuildingOptionsImpl(StandardServiceRegistry serviceRegistry) { this.serviceRegistry = serviceRegistry; @@ -635,7 +634,11 @@ public MetadataBuildingOptionsImpl(StandardServiceRegistry serviceRegistry) { this.multiTenancyStrategy = MultiTenancyStrategy.determineMultiTenancyStrategy( configService.getSettings() ); - xmlMappingOptions = XmlMappingOptions.get( serviceRegistry ); + this.xmlMappingEnabled = configService.getSetting( + AvailableSettings.XML_MAPPING_ENABLED, + StandardConverters.BOOLEAN, + true + ); this.implicitDiscriminatorsForJoinedInheritanceSupported = configService.getSetting( AvailableSettings.IMPLICIT_DISCRIMINATOR_COLUMNS_FOR_JOINED_SUBCLASS, @@ -923,8 +926,8 @@ public String getSchemaCharset() { } @Override - public XmlMappingOptions getXmlMappingOptions() { - return xmlMappingOptions; + public boolean isXmlMappingEnabled() { + return xmlMappingEnabled; } /** diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/DefaultXmlMappingOptions.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/DefaultXmlMappingOptions.java deleted file mode 100644 index 9812b21fc984..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/DefaultXmlMappingOptions.java +++ /dev/null @@ -1,12 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later - * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html - */ -package org.hibernate.boot.jaxb.internal; - -import org.hibernate.boot.jaxb.spi.XmlMappingOptions; - -public class DefaultXmlMappingOptions implements XmlMappingOptions { -} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/MappingBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/MappingBinder.java index 84cd9ef7f51a..ae63d215a8dd 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/MappingBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/internal/MappingBinder.java @@ -19,7 +19,6 @@ import org.hibernate.boot.jaxb.internal.stax.JpaOrmXmlEventReader; import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappings; import org.hibernate.boot.jaxb.spi.Binding; -import org.hibernate.boot.jaxb.spi.XmlMappingOptions; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.xsd.MappingXsdSupport; import org.hibernate.internal.util.config.ConfigurationException; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/spi/XmlMappingOptions.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/spi/XmlMappingOptions.java deleted file mode 100644 index af5b02d066da..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/spi/XmlMappingOptions.java +++ /dev/null @@ -1,75 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later - * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html - */ -package org.hibernate.boot.jaxb.spi; - -import org.hibernate.boot.jaxb.internal.DefaultXmlMappingOptions; -import org.hibernate.boot.registry.selector.spi.StrategySelector; -import org.hibernate.cfg.AvailableSettings; -import org.hibernate.engine.config.spi.ConfigurationService; -import org.hibernate.engine.config.spi.StandardConverters; -import org.hibernate.service.ServiceRegistry; - -/** - * The options of XML mapping. - *

- * We're using an interface instead of simply configuration properties, - * so that we can override the options easily in integrations (Quarkus) - * and tests (to run the tests multiple times with different options). - */ -public interface XmlMappingOptions { - - String DEFAULT_NAME = "default"; - - static XmlMappingOptions get(ServiceRegistry serviceRegistry) { - final ConfigurationService configService = serviceRegistry.getService( ConfigurationService.class ); - - // The config service may be null if we're using a BootstrapServiceRegistry, - // since configuration properties are unknown at that point. - // That can happen with MetadataSources in particular, - // because for some reason we allow MetadataSources to be built before the StandardServiceRegistry - // (and Quarkus relies on that). - // That's why we prefer to rely on strategies (see below): - // they can be customized without relying on configuration properties - // through the service loader. - boolean xmlMappingEnabled = configService == null || configService.getSetting( - AvailableSettings.XML_MAPPING_ENABLED, - StandardConverters.BOOLEAN, - true - ); - - XmlMappingOptions result; - if ( !xmlMappingEnabled ) { - result = new XmlMappingOptions() { - @Override - public boolean isEnabled() { - return false; - } - }; - } - else { - StrategySelector strategySelector = serviceRegistry.getService( StrategySelector.class ); - result = strategySelector.resolveDefaultableStrategy( - XmlMappingOptions.class, - XmlMappingOptions.DEFAULT_NAME, - new DefaultXmlMappingOptions() - ); - } - - return result; - } - - /** - * Allows to skip processing of XML Mapping. - * This is for people using exclusively annotations to define their model, and might - * be able to improve efficiency of booting Hibernate ORM. - * By default, the XML mapping is taken into account. - */ - default boolean isEnabled() { - return true; - } - -} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/process/spi/MetadataBuildingProcess.java b/hibernate-core/src/main/java/org/hibernate/boot/model/process/spi/MetadataBuildingProcess.java index bef1390faf89..da6596db91a0 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/process/spi/MetadataBuildingProcess.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/process/spi/MetadataBuildingProcess.java @@ -15,7 +15,6 @@ import org.hibernate.boot.internal.InFlightMetadataCollectorImpl; import org.hibernate.boot.internal.MetadataBuildingContextRootImpl; import org.hibernate.boot.jaxb.internal.MappingBinder; -import org.hibernate.boot.jaxb.spi.XmlMappingOptions; import org.hibernate.boot.model.TypeContributions; import org.hibernate.boot.model.TypeContributor; import org.hibernate.boot.model.process.internal.ManagedResourcesImpl; @@ -33,8 +32,11 @@ import org.hibernate.boot.spi.MetadataBuildingOptions; import org.hibernate.boot.spi.MetadataContributor; import org.hibernate.boot.spi.MetadataImplementor; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.MetadataSourceType; import org.hibernate.dialect.Dialect; +import org.hibernate.engine.config.spi.ConfigurationService; +import org.hibernate.engine.config.spi.StandardConverters; import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.type.BasicType; import org.hibernate.type.BasicTypeRegistry; @@ -96,11 +98,16 @@ public static ManagedResources prepare( final MetadataSources sources, final BootstrapContext bootstrapContext) { final ManagedResourcesImpl managedResources = ManagedResourcesImpl.baseline( sources, bootstrapContext ); - XmlMappingOptions xmlMappingOptions = XmlMappingOptions.get( bootstrapContext.getServiceRegistry() ); + final ConfigurationService configService = bootstrapContext.getServiceRegistry().getService( ConfigurationService.class ); + final boolean xmlMappingEnabled = configService.getSetting( + AvailableSettings.XML_MAPPING_ENABLED, + StandardConverters.BOOLEAN, + true + ); ScanningCoordinator.INSTANCE.coordinateScan( managedResources, bootstrapContext, - xmlMappingOptions.isEnabled() ? sources.getXmlMappingBinderAccess() : null + xmlMappingEnabled ? sources.getXmlMappingBinderAccess() : null ); return managedResources; } @@ -150,7 +157,7 @@ public static MetadataImplementor complete( final MetadataSourceProcessor processor = new MetadataSourceProcessor() { private final MetadataSourceProcessor hbmProcessor = - options.getXmlMappingOptions().isEnabled() + options.isXmlMappingEnabled() ? new HbmMetadataSourceProcessorImpl( managedResources, rootMetadataBuildingContext ) : new NoOpMetadataSourceProcessorImpl(); @@ -287,9 +294,8 @@ public void finishUp() { metadataCollector.processSecondPasses( rootMetadataBuildingContext ); - XmlMappingOptions xmlMappingOptions = options.getXmlMappingOptions(); - if ( xmlMappingOptions.isEnabled() ) { - Iterable producers = classLoaderService.loadJavaServices( AdditionalJaxbMappingProducer.class ); + if ( options.isXmlMappingEnabled() ) { + final Iterable producers = classLoaderService.loadJavaServices( AdditionalJaxbMappingProducer.class ); if ( producers != null ) { final EntityHierarchyBuilder hierarchyBuilder = new EntityHierarchyBuilder(); // final MappingBinder mappingBinder = new MappingBinder( true ); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/annotations/AnnotationMetadataSourceProcessorImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/annotations/AnnotationMetadataSourceProcessorImpl.java index 68d8d225a6ce..2b278a0632c4 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/annotations/AnnotationMetadataSourceProcessorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/annotations/AnnotationMetadataSourceProcessorImpl.java @@ -24,7 +24,6 @@ import org.hibernate.boot.internal.MetadataBuildingContextRootImpl; import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappings; import org.hibernate.boot.jaxb.spi.Binding; -import org.hibernate.boot.jaxb.spi.XmlMappingOptions; import org.hibernate.boot.model.convert.spi.ConverterDescriptor; import org.hibernate.boot.model.process.spi.ManagedResources; import org.hibernate.boot.model.source.spi.MetadataSourceProcessor; @@ -77,8 +76,7 @@ public AnnotationMetadataSourceProcessorImpl( this.classLoaderService = rootMetadataBuildingContext.getBuildingOptions().getServiceRegistry().getService( ClassLoaderService.class ); MetadataBuildingOptions metadataBuildingOptions = rootMetadataBuildingContext.getBuildingOptions(); - XmlMappingOptions xmlMappingOptions = metadataBuildingOptions.getXmlMappingOptions(); - if ( xmlMappingOptions.isEnabled() ) { + if ( metadataBuildingOptions.isXmlMappingEnabled() ) { // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // Ewww. This is temporary until we migrate to Jandex + StAX for annotation binding final JPAXMLOverriddenMetadataProvider jpaMetadataProvider = (JPAXMLOverriddenMetadataProvider) ( (MetadataProviderInjector) reflectionManager ) diff --git a/hibernate-core/src/main/java/org/hibernate/boot/registry/selector/internal/StrategySelectorBuilder.java b/hibernate-core/src/main/java/org/hibernate/boot/registry/selector/internal/StrategySelectorBuilder.java index a09c90cc5f2e..0d0f48c3c8e3 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/registry/selector/internal/StrategySelectorBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/registry/selector/internal/StrategySelectorBuilder.java @@ -9,8 +9,6 @@ import java.util.ArrayList; import java.util.List; -import org.hibernate.boot.jaxb.internal.DefaultXmlMappingOptions; -import org.hibernate.boot.jaxb.spi.XmlMappingOptions; import org.hibernate.boot.model.naming.ImplicitNamingStrategy; import org.hibernate.boot.model.naming.ImplicitNamingStrategyComponentPathImpl; import org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl; @@ -102,8 +100,6 @@ public StrategySelector buildSelector(ClassLoaderService classLoaderService) { addMultiTableBulkIdStrategies( strategySelector ); addImplicitNamingStrategies( strategySelector ); addCacheKeysFactories( strategySelector ); - strategySelector.registerStrategyImplementor( XmlMappingOptions.class, XmlMappingOptions.DEFAULT_NAME, - DefaultXmlMappingOptions.class ); // apply auto-discovered registrations for ( StrategyRegistrationProvider provider : classLoaderService.loadJavaServices( StrategyRegistrationProvider.class ) ) { diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingMetadataBuildingOptions.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingMetadataBuildingOptions.java index b2abe158798c..3b8be18e370e 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingMetadataBuildingOptions.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingMetadataBuildingOptions.java @@ -18,7 +18,6 @@ import org.hibernate.boot.archive.scan.spi.ScanEnvironment; import org.hibernate.boot.archive.scan.spi.ScanOptions; import org.hibernate.boot.archive.spi.ArchiveDescriptorFactory; -import org.hibernate.boot.jaxb.spi.XmlMappingOptions; import org.hibernate.boot.model.IdGeneratorStrategyInterpreter; import org.hibernate.boot.model.naming.ImplicitNamingStrategy; import org.hibernate.boot.model.naming.PhysicalNamingStrategy; @@ -204,8 +203,8 @@ public String getSchemaCharset() { } @Override - public XmlMappingOptions getXmlMappingOptions() { - return delegate.getXmlMappingOptions(); + public boolean isXmlMappingEnabled() { + return delegate.isXmlMappingEnabled(); } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/MetadataBuildingOptions.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/MetadataBuildingOptions.java index 0fc02ca34293..65a964e92433 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/spi/MetadataBuildingOptions.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/MetadataBuildingOptions.java @@ -17,7 +17,6 @@ import org.hibernate.boot.archive.scan.spi.ScanEnvironment; import org.hibernate.boot.archive.scan.spi.ScanOptions; import org.hibernate.boot.archive.spi.ArchiveDescriptorFactory; -import org.hibernate.boot.jaxb.spi.XmlMappingOptions; import org.hibernate.boot.model.IdGeneratorStrategyInterpreter; import org.hibernate.boot.model.naming.ImplicitNamingStrategy; import org.hibernate.boot.model.naming.PhysicalNamingStrategy; @@ -252,8 +251,8 @@ default String getSchemaCharset() { return null; } - default XmlMappingOptions getXmlMappingOptions() { - return XmlMappingOptions.get( getServiceRegistry() ); + default boolean isXmlMappingEnabled() { + return true; } /** diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/XmlMappingBinderAccess.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/XmlMappingBinderAccess.java index 80c825b42811..5bd5e5617334 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/spi/XmlMappingBinderAccess.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/XmlMappingBinderAccess.java @@ -20,11 +20,7 @@ import org.hibernate.boot.jaxb.internal.MappingBinder; import org.hibernate.boot.jaxb.internal.UrlXmlSource; import org.hibernate.boot.jaxb.spi.Binding; -import org.hibernate.boot.jaxb.spi.XmlMappingOptions; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; -import org.hibernate.cfg.AvailableSettings; -import org.hibernate.engine.config.spi.ConfigurationService; -import org.hibernate.engine.config.spi.StandardConverters; import org.hibernate.service.ServiceRegistry; import org.jboss.logging.Logger; diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenMetadataProvider.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenMetadataProvider.java index 99bf8efd5484..f65c1f275202 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenMetadataProvider.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenMetadataProvider.java @@ -26,7 +26,6 @@ import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappings; import org.hibernate.boot.jaxb.mapping.spi.JaxbSequenceGenerator; import org.hibernate.boot.jaxb.mapping.spi.JaxbTableGenerator; -import org.hibernate.boot.jaxb.spi.XmlMappingOptions; import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; import org.hibernate.boot.spi.BootstrapContext; import org.hibernate.boot.spi.ClassLoaderAccess; @@ -48,7 +47,7 @@ public final class JPAXMLOverriddenMetadataProvider implements MetadataProvider * We allow fully disabling XML sources so to improve the efficiency of * the boot process for those not using it. */ - private final XmlMappingOptions xmlMappingOptions; + private final boolean xmlMappingEnabled; private Map defaults; private Map cache; @@ -56,7 +55,7 @@ public final class JPAXMLOverriddenMetadataProvider implements MetadataProvider public JPAXMLOverriddenMetadataProvider(BootstrapContext bootstrapContext) { this.classLoaderAccess = bootstrapContext.getClassLoaderAccess(); this.xmlContext = new XMLContext( classLoaderAccess ); - this.xmlMappingOptions = bootstrapContext.getMetadataBuildingOptions().getXmlMappingOptions(); + this.xmlMappingEnabled = bootstrapContext.getMetadataBuildingOptions().isXmlMappingEnabled(); } //all of the above can be safely rebuilt from XMLContext: only XMLContext this object is serialized @@ -89,7 +88,7 @@ public void reset() { @Override public Map getDefaults() { - if ( !xmlMappingOptions.isEnabled() ) { + if ( !xmlMappingEnabled ) { return Collections.emptyMap(); } else { diff --git a/hibernate-core/src/test/java/org/hibernate/internal/util/xml/XMLMappingHelper.java b/hibernate-core/src/test/java/org/hibernate/internal/util/xml/XMLMappingHelper.java index 2e1d5601b16f..ad1c7f0eab7a 100644 --- a/hibernate-core/src/test/java/org/hibernate/internal/util/xml/XMLMappingHelper.java +++ b/hibernate-core/src/test/java/org/hibernate/internal/util/xml/XMLMappingHelper.java @@ -14,10 +14,6 @@ import org.hibernate.boot.jaxb.internal.MappingBinder; import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityMappings; import org.hibernate.boot.jaxb.spi.Binding; -import org.hibernate.boot.jaxb.spi.XmlMappingOptions; -import org.hibernate.boot.registry.BootstrapServiceRegistry; -import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder; -import org.hibernate.service.spi.ServiceRegistryImplementor; import org.hibernate.testing.boot.ClassLoaderServiceTestingImpl; import org.junit.Assert; diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/boot/internal/AdditionalJaxbMappingProducerImpl.java b/hibernate-envers/src/main/java/org/hibernate/envers/boot/internal/AdditionalJaxbMappingProducerImpl.java index 8a18b931ed98..4b902184213e 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/boot/internal/AdditionalJaxbMappingProducerImpl.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/boot/internal/AdditionalJaxbMappingProducerImpl.java @@ -24,21 +24,18 @@ import org.hibernate.boot.jaxb.hbm.spi.JaxbHbmHibernateMapping; import org.hibernate.boot.jaxb.internal.MappingBinder; import org.hibernate.boot.jaxb.spi.Binding; -import org.hibernate.boot.jaxb.spi.XmlMappingOptions; import org.hibernate.boot.model.source.internal.hbm.MappingDocument; import org.hibernate.boot.spi.AdditionalJaxbMappingProducer; import org.hibernate.boot.spi.MetadataBuildingContext; import org.hibernate.boot.spi.MetadataBuildingOptions; import org.hibernate.boot.spi.MetadataImplementor; import org.hibernate.envers.configuration.internal.MappingCollector; -import org.hibernate.internal.util.config.ConfigurationHelper; import org.hibernate.service.ServiceRegistry; import org.jboss.jandex.IndexView; import org.jboss.logging.Logger; import org.dom4j.Document; -import org.dom4j.DocumentException; import org.dom4j.io.OutputFormat; import org.dom4j.io.XMLWriter; @@ -65,7 +62,7 @@ public Collection produceAdditionalMappings( return Collections.emptyList(); } - if ( !metadataBuildingOptions.getXmlMappingOptions().isEnabled() ) { + if ( !metadataBuildingOptions.isXmlMappingEnabled() ) { throw new HibernateException( "Hibernate Envers currently requires XML mapping to be enabled." + " Please don't disable setting `" + XML_MAPPING_ENABLED + "`; alternatively disable Hibernate Envers." ); From 87a3e0a5d825e9bfeb36b9db32ac73719564be82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Fri, 16 Apr 2021 15:29:55 +0200 Subject: [PATCH 113/644] HHH-14563 Remove a few obsolete references to DOM4J entity-mode This mode was removed literally a decade ago. --- .../src/main/java/org/hibernate/annotations/Tuplizer.java | 2 +- .../org/hibernate/boot/model/source/spi/AttributeSource.java | 3 ++- .../java/org/hibernate/internal/log/DeprecationLogger.java | 3 ++- .../src/main/java/org/hibernate/tuple/Tuplizer.java | 4 ---- .../src/main/java/org/hibernate/type/CollectionType.java | 1 - 5 files changed, 5 insertions(+), 8 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/Tuplizer.java b/hibernate-core/src/main/java/org/hibernate/annotations/Tuplizer.java index 9774ac7ea13e..0b753e93a5a6 100644 --- a/hibernate-core/src/main/java/org/hibernate/annotations/Tuplizer.java +++ b/hibernate-core/src/main/java/org/hibernate/annotations/Tuplizer.java @@ -31,7 +31,7 @@ Class impl(); /** - * either pojo, dynamic-map or dom4j. + * either pojo or dynamic-map. * @deprecated should use #entityModeType instead */ @Deprecated diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/source/spi/AttributeSource.java b/hibernate-core/src/main/java/org/hibernate/boot/model/source/spi/AttributeSource.java index 9996267a5b02..8f0e247ea74d 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/source/spi/AttributeSource.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/source/spi/AttributeSource.java @@ -35,7 +35,8 @@ public interface AttributeSource extends ToolingHintContextContainer { public boolean isSingular(); /** - * Ugh. This is the deprecated DOM4J entity-mode feature + * This is only useful to log warnings when these deprecated attributes are populated. + * It was only useful for DOM4J entity-mode, which was removed a long time ago. * * @return The xml node name */ diff --git a/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java b/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java index 455b09d2447b..2866a1a3097b 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java @@ -53,7 +53,8 @@ public interface DeprecationLogger extends BasicLogger { public void logDeprecationOfMultipleEntityModeSupport(); /** - * Log message indicating the use of DOM4J EntityMode. + * Log message indicating the use of features that were only useful for DOM4J EntityMode, + * which was removed a long time ago. */ @LogMessage( level = WARN ) @Message( diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/Tuplizer.java b/hibernate-core/src/main/java/org/hibernate/tuple/Tuplizer.java index 65faa25f627c..9c0120b185e4 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/Tuplizer.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/Tuplizer.java @@ -27,10 +27,6 @@ *

  • extract and inject values through getters/setter, or by direct field access, etc * *

    - * That same piece of data might also be represented as a DOM structure, using - * the tuplizer associated with the DOM4J entity-mode, which would generate instances - * of {@link org.dom4j.Element} as the data structure and know how to access the - * values as either nested {@link org.dom4j.Element}s or as {@link org.dom4j.Attribute}s. * * @see org.hibernate.tuple.entity.EntityTuplizer * @see org.hibernate.tuple.component.ComponentTuplizer diff --git a/hibernate-core/src/main/java/org/hibernate/type/CollectionType.java b/hibernate-core/src/main/java/org/hibernate/type/CollectionType.java index 1f4ac97ab30a..005ab12ad0d4 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/CollectionType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/CollectionType.java @@ -576,7 +576,6 @@ public Object replaceElements( Object owner, Map copyCache, SharedSessionContractImplementor session) { - // TODO: does not work for EntityMode.DOM4J yet! java.util.Collection result = ( java.util.Collection ) target; result.clear(); From 4264bc55ac96d41d7baed796edc2e48fdad05162 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Fri, 16 Apr 2021 15:38:16 +0200 Subject: [PATCH 114/644] HHH-14563 Remove the DOM4J dependency from hibernate-core --- hibernate-core/hibernate-core.gradle | 5 ----- hibernate-entitymanager/hibernate-entitymanager.gradle | 1 - hibernate-envers/hibernate-envers.gradle | 3 +++ .../boot/internal/AdditionalJaxbMappingProducerImpl.java | 2 +- hibernate-osgi/hibernate-osgi.gradle | 4 ++++ 5 files changed, 8 insertions(+), 7 deletions(-) diff --git a/hibernate-core/hibernate-core.gradle b/hibernate-core/hibernate-core.gradle index 8008fa1c4fd2..c47a0466ea77 100644 --- a/hibernate-core/hibernate-core.gradle +++ b/hibernate-core/hibernate-core.gradle @@ -61,11 +61,6 @@ dependencies { compile( libraries.classmate ) compile( libraries.activation ) - // We need dom4j for a number of things temporarily: - // 1) (unsupported) EntityMode.DOM4J support - // 2) Envers - // 3) hibernate-commons-annotations - compile( libraries.dom4j ) compile( libraries.commons_annotations ) antlr( libraries.antlr ) diff --git a/hibernate-entitymanager/hibernate-entitymanager.gradle b/hibernate-entitymanager/hibernate-entitymanager.gradle index 6d9e7a9fa762..b2c7a1541148 100644 --- a/hibernate-entitymanager/hibernate-entitymanager.gradle +++ b/hibernate-entitymanager/hibernate-entitymanager.gradle @@ -4,7 +4,6 @@ apply from: rootProject.file( 'gradle/published-java-module.gradle' ) dependencies { compile( project( ':hibernate-core' ) ) - compile( libraries.dom4j ) compile( libraries.commons_annotations ) compile( libraries.jpa ) compile( libraries.byteBuddy ) diff --git a/hibernate-envers/hibernate-envers.gradle b/hibernate-envers/hibernate-envers.gradle index 9d97794a3feb..a16dcbc33509 100644 --- a/hibernate-envers/hibernate-envers.gradle +++ b/hibernate-envers/hibernate-envers.gradle @@ -16,6 +16,9 @@ dependencies { exclude group: "org.javassist", module: "javassist" } + // TODO HHH-13703: get rid of this dependency + compile( libraries.dom4j ) + provided( libraries.ant ) annotationProcessor( project( ':hibernate-jpamodelgen' ) ) diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/boot/internal/AdditionalJaxbMappingProducerImpl.java b/hibernate-envers/src/main/java/org/hibernate/envers/boot/internal/AdditionalJaxbMappingProducerImpl.java index 4b902184213e..d18f9d38b108 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/boot/internal/AdditionalJaxbMappingProducerImpl.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/boot/internal/AdditionalJaxbMappingProducerImpl.java @@ -76,7 +76,7 @@ public Collection produceAdditionalMappings( final MappingCollector mappingCollector = new MappingCollector() { @Override - public void addDocument(Document document) throws DocumentException { + public void addDocument(Document document) { dump( document ); // while the commented-out code here is more efficient (well, understanding that diff --git a/hibernate-osgi/hibernate-osgi.gradle b/hibernate-osgi/hibernate-osgi.gradle index ffd5b1384d90..d9567e2d6139 100644 --- a/hibernate-osgi/hibernate-osgi.gradle +++ b/hibernate-osgi/hibernate-osgi.gradle @@ -95,6 +95,7 @@ dependencies { karafDistro "org.apache.karaf:apache-karaf:${project.karafVersion}@tar.gz" hibernateEnvers( project( ':hibernate-envers' ) ) + hibernateEnvers( libraries.dom4j ) } jar { @@ -160,6 +161,9 @@ karaf { name = 'hibernate-envers' description = 'Feature for easily adding Envers support to hibernate-orm' includeProject = false + feature ('wrap') { + prerequisite = true + } configurations 'hibernateEnvers' feature('hibernate-orm') { version = project.version From d7e85a3c3cbbdf82db21741466acb52a12c36b84 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Fri, 16 Apr 2021 15:38:55 +0200 Subject: [PATCH 115/644] HHH-14563 Clarify that hibernate-spatial only needs dom4j for tests For org.hibernate.spatial.testing.TestDataReader, to be precise. --- hibernate-spatial/hibernate-spatial.gradle | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/hibernate-spatial/hibernate-spatial.gradle b/hibernate-spatial/hibernate-spatial.gradle index ab0edc0fc4e8..a33a535903f7 100644 --- a/hibernate-spatial/hibernate-spatial.gradle +++ b/hibernate-spatial/hibernate-spatial.gradle @@ -19,10 +19,6 @@ dependencies { compile( libraries.postgresql ) - compile(libraries.dom4j) { - transitive = false - } - testCompile(libraries.junit) testCompile(project(':hibernate-testing')) testCompile( project( path: ':hibernate-core', configuration: 'tests' ) ) @@ -34,6 +30,9 @@ dependencies { // for test runtime transitive = true } + testCompile(libraries.dom4j) { + transitive = false + } testRuntime( libraries.expression_language ) From b0abe9f37e100d6ab225a86fd37dbc530e0c4589 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Fri, 16 Apr 2021 15:43:03 +0200 Subject: [PATCH 116/644] HHH-14563 Remove the DOM4J dependency from hibernate-enhance-maven-plugin As far as I can tell, this was only necessary as a transitive dependency of Hibernate ORM. --- .../hibernate-enhance-maven-plugin.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/tooling/hibernate-enhance-maven-plugin/hibernate-enhance-maven-plugin.gradle b/tooling/hibernate-enhance-maven-plugin/hibernate-enhance-maven-plugin.gradle index 4325e1eb7a17..7b5f2e0180ad 100644 --- a/tooling/hibernate-enhance-maven-plugin/hibernate-enhance-maven-plugin.gradle +++ b/tooling/hibernate-enhance-maven-plugin/hibernate-enhance-maven-plugin.gradle @@ -55,7 +55,6 @@ task processPluginXml(type: Copy) { filter(ReplaceTokens, tokens: ['version' : project.version, 'generated-dependencies' :\ generateMavenDependency(libraries.jpa)\ + generateMavenDependency(libraries.antlr)\ - + generateMavenDependency(libraries.dom4j)\ + generateMavenDependency(libraries.jta)\ + generateMavenDependency(libraries.commons_annotations)\ + generateMavenDependency(libraries.javassist)\ From 3bac846de210fe01e66cded2768d4ff214f2e657 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Mon, 19 Apr 2021 16:40:14 +0200 Subject: [PATCH 117/644] HHH-14567 Test enabling filters after query creation but before query execution --- .../test/filter/DynamicFilterTest.java | 25 +++++++++++++++++++ .../hibernate/test/filter/Salesperson.java | 7 ++++++ 2 files changed, 32 insertions(+) diff --git a/hibernate-core/src/test/java/org/hibernate/test/filter/DynamicFilterTest.java b/hibernate-core/src/test/java/org/hibernate/test/filter/DynamicFilterTest.java index ed578f3c12e2..159f21d5c797 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/filter/DynamicFilterTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/filter/DynamicFilterTest.java @@ -31,6 +31,7 @@ import org.hibernate.dialect.SybaseASE15Dialect; import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.persister.collection.CollectionPersister; +import org.hibernate.query.Query; import org.hibernate.transform.DistinctRootEntityResultTransformer; import org.hibernate.testing.SkipForDialect; @@ -38,6 +39,7 @@ import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; import org.junit.Test; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertSame; @@ -213,6 +215,29 @@ public void testHqlFilters() { testData.release(); } + @Test + @TestForIssue(jiraKey = "HHH-14567") + public void testHqlFiltersAppliedAfterQueryCreation() { + TestData testData = new TestData(); + testData.prepare(); + + try { + inTransaction( session -> { + Query query = session.createQuery( + "select s from Salesperson s", + Salesperson.class + ); + assertThat( query.list() ).hasSize( 2 ); + + session.enableFilter( "region" ).setParameter( "region", "APAC" ); + assertThat( query.list() ).hasSize( 1 ); + } ); + } + finally { + testData.release(); + } + } + @Test public void testFiltersWithCustomerReadAndWrite() { //~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ diff --git a/hibernate-core/src/test/java/org/hibernate/test/filter/Salesperson.java b/hibernate-core/src/test/java/org/hibernate/test/filter/Salesperson.java index 38d9342d7100..059ee4e8848d 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/filter/Salesperson.java +++ b/hibernate-core/src/test/java/org/hibernate/test/filter/Salesperson.java @@ -24,6 +24,13 @@ public class Salesperson { private Department department; private Set orders = new HashSet(); + @Override + public String toString() { + return "Salesperson#" + id + "{" + + ", name='" + name + '\'' + + '}'; + } + public Long getId() { return id; } From 8389b1a7a2aaba0f57c677b77bd4dbb07a22c75c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Mon, 19 Apr 2021 16:50:35 +0200 Subject: [PATCH 118/644] HHH-14567 Do not reuse query plans after session filters changed --- .../src/main/java/org/hibernate/query/internal/QueryImpl.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/QueryImpl.java b/hibernate-core/src/main/java/org/hibernate/query/internal/QueryImpl.java index 35d8ad55dd1e..327471f1a219 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/internal/QueryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/internal/QueryImpl.java @@ -92,7 +92,9 @@ protected void appendQueryPlanToQueryParameters( if ( queryPlan != null ) { queryParameters.setQueryPlan( queryPlan ); } - else if ( hql.equals( getQueryString() ) ) { + else if ( hql.equals( getQueryString() ) + && getQueryPlan().getEnabledFilterNames() + .equals( getProducer().getLoadQueryInfluencers().getEnabledFilters().values() ) ) { queryParameters.setQueryPlan( getQueryPlan() ); } } From 179327cd403942ab1256d93467f2de56788750e1 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Tue, 25 Aug 2020 13:54:07 +0200 Subject: [PATCH 119/644] [HHH-14031] on H2 1.4.200 and above use localtime/localtimestamp As suggested by @famod we need to use localtime instead or current_time because of changes in H2. In particular the JDBC driver now refuses to convert TIME/TIMESTAMP WITH TIME ZONE to plain TIME/TIMESTAMP. --- .../src/main/java/org/hibernate/dialect/H2Dialect.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java index c3f9b7ab26a7..319b64943d9d 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java @@ -210,8 +210,12 @@ public H2Dialect() { registerFunction( "curtime", new NoArgSQLFunction( "curtime", StandardBasicTypes.TIME ) ); registerFunction( "curtimestamp", new NoArgSQLFunction( "curtimestamp", StandardBasicTypes.TIME ) ); registerFunction( "current_date", new NoArgSQLFunction( "current_date", StandardBasicTypes.DATE ) ); - registerFunction( "current_time", new NoArgSQLFunction( "current_time", StandardBasicTypes.TIME ) ); - registerFunction( "current_timestamp", new NoArgSQLFunction( "current_timestamp", StandardBasicTypes.TIMESTAMP ) ); + // H2 made a nasty breaking change that changed the type of + // - current_timestamp to timestamp with time zone + // - current_time to time with time zone + // and also refuses to implicitly convert the type + registerFunction( "current_time", new NoArgSQLFunction( buildId >= 200 ? "localtime" : "current_time", StandardBasicTypes.TIME ) ); + registerFunction( "current_timestamp", new NoArgSQLFunction( buildId >= 200 ? "localtimestamp" : "current_timestamp", StandardBasicTypes.TIMESTAMP ) ); registerFunction( "datediff", new StandardSQLFunction( "datediff", StandardBasicTypes.INTEGER ) ); registerFunction( "dayname", new StandardSQLFunction( "dayname", StandardBasicTypes.STRING ) ); registerFunction( "dayofmonth", new StandardSQLFunction( "dayofmonth", StandardBasicTypes.INTEGER ) ); From 96980606fdcb3d196c43e91220672bf28289c0d1 Mon Sep 17 00:00:00 2001 From: Burkhard Graves Date: Fri, 12 Mar 2021 18:39:03 +0100 Subject: [PATCH 120/644] HHH-14475 - select indices from ternary relation is broken since 5.4.13 (at least in mariadb) --- .../org/hibernate/test/hql/IndicesTest.java | 111 ++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/hql/IndicesTest.java diff --git a/hibernate-core/src/test/java/org/hibernate/test/hql/IndicesTest.java b/hibernate-core/src/test/java/org/hibernate/test/hql/IndicesTest.java new file mode 100644 index 000000000000..ddeae05664ee --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/hql/IndicesTest.java @@ -0,0 +1,111 @@ +package org.hibernate.test.hql; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.MapKeyJoinColumn; +import javax.persistence.OneToMany; +import javax.persistence.Table; +import static org.hamcrest.core.Is.is; +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; +import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; +import org.junit.Before; +import org.junit.Test; +import static org.junit.Assert.assertThat; + +/** + * @author Burkhard Graves + */ +@TestForIssue(jiraKey = "HHH-14475") +public class IndicesTest extends BaseNonConfigCoreFunctionalTestCase { + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] {Project.class, Role.class, Person.class}; + } + + @Before + public void setUp() { + doInHibernate( this::sessionFactory, session -> { + + Project project = new Project(1); + Role role = new Role(1); + + session.save( project ); + session.save( role ); + + Person person = new Person(1, project, role); + + session.save( person ); + }); + } + + @Test + public void testSelectIndices() { + doInHibernate( this::sessionFactory, session -> { + + List result = session.createQuery( + "select indices(p.roles) from Person p" + ).list(); + + assertThat( result.size(), is( 1 ) ); + }); + } + + @Entity(name = "Person") + public static class Person { + + @Id + private Integer id; + + @OneToMany + @JoinTable(name = "person_to_role", + joinColumns = @JoinColumn(name = "person_id"), + inverseJoinColumns = @JoinColumn(name = "role_id") + ) + @MapKeyJoinColumn(name = "project_id") + private Map roles; + + public Person() { + } + + public Person(Integer id, Project project, Role role) { + this.id = id; + roles = new HashMap<>(); + roles.put(project, role); + } + } + + @Entity(name = "Project") + public static class Project { + + @Id + private Integer id; + + public Project() { + } + + public Project(Integer id) { + this.id = id; + } + } + + @Entity(name = "Role") + public static class Role { + + @Id + private Integer id; + + public Role() { + } + + public Role(Integer id) { + this.id = id; + } + } +} From 12f1c7917e5a9ad188b802217afb679787c0f007 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Mon, 15 Mar 2021 16:23:09 +0100 Subject: [PATCH 121/644] HHH-14475 Don't render subquery for collection functions --- .../hql/internal/ast/tree/MethodNode.java | 39 +++++++------------ 1 file changed, 14 insertions(+), 25 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/MethodNode.java b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/MethodNode.java index c0fbf9b56be1..75d55c1f1630 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/MethodNode.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/MethodNode.java @@ -141,20 +141,25 @@ protected void resolveCollectionProperty(AST expr) throws SemanticException { String propertyName = CollectionProperties.getNormalizedPropertyName( methodName ); if ( expr instanceof FromReferenceNode ) { FromReferenceNode collectionNode = (FromReferenceNode) expr; + fromElement = collectionNode.getFromElement(); // If this is 'elements' then create a new FROM element. if ( CollectionPropertyNames.COLLECTION_ELEMENTS.equals( propertyName ) ) { - handleElements( collectionNode, propertyName ); + QueryableCollection queryableCollection = fromElement.getQueryableCollection(); + + String path = collectionNode.getPath() + "[]." + propertyName; + LOG.debugf( "Creating elements for %s", path ); + + if ( !fromElement.isCollectionOfValuesOrComponents() ) { + getWalker().addQuerySpaces( queryableCollection.getElementPersister().getQuerySpaces() ); + } + + setDataType( queryableCollection.getElementType() ); + selectColumns = fromElement.toColumns( fromElement.getTableAlias(), propertyName, inSelect ); } else { // Not elements(x) - fromElement = collectionNode.getFromElement(); - - final CollectionPropertyReference cpr = fromElement.getCollectionPropertyReference( propertyName ); - setDataType( cpr.getType() ); - selectColumns = cpr.toColumns( fromElement.getTableAlias() ); - -// setDataType( fromElement.getPropertyType( propertyName, propertyName ) ); -// selectColumns = fromElement.toColumns( fromElement.getTableAlias(), propertyName, inSelect ); + setDataType( fromElement.getPropertyType( propertyName, propertyName ) ); + selectColumns = fromElement.toColumns( fromElement.getTableAlias(), propertyName, inSelect ); } if ( collectionNode instanceof DotNode ) { @@ -190,22 +195,6 @@ private void prepareAnyImplicitJoins(DotNode dotNode) throws SemanticException { } } - private void handleElements(FromReferenceNode collectionNode, String propertyName) { - FromElement collectionFromElement = collectionNode.getFromElement(); - QueryableCollection queryableCollection = collectionFromElement.getQueryableCollection(); - - String path = collectionNode.getPath() + "[]." + propertyName; - LOG.debugf( "Creating elements for %s", path ); - - fromElement = collectionFromElement; - if ( !collectionFromElement.isCollectionOfValuesOrComponents() ) { - getWalker().addQuerySpaces( queryableCollection.getElementPersister().getQuerySpaces() ); - } - - setDataType( queryableCollection.getElementType() ); - selectColumns = collectionFromElement.toColumns( fromElement.getTableAlias(), propertyName, inSelect ); - } - @Override public void setScalarColumnText(int i) throws SemanticException { if ( selectColumns == null ) { // Dialect function From 6bc8421972c67492ef93947e54621b7d1755ecf5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Thu, 22 Apr 2021 15:50:48 +0200 Subject: [PATCH 122/644] HHH-14571 Test that the identifier is always reported as initialized by Hibernate.isPropertyInitialized when using enhanced proxies --- .../lazy/IdInUninitializedProxyTest.java | 80 +++++++++++++++++++ 1 file changed, 80 insertions(+) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/IdInUninitializedProxyTest.java diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/IdInUninitializedProxyTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/IdInUninitializedProxyTest.java new file mode 100644 index 000000000000..6b139e61741a --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/IdInUninitializedProxyTest.java @@ -0,0 +1,80 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.test.bytecode.enhancement.lazy; + +import javax.persistence.Basic; +import javax.persistence.Entity; +import javax.persistence.Id; + +import org.hibernate.Hibernate; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.cfg.AvailableSettings; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; +import org.hibernate.testing.bytecode.enhancement.EnhancementOptions; +import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +@TestForIssue(jiraKey = "HHH-14571") +@RunWith(BytecodeEnhancerRunner.class) +@EnhancementOptions(lazyLoading = true, extendedEnhancement = true) +public class IdInUninitializedProxyTest extends BaseNonConfigCoreFunctionalTestCase { + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { AnEntity.class }; + } + + @Override + protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { + super.configureStandardServiceRegistryBuilder( ssrb ); + ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, true ); + } + + @Test + public void testIdIsAlwaysConsideredInitialized() { + inTransaction( session -> { + final AnEntity e = session.byId( AnEntity.class ).getReference( 1 ); + assertFalse( Hibernate.isInitialized( e ) ); + // This is the gist of the problem + assertTrue( Hibernate.isPropertyInitialized( e, "id" ) ); + assertFalse( Hibernate.isPropertyInitialized( e, "name" ) ); + + assertEquals( "George", e.name ); + assertTrue( Hibernate.isInitialized( e ) ); + assertTrue( Hibernate.isPropertyInitialized( e, "id" ) ); + assertTrue( Hibernate.isPropertyInitialized( e, "name" ) ); + } ); + } + + @Before + public void prepareTestData() { + inTransaction( session -> { + AnEntity anEntity = new AnEntity(); + anEntity.id = 1; + anEntity.name = "George"; + session.persist( anEntity ); + } ); + } + + @Entity(name = "AnEntity") + public static class AnEntity { + @Id + private int id; + + @Basic + private String name; + } + +} From 1023ee02b9649209a80549b5a851596572d4f467 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Thu, 22 Apr 2021 15:56:45 +0200 Subject: [PATCH 123/644] HHH-14571 Always report identifiers as initialized when using enhanced proxies --- .../src/main/java/org/hibernate/Hibernate.java | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/Hibernate.java b/hibernate-core/src/main/java/org/hibernate/Hibernate.java index ff12828e3e5f..9f4fea0184d5 100644 --- a/hibernate-core/src/main/java/org/hibernate/Hibernate.java +++ b/hibernate-core/src/main/java/org/hibernate/Hibernate.java @@ -8,8 +8,8 @@ import java.util.Iterator; +import org.hibernate.bytecode.enhance.spi.interceptor.BytecodeLazyAttributeInterceptor; import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor; -import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor; import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.engine.HibernateIterator; import org.hibernate.engine.jdbc.LobCreator; @@ -202,11 +202,8 @@ public static boolean isPropertyInitialized(Object proxy, String propertyName) { if ( entity instanceof PersistentAttributeInterceptable ) { PersistentAttributeInterceptor interceptor = ( (PersistentAttributeInterceptable) entity ).$$_hibernate_getInterceptor(); - if ( interceptor instanceof EnhancementAsProxyLazinessInterceptor ) { - return false; - } - if ( interceptor instanceof LazyAttributeLoadingInterceptor ) { - return ( (LazyAttributeLoadingInterceptor) interceptor ).isAttributeLoaded( propertyName ); + if ( interceptor instanceof BytecodeLazyAttributeInterceptor ) { + return ( (BytecodeLazyAttributeInterceptor) interceptor ).isAttributeLoaded( propertyName ); } } From 0a4cd8e800beb9623cec660fbdb63fab2f26324e Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Wed, 28 Apr 2021 10:24:20 +0100 Subject: [PATCH 124/644] HHH-14575 Adapt BasicProxyFactoryImpl to be more native-image friendly --- .../internal/bytebuddy/BasicProxyFactoryImpl.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/bytebuddy/BasicProxyFactoryImpl.java b/hibernate-core/src/main/java/org/hibernate/bytecode/internal/bytebuddy/BasicProxyFactoryImpl.java index eae143eb673a..a2004408e57c 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/bytebuddy/BasicProxyFactoryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/internal/bytebuddy/BasicProxyFactoryImpl.java @@ -6,6 +6,7 @@ */ package org.hibernate.bytecode.internal.bytebuddy; +import java.lang.reflect.Constructor; import java.util.Arrays; import java.util.HashSet; import java.util.Set; @@ -28,6 +29,7 @@ public class BasicProxyFactoryImpl implements BasicProxyFactory { private final Class proxyClass; private final ProxyConfiguration.Interceptor interceptor; + private final Constructor proxyClassConstructor; @SuppressWarnings({ "unchecked", "rawtypes" }) public BasicProxyFactoryImpl(Class superClass, Class[] interfaces, ByteBuddyState byteBuddyState) { @@ -49,12 +51,18 @@ public BasicProxyFactoryImpl(Class superClass, Class[] interfaces, ByteBuddyStat .intercept( byteBuddyState.getProxyDefinitionHelpers().getInterceptorFieldAccessor() ) ); this.interceptor = new PassThroughInterceptor( proxyClass.getName() ); + try { + proxyClassConstructor = proxyClass.getConstructor(); + } + catch (NoSuchMethodException e) { + throw new AssertionFailure( "Could not access default constructor from newly generated basic proxy" ); + } } @Override public Object getProxy() { try { - final ProxyConfiguration proxy = (ProxyConfiguration) proxyClass.newInstance(); + final ProxyConfiguration proxy = (ProxyConfiguration) proxyClassConstructor.newInstance(); proxy.$$_hibernate_set_interceptor( this.interceptor ); return proxy; } From 127ee26f826d3ab02dbe19cba0d3df59eb3d520f Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Thu, 29 Apr 2021 11:05:55 +0200 Subject: [PATCH 125/644] HHH-14513 Move publishing release artifacts from BinTray --- build.gradle | 25 ++++++++++- gradle/published-java-module.gradle | 4 +- gradle/publishing-repos.gradle | 43 ------------------- .../hibernate-infinispan.gradle | 2 +- 4 files changed, 27 insertions(+), 47 deletions(-) diff --git a/build.gradle b/build.gradle index d7063ed4c161..eea9b1ba8008 100644 --- a/build.gradle +++ b/build.gradle @@ -15,18 +15,38 @@ buildscript { classpath 'org.hibernate.build.gradle:version-injection-plugin:1.0.0' classpath 'gradle.plugin.com.github.lburgazzoli:gradle-karaf-plugin:0.5.1' classpath 'org.asciidoctor:asciidoctor-gradle-plugin:1.5.7' - classpath 'com.jfrog.bintray.gradle:gradle-bintray-plugin:1.8.4' classpath 'de.thetaphi:forbiddenapis:3.0.1' } } plugins { id 'me.champeau.buildscan-recipes' version '0.2.3' + id 'io.github.gradle-nexus.publish-plugin' version '1.0.0' + id 'nu.studer.credentials' version '2.1' apply false id 'org.hibernate.build.xjc' version '2.0.1' apply false id 'org.hibernate.build.maven-repo-auth' version '3.0.3' apply false id 'biz.aQute.bnd' version '5.1.1' apply false } +ext { + sonatypeOssrhUser = project.findProperty( 'SONATYPE_OSSRH_USER' ) + sonatypeOssrhPassword = project.findProperty( 'SONATYPE_OSSRH_PASSWORD' ) +} + +// nexusPublishing uses group and version +// as defaults +group = project.group +version = project.version + +nexusPublishing { + repositories { + sonatype { + username = project.sonatypeOssrhUser + password = project.sonatypeOssrhPassword + } + } +} + allprojects { repositories { mavenCentral() @@ -40,6 +60,9 @@ allprojects { } apply plugin: 'idea' + group = project.group + version = project.version + // minimize changes, at least for now (gradle uses 'build' by default).. buildDir = "target" diff --git a/gradle/published-java-module.gradle b/gradle/published-java-module.gradle index ac2a152860f9..cfee264828ef 100644 --- a/gradle/published-java-module.gradle +++ b/gradle/published-java-module.gradle @@ -165,6 +165,6 @@ publishing { task ciBuild( dependsOn: [test, publish] ) -task release( dependsOn: [test, bintrayUpload] ) -bintrayUpload.mustRunAfter test +task release( dependsOn: [test, publishToSonatype] ) +publishToSonatype.mustRunAfter test diff --git a/gradle/publishing-repos.gradle b/gradle/publishing-repos.gradle index e78d6329039a..0d33df825dbb 100644 --- a/gradle/publishing-repos.gradle +++ b/gradle/publishing-repos.gradle @@ -10,16 +10,6 @@ apply from: rootProject.file( 'gradle/base-information.gradle' ) apply plugin: 'maven-publish' apply plugin: 'org.hibernate.build.maven-repo-auth' -apply plugin: 'com.jfrog.bintray' - - -ext { - bintrayUser = project.findProperty( 'PERSONAL_BINTRAY_USER' ) - bintrayKey = project.findProperty( 'PERSONAL_BINTRAY_API_KEY' ) - sonatypeOssrhUser = project.findProperty( 'SONATYPE_OSSRH_USER' ) - sonatypeOssrhPassword = project.findProperty( 'SONATYPE_OSSRH_PASSWORD' ) -} - publishing { publications { @@ -34,39 +24,6 @@ publishing { } } -bintray { - user = project.bintrayUser - key = project.bintrayKey - - publications = ['publishedArtifacts'] - - pkg { - userOrg = 'hibernate' - repo = 'artifacts' - name = 'hibernate-orm' - - publish = true - - version { - name = project.version - released = new Date() - vcsTag = project.version - gpg { - sign = true - } - attributes = [ - 'jpa': project.jpaVersion, - 'family': project.ormVersion.family - ] - mavenCentralSync { - sync = true - user = project.sonatypeOssrhUser - password = project.sonatypeOssrhPassword - } - } - } -} - model { tasks.generatePomFileForPublishedArtifactsPublication { destination = file( "${buildDir}/generated-pom.xml" ) diff --git a/hibernate-infinispan/hibernate-infinispan.gradle b/hibernate-infinispan/hibernate-infinispan.gradle index 399c41ec25fb..893f58bf0ffc 100644 --- a/hibernate-infinispan/hibernate-infinispan.gradle +++ b/hibernate-infinispan/hibernate-infinispan.gradle @@ -32,4 +32,4 @@ publishing { } } -task release( dependsOn: bintrayUpload ) \ No newline at end of file +task release( dependsOn: publishToSonatype ) \ No newline at end of file From c096b463eef9e2447e9b68fcfd7354d6debe2bf2 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Thu, 29 Apr 2021 13:43:31 +0200 Subject: [PATCH 126/644] Emulate null ordering for CockroachDB --- .../dialect/CockroachDB192Dialect.java | 20 +++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/CockroachDB192Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/CockroachDB192Dialect.java index 1b89423dedc4..18ad31c3388d 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/CockroachDB192Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/CockroachDB192Dialect.java @@ -14,6 +14,7 @@ import org.hibernate.JDBCException; import org.hibernate.LockMode; import org.hibernate.LockOptions; +import org.hibernate.NullPrecedence; import org.hibernate.PessimisticLockException; import org.hibernate.boot.model.TypeContributions; import org.hibernate.cfg.Environment; @@ -234,6 +235,25 @@ public boolean bindLimitParametersInReverseOrder() { return true; } + @Override + public String renderOrderByElement(String expression, String collation, String order, NullPrecedence nulls) { + final StringBuilder orderByElement = new StringBuilder(); + if ( nulls != NullPrecedence.NONE ) { + // Workaround for NULLS FIRST / LAST support. + orderByElement.append( "case when " ).append( expression ).append( " is null then " ); + if ( nulls == NullPrecedence.FIRST ) { + orderByElement.append( "0 else 1" ); + } + else { + orderByElement.append( "1 else 0" ); + } + orderByElement.append( " end, " ); + } + // Nulls precedence has already been handled so passing NONE value. + orderByElement.append( super.renderOrderByElement( expression, collation, order, NullPrecedence.NONE ) ); + return orderByElement.toString(); + } + @Override public String getForUpdateString(String aliases) { return getForUpdateString() + " of " + aliases; From 9bcf10fb3fc20b7ce566754c488b444b12617d78 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Thu, 29 Apr 2021 15:50:25 +0200 Subject: [PATCH 127/644] HHH-14513 Move publishing release artifacts from BinTray --- build.gradle | 88 +++++++++++++++++-- gradle/base-information.gradle | 83 ----------------- gradle/java-module.gradle | 1 - gradle/publishing-repos.gradle | 3 - .../hibernate-infinispan.gradle | 1 - release/release.gradle | 2 - 6 files changed, 79 insertions(+), 99 deletions(-) delete mode 100644 gradle/base-information.gradle diff --git a/build.gradle b/build.gradle index eea9b1ba8008..27dfbb9da078 100644 --- a/build.gradle +++ b/build.gradle @@ -22,7 +22,7 @@ buildscript { plugins { id 'me.champeau.buildscan-recipes' version '0.2.3' id 'io.github.gradle-nexus.publish-plugin' version '1.0.0' - id 'nu.studer.credentials' version '2.1' apply false + id 'nu.studer.credentials' version '2.1' id 'org.hibernate.build.xjc' version '2.0.1' apply false id 'org.hibernate.build.maven-repo-auth' version '3.0.3' apply false id 'biz.aQute.bnd' version '5.1.1' apply false @@ -33,10 +33,22 @@ ext { sonatypeOssrhPassword = project.findProperty( 'SONATYPE_OSSRH_PASSWORD' ) } -// nexusPublishing uses group and version -// as defaults -group = project.group -version = project.version +File versionFile = file( "${rootProject.projectDir}/gradle/version.properties" ) + +ext { + ormVersionFile = versionFile + ormVersion = HibernateVersion.fromFile( versionFile, project ) + // Override during releases + if ( project.hasProperty( 'releaseVersion' ) ) { + ormVersion = new HibernateVersion( project.releaseVersion, project ) + } + jpaVersion = new JpaVersion('2.2') +} + +// The Gradle Nexus Publish Plugin must be applied to the root project and requires group and version + +group = 'org.hibernate' +version = project.ormVersion.fullName nexusPublishing { repositories { @@ -60,13 +72,11 @@ allprojects { } apply plugin: 'idea' - group = project.group - version = project.version - // minimize changes, at least for now (gradle uses 'build' by default).. buildDir = "target" - apply from: rootProject.file( 'gradle/base-information.gradle' ) + group = 'org.hibernate' + version = project.ormVersion.fullName } @@ -125,6 +135,66 @@ buildScanRecipes { recipe 'git-commit', baseUrl: 'https://github.com/hibernate/hibernate-orm/tree' } +class JpaVersion { + /** The *normal* name (1.0, 2.0, ..) */ + final String name; + + final String osgiName + + JpaVersion(String version){ + this.name = version + this.osgiName = version + ".0" + } + + @Override + String toString() { + return name + } +} + +class HibernateVersion { + final String fullName + final String majorVersion + final String family + + final String osgiVersion + + final boolean isSnapshot + + HibernateVersion(String fullName, Project project) { + this.fullName = fullName + + final String[] hibernateVersionComponents = fullName.split( '\\.' ) + this.majorVersion = hibernateVersionComponents[0] + this.family = hibernateVersionComponents[0] + '.' + hibernateVersionComponents[1] + + this.isSnapshot = fullName.endsWith( '-SNAPSHOT' ) + + this.osgiVersion = isSnapshot ? family + '.' + hibernateVersionComponents[2] + '.SNAPSHOT' : fullName + } + + static HibernateVersion fromFile(File file, Project project){ + def fullName = readVersionProperties(file) + return new HibernateVersion(fullName, project) + } + + private static String readVersionProperties(File file) { + if ( !file.exists() ) { + throw new GradleException( "Version file $file.canonicalPath does not exists" ) + } + Properties versionProperties = new Properties() + file.withInputStream { + stream -> versionProperties.load( stream ) + } + return versionProperties.hibernateVersion + } + + @Override + String toString() { + return this.fullName + } +} + //idea { // project { // jdkName = gradle.ext.baselineJavaVersion diff --git a/gradle/base-information.gradle b/gradle/base-information.gradle deleted file mode 100644 index d3d00808e179..000000000000 --- a/gradle/base-information.gradle +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later - * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html - */ - -apply plugin: 'base' - -File versionFile = file( "${rootProject.projectDir}/gradle/version.properties" ) - -ext { - ormVersionFile = versionFile - ormVersion = HibernateVersion.fromFile( versionFile, project ) - // Override during releases - if ( project.hasProperty( 'releaseVersion' ) ) { - ormVersion = new HibernateVersion( project.releaseVersion, project ) - } - jpaVersion = new JpaVersion('2.2') -} - -group = 'org.hibernate' -version = project.ormVersion.fullName - -class JpaVersion { - /** The *normal* name (1.0, 2.0, ..) */ - final String name; - - final String osgiName - - JpaVersion(String version){ - this.name = version - this.osgiName = version + ".0" - } - - @Override - String toString() { - return name - } -} - -class HibernateVersion { - final String fullName - final String majorVersion - final String family - - final String osgiVersion - - final boolean isSnapshot - - HibernateVersion(String fullName, Project project) { - this.fullName = fullName - - final String[] hibernateVersionComponents = fullName.split( '\\.' ) - this.majorVersion = hibernateVersionComponents[0] - this.family = hibernateVersionComponents[0] + '.' + hibernateVersionComponents[1] - - this.isSnapshot = fullName.endsWith( '-SNAPSHOT' ) - - this.osgiVersion = isSnapshot ? family + '.' + hibernateVersionComponents[2] + '.SNAPSHOT' : fullName - } - - static HibernateVersion fromFile(File file, Project project){ - def fullName = readVersionProperties(file) - return new HibernateVersion(fullName, project) - } - - private static String readVersionProperties(File file) { - if ( !file.exists() ) { - throw new GradleException( "Version file $file.canonicalPath does not exists" ) - } - Properties versionProperties = new Properties() - file.withInputStream { - stream -> versionProperties.load( stream ) - } - return versionProperties.hibernateVersion - } - - @Override - String toString() { - return this.fullName - } -} diff --git a/gradle/java-module.gradle b/gradle/java-module.gradle index fee82c2567cb..e3d60db62364 100644 --- a/gradle/java-module.gradle +++ b/gradle/java-module.gradle @@ -21,7 +21,6 @@ import org.apache.tools.ant.filters.ReplaceTokens * Support for modules that contain Java code */ -apply from: rootProject.file( 'gradle/base-information.gradle' ) apply from: rootProject.file( 'gradle/libraries.gradle' ) apply from: rootProject.file( 'gradle/databases.gradle' ) diff --git a/gradle/publishing-repos.gradle b/gradle/publishing-repos.gradle index 0d33df825dbb..77b3bfdc39ad 100644 --- a/gradle/publishing-repos.gradle +++ b/gradle/publishing-repos.gradle @@ -5,9 +5,6 @@ * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html */ -apply from: rootProject.file( 'gradle/base-information.gradle' ) - - apply plugin: 'maven-publish' apply plugin: 'org.hibernate.build.maven-repo-auth' diff --git a/hibernate-infinispan/hibernate-infinispan.gradle b/hibernate-infinispan/hibernate-infinispan.gradle index 893f58bf0ffc..d7784beed062 100644 --- a/hibernate-infinispan/hibernate-infinispan.gradle +++ b/hibernate-infinispan/hibernate-infinispan.gradle @@ -7,7 +7,6 @@ description = '(deprecated - use org.infinispan:infinispan-hibernate-cache-v53 instead)' -apply from: rootProject.file( 'gradle/base-information.gradle' ) apply from: rootProject.file( 'gradle/publishing-repos.gradle' ) apply from: rootProject.file( 'gradle/publishing-pom.gradle' ) apply plugin: 'maven-publish' diff --git a/release/release.gradle b/release/release.gradle index 8b6304abc387..ee6ae330fb56 100644 --- a/release/release.gradle +++ b/release/release.gradle @@ -8,8 +8,6 @@ import groovy.json.JsonSlurper * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -apply from: rootProject.file( 'gradle/base-information.gradle' ) - apply plugin: 'idea' apply plugin: 'distribution' From cd97e59d2174578eeb8be7f16b630f5945d51a13 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Thu, 29 Apr 2021 20:17:45 +0200 Subject: [PATCH 128/644] HHH-14513 Move publishing release artifacts from BinTray --- build.gradle | 2 +- gradle/publishing-repos.gradle | 4 +++- hibernate-infinispan/hibernate-infinispan.gradle | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/build.gradle b/build.gradle index 27dfbb9da078..3690ac49ff35 100644 --- a/build.gradle +++ b/build.gradle @@ -21,7 +21,7 @@ buildscript { plugins { id 'me.champeau.buildscan-recipes' version '0.2.3' - id 'io.github.gradle-nexus.publish-plugin' version '1.0.0' + id 'io.github.gradle-nexus.publish-plugin' version '1.1.0' id 'nu.studer.credentials' version '2.1' id 'org.hibernate.build.xjc' version '2.0.1' apply false id 'org.hibernate.build.maven-repo-auth' version '3.0.3' apply false diff --git a/gradle/publishing-repos.gradle b/gradle/publishing-repos.gradle index 77b3bfdc39ad..b417e1eba3ca 100644 --- a/gradle/publishing-repos.gradle +++ b/gradle/publishing-repos.gradle @@ -6,7 +6,9 @@ */ apply plugin: 'maven-publish' -apply plugin: 'org.hibernate.build.maven-repo-auth' +if ( rootProject.ormVersion.isSnapshot ) { + apply plugin: 'org.hibernate.build.maven-repo-auth' +} publishing { publications { diff --git a/hibernate-infinispan/hibernate-infinispan.gradle b/hibernate-infinispan/hibernate-infinispan.gradle index d7784beed062..24393e7568ed 100644 --- a/hibernate-infinispan/hibernate-infinispan.gradle +++ b/hibernate-infinispan/hibernate-infinispan.gradle @@ -10,7 +10,7 @@ description = '(deprecated - use org.infinispan:infinispan-hibernate-cache-v53 i apply from: rootProject.file( 'gradle/publishing-repos.gradle' ) apply from: rootProject.file( 'gradle/publishing-pom.gradle' ) apply plugin: 'maven-publish' -apply plugin: 'org.hibernate.build.maven-repo-auth' +//apply plugin: 'org.hibernate.build.maven-repo-auth' ext { relocatedGroupId = 'org.infinispan' From 14b35bb3b6b6e66b9aa52da4439afebee2b7475a Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Tue, 20 Apr 2021 13:11:26 +0200 Subject: [PATCH 129/644] HHH-14273 Support for jakarta.persistence prefixed String properties --- .../org/hibernate/annotations/QueryHints.java | 5 + .../boot/internal/ClassLoaderAccessImpl.java | 1 + .../boot/internal/MetadataBuilderImpl.java | 21 +- .../SessionFactoryOptionsBuilder.java | 10 +- .../org/hibernate/cfg/AvailableSettings.java | 345 ++++++++++++++++++ .../cfg/annotations/QueryHintDefinition.java | 9 +- .../engine/spi/EffectiveEntityGraph.java | 10 +- .../org/hibernate/graph/GraphSemantic.java | 16 +- .../internal/FastSessionServices.java | 27 +- .../internal/SessionFactoryImpl.java | 9 +- .../org/hibernate/internal/SessionImpl.java | 46 ++- .../java/org/hibernate/jpa/QueryHints.java | 25 ++ .../EntityManagerFactoryBuilderImpl.java | 148 +++++++- .../boot/internal/PersistenceXmlParser.java | 13 + .../org/hibernate/jpa/boot/spi/Bootstrap.java | 1 - .../jpa/boot/spi/ProviderChecker.java | 6 +- .../jpa/internal/util/LockOptionsHelper.java | 20 +- .../query/internal/AbstractProducedQuery.java | 25 +- .../spi/ManagedBeanRegistryInitiator.java | 5 +- .../tool/schema/internal/Helper.java | 18 +- .../HibernateSchemaManagementTool.java | 25 +- .../schema/internal/SchemaCreatorImpl.java | 6 +- .../spi/SchemaManagementToolCoordinator.java | 62 +++- 23 files changed, 792 insertions(+), 61 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/QueryHints.java b/hibernate-core/src/main/java/org/hibernate/annotations/QueryHints.java index 7bfd3ec0129a..dfb436ed6857 100644 --- a/hibernate-core/src/main/java/org/hibernate/annotations/QueryHints.java +++ b/hibernate-core/src/main/java/org/hibernate/annotations/QueryHints.java @@ -96,6 +96,11 @@ private QueryHints() { */ public static final String TIMEOUT_JPA = "javax.persistence.query.timeout"; + /** + * Apply a JPA query timeout, which is defined in milliseconds. + */ + public static final String TIMEOUT_JAKARTA_JPA = "jakarta.persistence.query.timeout"; + /** * Available to apply lock mode to a native SQL query since JPA requires that * {@link javax.persistence.Query#setLockMode} throw an IllegalStateException if called for a native query. diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/ClassLoaderAccessImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/ClassLoaderAccessImpl.java index 6797a0298c03..0234da61935b 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/ClassLoaderAccessImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/ClassLoaderAccessImpl.java @@ -85,6 +85,7 @@ private boolean isSafeClass(String name) { // classes in any of these packages are safe to load through the "live" ClassLoader return name.startsWith( "java." ) || name.startsWith( "javax." ) + || name.startsWith( "jakarta." ) || name.startsWith( "org.hibernate." ); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/MetadataBuilderImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/MetadataBuilderImpl.java index 5c96508086f8..61f98f680e9a 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/MetadataBuilderImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/MetadataBuilderImpl.java @@ -659,7 +659,7 @@ public MetadataBuildingOptionsImpl(StandardServiceRegistry serviceRegistry) { ); this.sharedCacheMode = configService.getSetting( - "javax.persistence.sharedCache.mode", + AvailableSettings.JPA_SHARED_CACHE_MODE, new ConfigurationService.Converter() { @Override public SharedCacheMode convert(Object value) { @@ -674,7 +674,24 @@ public SharedCacheMode convert(Object value) { return SharedCacheMode.valueOf( value.toString() ); } }, - SharedCacheMode.UNSPECIFIED + configService.getSetting( + AvailableSettings.JAKARTA_JPA_SHARED_CACHE_MODE, + new ConfigurationService.Converter() { + @Override + public SharedCacheMode convert(Object value) { + if ( value == null ) { + return null; + } + + if ( SharedCacheMode.class.isInstance( value ) ) { + return (SharedCacheMode) value; + } + + return SharedCacheMode.valueOf( value.toString() ); + } + }, + SharedCacheMode.UNSPECIFIED + ) ); this.defaultCacheAccessType = configService.getSetting( diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java index 364ccd6fc3f0..7ddff3bf790e 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java @@ -272,8 +272,14 @@ public SessionFactoryOptionsBuilder(StandardServiceRegistry serviceRegistry, Boo ( (ConfigurationServiceImpl) cfgService ).injectServices( (ServiceRegistryImplementor) serviceRegistry ); } - this.beanManagerReference = configurationSettings.get( "javax.persistence.bean.manager" ); - this.validatorFactoryReference = configurationSettings.get( "javax.persistence.validation.factory" ); + this.beanManagerReference = configurationSettings.getOrDefault( + AvailableSettings.CDI_BEAN_MANAGER, + configurationSettings.get( AvailableSettings.JAKARTA_CDI_BEAN_MANAGER ) + ); + this.validatorFactoryReference = configurationSettings.getOrDefault( + AvailableSettings.JPA_VALIDATION_FACTORY, + configurationSettings.get( AvailableSettings.JAKARTA_JPA_VALIDATION_FACTORY ) + ); this.sessionFactoryName = (String) configurationSettings.get( SESSION_FACTORY_NAME ); this.sessionFactoryNameAlsoJndiName = cfgService.getSetting( diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java index 65ef3f9afa89..88338b5d0f42 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java @@ -208,6 +208,185 @@ public interface AvailableSettings extends org.hibernate.jpa.AvailableSettings { String CDI_BEAN_MANAGER = "javax.persistence.bean.manager"; + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // Jakarta JPA defined settings + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + /** + * The name of the {@link javax.persistence.spi.PersistenceProvider} implementor + *

    + * See JPA 2 sections 9.4.3 and 8.2.1.4 + */ + String JAKARTA_JPA_PERSISTENCE_PROVIDER = "jakarta.persistence.provider"; + + /** + * The type of transactions supported by the entity managers. + *

    + * See JPA 2 sections 9.4.3 and 8.2.1.2 + */ + String JAKARTA_JPA_TRANSACTION_TYPE = "jakarta.persistence.transactionType"; + + /** + * The JNDI name of a JTA {@link javax.sql.DataSource}. + *

    + * See JPA 2 sections 9.4.3 and 8.2.1.5 + */ + String JAKARTA_JPA_JTA_DATASOURCE = "jakarta.persistence.jtaDataSource"; + + /** + * The JNDI name of a non-JTA {@link javax.sql.DataSource}. + *

    + * See JPA 2 sections 9.4.3 and 8.2.1.5 + */ + String JAKARTA_JPA_NON_JTA_DATASOURCE = "jakarta.persistence.nonJtaDataSource"; + + /** + * The name of a JDBC driver to use to connect to the database. + *

    + * Used in conjunction with {@link #JPA_JDBC_URL}, {@link #JPA_JDBC_USER} and {@link #JPA_JDBC_PASSWORD} + * to define how to make connections to the database in lieu of + * a datasource (either {@link #JPA_JTA_DATASOURCE} or {@link #JPA_NON_JTA_DATASOURCE}). + *

    + * See section 8.2.1.9 + */ + String JAKARTA_JPA_JDBC_DRIVER = "jakarta.persistence.jdbc.driver"; + + /** + * The JDBC connection url to use to connect to the database. + *

    + * Used in conjunction with {@link #JPA_JDBC_DRIVER}, {@link #JPA_JDBC_USER} and {@link #JPA_JDBC_PASSWORD} + * to define how to make connections to the database in lieu of + * a datasource (either {@link #JPA_JTA_DATASOURCE} or {@link #JPA_NON_JTA_DATASOURCE}). + *

    + * See section 8.2.1.9 + */ + String JAKARTA_JPA_JDBC_URL = "jakarta.persistence.jdbc.url"; + + /** + * The JDBC connection user name. + *

    + * Used in conjunction with {@link #JPA_JDBC_DRIVER}, {@link #JPA_JDBC_URL} and {@link #JPA_JDBC_PASSWORD} + * to define how to make connections to the database in lieu of + * a datasource (either {@link #JPA_JTA_DATASOURCE} or {@link #JPA_NON_JTA_DATASOURCE}). + *

    + * See section 8.2.1.9 + */ + String JAKARTA_JPA_JDBC_USER = "jakarta.persistence.jdbc.user"; + + /** + * The JDBC connection password. + *

    + * Used in conjunction with {@link #JPA_JDBC_DRIVER}, {@link #JPA_JDBC_URL} and {@link #JPA_JDBC_USER} + * to define how to make connections to the database in lieu of + * a datasource (either {@link #JPA_JTA_DATASOURCE} or {@link #JPA_NON_JTA_DATASOURCE}). + *

    + * See JPA 2 section 8.2.1.9 + */ + String JAKARTA_JPA_JDBC_PASSWORD = "jakarta.persistence.jdbc.password"; + + /** + * Used to indicate whether second-level (what JPA terms shared cache) caching is + * enabled as per the rules defined in JPA 2 section 3.1.7. + *

    + * See JPA 2 sections 9.4.3 and 8.2.1.7 + * @see javax.persistence.SharedCacheMode + */ + String JAKARTA_JPA_SHARED_CACHE_MODE = "jakarta.persistence.sharedCache.mode"; + + /** + * NOTE : Not a valid EMF property... + *

    + * Used to indicate if the provider should attempt to retrieve requested data + * in the shared cache. + * + * @see javax.persistence.CacheRetrieveMode + */ + String JAKARTA_JPA_SHARED_CACHE_RETRIEVE_MODE ="jakarta.persistence.cache.retrieveMode"; + + /** + * NOTE : Not a valid EMF property... + *

    + * Used to indicate if the provider should attempt to store data loaded from the database + * in the shared cache. + * + * @see javax.persistence.CacheStoreMode + */ + String JAKARTA_JPA_SHARED_CACHE_STORE_MODE ="jakarta.persistence.cache.storeMode"; + + /** + * Used to indicate what form of automatic validation is in effect as per rules defined + * in JPA 2 section 3.6.1.1 + *

    + * See JPA 2 sections 9.4.3 and 8.2.1.8 + * @see javax.persistence.ValidationMode + */ + String JAKARTA_JPA_VALIDATION_MODE = "jakarta.persistence.validation.mode"; + + /** + * Used to pass along any discovered validator factory. + */ + String JAKARTA_JPA_VALIDATION_FACTORY = "jakarta.persistence.validation.factory"; + + /** + * Used to coordinate with bean validators + *

    + * See JPA 2 section 8.2.1.9 + */ + String JAKARTA_JPA_PERSIST_VALIDATION_GROUP = "jakarta.persistence.validation.group.pre-persist"; + + /** + * Used to coordinate with bean validators + *

    + * See JPA 2 section 8.2.1.9 + */ + String JAKARTA_JPA_UPDATE_VALIDATION_GROUP = "jakarta.persistence.validation.group.pre-update"; + + /** + * Used to coordinate with bean validators + *

    + * See JPA 2 section 8.2.1.9 + */ + String JAKARTA_JPA_REMOVE_VALIDATION_GROUP = "jakarta.persistence.validation.group.pre-remove"; + + /** + * Used to request (hint) a pessimistic lock scope. + *

    + * See JPA 2 sections 8.2.1.9 and 3.4.4.3 + */ + String JAKARTA_JPA_LOCK_SCOPE = "jakarta.persistence.lock.scope"; + + /** + * Used to request (hint) a pessimistic lock timeout (in milliseconds). + *

    + * See JPA 2 sections 8.2.1.9 and 3.4.4.3 + */ + String JAKARTA_JPA_LOCK_TIMEOUT = "jakarta.persistence.lock.timeout"; + + /** + * Used to pass along the CDI BeanManager, if any, to be used. + * + * According to JPA, strictly, the BeanManager should be passed in + * at boot-time and be ready for use at that time. However not all + * environments can do this (WildFly e.g.). To accommodate such + * environments, Hibernate provides 2 options: + * + * * a proprietary CDI extension SPI (that we have proposed to + * the CDI spec group as a standard option) that can be used + * to provide delayed BeanManager access. To use this solution, + * the reference passed as the BeanManager during bootstrap + * should be typed as {@link ExtendedBeanManager} + * * delayed access to the BeanManager reference. Here, Hibernate + * will not access the reference passed as the BeanManager during + * bootstrap until it is first needed. Note however that this has + * the effect of delaying any deployment problems until after + * bootstrapping. + * + * This setting is used to configure Hibernate ORM's access to + * the BeanManager (either directly or via {@link ExtendedBeanManager}). + */ + String JAKARTA_CDI_BEAN_MANAGER = "jakarta.persistence.bean.manager"; + + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // BootstrapServiceRegistry level settings // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -1486,6 +1665,172 @@ public interface AvailableSettings extends org.hibernate.jpa.AvailableSettings { */ String HBM2DDL_CREATE_SCHEMAS = "javax.persistence.create-database-schemas"; + /** + * Setting to perform SchemaManagementTool actions against the database directly via JDBC + * automatically as part of the SessionFactory lifecycle. Valid options are defined by the + * {@link org.hibernate.tool.schema.Action} enum. + *

    + * Interpreted in combination with {@link #HBM2DDL_AUTO}. If no value is specified, the default + * is "none" ({@link org.hibernate.tool.schema.Action#NONE}). + * + * @see org.hibernate.tool.schema.Action + */ + String JAKARTA_HBM2DDL_DATABASE_ACTION = "jakarta.persistence.schema-generation.database.action"; + + /** + * Setting to perform SchemaManagementTool actions writing the commands into a DDL script file. + * Valid options are defined by the {@link org.hibernate.tool.schema.Action} enum. + *

    + * Interpreted in combination with {@link #HBM2DDL_AUTO}. If no value is specified, the default + * is "none" ({@link org.hibernate.tool.schema.Action#NONE}). + * + * @see org.hibernate.tool.schema.Action + */ + String JAKARTA_HBM2DDL_SCRIPTS_ACTION = "jakarta.persistence.schema-generation.scripts.action"; + + /** + * Allows passing a specific {@link java.sql.Connection} instance to be used by SchemaManagementTool. + *

    + * May also be used to determine the values for {@value #HBM2DDL_DB_NAME}, + * {@value #HBM2DDL_DB_MAJOR_VERSION} and {@value #HBM2DDL_DB_MINOR_VERSION}. + */ + String JAKARTA_HBM2DDL_CONNECTION = "jakarta.persistence.schema-generation-connection"; + + /** + * Specifies the name of the database provider in cases where a Connection to the underlying database is + * not available (aka, mainly in generating scripts). In such cases, a value for this setting + * *must* be specified. + *

    + * The value of this setting is expected to match the value returned by + * {@link java.sql.DatabaseMetaData#getDatabaseProductName()} for the target database. + *

    + * Additionally specifying {@value #HBM2DDL_DB_MAJOR_VERSION} and/or {@value #HBM2DDL_DB_MINOR_VERSION} + * may be required to understand exactly how to generate the required schema commands. + * + * @see #HBM2DDL_DB_MAJOR_VERSION + * @see #HBM2DDL_DB_MINOR_VERSION + */ + @SuppressWarnings("JavaDoc") + String JAKARTA_HBM2DDL_DB_NAME = "jakarta.persistence.database-product-name"; + + /** + * Specifies the major version of the underlying database, as would be returned by + * {@link java.sql.DatabaseMetaData#getDatabaseMajorVersion} for the target database. This value is used to + * help more precisely determine how to perform schema generation tasks for the underlying database in cases + * where {@value #HBM2DDL_DB_NAME} does not provide enough distinction. + + * @see #HBM2DDL_DB_NAME + * @see #HBM2DDL_DB_MINOR_VERSION + */ + String JAKARTA_HBM2DDL_DB_MAJOR_VERSION = "jakarta.persistence.database-major-version"; + + /** + * Specifies the minor version of the underlying database, as would be returned by + * {@link java.sql.DatabaseMetaData#getDatabaseMinorVersion} for the target database. This value is used to + * help more precisely determine how to perform schema generation tasks for the underlying database in cases + * where the combination of {@value #HBM2DDL_DB_NAME} and {@value #HBM2DDL_DB_MAJOR_VERSION} does not provide + * enough distinction. + * + * @see #HBM2DDL_DB_NAME + * @see #HBM2DDL_DB_MAJOR_VERSION + */ + String JAKARTA_HBM2DDL_DB_MINOR_VERSION = "jakarta.persistence.database-minor-version"; + + /** + * Specifies whether schema generation commands for schema creation are to be determined based on object/relational + * mapping metadata, DDL scripts, or a combination of the two. See {@link SourceType} for valid set of values. + * If no value is specified, a default is assumed as follows:

      + *
    • + * if source scripts are specified (per {@value #HBM2DDL_CREATE_SCRIPT_SOURCE}),then "scripts" is assumed + *
    • + *
    • + * otherwise, "metadata" is assumed + *
    • + *
    + * + * @see SourceType + */ + String JAKARTA_HBM2DDL_CREATE_SOURCE = "jakarta.persistence.schema-generation.create-source"; + + /** + * Specifies whether schema generation commands for schema dropping are to be determined based on object/relational + * mapping metadata, DDL scripts, or a combination of the two. See {@link SourceType} for valid set of values. + * If no value is specified, a default is assumed as follows:
      + *
    • + * if source scripts are specified (per {@value #HBM2DDL_DROP_SCRIPT_SOURCE}),then "scripts" is assumed + *
    • + *
    • + * otherwise, "metadata" is assumed + *
    • + *
    + * + * @see SourceType + */ + String JAKARTA_HBM2DDL_DROP_SOURCE = "jakarta.persistence.schema-generation.drop-source"; + + /** + * Specifies the CREATE script file as either a {@link java.io.Reader} configured for reading of the DDL script + * file or a string designating a file {@link java.net.URL} for the DDL script. + *

    + * Hibernate historically also accepted {@link #HBM2DDL_IMPORT_FILES} for a similar purpose. This setting + * should be preferred over {@link #HBM2DDL_IMPORT_FILES} moving forward + * + * @see #HBM2DDL_CREATE_SOURCE + * @see #HBM2DDL_IMPORT_FILES + */ + String JAKARTA_HBM2DDL_CREATE_SCRIPT_SOURCE = "jakarta.persistence.schema-generation.create-script-source"; + + /** + * Specifies the DROP script file as either a {@link java.io.Reader} configured for reading of the DDL script + * file or a string designating a file {@link java.net.URL} for the DDL script. + * + * @see #HBM2DDL_DROP_SOURCE + */ + String JAKARTA_HBM2DDL_DROP_SCRIPT_SOURCE = "jakarta.persistence.schema-generation.drop-script-source"; + + /** + * For cases where the {@value #HBM2DDL_SCRIPTS_ACTION} value indicates that schema creation commands should + * be written to DDL script file, {@value #HBM2DDL_SCRIPTS_CREATE_TARGET} specifies either a + * {@link java.io.Writer} configured for output of the DDL script or a string specifying the file URL for the DDL + * script. + * + * @see #HBM2DDL_SCRIPTS_ACTION + */ + @SuppressWarnings("JavaDoc") + String JAKARTA_HBM2DDL_SCRIPTS_CREATE_TARGET = "jakarta.persistence.schema-generation.scripts.create-target"; + + /** + * For cases where the {@value #HBM2DDL_SCRIPTS_ACTION} value indicates that schema drop commands should + * be written to DDL script file, {@value #HBM2DDL_SCRIPTS_DROP_TARGET} specifies either a + * {@link java.io.Writer} configured for output of the DDL script or a string specifying the file URL for the DDL + * script. + * + * @see #HBM2DDL_SCRIPTS_ACTION + */ + @SuppressWarnings("JavaDoc") + String JAKARTA_HBM2DDL_SCRIPTS_DROP_TARGET = "jakarta.persistence.schema-generation.scripts.drop-target"; + + /** + * JPA variant of {@link #HBM2DDL_IMPORT_FILES} + *

    + * Specifies a {@link java.io.Reader} configured for reading of the SQL load script or a string designating the + * file {@link java.net.URL} for the SQL load script. + *

    + * A "SQL load script" is a script that performs some database initialization (INSERT, etc). + */ + String JAKARTA_HBM2DDL_LOAD_SCRIPT_SOURCE = "jakarta.persistence.sql-load-script-source"; + + /** + * The JPA variant of {@link #HBM2DDL_CREATE_NAMESPACES} + *

    + * Specifies whether the persistence provider is to create the database schema(s) in addition to creating + * database objects (tables, sequences, constraints, etc). The value of this boolean property should be set + * to {@code true} if the persistence provider is to create schemas in the database or to generate DDL that + * contains "CREATE SCHEMA" commands. If this property is not supplied (or is explicitly {@code false}), the + * provider should not attempt to create database schemas. + */ + String JAKARTA_HBM2DDL_CREATE_SCHEMAS = "jakarta.persistence.create-database-schemas"; + /** * @deprecated Use {@link #HBM2DDL_CREATE_SCHEMAS} instead: this variable name had a typo. */ diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/QueryHintDefinition.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/QueryHintDefinition.java index de617814761b..da782f082d84 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/QueryHintDefinition.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/QueryHintDefinition.java @@ -21,6 +21,7 @@ import org.hibernate.LockOptions; import org.hibernate.MappingException; import org.hibernate.annotations.QueryHints; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.internal.util.LockModeConverter; /** @@ -128,6 +129,9 @@ public Integer getInteger(String query, String hintName) { public Integer getTimeout(String queryName) { Integer timeout = getInteger( queryName, QueryHints.TIMEOUT_JPA ); + if ( timeout == null ) { + timeout = getInteger( queryName, QueryHints.TIMEOUT_JAKARTA_JPA ); + } if ( timeout != null ) { // convert milliseconds to seconds @@ -142,7 +146,10 @@ public Integer getTimeout(String queryName) { public LockOptions determineLockOptions(NamedQuery namedQueryAnnotation) { LockModeType lockModeType = namedQueryAnnotation.lockMode(); - Integer lockTimeoutHint = getInteger( namedQueryAnnotation.name(), "javax.persistence.lock.timeout" ); + Integer lockTimeoutHint = getInteger( namedQueryAnnotation.name(), AvailableSettings.JPA_LOCK_TIMEOUT ); + if ( lockTimeoutHint == null ) { + lockTimeoutHint = getInteger( namedQueryAnnotation.name(), AvailableSettings.JAKARTA_JPA_LOCK_TIMEOUT ); + } Boolean followOnLocking = getBoolean( namedQueryAnnotation.name(), QueryHints.FOLLOW_ON_LOCKING ); return determineLockOptions(lockModeType, lockTimeoutHint, followOnLocking); diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/EffectiveEntityGraph.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/EffectiveEntityGraph.java index fa96dc082ae6..bb07a15e3eed 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/EffectiveEntityGraph.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/EffectiveEntityGraph.java @@ -113,8 +113,14 @@ public void applyConfiguredGraph(Map properties) { return; } - final RootGraphImplementor fetchHint = (RootGraphImplementor) properties.get( GraphSemantic.FETCH.getJpaHintName() ); - final RootGraphImplementor loadHint = (RootGraphImplementor) properties.get( GraphSemantic.LOAD.getJpaHintName() ); + RootGraphImplementor fetchHint = (RootGraphImplementor) properties.get( GraphSemantic.FETCH.getJpaHintName() ); + RootGraphImplementor loadHint = (RootGraphImplementor) properties.get( GraphSemantic.LOAD.getJpaHintName() ); + if (fetchHint == null) { + fetchHint = (RootGraphImplementor) properties.get( GraphSemantic.FETCH.getJakartaJpaHintName() ); + } + if (loadHint == null) { + loadHint = (RootGraphImplementor) properties.get( GraphSemantic.LOAD.getJakartaJpaHintName() ); + } if ( fetchHint == null && loadHint == null ) { log.debugf( "Neither LOAD nor FETCH graph were found in properties" ); diff --git a/hibernate-core/src/main/java/org/hibernate/graph/GraphSemantic.java b/hibernate-core/src/main/java/org/hibernate/graph/GraphSemantic.java index 12498834e7f5..ceb081723425 100644 --- a/hibernate-core/src/main/java/org/hibernate/graph/GraphSemantic.java +++ b/hibernate-core/src/main/java/org/hibernate/graph/GraphSemantic.java @@ -19,7 +19,7 @@ public enum GraphSemantic { * subsequent select). Attributes that are not specified are treated as * FetchType.LAZY invariably. */ - FETCH( "javax.persistence.fetchgraph" ), + FETCH( "javax.persistence.fetchgraph", "jakarta.persistence.fetchgraph" ), /** * Indicates a "load graph" EntityGraph. Attributes explicitly specified @@ -28,26 +28,32 @@ public enum GraphSemantic { * FetchType.LAZY or FetchType.EAGER depending on the attribute's definition * in metadata. */ - LOAD( "javax.persistence.loadgraph" ); + LOAD( "javax.persistence.loadgraph", "jakarta.persistence.loadgraph" ); private final String jpaHintName; + private final String jakartaJpaHintName; - GraphSemantic(String jpaHintName) { + GraphSemantic(String jpaHintName, String jakartaJpaHintName) { this.jpaHintName = jpaHintName; + this.jakartaJpaHintName = jakartaJpaHintName; } public String getJpaHintName() { return jpaHintName; } + public String getJakartaJpaHintName() { + return jakartaJpaHintName; + } + public static GraphSemantic fromJpaHintName(String hintName) { assert hintName != null; - if ( FETCH.getJpaHintName().equals( hintName ) ) { + if ( FETCH.getJpaHintName().equals( hintName ) || FETCH.getJakartaJpaHintName().equals( hintName ) ) { return FETCH; } - if ( LOAD.getJpaHintName().equalsIgnoreCase( hintName ) ) { + if ( LOAD.getJpaHintName().equalsIgnoreCase( hintName ) || LOAD.getJakartaJpaHintName().equalsIgnoreCase( hintName ) ) { return LOAD; } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/FastSessionServices.java b/hibernate-core/src/main/java/org/hibernate/internal/FastSessionServices.java index 8f04bcb53e6a..a8fac37fe30d 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/FastSessionServices.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/FastSessionServices.java @@ -71,6 +71,10 @@ import javax.persistence.CacheStoreMode; import javax.persistence.PessimisticLockScope; +import static org.hibernate.cfg.AvailableSettings.JAKARTA_JPA_LOCK_SCOPE; +import static org.hibernate.cfg.AvailableSettings.JAKARTA_JPA_LOCK_TIMEOUT; +import static org.hibernate.cfg.AvailableSettings.JAKARTA_JPA_SHARED_CACHE_RETRIEVE_MODE; +import static org.hibernate.cfg.AvailableSettings.JAKARTA_JPA_SHARED_CACHE_STORE_MODE; import static org.hibernate.cfg.AvailableSettings.JPA_LOCK_SCOPE; import static org.hibernate.cfg.AvailableSettings.JPA_LOCK_TIMEOUT; import static org.hibernate.cfg.AvailableSettings.JPA_SHARED_CACHE_RETRIEVE_MODE; @@ -277,18 +281,27 @@ private static Map initializeDefaultSessionProperties(SessionFac //Static defaults: p.putIfAbsent( AvailableSettings.FLUSH_MODE, FlushMode.AUTO.name() ); p.putIfAbsent( JPA_LOCK_SCOPE, PessimisticLockScope.EXTENDED.name() ); + p.putIfAbsent( JAKARTA_JPA_LOCK_SCOPE, PessimisticLockScope.EXTENDED.name() ); p.putIfAbsent( JPA_LOCK_TIMEOUT, LockOptions.WAIT_FOREVER ); + p.putIfAbsent( JAKARTA_JPA_LOCK_TIMEOUT, LockOptions.WAIT_FOREVER ); p.putIfAbsent( JPA_SHARED_CACHE_RETRIEVE_MODE, CacheModeHelper.DEFAULT_RETRIEVE_MODE ); + p.putIfAbsent( JAKARTA_JPA_SHARED_CACHE_RETRIEVE_MODE, CacheModeHelper.DEFAULT_RETRIEVE_MODE ); p.putIfAbsent( JPA_SHARED_CACHE_STORE_MODE, CacheModeHelper.DEFAULT_STORE_MODE ); + p.putIfAbsent( JAKARTA_JPA_SHARED_CACHE_STORE_MODE, CacheModeHelper.DEFAULT_STORE_MODE ); //Defaults defined by SessionFactory configuration: final String[] ENTITY_MANAGER_SPECIFIC_PROPERTIES = { JPA_LOCK_SCOPE, + JAKARTA_JPA_LOCK_SCOPE, JPA_LOCK_TIMEOUT, + JAKARTA_JPA_LOCK_TIMEOUT, AvailableSettings.FLUSH_MODE, JPA_SHARED_CACHE_RETRIEVE_MODE, + JAKARTA_JPA_SHARED_CACHE_RETRIEVE_MODE, JPA_SHARED_CACHE_STORE_MODE, - QueryHints.SPEC_HINT_TIMEOUT + JAKARTA_JPA_SHARED_CACHE_STORE_MODE, + QueryHints.SPEC_HINT_TIMEOUT, + QueryHints.JAKARTA_SPEC_HINT_TIMEOUT }; final Map properties = sf.getProperties(); for ( String key : ENTITY_MANAGER_SPECIFIC_PROPERTIES ) { @@ -328,11 +341,19 @@ CacheRetrieveMode getCacheRetrieveMode(Map properties) { } private static CacheRetrieveMode determineCacheRetrieveMode(Map settings) { - return ( CacheRetrieveMode ) settings.get( JPA_SHARED_CACHE_RETRIEVE_MODE ); + final CacheRetrieveMode cacheRetrieveMode = (CacheRetrieveMode) settings.get( JPA_SHARED_CACHE_RETRIEVE_MODE ); + if ( cacheRetrieveMode == null ) { + return (CacheRetrieveMode) settings.get( JAKARTA_JPA_SHARED_CACHE_RETRIEVE_MODE ); + } + return cacheRetrieveMode; } private static CacheStoreMode determineCacheStoreMode(Map settings) { - return ( CacheStoreMode ) settings.get( JPA_SHARED_CACHE_STORE_MODE ); + final CacheStoreMode cacheStoreMode = (CacheStoreMode) settings.get( JPA_SHARED_CACHE_STORE_MODE ); + if ( cacheStoreMode == null ) { + return ( CacheStoreMode ) settings.get( JAKARTA_JPA_SHARED_CACHE_STORE_MODE ); + } + return cacheStoreMode; } public ConnectionObserverStatsBridge getDefaultJdbcObserver() { diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java index d2a00b82ed8b..2c8bf16f09fd 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java @@ -234,12 +234,17 @@ public SessionFactoryImpl( this.properties = new HashMap<>(); this.properties.putAll( serviceRegistry.getService( ConfigurationService.class ).getSettings() ); - if ( !properties.containsKey( AvailableSettings.JPA_VALIDATION_FACTORY ) ) { + if ( !properties.containsKey( AvailableSettings.JPA_VALIDATION_FACTORY ) + && !properties.containsKey( AvailableSettings.JAKARTA_JPA_VALIDATION_FACTORY ) ) { if ( getSessionFactoryOptions().getValidatorFactoryReference() != null ) { properties.put( AvailableSettings.JPA_VALIDATION_FACTORY, getSessionFactoryOptions().getValidatorFactoryReference() ); + properties.put( + AvailableSettings.JAKARTA_JPA_VALIDATION_FACTORY, + getSessionFactoryOptions().getValidatorFactoryReference() + ); } } @@ -1647,6 +1652,8 @@ static SessionFactoryImpl deserialize(ObjectInputStream ois) throws IOException, private void maskOutSensitiveInformation(Map props) { maskOutIfSet( props, AvailableSettings.JPA_JDBC_USER ); maskOutIfSet( props, AvailableSettings.JPA_JDBC_PASSWORD ); + maskOutIfSet( props, AvailableSettings.JAKARTA_JPA_JDBC_USER ); + maskOutIfSet( props, AvailableSettings.JAKARTA_JPA_JDBC_PASSWORD ); maskOutIfSet( props, AvailableSettings.USER ); maskOutIfSet( props, AvailableSettings.PASS ); } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java index 6cef2427fa62..e54aabe09251 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java @@ -175,6 +175,10 @@ import org.hibernate.stat.internal.SessionStatisticsImpl; import org.hibernate.stat.spi.StatisticsImplementor; +import static org.hibernate.cfg.AvailableSettings.JAKARTA_JPA_LOCK_SCOPE; +import static org.hibernate.cfg.AvailableSettings.JAKARTA_JPA_LOCK_TIMEOUT; +import static org.hibernate.cfg.AvailableSettings.JAKARTA_JPA_SHARED_CACHE_RETRIEVE_MODE; +import static org.hibernate.cfg.AvailableSettings.JAKARTA_JPA_SHARED_CACHE_STORE_MODE; import static org.hibernate.cfg.AvailableSettings.JPA_LOCK_SCOPE; import static org.hibernate.cfg.AvailableSettings.JPA_LOCK_TIMEOUT; import static org.hibernate.cfg.AvailableSettings.JPA_SHARED_CACHE_RETRIEVE_MODE; @@ -305,8 +309,28 @@ protected void applyQuerySettingsAndHints(Query query) { if ( ( queryTimeout = getSessionProperty( QueryHints.SPEC_HINT_TIMEOUT ) ) != null ) { query.setHint( QueryHints.SPEC_HINT_TIMEOUT, queryTimeout ); } + final Object jakartaQueryTimeout; + if ( ( jakartaQueryTimeout = getSessionProperty( QueryHints.JAKARTA_SPEC_HINT_TIMEOUT ) ) != null ) { + query.setHint( QueryHints.JAKARTA_SPEC_HINT_TIMEOUT, jakartaQueryTimeout ); + } final Object lockTimeout; - if ( ( lockTimeout = getSessionProperty( JPA_LOCK_TIMEOUT ) ) != null ) { + final Object jpaLockTimeout = getSessionProperty( JPA_LOCK_TIMEOUT ); + if ( jpaLockTimeout == null ) { + lockTimeout = getSessionProperty( JAKARTA_JPA_LOCK_TIMEOUT ); + } + else if ( Integer.valueOf( LockOptions.WAIT_FOREVER ).equals( jpaLockTimeout ) ) { + final Object jakartaLockTimeout = getSessionProperty( JAKARTA_JPA_LOCK_TIMEOUT ); + if ( jakartaLockTimeout == null ) { + lockTimeout = jpaLockTimeout; + } + else { + lockTimeout = jakartaLockTimeout; + } + } + else { + lockTimeout = jpaLockTimeout; + } + if ( lockTimeout != null ) { query.setHint( JPA_LOCK_TIMEOUT, lockTimeout ); } } @@ -3424,11 +3448,19 @@ protected CacheMode determineAppropriateLocalCacheMode(Map local } private static CacheRetrieveMode determineCacheRetrieveMode(Map settings) { - return ( CacheRetrieveMode ) settings.get( JPA_SHARED_CACHE_RETRIEVE_MODE ); + final CacheRetrieveMode cacheRetrieveMode = (CacheRetrieveMode) settings.get( JPA_SHARED_CACHE_RETRIEVE_MODE ); + if ( cacheRetrieveMode == null ) { + return (CacheRetrieveMode) settings.get( JAKARTA_JPA_SHARED_CACHE_RETRIEVE_MODE ); + } + return cacheRetrieveMode; } private static CacheStoreMode determineCacheStoreMode(Map settings) { - return ( CacheStoreMode ) settings.get( JPA_SHARED_CACHE_STORE_MODE ); + final CacheStoreMode cacheStoreMode = (CacheStoreMode) settings.get( JPA_SHARED_CACHE_STORE_MODE ); + if ( cacheStoreMode == null ) { + return ( CacheStoreMode ) settings.get( JAKARTA_JPA_SHARED_CACHE_STORE_MODE ); + } + return cacheStoreMode; } private void checkTransactionNeededForUpdateOperation() { @@ -3574,10 +3606,14 @@ public void setProperty(String propertyName, Object value) { if ( AvailableSettings.FLUSH_MODE.equals( propertyName ) ) { setHibernateFlushMode( ConfigurationHelper.getFlushMode( value, FlushMode.AUTO ) ); } - else if ( JPA_LOCK_SCOPE.equals( propertyName ) || JPA_LOCK_TIMEOUT.equals( propertyName ) ) { + else if ( JPA_LOCK_SCOPE.equals( propertyName ) || JPA_LOCK_TIMEOUT.equals( propertyName ) + || JAKARTA_JPA_LOCK_SCOPE.equals( propertyName ) || JAKARTA_JPA_LOCK_TIMEOUT.equals( propertyName ) ) { LockOptionsHelper.applyPropertiesToLockOptions( properties, this::getLockOptionsForWrite ); } - else if ( JPA_SHARED_CACHE_RETRIEVE_MODE.equals( propertyName ) || JPA_SHARED_CACHE_STORE_MODE.equals( propertyName ) ) { + else if ( JPA_SHARED_CACHE_RETRIEVE_MODE.equals( propertyName ) + || JPA_SHARED_CACHE_STORE_MODE.equals( propertyName ) + || JAKARTA_JPA_SHARED_CACHE_RETRIEVE_MODE.equals( propertyName ) + || JAKARTA_JPA_SHARED_CACHE_STORE_MODE.equals( propertyName ) ) { getSession().setCacheMode( CacheModeHelper.interpretCacheMode( determineCacheStoreMode( properties ), diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/QueryHints.java b/hibernate-core/src/main/java/org/hibernate/jpa/QueryHints.java index b71d4cdf359c..47c42a7a4fab 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/QueryHints.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/QueryHints.java @@ -23,6 +23,7 @@ import static org.hibernate.annotations.QueryHints.PASS_DISTINCT_THROUGH; import static org.hibernate.annotations.QueryHints.READ_ONLY; import static org.hibernate.annotations.QueryHints.TIMEOUT_HIBERNATE; +import static org.hibernate.annotations.QueryHints.TIMEOUT_JAKARTA_JPA; import static org.hibernate.annotations.QueryHints.TIMEOUT_JPA; /** @@ -42,6 +43,11 @@ public class QueryHints { */ public static final String SPEC_HINT_TIMEOUT = TIMEOUT_JPA; + /** + * The hint key for specifying a query timeout per JPA, which defines the timeout in milliseconds + */ + public static final String JAKARTA_SPEC_HINT_TIMEOUT = TIMEOUT_JAKARTA_JPA; + /** * The hint key for specifying a comment which is to be embedded into the SQL sent to the database. */ @@ -100,6 +106,22 @@ public class QueryHints { */ public static final String HINT_LOADGRAPH = GraphSemantic.LOAD.getJpaHintName(); + /** + * Hint providing a "fetchgraph" EntityGraph. Attributes explicitly specified as AttributeNodes are treated as + * FetchType.EAGER (via join fetch or subsequent select). + * + * Note: Currently, attributes that are not specified are treated as FetchType.LAZY or FetchType.EAGER depending + * on the attribute's definition in metadata, rather than forcing FetchType.LAZY. + */ + public static final String JAKARTA_HINT_FETCHGRAPH = GraphSemantic.FETCH.getJakartaJpaHintName(); + + /** + * Hint providing a "loadgraph" EntityGraph. Attributes explicitly specified as AttributeNodes are treated as + * FetchType.EAGER (via join fetch or subsequent select). Attributes that are not specified are treated as + * FetchType.LAZY or FetchType.EAGER depending on the attribute's definition in metadata + */ + public static final String JAKARTA_HINT_LOADGRAPH = GraphSemantic.LOAD.getJakartaJpaHintName(); + public static final String HINT_FOLLOW_ON_LOCKING = FOLLOW_ON_LOCKING; public static final String HINT_PASS_DISTINCT_THROUGH = PASS_DISTINCT_THROUGH; @@ -113,6 +135,7 @@ private static Set buildHintsSet() { HashSet hints = new HashSet<>(); hints.add( HINT_TIMEOUT ); hints.add( SPEC_HINT_TIMEOUT ); + hints.add( JAKARTA_SPEC_HINT_TIMEOUT ); hints.add( HINT_COMMENT ); hints.add( HINT_FETCH_SIZE ); hints.add( HINT_CACHE_REGION ); @@ -123,6 +146,8 @@ private static Set buildHintsSet() { hints.add( HINT_NATIVE_LOCKMODE ); hints.add( HINT_FETCHGRAPH ); hints.add( HINT_LOADGRAPH ); + hints.add( JAKARTA_HINT_FETCHGRAPH ); + hints.add( JAKARTA_HINT_LOADGRAPH ); hints.add( HINT_NATIVE_SPACES ); return java.util.Collections.unmodifiableSet( hints ); } diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java b/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java index 3894e2c3588f..8d0adeea1c80 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java @@ -91,6 +91,15 @@ import static org.hibernate.cfg.AvailableSettings.JACC_CONTEXT_ID; import static org.hibernate.cfg.AvailableSettings.JACC_ENABLED; import static org.hibernate.cfg.AvailableSettings.JACC_PREFIX; +import static org.hibernate.cfg.AvailableSettings.JAKARTA_JPA_JDBC_DRIVER; +import static org.hibernate.cfg.AvailableSettings.JAKARTA_JPA_JDBC_PASSWORD; +import static org.hibernate.cfg.AvailableSettings.JAKARTA_JPA_JDBC_URL; +import static org.hibernate.cfg.AvailableSettings.JAKARTA_JPA_JDBC_USER; +import static org.hibernate.cfg.AvailableSettings.JAKARTA_JPA_JTA_DATASOURCE; +import static org.hibernate.cfg.AvailableSettings.JAKARTA_JPA_NON_JTA_DATASOURCE; +import static org.hibernate.cfg.AvailableSettings.JAKARTA_JPA_SHARED_CACHE_MODE; +import static org.hibernate.cfg.AvailableSettings.JAKARTA_JPA_TRANSACTION_TYPE; +import static org.hibernate.cfg.AvailableSettings.JAKARTA_JPA_VALIDATION_MODE; import static org.hibernate.cfg.AvailableSettings.JPA_JDBC_DRIVER; import static org.hibernate.cfg.AvailableSettings.JPA_JDBC_PASSWORD; import static org.hibernate.cfg.AvailableSettings.JPA_JDBC_URL; @@ -259,7 +268,13 @@ private EntityManagerFactoryBuilderImpl( metamodelBuilder.getBootstrapContext() ); - withValidatorFactory( configurationValues.get( org.hibernate.cfg.AvailableSettings.JPA_VALIDATION_FACTORY ) ); + final Object validatorFactory = configurationValues.get( org.hibernate.cfg.AvailableSettings.JPA_VALIDATION_FACTORY ); + if ( validatorFactory == null ) { + withValidatorFactory( configurationValues.get( org.hibernate.cfg.AvailableSettings.JAKARTA_JPA_VALIDATION_FACTORY ) ); + } + else { + withValidatorFactory( validatorFactory ); + } // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // push back class transformation to the environment; for the time being this only has any effect in EE @@ -572,20 +587,30 @@ private void normalizeSettings( // normalize ValidationMode final Object intgValidationMode = integrationSettingsCopy.remove( JPA_VALIDATION_MODE ); + final Object jakartaIntgValidationMode = integrationSettingsCopy.remove( JAKARTA_JPA_VALIDATION_MODE ); if ( intgValidationMode != null ) { mergedSettings.configurationValues.put( JPA_VALIDATION_MODE, intgValidationMode ); } + else if ( jakartaIntgValidationMode != null ) { + mergedSettings.configurationValues.put( JAKARTA_JPA_VALIDATION_MODE, jakartaIntgValidationMode ); + } else if ( persistenceUnit.getValidationMode() != null ) { mergedSettings.configurationValues.put( JPA_VALIDATION_MODE, persistenceUnit.getValidationMode() ); + mergedSettings.configurationValues.put( JAKARTA_JPA_VALIDATION_MODE, persistenceUnit.getValidationMode() ); } // normalize SharedCacheMode final Object intgCacheMode = integrationSettingsCopy.remove( JPA_SHARED_CACHE_MODE ); + final Object jakartaIntgCacheMode = integrationSettingsCopy.remove( JAKARTA_JPA_SHARED_CACHE_MODE ); if ( intgCacheMode != null ) { mergedSettings.configurationValues.put( JPA_SHARED_CACHE_MODE, intgCacheMode ); } + else if ( jakartaIntgCacheMode != null ) { + mergedSettings.configurationValues.put( JAKARTA_JPA_SHARED_CACHE_MODE, jakartaIntgCacheMode ); + } else if ( persistenceUnit.getSharedCacheMode() != null ) { mergedSettings.configurationValues.put( JPA_SHARED_CACHE_MODE, persistenceUnit.getSharedCacheMode() ); + mergedSettings.configurationValues.put( JAKARTA_JPA_SHARED_CACHE_MODE, persistenceUnit.getSharedCacheMode() ); } // Apply all "integration overrides" as the last step. By specification, @@ -618,16 +643,20 @@ private void normalizeConnectionAccessUserAndPass( final Object effectiveUser = NullnessHelper.coalesceSuppliedValues( () -> integrationSettingsCopy.remove( USER ), () -> integrationSettingsCopy.remove( JPA_JDBC_USER ), + () -> integrationSettingsCopy.remove( JAKARTA_JPA_JDBC_USER ), () -> extractPuProperty( persistenceUnit, USER ), - () -> extractPuProperty( persistenceUnit, JPA_JDBC_USER ) + () -> extractPuProperty( persistenceUnit, JPA_JDBC_USER ), + () -> extractPuProperty( persistenceUnit, JAKARTA_JPA_JDBC_USER ) ); //noinspection unchecked final Object effectivePass = NullnessHelper.coalesceSuppliedValues( () -> integrationSettingsCopy.remove( PASS ), () -> integrationSettingsCopy.remove( JPA_JDBC_PASSWORD ), + () -> integrationSettingsCopy.remove( JAKARTA_JPA_JDBC_PASSWORD ), () -> extractPuProperty( persistenceUnit, PASS ), - () -> extractPuProperty( persistenceUnit, JPA_JDBC_PASSWORD ) + () -> extractPuProperty( persistenceUnit, JPA_JDBC_PASSWORD ), + () -> extractPuProperty( persistenceUnit, JAKARTA_JPA_JDBC_PASSWORD ) ); if ( effectiveUser != null || effectivePass != null ) { @@ -645,11 +674,13 @@ private void applyUserAndPass(Object effectiveUser, Object effectivePass, Merged if ( effectiveUser != null ) { mergedSettings.configurationValues.put( USER, effectiveUser ); mergedSettings.configurationValues.put( JPA_JDBC_USER, effectiveUser ); + mergedSettings.configurationValues.put( JAKARTA_JPA_JDBC_USER, effectiveUser ); } if ( effectivePass != null ) { mergedSettings.configurationValues.put( PASS, effectivePass ); mergedSettings.configurationValues.put( JPA_JDBC_PASSWORD, effectivePass ); + mergedSettings.configurationValues.put( JAKARTA_JPA_JDBC_PASSWORD, effectivePass ); } } @@ -662,7 +693,10 @@ private void normalizeTransactionCoordinator( MergedSettings mergedSettings) { PersistenceUnitTransactionType txnType = null; - final Object intgTxnType = integrationSettingsCopy.remove( JPA_TRANSACTION_TYPE ); + Object intgTxnType = integrationSettingsCopy.remove( JPA_TRANSACTION_TYPE ); + if ( intgTxnType == null ) { + intgTxnType = integrationSettingsCopy.remove( JAKARTA_JPA_TRANSACTION_TYPE ); + } if ( intgTxnType != null ) { txnType = PersistenceUnitTransactionTypeHelper.interpretTransactionType( intgTxnType ); @@ -671,7 +705,10 @@ else if ( persistenceUnit.getTransactionType() != null ) { txnType = persistenceUnit.getTransactionType(); } else { - final Object puPropTxnType = mergedSettings.configurationValues.get( JPA_TRANSACTION_TYPE ); + Object puPropTxnType = mergedSettings.configurationValues.get( JPA_TRANSACTION_TYPE ); + if ( puPropTxnType == null ) { + puPropTxnType = mergedSettings.configurationValues.get( JAKARTA_JPA_TRANSACTION_TYPE ); + } if ( puPropTxnType != null ) { txnType = PersistenceUnitTransactionTypeHelper.interpretTransactionType( puPropTxnType ); } @@ -762,6 +799,21 @@ private void normalizeDataAccess( } } + if ( integrationSettingsCopy.containsKey( JAKARTA_JPA_JTA_DATASOURCE ) ) { + final Object dataSourceRef = integrationSettingsCopy.remove( JAKARTA_JPA_JTA_DATASOURCE ); + if ( dataSourceRef != null ) { + applyDataSource( + dataSourceRef, + true, + integrationSettingsCopy, + mergedSettings + ); + + // EARLY EXIT!! + return; + } + } + if ( integrationSettingsCopy.containsKey( JPA_NON_JTA_DATASOURCE ) ) { final Object dataSourceRef = integrationSettingsCopy.remove( JPA_NON_JTA_DATASOURCE ); @@ -776,6 +828,20 @@ private void normalizeDataAccess( return; } + if ( integrationSettingsCopy.containsKey( JAKARTA_JPA_NON_JTA_DATASOURCE ) ) { + final Object dataSourceRef = integrationSettingsCopy.remove( JAKARTA_JPA_NON_JTA_DATASOURCE ); + + applyDataSource( + dataSourceRef, + false, + integrationSettingsCopy, + mergedSettings + ); + + // EARLY EXIT!! + return; + } + if ( integrationSettingsCopy.containsKey( URL ) ) { // these have precedence over the JPA ones final Object integrationJdbcUrl = integrationSettingsCopy.get( URL ); @@ -786,8 +852,10 @@ private void normalizeDataAccess( NullnessHelper.coalesceSuppliedValues( () -> ConfigurationHelper.getString( DRIVER, integrationSettingsCopy ), () -> ConfigurationHelper.getString( JPA_JDBC_DRIVER, integrationSettingsCopy ), + () -> ConfigurationHelper.getString( JAKARTA_JPA_JDBC_DRIVER, integrationSettingsCopy ), () -> ConfigurationHelper.getString( DRIVER, mergedSettings.configurationValues ), - () -> ConfigurationHelper.getString( JPA_JDBC_DRIVER, mergedSettings.configurationValues ) + () -> ConfigurationHelper.getString( JPA_JDBC_DRIVER, mergedSettings.configurationValues ), + () -> ConfigurationHelper.getString( JAKARTA_JPA_JDBC_DRIVER, mergedSettings.configurationValues ) ), integrationSettingsCopy, mergedSettings @@ -818,6 +886,26 @@ private void normalizeDataAccess( } } + if ( integrationSettingsCopy.containsKey( JAKARTA_JPA_JDBC_URL ) ) { + final Object integrationJdbcUrl = integrationSettingsCopy.get( JAKARTA_JPA_JDBC_URL ); + + if ( integrationJdbcUrl != null ) { + //noinspection unchecked + applyJdbcSettings( + integrationJdbcUrl, + NullnessHelper.coalesceSuppliedValues( + () -> ConfigurationHelper.getString( JAKARTA_JPA_JDBC_DRIVER, integrationSettingsCopy ), + () -> ConfigurationHelper.getString( JAKARTA_JPA_JDBC_DRIVER, mergedSettings.configurationValues ) + ), + integrationSettingsCopy, + mergedSettings + ); + + // EARLY EXIT!! + return; + } + } + if ( persistenceUnit.getJtaDataSource() != null ) { applyDataSource( persistenceUnit.getJtaDataSource(), @@ -874,6 +962,22 @@ private void normalizeDataAccess( } } + if ( mergedSettings.configurationValues.containsKey( JAKARTA_JPA_JDBC_URL ) ) { + final Object url = mergedSettings.configurationValues.get( JAKARTA_JPA_JDBC_URL ); + + if ( url != null && ( ! ( url instanceof String ) || StringHelper.isNotEmpty( (String) url ) ) ) { + applyJdbcSettings( + url, + ConfigurationHelper.getString( JAKARTA_JPA_JDBC_DRIVER, mergedSettings.configurationValues ), + integrationSettingsCopy, + mergedSettings + ); + + // EARLY EXIT!! + return; + } + } + // any other conditions to account for? } @@ -894,31 +998,48 @@ private void applyDataSource( // add to EMF properties (questionable - see HHH-13432) final String emfKey; final String inverseEmfKey; + final String jakartaEmfKey; + final String jakartaInverseEmfKey; if ( isJta ) { emfKey = JPA_JTA_DATASOURCE; + jakartaEmfKey = JAKARTA_JPA_JTA_DATASOURCE; inverseEmfKey = JPA_NON_JTA_DATASOURCE; + jakartaInverseEmfKey = JAKARTA_JPA_NON_JTA_DATASOURCE; } else { emfKey = JPA_NON_JTA_DATASOURCE; + jakartaEmfKey = JAKARTA_JPA_NON_JTA_DATASOURCE; inverseEmfKey = JPA_JTA_DATASOURCE; + jakartaInverseEmfKey = JAKARTA_JPA_JTA_DATASOURCE; } mergedSettings.configurationValues.put( emfKey, dataSourceRef ); + mergedSettings.configurationValues.put( jakartaEmfKey, dataSourceRef ); // clear any settings logically overridden by this datasource cleanUpConfigKeys( integrationSettingsCopy, mergedSettings, inverseEmfKey, + jakartaInverseEmfKey, JPA_JDBC_DRIVER, + JAKARTA_JPA_JDBC_DRIVER, DRIVER, JPA_JDBC_URL, + JAKARTA_JPA_JDBC_URL, URL ); // clean-up the entries in the "integration overrides" so they do not get get picked // up in the general "integration overrides" handling - cleanUpConfigKeys( integrationSettingsCopy, DATASOURCE, JPA_JTA_DATASOURCE, JPA_NON_JTA_DATASOURCE ); + cleanUpConfigKeys( + integrationSettingsCopy, + DATASOURCE, + JPA_JTA_DATASOURCE, + JAKARTA_JPA_JTA_DATASOURCE, + JPA_NON_JTA_DATASOURCE, + JAKARTA_JPA_NON_JTA_DATASOURCE + ); // add under Hibernate's DATASOURCE setting where the ConnectionProvider will find it mergedSettings.configurationValues.put( DATASOURCE, dataSourceRef ); @@ -952,14 +1073,17 @@ private void applyJdbcSettings( MergedSettings mergedSettings) { mergedSettings.configurationValues.put( URL, url ); mergedSettings.configurationValues.put( JPA_JDBC_URL, url ); + mergedSettings.configurationValues.put( JAKARTA_JPA_JDBC_URL, url ); if ( driver != null ) { mergedSettings.configurationValues.put( DRIVER, driver ); mergedSettings.configurationValues.put( JPA_JDBC_DRIVER, driver ); + mergedSettings.configurationValues.put( JAKARTA_JPA_JDBC_DRIVER, driver ); } else { mergedSettings.configurationValues.remove( DRIVER ); mergedSettings.configurationValues.remove( JPA_JDBC_DRIVER ); + mergedSettings.configurationValues.remove( JAKARTA_JPA_JDBC_DRIVER ); } // clean up the integration-map values @@ -967,12 +1091,16 @@ private void applyJdbcSettings( integrationSettingsCopy, DRIVER, JPA_JDBC_DRIVER, + JAKARTA_JPA_JDBC_DRIVER, URL, JPA_JDBC_URL, + JAKARTA_JPA_JDBC_URL, USER, JPA_JDBC_USER, + JAKARTA_JPA_JDBC_USER, PASS, - JPA_JDBC_PASSWORD + JPA_JDBC_PASSWORD, + JAKARTA_JPA_JDBC_PASSWORD ); cleanUpConfigKeys( @@ -980,7 +1108,9 @@ private void applyJdbcSettings( mergedSettings, DATASOURCE, JPA_JTA_DATASOURCE, - JPA_NON_JTA_DATASOURCE + JAKARTA_JPA_JTA_DATASOURCE, + JPA_NON_JTA_DATASOURCE, + JAKARTA_JPA_NON_JTA_DATASOURCE ); } diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/PersistenceXmlParser.java b/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/PersistenceXmlParser.java index 2be47723e4c9..1565e5b68f22 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/PersistenceXmlParser.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/PersistenceXmlParser.java @@ -269,16 +269,29 @@ protected void parsePersistenceXml(URL xmlUrl, Map integration) { if ( integration.containsKey( AvailableSettings.JPA_PERSISTENCE_PROVIDER ) ) { persistenceUnit.setProviderClassName( (String) integration.get( AvailableSettings.JPA_PERSISTENCE_PROVIDER ) ); } + else if ( integration.containsKey( AvailableSettings.JAKARTA_JPA_PERSISTENCE_PROVIDER ) ) { + persistenceUnit.setProviderClassName( (String) integration.get( AvailableSettings.JAKARTA_JPA_PERSISTENCE_PROVIDER ) ); + } if ( integration.containsKey( AvailableSettings.JPA_TRANSACTION_TYPE ) ) { String transactionType = (String) integration.get( AvailableSettings.JPA_TRANSACTION_TYPE ); persistenceUnit.setTransactionType( parseTransactionType( transactionType ) ); } + else if ( integration.containsKey( AvailableSettings.JAKARTA_JPA_TRANSACTION_TYPE ) ) { + String transactionType = (String) integration.get( AvailableSettings.JAKARTA_JPA_TRANSACTION_TYPE ); + persistenceUnit.setTransactionType( parseTransactionType( transactionType ) ); + } if ( integration.containsKey( AvailableSettings.JPA_JTA_DATASOURCE ) ) { persistenceUnit.setJtaDataSource( integration.get( AvailableSettings.JPA_JTA_DATASOURCE ) ); } + else if ( integration.containsKey( AvailableSettings.JAKARTA_JPA_JTA_DATASOURCE ) ) { + persistenceUnit.setJtaDataSource( integration.get( AvailableSettings.JAKARTA_JPA_JTA_DATASOURCE ) ); + } if ( integration.containsKey( AvailableSettings.JPA_NON_JTA_DATASOURCE ) ) { persistenceUnit.setNonJtaDataSource( integration.get( AvailableSettings.JPA_NON_JTA_DATASOURCE ) ); } + else if ( integration.containsKey( AvailableSettings.JAKARTA_JPA_NON_JTA_DATASOURCE ) ) { + persistenceUnit.setNonJtaDataSource( integration.get( AvailableSettings.JAKARTA_JPA_NON_JTA_DATASOURCE ) ); + } decodeTransactionType( persistenceUnit ); diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/boot/spi/Bootstrap.java b/hibernate-core/src/main/java/org/hibernate/jpa/boot/spi/Bootstrap.java index 53677815e43a..404ecfc60a32 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/boot/spi/Bootstrap.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/boot/spi/Bootstrap.java @@ -62,7 +62,6 @@ public static EntityManagerFactoryBuilder getEntityManagerFactoryBuilder( String persistenceUnitName, PersistenceUnitTransactionType transactionType, Map integration) { - ; return new EntityManagerFactoryBuilderImpl( PersistenceXmlParser.parse( persistenceXmlUrl, transactionType, integration ).get( persistenceUnitName ), integration diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/boot/spi/ProviderChecker.java b/hibernate-core/src/main/java/org/hibernate/jpa/boot/spi/ProviderChecker.java index a88d09bc55f8..5e683093973d 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/boot/spi/ProviderChecker.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/boot/spi/ProviderChecker.java @@ -9,7 +9,6 @@ import java.util.Map; import org.hibernate.cfg.AvailableSettings; -import org.hibernate.internal.EntityManagerMessageLogger; import org.hibernate.internal.HEMLogging; import org.hibernate.jpa.HibernatePersistenceProvider; @@ -100,7 +99,10 @@ private static String extractProviderName(Map integration) { if ( integration == null ) { return null; } - final String setting = (String) integration.get( AvailableSettings.JPA_PERSISTENCE_PROVIDER ); + String setting = (String) integration.get(AvailableSettings.JPA_PERSISTENCE_PROVIDER); + if ( setting == null ) { + setting = (String) integration.get(AvailableSettings.JAKARTA_JPA_PERSISTENCE_PROVIDER); + } return setting == null ? null : setting.trim(); } diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/internal/util/LockOptionsHelper.java b/hibernate-core/src/main/java/org/hibernate/jpa/internal/util/LockOptionsHelper.java index 20e1ea641b79..621258df6db5 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/internal/util/LockOptionsHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/internal/util/LockOptionsHelper.java @@ -13,6 +13,8 @@ import org.hibernate.LockOptions; +import static org.hibernate.cfg.AvailableSettings.JAKARTA_JPA_LOCK_SCOPE; +import static org.hibernate.cfg.AvailableSettings.JAKARTA_JPA_LOCK_TIMEOUT; import static org.hibernate.cfg.AvailableSettings.JPA_LOCK_SCOPE; import static org.hibernate.cfg.AvailableSettings.JPA_LOCK_TIMEOUT; @@ -31,7 +33,12 @@ private LockOptionsHelper() { * @param lockOptionsSupplier The reference to the lock to modify */ public static void applyPropertiesToLockOptions(final Map props, final Supplier lockOptionsSupplier) { - Object lockScope = props.get( JPA_LOCK_SCOPE ); + String lockScopeHint = JPA_LOCK_SCOPE; + Object lockScope = props.get( lockScopeHint ); + if ( lockScope == null ) { + lockScopeHint = JAKARTA_JPA_LOCK_SCOPE; + lockScope = props.get( lockScopeHint ); + } if ( lockScope instanceof String && PessimisticLockScope.valueOf( (String) lockScope ) == PessimisticLockScope.EXTENDED ) { lockOptionsSupplier.get().setScope( true ); } @@ -40,10 +47,15 @@ else if ( lockScope instanceof PessimisticLockScope ) { lockOptionsSupplier.get().setScope( extended ); } else if ( lockScope != null ) { - throw new PersistenceException( "Unable to parse " + JPA_LOCK_SCOPE + ": " + lockScope ); + throw new PersistenceException( "Unable to parse " + lockScopeHint + ": " + lockScope ); } - Object lockTimeout = props.get( JPA_LOCK_TIMEOUT ); + String timeoutHint = JPA_LOCK_TIMEOUT; + Object lockTimeout = props.get( timeoutHint ); + if (lockTimeout == null) { + timeoutHint = JAKARTA_JPA_LOCK_TIMEOUT; + lockTimeout = props.get( timeoutHint ); + } int timeout = 0; boolean timeoutSet = false; if ( lockTimeout instanceof String ) { @@ -55,7 +67,7 @@ else if ( lockTimeout instanceof Number ) { timeoutSet = true; } else if ( lockTimeout != null ) { - throw new PersistenceException( "Unable to parse " + JPA_LOCK_TIMEOUT + ": " + lockTimeout ); + throw new PersistenceException( "Unable to parse " + timeoutHint + ": " + lockTimeout ); } if ( timeoutSet ) { diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/AbstractProducedQuery.java b/hibernate-core/src/main/java/org/hibernate/query/internal/AbstractProducedQuery.java index 170a7288a2cc..28cf0418c1ee 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/internal/AbstractProducedQuery.java +++ b/hibernate-core/src/main/java/org/hibernate/query/internal/AbstractProducedQuery.java @@ -90,6 +90,10 @@ import org.jboss.logging.Logger; import static org.hibernate.LockOptions.WAIT_FOREVER; +import static org.hibernate.cfg.AvailableSettings.JAKARTA_JPA_LOCK_SCOPE; +import static org.hibernate.cfg.AvailableSettings.JAKARTA_JPA_LOCK_TIMEOUT; +import static org.hibernate.cfg.AvailableSettings.JAKARTA_JPA_SHARED_CACHE_RETRIEVE_MODE; +import static org.hibernate.cfg.AvailableSettings.JAKARTA_JPA_SHARED_CACHE_STORE_MODE; import static org.hibernate.cfg.AvailableSettings.JPA_LOCK_SCOPE; import static org.hibernate.cfg.AvailableSettings.JPA_LOCK_TIMEOUT; import static org.hibernate.cfg.AvailableSettings.JPA_SHARED_CACHE_RETRIEVE_MODE; @@ -107,6 +111,9 @@ import static org.hibernate.jpa.QueryHints.HINT_NATIVE_SPACES; import static org.hibernate.jpa.QueryHints.HINT_READONLY; import static org.hibernate.jpa.QueryHints.HINT_TIMEOUT; +import static org.hibernate.jpa.QueryHints.JAKARTA_HINT_FETCHGRAPH; +import static org.hibernate.jpa.QueryHints.JAKARTA_HINT_LOADGRAPH; +import static org.hibernate.jpa.QueryHints.JAKARTA_SPEC_HINT_TIMEOUT; import static org.hibernate.jpa.QueryHints.SPEC_HINT_TIMEOUT; /** @@ -1003,16 +1010,19 @@ protected void collectHints(Map hints) { if ( queryTimeout != null ) { hints.put( HINT_TIMEOUT, queryTimeout ); hints.put( SPEC_HINT_TIMEOUT, queryTimeout * 1000 ); + hints.put( JAKARTA_SPEC_HINT_TIMEOUT, queryTimeout * 1000 ); } final LockOptions lockOptions = getLockOptions(); final int lockOptionsTimeOut = lockOptions.getTimeOut(); if ( lockOptionsTimeOut != WAIT_FOREVER ) { hints.put( JPA_LOCK_TIMEOUT, lockOptionsTimeOut ); + hints.put( JAKARTA_JPA_LOCK_TIMEOUT, lockOptionsTimeOut ); } if ( lockOptions.getScope() ) { hints.put( JPA_LOCK_SCOPE, lockOptions.getScope() ); + hints.put( JAKARTA_JPA_LOCK_SCOPE, lockOptions.getScope() ); } if ( lockOptions.hasAliasSpecificLockModes() && canApplyAliasSpecificLockModeHints() ) { @@ -1031,7 +1041,9 @@ protected void collectHints(Map hints) { if ( cacheStoreMode != null || cacheRetrieveMode != null ) { putIfNotNull( hints, HINT_CACHE_MODE, CacheModeHelper.interpretCacheMode( cacheStoreMode, cacheRetrieveMode ) ); putIfNotNull( hints, JPA_SHARED_CACHE_RETRIEVE_MODE, cacheRetrieveMode ); + putIfNotNull( hints, JAKARTA_JPA_SHARED_CACHE_RETRIEVE_MODE, cacheRetrieveMode ); putIfNotNull( hints, JPA_SHARED_CACHE_STORE_MODE, cacheStoreMode ); + putIfNotNull( hints, JAKARTA_JPA_SHARED_CACHE_STORE_MODE, cacheStoreMode ); } if ( isCacheable() ) { @@ -1072,12 +1084,12 @@ public QueryImplementor setHint(String hintName, Object value) { if ( HINT_TIMEOUT.equals( hintName ) ) { applied = applyTimeoutHint( ConfigurationHelper.getInteger( value ) ); } - else if ( SPEC_HINT_TIMEOUT.equals( hintName ) ) { + else if ( SPEC_HINT_TIMEOUT.equals( hintName ) || JAKARTA_SPEC_HINT_TIMEOUT.equals( hintName ) ) { // convert milliseconds to seconds int timeout = (int)Math.round( ConfigurationHelper.getInteger( value ).doubleValue() / 1000.0 ); applied = applyTimeoutHint( timeout ); } - else if ( JPA_LOCK_TIMEOUT.equals( hintName ) ) { + else if ( JPA_LOCK_TIMEOUT.equals( hintName ) || JAKARTA_JPA_LOCK_TIMEOUT.equals( hintName ) ) { applied = applyLockTimeoutHint( ConfigurationHelper.getInteger( value ) ); } else if ( HINT_COMMENT.equals( hintName ) ) { @@ -1101,11 +1113,11 @@ else if ( HINT_FLUSH_MODE.equals( hintName ) ) { else if ( HINT_CACHE_MODE.equals( hintName ) ) { applied = applyCacheModeHint( ConfigurationHelper.getCacheMode( value ) ); } - else if ( JPA_SHARED_CACHE_RETRIEVE_MODE.equals( hintName ) ) { + else if ( JPA_SHARED_CACHE_RETRIEVE_MODE.equals( hintName ) || JAKARTA_JPA_SHARED_CACHE_RETRIEVE_MODE.equals( hintName ) ) { final CacheRetrieveMode retrieveMode = value != null ? CacheRetrieveMode.valueOf( value.toString() ) : null; applied = applyJpaCacheRetrieveMode( retrieveMode ); } - else if ( JPA_SHARED_CACHE_STORE_MODE.equals( hintName ) ) { + else if ( JPA_SHARED_CACHE_STORE_MODE.equals( hintName ) || JAKARTA_JPA_SHARED_CACHE_STORE_MODE.equals( hintName ) ) { final CacheStoreMode storeMode = value != null ? CacheStoreMode.valueOf( value.toString() ) : null; applied = applyJpaCacheStoreMode( storeMode ); } @@ -1133,7 +1145,10 @@ else if ( hintName.startsWith( ALIAS_SPECIFIC_LOCK_MODE ) ) { applied = false; } } - else if ( HINT_FETCHGRAPH.equals( hintName ) || HINT_LOADGRAPH.equals( hintName ) ) { + else if ( HINT_FETCHGRAPH.equals( hintName ) + || HINT_LOADGRAPH.equals( hintName ) + || JAKARTA_HINT_FETCHGRAPH.equals( hintName ) + || JAKARTA_HINT_LOADGRAPH.equals( hintName ) ) { if ( value instanceof RootGraph ) { applyGraph( (RootGraph) value, GraphSemantic.fromJpaHintName( hintName ) ); applyEntityGraphQueryHint( new EntityGraphQueryHint( hintName, (RootGraphImpl) value ) ); diff --git a/hibernate-core/src/main/java/org/hibernate/resource/beans/spi/ManagedBeanRegistryInitiator.java b/hibernate-core/src/main/java/org/hibernate/resource/beans/spi/ManagedBeanRegistryInitiator.java index 61bf74b3f38d..119ea6f9dae4 100644 --- a/hibernate-core/src/main/java/org/hibernate/resource/beans/spi/ManagedBeanRegistryInitiator.java +++ b/hibernate-core/src/main/java/org/hibernate/resource/beans/spi/ManagedBeanRegistryInitiator.java @@ -60,7 +60,10 @@ private BeanContainer resolveBeanContainer(Map configurationValues, ServiceRegis // simplified CDI support final boolean isCdiAvailable = isCdiAvailable( classLoaderService ); - final Object beanManagerRef = cfgSvc.getSettings().get( AvailableSettings.CDI_BEAN_MANAGER ); + Object beanManagerRef = cfgSvc.getSettings().get( AvailableSettings.CDI_BEAN_MANAGER ); + if ( beanManagerRef == null ) { + beanManagerRef = cfgSvc.getSettings().get( AvailableSettings.JAKARTA_CDI_BEAN_MANAGER ); + } if ( beanManagerRef != null ) { if ( !isCdiAvailable ) { BeansMessageLogger.BEANS_LOGGER.beanManagerButCdiNotAvailable( beanManagerRef ); diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/Helper.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/Helper.java index f6abe610c741..1701ed4e4813 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/Helper.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/Helper.java @@ -111,6 +111,9 @@ public static boolean interpretNamespaceHandling(Map configurationValues) { if ( configurationValues.containsKey( AvailableSettings.HBM2DDL_CREATE_SCHEMAS ) ) { count++; } + if ( configurationValues.containsKey( AvailableSettings.JAKARTA_HBM2DDL_CREATE_SCHEMAS ) ) { + count++; + } if ( configurationValues.containsKey( AvailableSettings.HBM2DDL_CREATE_NAMESPACES ) ) { count++; } @@ -124,15 +127,20 @@ public static boolean interpretNamespaceHandling(Map configurationValues) { return ConfigurationHelper.getBoolean( AvailableSettings.HBM2DDL_CREATE_SCHEMAS, configurationValues, - //Then try the Hibernate ORM setting: + //Then try the Jakarta JPA setting: ConfigurationHelper.getBoolean( - AvailableSettings.HBM2DDL_CREATE_NAMESPACES, + AvailableSettings.JAKARTA_HBM2DDL_CREATE_SCHEMAS, configurationValues, - //And finally fall back to the old name this had before we fixed the typo: + //Then try the Hibernate ORM setting: ConfigurationHelper.getBoolean( - AvailableSettings.HBM2DLL_CREATE_NAMESPACES, + AvailableSettings.HBM2DDL_CREATE_NAMESPACES, configurationValues, - false + //And finally fall back to the old name this had before we fixed the typo: + ConfigurationHelper.getBoolean( + AvailableSettings.HBM2DLL_CREATE_NAMESPACES, + configurationValues, + false + ) ) ) ); diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/HibernateSchemaManagementTool.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/HibernateSchemaManagementTool.java index f8c05801f1e4..60cc75ed9a85 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/HibernateSchemaManagementTool.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/HibernateSchemaManagementTool.java @@ -46,6 +46,7 @@ import static org.hibernate.cfg.AvailableSettings.HBM2DDL_CONNECTION; import static org.hibernate.cfg.AvailableSettings.HBM2DDL_DELIMITER; +import static org.hibernate.cfg.AvailableSettings.JAKARTA_HBM2DDL_CONNECTION; /** * The standard Hibernate implementation for performing schema management. @@ -196,12 +197,30 @@ public JdbcContext resolveJdbcContext(Map configurationValues) { if ( providedConnection != null ) { jdbcContextBuilder.jdbcConnectionAccess = new JdbcConnectionAccessProvidedConnectionImpl( providedConnection ); } + else { + final Connection jakartaProvidedConnection = (Connection) configurationValues.get( JAKARTA_HBM2DDL_CONNECTION ); + if ( jakartaProvidedConnection != null ) { + jdbcContextBuilder.jdbcConnectionAccess = new JdbcConnectionAccessProvidedConnectionImpl( jakartaProvidedConnection ); + } + } // see if a specific Dialect override has been provided... - final String explicitDbName = (String) configurationValues.get( AvailableSettings.HBM2DDL_DB_NAME ); + String dbName = (String) configurationValues.get( AvailableSettings.HBM2DDL_DB_NAME ); + if ( dbName == null ) { + dbName = (String) configurationValues.get( AvailableSettings.JAKARTA_HBM2DDL_DB_NAME ); + } + final String explicitDbName = dbName; if ( StringHelper.isNotEmpty( explicitDbName ) ) { - final String explicitDbMajor = (String) configurationValues.get( AvailableSettings.HBM2DDL_DB_MAJOR_VERSION ); - final String explicitDbMinor = (String) configurationValues.get( AvailableSettings.HBM2DDL_DB_MINOR_VERSION ); + String dbMajor = (String) configurationValues.get( AvailableSettings.HBM2DDL_DB_MAJOR_VERSION ); + if ( dbMajor == null ) { + dbMajor = (String) configurationValues.get( AvailableSettings.JAKARTA_HBM2DDL_DB_MAJOR_VERSION ); + } + String dbMinor = (String) configurationValues.get( AvailableSettings.HBM2DDL_DB_MINOR_VERSION ); + if ( dbMinor == null ) { + dbMinor = (String) configurationValues.get( AvailableSettings.JAKARTA_HBM2DDL_DB_MINOR_VERSION ); + } + final String explicitDbMajor = dbMajor; + final String explicitDbMinor = dbMinor; final Dialect indicatedDialect = serviceRegistry.getService( DialectResolver.class ).resolveDialect( new DialectResolutionInfo() { diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/SchemaCreatorImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/SchemaCreatorImpl.java index 6c8744fdea5b..f2d8e530a60e 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/SchemaCreatorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/SchemaCreatorImpl.java @@ -60,6 +60,7 @@ import static org.hibernate.cfg.AvailableSettings.HBM2DDL_CHARSET_NAME; import static org.hibernate.cfg.AvailableSettings.HBM2DDL_LOAD_SCRIPT_SOURCE; +import static org.hibernate.cfg.AvailableSettings.JAKARTA_HBM2DDL_LOAD_SCRIPT_SOURCE; import static org.hibernate.tool.schema.internal.Helper.interpretScriptSourceSetting; /** @@ -457,7 +458,10 @@ private void applyImportSources( //final Formatter formatter = format ? DDLFormatterImpl.INSTANCE : FormatStyle.NONE.getFormatter(); final Formatter formatter = FormatStyle.NONE.getFormatter(); - final Object importScriptSetting = options.getConfigurationValues().get( HBM2DDL_LOAD_SCRIPT_SOURCE ); + Object importScriptSetting = options.getConfigurationValues().get( HBM2DDL_LOAD_SCRIPT_SOURCE ); + if ( importScriptSetting == null ) { + importScriptSetting = options.getConfigurationValues().get( JAKARTA_HBM2DDL_LOAD_SCRIPT_SOURCE ); + } String charsetName = (String) options.getConfigurationValues().get( HBM2DDL_CHARSET_NAME ); if ( importScriptSetting != null ) { diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/SchemaManagementToolCoordinator.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/SchemaManagementToolCoordinator.java index 4f4e07529eed..d0d27aaccf59 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/SchemaManagementToolCoordinator.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/SchemaManagementToolCoordinator.java @@ -33,6 +33,14 @@ import static org.hibernate.cfg.AvailableSettings.HBM2DDL_SCRIPTS_ACTION; import static org.hibernate.cfg.AvailableSettings.HBM2DDL_SCRIPTS_CREATE_TARGET; import static org.hibernate.cfg.AvailableSettings.HBM2DDL_SCRIPTS_DROP_TARGET; +import static org.hibernate.cfg.AvailableSettings.JAKARTA_HBM2DDL_CREATE_SCRIPT_SOURCE; +import static org.hibernate.cfg.AvailableSettings.JAKARTA_HBM2DDL_CREATE_SOURCE; +import static org.hibernate.cfg.AvailableSettings.JAKARTA_HBM2DDL_DATABASE_ACTION; +import static org.hibernate.cfg.AvailableSettings.JAKARTA_HBM2DDL_DROP_SCRIPT_SOURCE; +import static org.hibernate.cfg.AvailableSettings.JAKARTA_HBM2DDL_DROP_SOURCE; +import static org.hibernate.cfg.AvailableSettings.JAKARTA_HBM2DDL_SCRIPTS_ACTION; +import static org.hibernate.cfg.AvailableSettings.JAKARTA_HBM2DDL_SCRIPTS_CREATE_TARGET; +import static org.hibernate.cfg.AvailableSettings.JAKARTA_HBM2DDL_SCRIPTS_DROP_TARGET; /** * Responsible for coordinating SchemaManagementTool execution(s) for auto-tooling whether @@ -394,17 +402,29 @@ private static class CreateSettingSelector implements SettingSelector { @Override public Object getSourceTypeSetting(Map configurationValues) { - return configurationValues.get( HBM2DDL_CREATE_SOURCE ); + Object setting = configurationValues.get( HBM2DDL_CREATE_SOURCE ); + if ( setting == null ) { + setting = configurationValues.get( JAKARTA_HBM2DDL_CREATE_SOURCE ); + } + return setting; } @Override public Object getScriptSourceSetting(Map configurationValues) { - return configurationValues.get( HBM2DDL_CREATE_SCRIPT_SOURCE ); + Object setting = configurationValues.get( HBM2DDL_CREATE_SCRIPT_SOURCE ); + if ( setting == null ) { + setting = configurationValues.get( JAKARTA_HBM2DDL_CREATE_SCRIPT_SOURCE ); + } + return setting; } @Override public Object getScriptTargetSetting(Map configurationValues) { - return configurationValues.get( HBM2DDL_SCRIPTS_CREATE_TARGET ); + Object setting = configurationValues.get( HBM2DDL_SCRIPTS_CREATE_TARGET ); + if ( setting == null ) { + setting = configurationValues.get( JAKARTA_HBM2DDL_SCRIPTS_CREATE_TARGET ); + } + return setting; } } @@ -416,17 +436,29 @@ private static class DropSettingSelector implements SettingSelector { @Override public Object getSourceTypeSetting(Map configurationValues) { - return configurationValues.get( HBM2DDL_DROP_SOURCE ); + Object setting = configurationValues.get( HBM2DDL_DROP_SOURCE ); + if ( setting == null ) { + setting = configurationValues.get( JAKARTA_HBM2DDL_DROP_SOURCE ); + } + return setting; } @Override public Object getScriptSourceSetting(Map configurationValues) { - return configurationValues.get( HBM2DDL_DROP_SCRIPT_SOURCE ); + Object setting = configurationValues.get( HBM2DDL_DROP_SCRIPT_SOURCE ); + if ( setting == null ) { + setting = configurationValues.get( JAKARTA_HBM2DDL_DROP_SCRIPT_SOURCE ); + } + return setting; } @Override public Object getScriptTargetSetting(Map configurationValues) { - return configurationValues.get( HBM2DDL_SCRIPTS_DROP_TARGET ); + Object setting = configurationValues.get( HBM2DDL_SCRIPTS_DROP_TARGET ); + if ( setting == null ) { + setting = configurationValues.get( JAKARTA_HBM2DDL_SCRIPTS_DROP_TARGET ); + } + return setting; } } @@ -454,7 +486,11 @@ public Object getScriptSourceSetting(Map configurationValues) { @Override public Object getScriptTargetSetting(Map configurationValues) { // for now, reuse the CREATE script target setting - return configurationValues.get( HBM2DDL_SCRIPTS_CREATE_TARGET ); + Object setting = configurationValues.get( HBM2DDL_SCRIPTS_CREATE_TARGET ); + if ( setting == null ) { + setting = configurationValues.get( JAKARTA_HBM2DDL_SCRIPTS_CREATE_TARGET ); + } + return setting; } } @@ -481,9 +517,17 @@ public Action getScriptAction() { } public static ActionGrouping interpret(Map configurationValues) { + Object databaseActionSetting = configurationValues.get( HBM2DDL_DATABASE_ACTION ); + Object scriptsActionSetting = configurationValues.get( HBM2DDL_SCRIPTS_ACTION ); + if ( databaseActionSetting == null ) { + databaseActionSetting = configurationValues.get( JAKARTA_HBM2DDL_DATABASE_ACTION ); + } + if ( scriptsActionSetting == null ) { + scriptsActionSetting = configurationValues.get( JAKARTA_HBM2DDL_SCRIPTS_ACTION ); + } // interpret the JPA settings first - Action databaseAction = Action.interpretJpaSetting( configurationValues.get( HBM2DDL_DATABASE_ACTION ) ); - Action scriptAction = Action.interpretJpaSetting( configurationValues.get( HBM2DDL_SCRIPTS_ACTION ) ); + Action databaseAction = Action.interpretJpaSetting( databaseActionSetting ); + Action scriptAction = Action.interpretJpaSetting( scriptsActionSetting ); // if no JPA settings were specified, look at the legacy HBM2DDL_AUTO setting... if ( databaseAction == Action.NONE && scriptAction == Action.NONE ) { From eb8b8620d7eee974b37ee421eb8044f4e818c5ff Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Tue, 20 Apr 2021 13:27:22 +0200 Subject: [PATCH 130/644] HHH-14274 Support for jakarta prefixed String properties for integrations --- .../BeanValidationIntegrator.java | 16 ++++++++-- .../beanvalidation/GroupsPerOperation.java | 22 +++++++++---- .../cfg/beanvalidation/TypeSafeActivator.java | 31 ++++++++++++++++--- .../spi/ManagedBeanRegistryInitiator.java | 7 ++++- 4 files changed, 62 insertions(+), 14 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/beanvalidation/BeanValidationIntegrator.java b/hibernate-core/src/main/java/org/hibernate/cfg/beanvalidation/BeanValidationIntegrator.java index f2524f714422..7ef254e5f52f 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/beanvalidation/BeanValidationIntegrator.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/beanvalidation/BeanValidationIntegrator.java @@ -33,8 +33,10 @@ public class BeanValidationIntegrator implements Integrator { public static final String APPLY_CONSTRAINTS = "hibernate.validator.apply_to_ddl"; public static final String BV_CHECK_CLASS = "javax.validation.ConstraintViolation"; + public static final String JAKARTA_BV_CHECK_CLASS = "jakarta.validation.ConstraintViolation"; public static final String MODE_PROPERTY = "javax.persistence.validation.mode"; + public static final String JAKARTA_MODE_PROPERTY = "jakarta.persistence.validation.mode"; private static final String ACTIVATOR_CLASS_NAME = "org.hibernate.cfg.beanvalidation.TypeSafeActivator"; private static final String VALIDATE_SUPPLIED_FACTORY_METHOD_NAME = "validateSuppliedFactory"; @@ -87,7 +89,11 @@ public void integrate( final SessionFactoryServiceRegistry serviceRegistry) { final ConfigurationService cfgService = serviceRegistry.getService( ConfigurationService.class ); // IMPL NOTE : see the comments on ActivationContext.getValidationModes() as to why this is multi-valued... - final Set modes = ValidationMode.getModes( cfgService.getSettings().get( MODE_PROPERTY ) ); + Object modeSetting = cfgService.getSettings().get( MODE_PROPERTY ); + if ( modeSetting == null ) { + modeSetting = cfgService.getSettings().get( JAKARTA_MODE_PROPERTY ); + } + final Set modes = ValidationMode.getModes( modeSetting ); if ( modes.size() > 1 ) { LOG.multipleValidationModes( ValidationMode.loggable( modes ) ); } @@ -157,7 +163,13 @@ private boolean isBeanValidationApiAvailable(ClassLoaderService classLoaderServi return true; } catch (Exception e) { - return false; + try { + classLoaderService.classForName( JAKARTA_BV_CHECK_CLASS ); + return true; + } + catch (Exception e2) { + return false; + } } } diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/beanvalidation/GroupsPerOperation.java b/hibernate-core/src/main/java/org/hibernate/cfg/beanvalidation/GroupsPerOperation.java index 525bc86b58e4..7776982c9739 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/beanvalidation/GroupsPerOperation.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/beanvalidation/GroupsPerOperation.java @@ -21,6 +21,7 @@ */ public class GroupsPerOperation { private static final String JPA_GROUP_PREFIX = "javax.persistence.validation.group."; + private static final String JAKARTA_JPA_GROUP_PREFIX = "javax.persistence.validation.group."; private static final String HIBERNATE_GROUP_PREFIX = "org.hibernate.validator.group."; private static final Class[] DEFAULT_GROUPS = new Class[] { Default.class }; @@ -54,7 +55,10 @@ private static void applyOperationGrouping( } public static Class[] buildGroupsForOperation(Operation operation, Map settings, ClassLoaderAccess classLoaderAccess) { - final Object property = settings.get( operation.getGroupPropertyName() ); + Object property = settings.get( operation.getGroupPropertyName() ); + if ( property == null ) { + property = settings.get( operation.getJakartaGroupPropertyName() ); + } if ( property == null ) { return operation == Operation.DELETE ? EMPTY_GROUPS : DEFAULT_GROUPS; @@ -95,18 +99,20 @@ public Class[] get(Operation operation) { } public static enum Operation { - INSERT("persist", JPA_GROUP_PREFIX + "pre-persist"), - UPDATE("update", JPA_GROUP_PREFIX + "pre-update"), - DELETE("remove", JPA_GROUP_PREFIX + "pre-remove"), - DDL("ddl", HIBERNATE_GROUP_PREFIX + "ddl"); + INSERT( "persist", JPA_GROUP_PREFIX + "pre-persist", JAKARTA_JPA_GROUP_PREFIX + "pre-persist" ), + UPDATE( "update", JPA_GROUP_PREFIX + "pre-update", JAKARTA_JPA_GROUP_PREFIX + "pre-update" ), + DELETE( "remove", JPA_GROUP_PREFIX + "pre-remove", JAKARTA_JPA_GROUP_PREFIX + "pre-remove" ), + DDL( "ddl", HIBERNATE_GROUP_PREFIX + "ddl", HIBERNATE_GROUP_PREFIX + "ddl" ); private final String exposedName; private final String groupPropertyName; + private final String jakartaGroupPropertyName; - Operation(String exposedName, String groupProperty) { + Operation(String exposedName, String groupProperty, String jakartaGroupPropertyName) { this.exposedName = exposedName; this.groupPropertyName = groupProperty; + this.jakartaGroupPropertyName = jakartaGroupPropertyName; } public String getName() { @@ -116,6 +122,10 @@ public String getName() { public String getGroupPropertyName() { return groupPropertyName; } + + public String getJakartaGroupPropertyName() { + return jakartaGroupPropertyName; + } } } diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/beanvalidation/TypeSafeActivator.java b/hibernate-core/src/main/java/org/hibernate/cfg/beanvalidation/TypeSafeActivator.java index c75ea495cc00..60c874da6ba3 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/beanvalidation/TypeSafeActivator.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/beanvalidation/TypeSafeActivator.java @@ -33,6 +33,7 @@ import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; import org.hibernate.boot.spi.ClassLoaderAccess; import org.hibernate.boot.spi.SessionFactoryOptions; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.Environment; import org.hibernate.dialect.Dialect; import org.hibernate.engine.config.spi.ConfigurationService; @@ -60,8 +61,6 @@ class TypeSafeActivator { private static final CoreMessageLogger LOG = Logger.getMessageLogger(CoreMessageLogger.class, TypeSafeActivator.class.getName()); - private static final String FACTORY_PROPERTY = "javax.persistence.validation.factory"; - /** * Used to validate a supplied ValidatorFactory instance as being castable to ValidatorFactory. * @@ -532,7 +531,7 @@ private static ValidatorFactory resolveProvidedFactory(SessionFactoryOptions opt @SuppressWarnings("unchecked") private static ValidatorFactory resolveProvidedFactory(ConfigurationService cfgService) { return cfgService.getSetting( - FACTORY_PROPERTY, + AvailableSettings.JPA_VALIDATION_FACTORY, new ConfigurationService.Converter() { @Override public ValidatorFactory convert(Object value) { @@ -544,7 +543,7 @@ public ValidatorFactory convert(Object value) { String.format( Locale.ENGLISH, "ValidatorFactory reference (provided via `%s` setting) was not castable to %s : %s", - FACTORY_PROPERTY, + AvailableSettings.JPA_VALIDATION_FACTORY, ValidatorFactory.class.getName(), value.getClass().getName() ) @@ -552,7 +551,29 @@ public ValidatorFactory convert(Object value) { } } }, - null + cfgService.getSetting( + AvailableSettings.JAKARTA_JPA_VALIDATION_FACTORY, + new ConfigurationService.Converter() { + @Override + public ValidatorFactory convert(Object value) { + try { + return ValidatorFactory.class.cast( value ); + } + catch ( ClassCastException e ) { + throw new IntegrationException( + String.format( + Locale.ENGLISH, + "ValidatorFactory reference (provided via `%s` setting) was not castable to %s : %s", + AvailableSettings.JAKARTA_JPA_VALIDATION_FACTORY, + ValidatorFactory.class.getName(), + value.getClass().getName() + ) + ); + } + } + }, + null + ) ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/resource/beans/spi/ManagedBeanRegistryInitiator.java b/hibernate-core/src/main/java/org/hibernate/resource/beans/spi/ManagedBeanRegistryInitiator.java index 119ea6f9dae4..105edf75acad 100644 --- a/hibernate-core/src/main/java/org/hibernate/resource/beans/spi/ManagedBeanRegistryInitiator.java +++ b/hibernate-core/src/main/java/org/hibernate/resource/beans/spi/ManagedBeanRegistryInitiator.java @@ -129,7 +129,12 @@ private static boolean isCdiAvailable(ClassLoaderService classLoaderService) { } public static Class cdiBeanManagerClass(ClassLoaderService classLoaderService) throws ClassLoadingException { - return classLoaderService.classForName( "javax.enterprise.inject.spi.BeanManager" ); + try { + return classLoaderService.classForName( "javax.enterprise.inject.spi.BeanManager" ); + } + catch (ClassLoadingException e) { + return classLoaderService.classForName( "jakarta.enterprise.inject.spi.BeanManager" ); + } } } From ff9e9eebc9992c7bc9128e9bf33d4b51b2bee7a4 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Thu, 22 Apr 2021 18:15:45 +0200 Subject: [PATCH 131/644] HHH-13946 Create Jakarta artifacts for hibernate-core, hibernate-envers, hibernate-jpamodelgen and hibernate-testing --- build.gradle | 1 + gradle/libraries.gradle | 28 +- .../hibernate-core-jakarta.gradle | 182 ++++++++++++ hibernate-core/hibernate-core.gradle | 6 +- .../cfgxmlpar/META-INF/persistence.xml | 0 .../jpa/test/pack/cfgxmlpar/hibernate.cfg.xml | 0 .../defaultpar/META-INF/orm.xml | 0 .../defaultpar/META-INF/persistence.xml | 0 .../jpa/test/pack/defaultpar/Mouse.hbm.xml | 0 .../defaultpar_1_0/META-INF/orm.xml | 0 .../defaultpar_1_0/META-INF/persistence.xml | 0 .../test/pack/defaultpar_1_0/Mouse1.hbm.xml | 0 .../excludehbmpar/META-INF/orm2.xml | 0 .../excludehbmpar/META-INF/persistence.xml | 0 .../jpa/test/pack/excludehbmpar/Mouse.hbm.xml | 0 .../explicitpar/META-INF/orm.xml | 0 .../explicitpar/META-INF/persistence.xml | 0 .../explicitpar2/META-INF/orm.xml | 0 .../explicitpar2/META-INF/persistence.xml | 0 .../explodedpar/META-INF/persistence.xml | 0 .../test/pack/explodedpar/Elephant.hbm.xml | 0 .../externaljar/META-INF/orm.xml | 0 .../overridenpar/META-INF/persistence.xml | 0 .../overridenpar/overridenpar.properties | 0 .../space par/META-INF/persistence.xml | 0 .../war/WEB-INF/classes/META-INF/orm.xml | 0 .../WEB-INF/classes/META-INF/persistence.xml | 0 .../hibernate/jpa/test/pack/war/Mouse.hbm.xml | 0 .../hibernate-envers-jakarta.gradle | 103 +++++++ hibernate-envers/hibernate-envers.gradle | 16 ++ .../hibernate-jboss-jta.gradle | 64 +++++ .../hibernate-testing-jakarta.gradle | 83 ++++++ hibernate-testing/hibernate-testing.gradle | 3 + .../hibernate-transaction-client.gradle | 62 +++++ .../hibernate-transaction-spi.gradle | 62 +++++ rules/jakarta-direct-modelgen.properties | 34 +++ rules/jakarta-direct.properties | 12 + rules/jakarta-renames.properties | 260 ++++++++++++++++++ rules/jakarta-versions.properties | 223 +++++++++++++++ settings.gradle | 12 + .../hibernate-jpamodelgen-jakarta.gradle | 68 +++++ .../hibernate/jpamodelgen/ClassWriter.java | 2 +- .../org/hibernate/jpamodelgen/Context.java | 12 +- 43 files changed, 1224 insertions(+), 9 deletions(-) create mode 100644 hibernate-core-jakarta/hibernate-core-jakarta.gradle rename hibernate-core/src/test/bundles/{ => templates}/cfgxmlpar/META-INF/persistence.xml (100%) rename hibernate-core/src/test/bundles/{ => templates}/cfgxmlpar/org/hibernate/jpa/test/pack/cfgxmlpar/hibernate.cfg.xml (100%) rename hibernate-core/src/test/bundles/{ => templates}/defaultpar/META-INF/orm.xml (100%) rename hibernate-core/src/test/bundles/{ => templates}/defaultpar/META-INF/persistence.xml (100%) rename hibernate-core/src/test/bundles/{ => templates}/defaultpar/org/hibernate/jpa/test/pack/defaultpar/Mouse.hbm.xml (100%) rename hibernate-core/src/test/bundles/{ => templates}/defaultpar_1_0/META-INF/orm.xml (100%) rename hibernate-core/src/test/bundles/{ => templates}/defaultpar_1_0/META-INF/persistence.xml (100%) rename hibernate-core/src/test/bundles/{ => templates}/defaultpar_1_0/org/hibernate/jpa/test/pack/defaultpar_1_0/Mouse1.hbm.xml (100%) rename hibernate-core/src/test/bundles/{ => templates}/excludehbmpar/META-INF/orm2.xml (100%) rename hibernate-core/src/test/bundles/{ => templates}/excludehbmpar/META-INF/persistence.xml (100%) rename hibernate-core/src/test/bundles/{ => templates}/excludehbmpar/org/hibernate/jpa/test/pack/excludehbmpar/Mouse.hbm.xml (100%) rename hibernate-core/src/test/bundles/{ => templates}/explicitpar/META-INF/orm.xml (100%) rename hibernate-core/src/test/bundles/{ => templates}/explicitpar/META-INF/persistence.xml (100%) rename hibernate-core/src/test/bundles/{ => templates}/explicitpar2/META-INF/orm.xml (100%) rename hibernate-core/src/test/bundles/{ => templates}/explicitpar2/META-INF/persistence.xml (100%) rename hibernate-core/src/test/bundles/{ => templates}/explodedpar/META-INF/persistence.xml (100%) rename hibernate-core/src/test/bundles/{ => templates}/explodedpar/org/hibernate/jpa/test/pack/explodedpar/Elephant.hbm.xml (100%) rename hibernate-core/src/test/bundles/{ => templates}/externaljar/META-INF/orm.xml (100%) rename hibernate-core/src/test/bundles/{ => templates}/overridenpar/META-INF/persistence.xml (100%) rename hibernate-core/src/test/bundles/{ => templates}/overridenpar/overridenpar.properties (100%) rename hibernate-core/src/test/bundles/{ => templates}/space par/META-INF/persistence.xml (100%) rename hibernate-core/src/test/bundles/{ => templates}/war/WEB-INF/classes/META-INF/orm.xml (100%) rename hibernate-core/src/test/bundles/{ => templates}/war/WEB-INF/classes/META-INF/persistence.xml (100%) rename hibernate-core/src/test/bundles/{ => templates}/war/WEB-INF/classes/org/hibernate/jpa/test/pack/war/Mouse.hbm.xml (100%) create mode 100644 hibernate-envers-jakarta/hibernate-envers-jakarta.gradle create mode 100644 hibernate-jboss-jta/hibernate-jboss-jta.gradle create mode 100644 hibernate-testing-jakarta/hibernate-testing-jakarta.gradle create mode 100644 hibernate-transaction-client/hibernate-transaction-client.gradle create mode 100644 hibernate-transaction-spi/hibernate-transaction-spi.gradle create mode 100644 rules/jakarta-direct-modelgen.properties create mode 100644 rules/jakarta-direct.properties create mode 100644 rules/jakarta-renames.properties create mode 100644 rules/jakarta-versions.properties create mode 100644 tooling/metamodel-generator-jakarta/hibernate-jpamodelgen-jakarta.gradle diff --git a/build.gradle b/build.gradle index 3690ac49ff35..15ab92bf1c80 100644 --- a/build.gradle +++ b/build.gradle @@ -43,6 +43,7 @@ ext { ormVersion = new HibernateVersion( project.releaseVersion, project ) } jpaVersion = new JpaVersion('2.2') + jakartaJpaVersion = new JpaVersion('3.0.0') } // The Gradle Nexus Publish Plugin must be applied to the root project and requires group and version diff --git a/gradle/libraries.gradle b/gradle/libraries.gradle index c97a65f5b4ca..9b82ada14cfa 100644 --- a/gradle/libraries.gradle +++ b/gradle/libraries.gradle @@ -18,9 +18,11 @@ ext { hibernateValidatorVersion = '6.1.6.Final' validationApiVersion = '2.0.1.Final' elVersion = '3.0.1-b09' + hibernateValidatorJakartaVersion = '7.0.1.Final' cdiVersion = '2.0' weldVersion = '3.1.5.Final' + jakartaWeldVersion = '4.0.1.SP1' javassistVersion = '3.27.0-GA' byteBuddyVersion = '1.10.21' @@ -40,6 +42,7 @@ ext { // We can't upgrade JAXB in Karaf (yet), but fortunately everything works fine with the version built in Karaf jaxbApiVersionOsgiRange = "[2.2,3)" jaxbRuntimeVersion = '2.3.1' + jakartaJaxbRuntimeVersion = '3.0.0' //GraalVM graalvmVersion = '19.3.1' @@ -76,6 +79,18 @@ ext { // required by JAXB from JDK 9 as it is not available anymore in JDK 9 activation: 'javax.activation:javax.activation-api:1.2.0', + // jakarta + jakarta_jpa: "jakarta.persistence:jakarta.persistence-api:${project.jakartaJpaVersion}", + jakarta_jta: 'jakarta.transaction:jakarta.transaction-api:2.0.0', + jakarta_validation: 'jakarta.validation:jakarta.validation-api:3.0.0', + jakarta_jacc: 'jakarta.authorization:jakarta.authorization-api:2.0.0', + jakarta_interceptor: 'jakarta.interceptor:jakarta.interceptor-api:2.0.0', + jakarta_activation: 'jakarta.activation:jakarta.activation-api:2.0.1', + jakarta_resource: 'jakarta.resource:jakarta.resource-api:2.0.0', + jakarta_jaxb_api: 'jakarta.xml.bind:jakarta.xml.bind-api:3.0.0', + jakarta_jaxb_runtime: "org.glassfish.jaxb:jaxb-runtime:${jakartaJaxbRuntimeVersion}", + jakarta_cdi: 'jakarta.enterprise:jakarta.enterprise.cdi-api:3.0.0', + // logging logging: 'org.jboss.logging:jboss-logging:3.4.1.Final', logging_annotations: 'org.jboss.logging:jboss-logging-annotations:2.1.0.Final', @@ -126,7 +141,11 @@ ext { jodaTime: "joda-time:joda-time:${jodaTimeVersion}", informix: 'com.ibm.informix:jdbc:4.10.12', - jboss_jta: "org.jboss.jbossts:jbossjta:4.16.4.Final", + jboss_jta: "org.jboss.narayana.jta:narayana-jta:5.11.1.Final", + jboss_tx_spi: "org.jboss:jboss-transaction-spi:7.6.0.Final", + // todo (jakarta): update the version when it is released + jboss_jta_jakarta: "org.jboss.narayana.jta:narayana-jta-jakarta:5.11.2.Final", + jboss_tx_spi_jakarta: "org.jboss:jboss-transaction-spi-jakarta:7.6.1.Final", xapool: "com.experlog:xapool:1.5.0", mockito: 'org.mockito:mockito-core:2.19.1', mockito_inline: 'org.mockito:mockito-inline:2.19.1', @@ -135,6 +154,10 @@ ext { // EL required by Hibernate Validator at test runtime expression_language: "org.glassfish:javax.el:${elVersion}", + jakarta_validator:"org.hibernate.validator:hibernate-validator:${hibernateValidatorJakartaVersion}", + // EL required by Hibernate Validator at test runtime + jakarta_el: 'org.glassfish:jakarta.el:4.0.1', + c3p0: "com.mchange:c3p0:0.9.5.5", ehcache: "net.sf.ehcache:ehcache:2.10.6", ehcache3: "org.ehcache:ehcache:3.6.1", @@ -151,6 +174,7 @@ ext { cdi: "javax.enterprise:cdi-api:${cdiVersion}", weld: "org.jboss.weld.se:weld-se-shaded:${weldVersion}", + jakarta_weld: "org.jboss.weld.se:weld-se-shaded:${jakartaWeldVersion}", assertj: "org.assertj:assertj-core:${assertjVersion}", @@ -163,6 +187,8 @@ ext { jboss_vfs: "org.jboss:jboss-vfs:3.2.11.Final", wildfly_transaction_client : 'org.wildfly.transaction:wildfly-transaction-client:1.1.7.Final', + // todo (jakarta): update the version when it is released + wildfly_transaction_client_jakarta : 'org.wildfly.transaction:wildfly-transaction-client-jakarta:1.2.0.Final-SNAPSHOT', jboss_ejb_spec_jar : 'org.jboss.spec.javax.ejb:jboss-ejb-api_3.2_spec:1.0.0.Final', jboss_annotation_spec_jar : 'org.jboss.spec.javax.annotation:jboss-annotations-api_1.2_spec:1.0.0.Final', diff --git a/hibernate-core-jakarta/hibernate-core-jakarta.gradle b/hibernate-core-jakarta/hibernate-core-jakarta.gradle new file mode 100644 index 000000000000..156d80a2694a --- /dev/null +++ b/hibernate-core-jakarta/hibernate-core-jakarta.gradle @@ -0,0 +1,182 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ + +import org.apache.tools.ant.filters.ReplaceTokens + +description = 'Hibernate O/RM implementation of the Jakarta Persistence specification' + +apply from: rootProject.file( 'gradle/published-java-module.gradle' ) + +configurations { + tests { + description = 'Configuration for the produced test jar' + } + jakartaeeTransformJars +} + +dependencies { + compile( libraries.jakarta_jpa ) + // This can now be made provided + compile( libraries.javassist ) + // Could be made optional? + compile( libraries.byteBuddy ) + compile( libraries.antlr ) + compile( libraries.jakarta_jta ) + compile( libraries.jandex ) + compile( libraries.classmate ) + compile( libraries.jakarta_activation ) + + provided( libraries.jakarta_jacc ) + provided( libraries.jakarta_validation ) + provided( libraries.ant ) + provided( libraries.jakarta_cdi ) + + compile( libraries.dom4j ) + compile( libraries.commons_annotations ) + + compile( libraries.jakarta_jaxb_api ) + compile( libraries.jakarta_jaxb_runtime ) + + jakartaeeTransformJars 'biz.aQute.bnd:biz.aQute.bnd.transform:5.1.1', + 'commons-cli:commons-cli:1.4', + 'org.slf4j:slf4j-simple:1.7.30', + 'org.slf4j:slf4j-api:1.7.26', + 'org.eclipse.transformer:org.eclipse.transformer:0.2.0', + 'org.eclipse.transformer:org.eclipse.transformer.cli:0.2.0' + testCompile( project(':hibernate-testing-jakarta') ) + testCompile fileTree(dir: 'libs', include: '*.jar') + + testCompile( libraries.shrinkwrap_api ) + testCompile( libraries.shrinkwrap ) + testCompile( libraries.jakarta_jacc ) + testCompile( libraries.jakarta_validation ) + testCompile( libraries.jandex ) + testCompile( libraries.classmate ) + testCompile( libraries.mockito ) + testCompile( libraries.mockito_inline ) + testCompile( libraries.jodaTime ) + testCompile( libraries.assertj ) + + testCompile( libraries.jakarta_cdi ) + + testCompile( libraries.jakarta_validator ) { + // for test runtime + transitive = true + } + + // for testing stored procedure support + testCompile( libraries.derby ) + + testRuntime( "org.jboss.spec.javax.ejb:jboss-ejb-api_3.2_spec:1.0.0.Final" ) + testRuntime( libraries.jakarta_el ) + testRuntime( 'jaxen:jaxen:1.1' ) + testRuntime( libraries.javassist ) + testRuntime( libraries.byteBuddy ) + testRuntime( libraries.jakarta_weld ) + testRuntime( libraries.atomikos ) + testRuntime( libraries.atomikos_jta ) +// todo (jakarta): replace this when the jakarta artifact is released + testRuntime( project(':hibernate-transaction-client') ) +// testRuntime( libraries.wildfly_transaction_client_jakarta ) + + testCompile libraries.shrinkwrap_descriptors_api_javaee + testCompile libraries.shrinkwrap_descriptors_impl_javaee + + testCompile libraries.jboss_ejb_spec_jar + testCompile libraries.jboss_annotation_spec_jar +} + +jar { + mustRunAfter project(':hibernate-core').tasks.jar + mustRunAfter project(':hibernate-core').tasks.testJar + dependsOn project(':hibernate-core').tasks.jar + dependsOn project(':hibernate-core').tasks.testJar + def baseDir = project(':hibernate-core').buildDir + def baseJars = fileTree(baseDir).matching {include 'libs/*.jar' } + inputs.files(baseJars).skipWhenEmpty() + outputs.dir project.buildDir + doLast { + new File(project.buildDir, "libs").mkdirs() + fileTree(project.buildDir).matching { include 'libs/*.jar' }.each { delete it } + + baseJars.each { bundleJar -> + def sourceJarPath = baseDir.path + '/libs/' + bundleJar.name + println 'Initial bundle jar name [ ' + sourceJarPath + ' ]' + + def finalBundleJarName = project.buildDir.path + '/libs/' + bundleJar.name.replaceAll( 'hibernate-core', 'hibernate-core-jakarta' ) + println 'Default jakarta final bundle jar name [ ' + finalBundleJarName + ' ]' + + def transformerArgs = [ + sourceJarPath, finalBundleJarName, + '-q', // quiet output + '-tr', new File(getProjectDir().getParentFile(), 'rules/jakarta-renames.properties').path, + '-tv', new File(getProjectDir().getParentFile(), 'rules/jakarta-versions.properties').path, + '-td', new File(getProjectDir().getParentFile(), 'rules/jakarta-direct.properties').path, + ] + + println 'Transformer options:' + transformerArgs.each { + println ' [ ' + it + ' ]' + } + + javaexec { + classpath configurations.jakartaeeTransformJars + main = 'org.eclipse.transformer.jakarta.JakartaTransformer' + args = transformerArgs + } + } + } +} + +task unpackTestJar(type: Copy) { + dependsOn jar + fileTree(project.buildDir).matching { include 'libs/*-test.jar' }.each { + def outputDir = file("${buildDir}/unpacked/" + it.name) + from zipTree(it) + into outputDir + } +} + +task copyBundleResources (type: Copy) { + dependsOn unpackTestJar + File unpackedDir = new File(project.buildDir, "libs/hibernate-core-jakarta-${project.version}-test.jar") + ext { + bundlesTargetDir = file( "${buildDir}/bundles" ) + bundleTokens = dbBundle[db] + ext.bundleTokens['buildDirName'] = buildDir.absolutePath + } + + from file("${buildDir}/unpacked/${unpackedDir.name}/templates") + into ext.bundlesTargetDir + filter( ReplaceTokens, tokens: ext.bundleTokens) + doFirst { + ext.bundlesTargetDir.mkdirs() + } +} + +processTestResources.dependsOn copyBundleResources + +artifacts { + tests new File(project.buildDir, "libs/hibernate-core-jakarta-${project.version}-test.jar") +} + +test { + fileTree(project.buildDir).matching { include 'libs/*-test.jar' }.each { + def outputDir = file("${buildDir}/unpacked/" + it.name) + testClassesDirs += files(outputDir) + classpath += files(outputDir) + } + systemProperty 'file.encoding', 'utf-8' + + if ( gradle.ext.javaVersions.test.launcher.asInt() >= 9 ) { + // See org.hibernate.boot.model.naming.NamingHelperTest.DefaultCharset.set + jvmArgs( ['--add-opens', 'java.base/java.nio.charset=ALL-UNNAMED'] ) + // Weld needs this to generate proxies + jvmArgs( ['--add-opens', 'java.base/java.security=ALL-UNNAMED'] ) + jvmArgs( ['--add-opens', 'java.base/java.lang=ALL-UNNAMED'] ) + } +} \ No newline at end of file diff --git a/hibernate-core/hibernate-core.gradle b/hibernate-core/hibernate-core.gradle index c47a0466ea77..069335b2b74b 100644 --- a/hibernate-core/hibernate-core.gradle +++ b/hibernate-core/hibernate-core.gradle @@ -25,7 +25,7 @@ sourceSets { // resources inherently exclude sources test { resources { - setSrcDirs( ['src/test/java','src/test/resources'] ) + setSrcDirs( ['src/test/java','src/test/resources','src/test/bundles'] ) } } @@ -145,6 +145,7 @@ jar { // For JPA, we don't want to target the automatically generated range, but a specific version "javax.persistence;version=\"${project.jpaVersion.osgiName}\"", // optionals + 'jakarta.persistence.spi;resolution:=optional', 'javax.management;resolution:=optional', 'javax.naming.event;resolution:=optional', 'javax.naming.spi;resolution:=optional', @@ -218,7 +219,7 @@ task copyBundleResources (type: Copy) { ext.bundleTokens['buildDirName'] = buildDir.absolutePath } - from file('src/test/bundles') + from file('src/test/bundles/templates') into ext.bundlesTargetDir filter( ReplaceTokens, tokens: ext.bundleTokens) @@ -229,6 +230,7 @@ task copyBundleResources (type: Copy) { processTestResources.dependsOn copyBundleResources task testJar(type: Jar, dependsOn: testClasses) { + duplicatesStrategy = DuplicatesStrategy.EXCLUDE archiveClassifier.set( 'test' ) from sourceSets.test.output } diff --git a/hibernate-core/src/test/bundles/cfgxmlpar/META-INF/persistence.xml b/hibernate-core/src/test/bundles/templates/cfgxmlpar/META-INF/persistence.xml similarity index 100% rename from hibernate-core/src/test/bundles/cfgxmlpar/META-INF/persistence.xml rename to hibernate-core/src/test/bundles/templates/cfgxmlpar/META-INF/persistence.xml diff --git a/hibernate-core/src/test/bundles/cfgxmlpar/org/hibernate/jpa/test/pack/cfgxmlpar/hibernate.cfg.xml b/hibernate-core/src/test/bundles/templates/cfgxmlpar/org/hibernate/jpa/test/pack/cfgxmlpar/hibernate.cfg.xml similarity index 100% rename from hibernate-core/src/test/bundles/cfgxmlpar/org/hibernate/jpa/test/pack/cfgxmlpar/hibernate.cfg.xml rename to hibernate-core/src/test/bundles/templates/cfgxmlpar/org/hibernate/jpa/test/pack/cfgxmlpar/hibernate.cfg.xml diff --git a/hibernate-core/src/test/bundles/defaultpar/META-INF/orm.xml b/hibernate-core/src/test/bundles/templates/defaultpar/META-INF/orm.xml similarity index 100% rename from hibernate-core/src/test/bundles/defaultpar/META-INF/orm.xml rename to hibernate-core/src/test/bundles/templates/defaultpar/META-INF/orm.xml diff --git a/hibernate-core/src/test/bundles/defaultpar/META-INF/persistence.xml b/hibernate-core/src/test/bundles/templates/defaultpar/META-INF/persistence.xml similarity index 100% rename from hibernate-core/src/test/bundles/defaultpar/META-INF/persistence.xml rename to hibernate-core/src/test/bundles/templates/defaultpar/META-INF/persistence.xml diff --git a/hibernate-core/src/test/bundles/defaultpar/org/hibernate/jpa/test/pack/defaultpar/Mouse.hbm.xml b/hibernate-core/src/test/bundles/templates/defaultpar/org/hibernate/jpa/test/pack/defaultpar/Mouse.hbm.xml similarity index 100% rename from hibernate-core/src/test/bundles/defaultpar/org/hibernate/jpa/test/pack/defaultpar/Mouse.hbm.xml rename to hibernate-core/src/test/bundles/templates/defaultpar/org/hibernate/jpa/test/pack/defaultpar/Mouse.hbm.xml diff --git a/hibernate-core/src/test/bundles/defaultpar_1_0/META-INF/orm.xml b/hibernate-core/src/test/bundles/templates/defaultpar_1_0/META-INF/orm.xml similarity index 100% rename from hibernate-core/src/test/bundles/defaultpar_1_0/META-INF/orm.xml rename to hibernate-core/src/test/bundles/templates/defaultpar_1_0/META-INF/orm.xml diff --git a/hibernate-core/src/test/bundles/defaultpar_1_0/META-INF/persistence.xml b/hibernate-core/src/test/bundles/templates/defaultpar_1_0/META-INF/persistence.xml similarity index 100% rename from hibernate-core/src/test/bundles/defaultpar_1_0/META-INF/persistence.xml rename to hibernate-core/src/test/bundles/templates/defaultpar_1_0/META-INF/persistence.xml diff --git a/hibernate-core/src/test/bundles/defaultpar_1_0/org/hibernate/jpa/test/pack/defaultpar_1_0/Mouse1.hbm.xml b/hibernate-core/src/test/bundles/templates/defaultpar_1_0/org/hibernate/jpa/test/pack/defaultpar_1_0/Mouse1.hbm.xml similarity index 100% rename from hibernate-core/src/test/bundles/defaultpar_1_0/org/hibernate/jpa/test/pack/defaultpar_1_0/Mouse1.hbm.xml rename to hibernate-core/src/test/bundles/templates/defaultpar_1_0/org/hibernate/jpa/test/pack/defaultpar_1_0/Mouse1.hbm.xml diff --git a/hibernate-core/src/test/bundles/excludehbmpar/META-INF/orm2.xml b/hibernate-core/src/test/bundles/templates/excludehbmpar/META-INF/orm2.xml similarity index 100% rename from hibernate-core/src/test/bundles/excludehbmpar/META-INF/orm2.xml rename to hibernate-core/src/test/bundles/templates/excludehbmpar/META-INF/orm2.xml diff --git a/hibernate-core/src/test/bundles/excludehbmpar/META-INF/persistence.xml b/hibernate-core/src/test/bundles/templates/excludehbmpar/META-INF/persistence.xml similarity index 100% rename from hibernate-core/src/test/bundles/excludehbmpar/META-INF/persistence.xml rename to hibernate-core/src/test/bundles/templates/excludehbmpar/META-INF/persistence.xml diff --git a/hibernate-core/src/test/bundles/excludehbmpar/org/hibernate/jpa/test/pack/excludehbmpar/Mouse.hbm.xml b/hibernate-core/src/test/bundles/templates/excludehbmpar/org/hibernate/jpa/test/pack/excludehbmpar/Mouse.hbm.xml similarity index 100% rename from hibernate-core/src/test/bundles/excludehbmpar/org/hibernate/jpa/test/pack/excludehbmpar/Mouse.hbm.xml rename to hibernate-core/src/test/bundles/templates/excludehbmpar/org/hibernate/jpa/test/pack/excludehbmpar/Mouse.hbm.xml diff --git a/hibernate-core/src/test/bundles/explicitpar/META-INF/orm.xml b/hibernate-core/src/test/bundles/templates/explicitpar/META-INF/orm.xml similarity index 100% rename from hibernate-core/src/test/bundles/explicitpar/META-INF/orm.xml rename to hibernate-core/src/test/bundles/templates/explicitpar/META-INF/orm.xml diff --git a/hibernate-core/src/test/bundles/explicitpar/META-INF/persistence.xml b/hibernate-core/src/test/bundles/templates/explicitpar/META-INF/persistence.xml similarity index 100% rename from hibernate-core/src/test/bundles/explicitpar/META-INF/persistence.xml rename to hibernate-core/src/test/bundles/templates/explicitpar/META-INF/persistence.xml diff --git a/hibernate-core/src/test/bundles/explicitpar2/META-INF/orm.xml b/hibernate-core/src/test/bundles/templates/explicitpar2/META-INF/orm.xml similarity index 100% rename from hibernate-core/src/test/bundles/explicitpar2/META-INF/orm.xml rename to hibernate-core/src/test/bundles/templates/explicitpar2/META-INF/orm.xml diff --git a/hibernate-core/src/test/bundles/explicitpar2/META-INF/persistence.xml b/hibernate-core/src/test/bundles/templates/explicitpar2/META-INF/persistence.xml similarity index 100% rename from hibernate-core/src/test/bundles/explicitpar2/META-INF/persistence.xml rename to hibernate-core/src/test/bundles/templates/explicitpar2/META-INF/persistence.xml diff --git a/hibernate-core/src/test/bundles/explodedpar/META-INF/persistence.xml b/hibernate-core/src/test/bundles/templates/explodedpar/META-INF/persistence.xml similarity index 100% rename from hibernate-core/src/test/bundles/explodedpar/META-INF/persistence.xml rename to hibernate-core/src/test/bundles/templates/explodedpar/META-INF/persistence.xml diff --git a/hibernate-core/src/test/bundles/explodedpar/org/hibernate/jpa/test/pack/explodedpar/Elephant.hbm.xml b/hibernate-core/src/test/bundles/templates/explodedpar/org/hibernate/jpa/test/pack/explodedpar/Elephant.hbm.xml similarity index 100% rename from hibernate-core/src/test/bundles/explodedpar/org/hibernate/jpa/test/pack/explodedpar/Elephant.hbm.xml rename to hibernate-core/src/test/bundles/templates/explodedpar/org/hibernate/jpa/test/pack/explodedpar/Elephant.hbm.xml diff --git a/hibernate-core/src/test/bundles/externaljar/META-INF/orm.xml b/hibernate-core/src/test/bundles/templates/externaljar/META-INF/orm.xml similarity index 100% rename from hibernate-core/src/test/bundles/externaljar/META-INF/orm.xml rename to hibernate-core/src/test/bundles/templates/externaljar/META-INF/orm.xml diff --git a/hibernate-core/src/test/bundles/overridenpar/META-INF/persistence.xml b/hibernate-core/src/test/bundles/templates/overridenpar/META-INF/persistence.xml similarity index 100% rename from hibernate-core/src/test/bundles/overridenpar/META-INF/persistence.xml rename to hibernate-core/src/test/bundles/templates/overridenpar/META-INF/persistence.xml diff --git a/hibernate-core/src/test/bundles/overridenpar/overridenpar.properties b/hibernate-core/src/test/bundles/templates/overridenpar/overridenpar.properties similarity index 100% rename from hibernate-core/src/test/bundles/overridenpar/overridenpar.properties rename to hibernate-core/src/test/bundles/templates/overridenpar/overridenpar.properties diff --git a/hibernate-core/src/test/bundles/space par/META-INF/persistence.xml b/hibernate-core/src/test/bundles/templates/space par/META-INF/persistence.xml similarity index 100% rename from hibernate-core/src/test/bundles/space par/META-INF/persistence.xml rename to hibernate-core/src/test/bundles/templates/space par/META-INF/persistence.xml diff --git a/hibernate-core/src/test/bundles/war/WEB-INF/classes/META-INF/orm.xml b/hibernate-core/src/test/bundles/templates/war/WEB-INF/classes/META-INF/orm.xml similarity index 100% rename from hibernate-core/src/test/bundles/war/WEB-INF/classes/META-INF/orm.xml rename to hibernate-core/src/test/bundles/templates/war/WEB-INF/classes/META-INF/orm.xml diff --git a/hibernate-core/src/test/bundles/war/WEB-INF/classes/META-INF/persistence.xml b/hibernate-core/src/test/bundles/templates/war/WEB-INF/classes/META-INF/persistence.xml similarity index 100% rename from hibernate-core/src/test/bundles/war/WEB-INF/classes/META-INF/persistence.xml rename to hibernate-core/src/test/bundles/templates/war/WEB-INF/classes/META-INF/persistence.xml diff --git a/hibernate-core/src/test/bundles/war/WEB-INF/classes/org/hibernate/jpa/test/pack/war/Mouse.hbm.xml b/hibernate-core/src/test/bundles/templates/war/WEB-INF/classes/org/hibernate/jpa/test/pack/war/Mouse.hbm.xml similarity index 100% rename from hibernate-core/src/test/bundles/war/WEB-INF/classes/org/hibernate/jpa/test/pack/war/Mouse.hbm.xml rename to hibernate-core/src/test/bundles/templates/war/WEB-INF/classes/org/hibernate/jpa/test/pack/war/Mouse.hbm.xml diff --git a/hibernate-envers-jakarta/hibernate-envers-jakarta.gradle b/hibernate-envers-jakarta/hibernate-envers-jakarta.gradle new file mode 100644 index 000000000000..66f4b7449307 --- /dev/null +++ b/hibernate-envers-jakarta/hibernate-envers-jakarta.gradle @@ -0,0 +1,103 @@ +import org.apache.tools.ant.filters.ReplaceTokens + +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ + +description = 'Hibernate\'s entity version (audit/history) support Jakarta edition' + +apply from: rootProject.file( 'gradle/published-java-module.gradle' ) + +configurations { + jakartaeeTransformJars +} + +dependencies { + compile( project( ':hibernate-core-jakarta' ) ) { + // Exclude access to this to avoid future use. + exclude group: "org.javassist", module: "javassist" + } + + jakartaeeTransformJars 'biz.aQute.bnd:biz.aQute.bnd.transform:5.1.1', + 'commons-cli:commons-cli:1.4', + 'org.slf4j:slf4j-simple:1.7.30', + 'org.slf4j:slf4j-api:1.7.26', + 'org.eclipse.transformer:org.eclipse.transformer:0.2.0', + 'org.eclipse.transformer:org.eclipse.transformer.cli:0.2.0' + + testCompile( project( ':hibernate-testing-jakarta' ) ) + testCompile( project( ':hibernate-envers-jakarta' ) ) + testCompile( project( path: ':hibernate-core-jakarta', configuration: 'tests' ) ) +} + +jar { + mustRunAfter project(':hibernate-envers').tasks.jar + mustRunAfter project(':hibernate-envers').tasks.testJar + dependsOn project(':hibernate-envers').tasks.jar + dependsOn project(':hibernate-envers').tasks.testJar + def baseDir = project(':hibernate-envers').buildDir + def baseJars = fileTree(baseDir).matching {include 'libs/*.jar' } + inputs.files(baseJars).skipWhenEmpty() + outputs.dir project.buildDir + doLast { + new File(project.buildDir, "libs").mkdirs() + fileTree(project.buildDir).matching { include 'libs/*.jar' }.each { delete it } + + baseJars.each { bundleJar -> + def sourceJarPath = baseDir.path + '/libs/' + bundleJar.name + println 'Initial bundle jar name [ ' + sourceJarPath + ' ]' + + def finalBundleJarName = project.buildDir.path + '/libs/' + bundleJar.name.replaceAll( 'hibernate-envers', 'hibernate-envers-jakarta' ) + println 'Default jakarta final bundle jar name [ ' + finalBundleJarName + ' ]' + + def transformerArgs = [ + sourceJarPath, finalBundleJarName, + '-q', // quiet output + '-tr', new File(getProjectDir().getParentFile(), 'rules/jakarta-renames.properties').path, + '-tv', new File(getProjectDir().getParentFile(), 'rules/jakarta-versions.properties').path, + '-td', new File(getProjectDir().getParentFile(), 'rules/jakarta-direct.properties').path, + ] + + println 'Transformer options:' + transformerArgs.each { + println ' [ ' + it + ' ]' + } + + javaexec { + classpath configurations.jakartaeeTransformJars + main = 'org.eclipse.transformer.jakarta.JakartaTransformer' + args = transformerArgs + } + } + } +} + +task unpackTestJar(type: Copy) { + dependsOn jar + fileTree(project.buildDir).matching { include 'libs/*-test.jar' }.each { + def outputDir = file("${buildDir}/unpacked/" + it.name) + from zipTree(it) + into outputDir + } +} + +test { + dependsOn unpackTestJar + fileTree(project.buildDir).matching { include 'libs/*-test.jar' }.each { + def outputDir = file("${buildDir}/unpacked/" + it.name) + testClassesDirs += files(outputDir) + classpath += files(outputDir) + } + systemProperty 'file.encoding', 'utf-8' + + if ( gradle.ext.javaVersions.test.launcher.asInt() >= 9 ) { + // See org.hibernate.boot.model.naming.NamingHelperTest.DefaultCharset.set + jvmArgs( ['--add-opens', 'java.base/java.nio.charset=ALL-UNNAMED'] ) + // Weld needs this to generate proxies + jvmArgs( ['--add-opens', 'java.base/java.security=ALL-UNNAMED'] ) + jvmArgs( ['--add-opens', 'java.base/java.lang=ALL-UNNAMED'] ) + } +} \ No newline at end of file diff --git a/hibernate-envers/hibernate-envers.gradle b/hibernate-envers/hibernate-envers.gradle index a16dcbc33509..5bcc7d4e9fce 100644 --- a/hibernate-envers/hibernate-envers.gradle +++ b/hibernate-envers/hibernate-envers.gradle @@ -41,6 +41,12 @@ sourceSets { } } +configurations { + tests { + description = 'Configuration for the produced test jar' + } +} + jar { manifest { attributes( @@ -65,6 +71,16 @@ jar { } } +task testJar(type: Jar, dependsOn: testClasses) { + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + archiveClassifier.set( 'test' ) + from sourceSets.test.output +} + +artifacts { + tests testJar +} + tasks."matrix_mariadb" { beforeTest { descriptor -> println "Starting test: " + descriptor diff --git a/hibernate-jboss-jta/hibernate-jboss-jta.gradle b/hibernate-jboss-jta/hibernate-jboss-jta.gradle new file mode 100644 index 000000000000..e0331957af4a --- /dev/null +++ b/hibernate-jboss-jta/hibernate-jboss-jta.gradle @@ -0,0 +1,64 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ + +description = 'JBoss JTA transformed to be JTA 2.0 compatible' + +apply from: rootProject.file( 'gradle/java-module.gradle' ) + +configurations { + jakartaeeTransformJars +} + +dependencies { + compile( libraries.jakarta_jta ) + compile( libraries.jakarta_resource ) + compile( project(':hibernate-transaction-spi') ) + + jakartaeeTransformJars 'biz.aQute.bnd:biz.aQute.bnd.transform:5.1.1', + 'commons-cli:commons-cli:1.4', + 'org.slf4j:slf4j-simple:1.7.30', + 'org.slf4j:slf4j-api:1.7.26', + 'org.eclipse.transformer:org.eclipse.transformer:0.2.0', + 'org.eclipse.transformer:org.eclipse.transformer.cli:0.2.0' + testCompile ( libraries.jboss_jta ) { + transitive=false; + } +} + +jar { + def sourceJarPath = project.configurations.testCompile.find { it.name.startsWith("narayana-jta-") } + inputs.files(sourceJarPath).skipWhenEmpty() + outputs.dir project.buildDir + doLast { + new File(project.buildDir, "libs").mkdirs() + fileTree(project.buildDir).matching { include 'libs/*.jar' }.each { delete it } + + println 'Initial bundle jar name [ ' + sourceJarPath + ' ]' + + def finalBundleJarName = project.buildDir.path + '/libs/hibernate-jboss-jta-' + project.version + ".jar" + println 'Default jakarta final bundle jar name [ ' + finalBundleJarName + ' ]' + + def transformerArgs = [ + sourceJarPath, finalBundleJarName, + '-q', // quiet output + '-tr', new File(getProjectDir().getParentFile(), 'rules/jakarta-renames.properties').path, + '-tv', new File(getProjectDir().getParentFile(), 'rules/jakarta-versions.properties').path, + '-td', new File(getProjectDir().getParentFile(), 'rules/jakarta-direct.properties').path, + ] + + println 'Transformer options:' + transformerArgs.each { + println ' [ ' + it + ' ]' + } + + javaexec { + classpath configurations.jakartaeeTransformJars + main = 'org.eclipse.transformer.jakarta.JakartaTransformer' + args = transformerArgs + } + } +} \ No newline at end of file diff --git a/hibernate-testing-jakarta/hibernate-testing-jakarta.gradle b/hibernate-testing-jakarta/hibernate-testing-jakarta.gradle new file mode 100644 index 000000000000..34aa2bed41b2 --- /dev/null +++ b/hibernate-testing-jakarta/hibernate-testing-jakarta.gradle @@ -0,0 +1,83 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ + +description = 'Support for testing Hibernate ORM Jakarta functionality' + +// todo (jakarta): replace this when the jakarta artifact is released +apply from: rootProject.file( 'gradle/java-module.gradle' ) +//apply from: rootProject.file( 'gradle/published-java-module.gradle' ) + +configurations { + jakartaeeTransformJars +} + +dependencies { + compile project( ':hibernate-core-jakarta' ) + compile( libraries.jakarta_jta ) + compile( libraries.junit ) + compile( libraries.byteman ) + compile( libraries.byteman_install ) + compile( libraries.byteman_bmunit ) + compile( libraries.xapool ) + compile( libraries.log4j ) +// todo (jakarta): replace this when the jakarta artifacts are released + compile project( ':hibernate-jboss-jta' ) +// compile( libraries.jboss_tx_spi_jakarta ) { +// transitive=false; +// } +// compile ( libraries.jboss_jta_jakarta ) { +// transitive=false; +// } + + jakartaeeTransformJars 'biz.aQute.bnd:biz.aQute.bnd.transform:5.1.1', + 'commons-cli:commons-cli:1.4', + 'org.slf4j:slf4j-simple:1.7.30', + 'org.slf4j:slf4j-api:1.7.26', + 'org.eclipse.transformer:org.eclipse.transformer:0.2.0', + 'org.eclipse.transformer:org.eclipse.transformer.cli:0.2.0' + testCompile fileTree(dir: 'libs', include: '*.jar') +} + +jar { + mustRunAfter project(':hibernate-testing').tasks.jar + dependsOn project(':hibernate-testing').tasks.jar + def baseDir = project(':hibernate-testing').buildDir + def baseJars = fileTree(baseDir).matching {include 'libs/*.jar' } + inputs.files(baseJars).skipWhenEmpty() + outputs.dir project.buildDir + doLast { + new File(project.buildDir, "libs").mkdirs() + fileTree(project.buildDir).matching { include 'libs/*.jar' }.each { delete it } + + baseJars.each { bundleJar -> + def sourceJarPath = baseDir.path + '/libs/' + bundleJar.name + println 'Initial bundle jar name [ ' + sourceJarPath + ' ]' + + def finalBundleJarName = project.buildDir.path + '/libs/' + bundleJar.name.replaceAll( 'hibernate-testing', 'hibernate-testing-jakarta' ) + println 'Default jakarta final bundle jar name [ ' + finalBundleJarName + ' ]' + + def transformerArgs = [ + sourceJarPath, finalBundleJarName, + '-q', // quiet output + '-tr', new File(getProjectDir().getParentFile(), 'rules/jakarta-renames.properties').path, + '-tv', new File(getProjectDir().getParentFile(), 'rules/jakarta-versions.properties').path, + '-td', new File(getProjectDir().getParentFile(), 'rules/jakarta-direct.properties').path, + ] + + println 'Transformer options:' + transformerArgs.each { + println ' [ ' + it + ' ]' + } + + javaexec { + classpath configurations.jakartaeeTransformJars + main = 'org.eclipse.transformer.jakarta.JakartaTransformer' + args = transformerArgs + } + } + } +} \ No newline at end of file diff --git a/hibernate-testing/hibernate-testing.gradle b/hibernate-testing/hibernate-testing.gradle index c0f9fb4e302f..abd8e3a5def9 100644 --- a/hibernate-testing/hibernate-testing.gradle +++ b/hibernate-testing/hibernate-testing.gradle @@ -19,6 +19,9 @@ dependencies { compile( libraries.byteman_bmunit ) compile( libraries.xapool ) compile( libraries.log4j ) + compile( libraries.jboss_tx_spi ) { + transitive=false; + } compile ( libraries.jboss_jta ) { transitive=false; } diff --git a/hibernate-transaction-client/hibernate-transaction-client.gradle b/hibernate-transaction-client/hibernate-transaction-client.gradle new file mode 100644 index 000000000000..bd3cb0430b80 --- /dev/null +++ b/hibernate-transaction-client/hibernate-transaction-client.gradle @@ -0,0 +1,62 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ + +description = 'Wildfly Transaction Client transformed to be JTA 2.0 compatible' + +apply from: rootProject.file( 'gradle/java-module.gradle' ) + +configurations { + jakartaeeTransformJars +} + +dependencies { + compile( libraries.jakarta_jta ) + + jakartaeeTransformJars 'biz.aQute.bnd:biz.aQute.bnd.transform:5.1.1', + 'commons-cli:commons-cli:1.4', + 'org.slf4j:slf4j-simple:1.7.30', + 'org.slf4j:slf4j-api:1.7.26', + 'org.eclipse.transformer:org.eclipse.transformer:0.2.0', + 'org.eclipse.transformer:org.eclipse.transformer.cli:0.2.0' + testCompile ( libraries.wildfly_transaction_client ) { + transitive=false; + } +} + +jar { + def sourceJarPath = project.configurations.testCompile.find { it.name.startsWith("wildfly-transaction-client-") } + inputs.files(sourceJarPath).skipWhenEmpty() + outputs.dir project.buildDir + doLast { + new File(project.buildDir, "libs").mkdirs() + fileTree(project.buildDir).matching { include 'libs/*.jar' }.each { delete it } + + println 'Initial bundle jar name [ ' + sourceJarPath + ' ]' + + def finalBundleJarName = project.buildDir.path + '/libs/hibernate-transaction-client-' + project.version + ".jar" + println 'Default jakarta final bundle jar name [ ' + finalBundleJarName + ' ]' + + def transformerArgs = [ + sourceJarPath, finalBundleJarName, + '-q', // quiet output + '-tr', new File(getProjectDir().getParentFile(), 'rules/jakarta-renames.properties').path, + '-tv', new File(getProjectDir().getParentFile(), 'rules/jakarta-versions.properties').path, + '-td', new File(getProjectDir().getParentFile(), 'rules/jakarta-direct.properties').path, + ] + + println 'Transformer options:' + transformerArgs.each { + println ' [ ' + it + ' ]' + } + + javaexec { + classpath configurations.jakartaeeTransformJars + main = 'org.eclipse.transformer.jakarta.JakartaTransformer' + args = transformerArgs + } + } +} \ No newline at end of file diff --git a/hibernate-transaction-spi/hibernate-transaction-spi.gradle b/hibernate-transaction-spi/hibernate-transaction-spi.gradle new file mode 100644 index 000000000000..57aced585fd6 --- /dev/null +++ b/hibernate-transaction-spi/hibernate-transaction-spi.gradle @@ -0,0 +1,62 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ + +description = 'Wildfly Transaction SPI transformed to be JTA 2.0 compatible' + +apply from: rootProject.file( 'gradle/java-module.gradle' ) + +configurations { + jakartaeeTransformJars +} + +dependencies { + compile( libraries.jakarta_jta ) + + jakartaeeTransformJars 'biz.aQute.bnd:biz.aQute.bnd.transform:5.1.1', + 'commons-cli:commons-cli:1.4', + 'org.slf4j:slf4j-simple:1.7.30', + 'org.slf4j:slf4j-api:1.7.26', + 'org.eclipse.transformer:org.eclipse.transformer:0.2.0', + 'org.eclipse.transformer:org.eclipse.transformer.cli:0.2.0' + testCompile ( libraries.jboss_tx_spi ) { + transitive=false; + } +} + +jar { + def sourceJarPath = project.configurations.testCompile.find { it.name.startsWith("jboss-transaction-spi-") } + inputs.files(sourceJarPath).skipWhenEmpty() + outputs.dir project.buildDir + doLast { + new File(project.buildDir, "libs").mkdirs() + fileTree(project.buildDir).matching { include 'libs/*.jar' }.each { delete it } + + println 'Initial bundle jar name [ ' + sourceJarPath + ' ]' + + def finalBundleJarName = project.buildDir.path + '/libs/hibernate-transaction-spi-' + project.version + ".jar" + println 'Default jakarta final bundle jar name [ ' + finalBundleJarName + ' ]' + + def transformerArgs = [ + sourceJarPath, finalBundleJarName, + '-q', // quiet output + '-tr', new File(getProjectDir().getParentFile(), 'rules/jakarta-renames.properties').path, + '-tv', new File(getProjectDir().getParentFile(), 'rules/jakarta-versions.properties').path, + '-td', new File(getProjectDir().getParentFile(), 'rules/jakarta-direct.properties').path, + ] + + println 'Transformer options:' + transformerArgs.each { + println ' [ ' + it + ' ]' + } + + javaexec { + classpath configurations.jakartaeeTransformJars + main = 'org.eclipse.transformer.jakarta.JakartaTransformer' + args = transformerArgs + } + } +} \ No newline at end of file diff --git a/rules/jakarta-direct-modelgen.properties b/rules/jakarta-direct-modelgen.properties new file mode 100644 index 000000000000..40142417e848 --- /dev/null +++ b/rules/jakarta-direct-modelgen.properties @@ -0,0 +1,34 @@ +# Taken from https://github.com/OpenLiberty/open-liberty/tree/30ca58383f9018227afd4b511bdedf33363b747e/dev/wlp-jakartaee-transform/rules + +# Direct String Replacement + +http\://java.sun.com/xml/ns/jaxb=https://jakarta.ee/xml/ns/jaxb + +# xmlBinding-3.0 properties +javax.xml.bind.JAXBElement=jakarta.xml.bind.JAXBElement + +com.sun.xml.bind.v2.ContextFactory=org.glassfish.jaxb.runtime.v2.JAXBContextFactory + +javax.annotation.security.RolesAllowed=jakarta.annotation.security.RolesAllowed + +javax.persistence.Entity=jakarta.persistence.Entity +javax.persistence.MappedSuperclass=jakarta.persistence.MappedSuperclass +javax.persistence.Embeddable=jakarta.persistence.Embeddable +javax.persistence.Id=jakarta.persistence.Id +javax.persistence.EmbeddedId=jakarta.persistence.EmbeddedId +javax.persistence.Transient=jakarta.persistence.Transient +javax.persistence.Basic=jakarta.persistence.Basic +javax.persistence.OneToOne=jakarta.persistence.OneToOne +javax.persistence.OneToMany=jakarta.persistence.OneToMany +javax.persistence.ManyToOne=jakarta.persistence.ManyToOne +javax.persistence.ManyToMany=jakarta.persistence.ManyToMany +javax.persistence.MapKeyClass=jakarta.persistence.MapKeyClass +javax.persistence.ElementCollection=jakarta.persistence.ElementCollection +javax.persistence.Access=jakarta.persistence.Access +javax.persistence.Convert=jakarta.persistence.Convert +javax.persistence.metamodel.StaticMetamodel=jakarta.persistence.metamodel.StaticMetamodel +javax.persistence.metamodel.SingularAttribute=jakarta.persistence.metamodel.SingularAttribute +javax.persistence.metamodel.CollectionAttribute=jakarta.persistence.metamodel.CollectionAttribute +javax.persistence.metamodel.SetAttribute=jakarta.persistence.metamodel.SetAttribute +javax.persistence.metamodel.ListAttribute=jakarta.persistence.metamodel.ListAttribute +javax.persistence.metamodel.MapAttribute=jakarta.persistence.metamodel.MapAttribute \ No newline at end of file diff --git a/rules/jakarta-direct.properties b/rules/jakarta-direct.properties new file mode 100644 index 000000000000..cd8e6b52ac68 --- /dev/null +++ b/rules/jakarta-direct.properties @@ -0,0 +1,12 @@ +# Taken from https://github.com/OpenLiberty/open-liberty/tree/30ca58383f9018227afd4b511bdedf33363b747e/dev/wlp-jakartaee-transform/rules + +# Direct String Replacement + +http\://java.sun.com/xml/ns/jaxb=https://jakarta.ee/xml/ns/jaxb + +# xmlBinding-3.0 properties +javax.xml.bind.JAXBElement=jakarta.xml.bind.JAXBElement + +com.sun.xml.bind.v2.ContextFactory=org.glassfish.jaxb.runtime.v2.JAXBContextFactory + +javax.annotation.security.RolesAllowed=jakarta.annotation.security.RolesAllowed diff --git a/rules/jakarta-renames.properties b/rules/jakarta-renames.properties new file mode 100644 index 000000000000..86e5ac487f69 --- /dev/null +++ b/rules/jakarta-renames.properties @@ -0,0 +1,260 @@ +# Taken from https://github.com/OpenLiberty/open-liberty/tree/30ca58383f9018227afd4b511bdedf33363b747e/dev/wlp-jakartaee-transform/rules + +com.sun.xml.bind=org.glassfish.jaxb.runtime +com.sun.xml.bind.api=org.glassfish.jaxb.runtime.api +com.sun.xml.bind.api.impl=org.glassfish.jaxb.core.api.impl +com.sun.xml.bind.marshaller=org.glassfish.jaxb.core.marshaller +com.sun.xml.bind.unmarshaller=org.glassfish.jaxb.core.unmarshaller +com.sun.xml.bind.util=org.glassfish.jaxb.runtime.util +com.sun.xml.bind.v2=org.glassfish.jaxb.runtime.v2 +com.sun.xml.bind.v2.model.annotation=org.glassfish.jaxb.runtime.v2.model.annotation +com.sun.xml.bind.v2.model.nav=org.glassfish.jaxb.core.v2.model.nav +com.sun.xml.bind.v2.model.runtime=org.glassfish.jaxb.runtime.v2.model.runtime +com.sun.xml.bind.v2.runtime=org.glassfish.jaxb.runtime.v2.runtime +com.sun.xml.bind.v2.runtime.unmarshaller=org.glassfish.jaxb.runtime.v2.runtime.unmarshaller +com.sun.xml.bind.v2.schemagen=org.glassfish.jaxb.runtime.v2.schemagen +com.sun.xml.bind.v2.schemagen.xmlschema=org.glassfish.jaxb.runtime.v2.schemagen.xmlschema +com.sun.xml.bind.v2.util=org.glassfish.jaxb.runtime.v2.util +com.sun.xml.internal.bind=org.glassfish.jaxb + +javax.activation=jakarta.activation +javax.annotation.security=jakarta.annotation.security +javax.annotation.sql=jakarta.annotation.sql +javax.annotation=jakarta.annotation +javax.batch.api=jakarta.batch.api +javax.batch.api.chunk=jakarta.batch.api.chunk +javax.batch.api.chunk.listener=jakarta.batch.api.chunk.listener +javax.batch.api.listener=jakarta.batch.api.listener +javax.batch.api.partition=jakarta.batch.api.partition +javax.batch.operations=jakarta.batch.operations +javax.batch.runtime=jakarta.batch.runtime +javax.batch.runtime.context=jakarta.batch.runtime.context +javax.decorator=jakarta.decorator +javax.ejb=jakarta.ejb +javax.ejb.embeddable=jakarta.ejb.embeddable +javax.ejb.spi=jakarta.ejb.spi +javax.el=jakarta.el +javax.enterprise.concurrent=jakarta.enterprise.concurrent +javax.enterprise.context.control=jakarta.enterprise.context.control +javax.enterprise.context.spi=jakarta.enterprise.context.spi +javax.enterprise.context=jakarta.enterprise.context +javax.enterprise.event=jakarta.enterprise.event +javax.enterprise.inject.literal=jakarta.enterprise.inject.literal +javax.enterprise.inject.se=jakarta.enterprise.inject.se +javax.enterprise.inject.spi.configurator=jakarta.enterprise.inject.spi.configurator +javax.enterprise.inject.spi=jakarta.enterprise.inject.spi +javax.enterprise.inject=jakarta.enterprise.inject +javax.enterprise.util=jakarta.enterprise.util +javax.faces=jakarta.faces +javax.faces.annotation=jakarta.faces.annotation +javax.faces.application=jakarta.faces.application +javax.faces.bean=jakarta.faces.bean +javax.faces.component=jakarta.faces.component +javax.faces.component.behavior=jakarta.faces.component.behavior +javax.faces.component.html=jakarta.faces.component.html +javax.faces.component.search=jakarta.faces.component.search +javax.faces.component.visit=jakarta.faces.component.visit +javax.faces.context=jakarta.faces.context +javax.faces.convert=jakarta.faces.convert +javax.faces.el=jakarta.faces.el +javax.faces.event=jakarta.faces.event +javax.faces.flow=jakarta.faces.flow +javax.faces.flow.builder=jakarta.faces.flow.builder +javax.faces.lifecycle=jakarta.faces.lifecycle +javax.faces.model=jakarta.faces.model +javax.faces.push=jakarta.faces.push +javax.faces.render=jakarta.faces.render +javax.faces.validator=jakarta.faces.validator +javax.faces.view=jakarta.faces.view +javax.faces.view.facelets=jakarta.faces.view.facelets +javax.faces.webapp=jakarta.faces.webapp +javax.inject=jakarta.inject +javax.interceptor=jakarta.interceptor +javax.jms=jakarta.jms +javax.json.bind.adapter=jakarta.json.bind.adapter +javax.json.bind.annotation=jakarta.json.bind.annotation +javax.json.bind.config=jakarta.json.bind.config +javax.json.bind.serializer=jakarta.json.bind.serializer +javax.json.bind.spi=jakarta.json.bind.spi +javax.json.bind=jakarta.json.bind +javax.json.spi=jakarta.json.spi +javax.json.stream=jakarta.json.stream +javax.json=jakarta.json +javax.jws=jakarta.jws +javax.jws.soap=jakarta.jws.soap +javax.mail=jakarta.mail +javax.persistence.criteria=jakarta.persistence.criteria +javax.persistence.metamodel=jakarta.persistence.metamodel +javax.persistence.spi=jakarta.persistence.spi +javax.persistence=jakarta.persistence +javax.persistence.cache.storeMode=jakarta.persistence.cache.storeMode +javax.persistence.cache.retrieveMode=jakarta.persistence.cache.retrieveMode +javax.persistence.bean.manager=jakarta.persistence.bean.manager +javax.persistence.validation.factory=jakarta.persistence.validation.factory +javax.resource.cci=jakarta.resource.cci +javax.resource.spi.endpoint=jakarta.resource.spi.endpoint +javax.resource.spi.security=jakarta.resource.spi.security +javax.resource.spi.work=jakarta.resource.spi.work +javax.resource.spi=jakarta.resource.spi +javax.resource=jakarta.resource +javax.security.auth.message=jakarta.security.auth.message +javax.security.auth.message.callback=jakarta.security.auth.message.callback +javax.security.auth.message.config=jakarta.security.auth.message.config +javax.security.auth.message.module=jakarta.security.auth.message.module +javax.security.enterprise=jakarta.security.enterprise +javax.security.enterprise.authentication.mechanism.http=jakarta.security.enterprise.authentication.mechanism.http +javax.security.enterprise.credential=jakarta.security.enterprise.credential +javax.security.enterprise.identitystore=jakarta.security.enterprise.identitystore +javax.security.jacc=jakarta.security.jacc +javax.servlet.annotation=jakarta.servlet.annotation +javax.servlet.descriptor=jakarta.servlet.descriptor +javax.servlet.http=jakarta.servlet.http +javax.servlet.jsp.el=jakarta.servlet.jsp.el +javax.servlet.jsp.jstl.core=jakarta.servlet.jsp.jstl.core +javax.servlet.jsp.jstl.fmt=jakarta.servlet.jsp.jstl.fmt +javax.servlet.jsp.jstl.sql=jakarta.servlet.jsp.jstl.sql +javax.servlet.jsp.jstl.tlv=jakarta.servlet.jsp.jstl.tlv +javax.servlet.jsp.jstl=jakarta.servlet.jsp.jstl +javax.servlet.jsp.resources=jakarta.servlet.jsp.resources +javax.servlet.jsp.tagext=jakarta.servlet.jsp.tagext +javax.servlet.jsp=jakarta.servlet.jsp +javax.servlet.resources=jakarta.servlet.resources +javax.servlet=jakarta.servlet +javax.transaction=jakarta.transaction +javax.validation=jakarta.validation +javax.validation.bootstrap=jakarta.validation.bootstrap +javax.validation.constraints=jakarta.validation.constraints +javax.validation.constraintvalidation=jakarta.validation.constraintvalidation +javax.validation.executable=jakarta.validation.executable +javax.validation.groups=jakarta.validation.groups +javax.validation.metadata=jakarta.validation.metadata +javax.validation.spi=jakarta.validation.spi +javax.validation.valueextraction=jakarta.validation.valueextraction +javax.websocket=jakarta.websocket +javax.websocket.server=jakarta.websocket.server +javax.ws.rs=jakarta.ws.rs +javax.ws.rs.client=jakarta.ws.rs.client +javax.ws.rs.container=jakarta.ws.rs.container +javax.ws.rs.core=jakarta.ws.rs.core +javax.ws.rs.ext=jakarta.ws.rs.ext +javax.ws.rs.sse=jakarta.ws.rs.sse +javax.xml.bind.annotation.adapters=jakarta.xml.bind.annotation.adapters +javax.xml.bind.annotation=jakarta.xml.bind.annotation +javax.xml.bind.attachment=jakarta.xml.bind.attachment +javax.xml.bind.helpers=jakarta.xml.bind.helpers +javax.xml.bind.util=jakarta.xml.bind.util +javax.xml.bind=jakarta.xml.bind +javax.xml.soap=jakarta.xml.soap +javax.xml.ws=jakarta.xml.ws +javax.xml.ws.handler=jakarta.xml.ws.handler +javax.xml.ws.handler.soap=jakarta.xml.ws.handler.soap +javax.xml.ws.http=jakarta.xml.ws.http +javax.xml.ws.soap=jakarta.xml.ws.soap +javax.xml.ws.spi=jakarta.xml.ws.spi +javax.xml.ws.spi.http=jakarta.xml.ws.spi.http +javax.xml.ws.wsaddressing=jakarta.xml.ws.wsaddressing + + +#Required for common enterprise beans test tools +com.ibm.websphere.ejbcontainer.test.mdb=io.openliberty.ejbcontainer.jakarta.test.mdb +com.ibm.websphere.ejbcontainer.test.mdb.interceptors=io.openliberty.ejbcontainer.jakarta.test.mdb.interceptors +com.ibm.websphere.ejbcontainer.test.osgi.pmi=io.openliberty.ejbcontainer.jakarta.test.osgi.pmi +com.ibm.websphere.ejbcontainer.test.osgi.pmi.internal=io.openliberty.ejbcontainer.jakarta.test.osgi.pmi.internal +com.ibm.websphere.ejbcontainer.test.tools=io.openliberty.ejbcontainer.jakarta.test.tools + +#Required to transform the package versions only +com.ibm.wsspi.el=com.ibm.wsspi.el +org.apache.myfaces.cdi.util=org.apache.myfaces.cdi.util +org.apache.myfaces.config.annotation=org.apache.myfaces.config.annotation +org.apache.myfaces.ee=org.apache.myfaces.ee +org.apache.myfaces.shared.util=org.apache.myfaces.shared.util +org.apache.myfaces.spi=org.apache.myfaces.spi +org.apache.myfaces.util=org.apache.myfaces.util +org.apache.myfaces.webapp=org.apache.myfaces.webapp +org.hibernate.validator=org.hibernate.validator +org.hibernate.validator.cdi.internal=org.hibernate.validator.cdi.internal +org.hibernate.validator.cdi=org.hibernate.validator.cdi +org.hibernate.validator.internal.engine.valueextraction=org.hibernate.validator.internal.engine.valueextraction +org.hibernate.validator.internal.properties=org.hibernate.validator.internal.properties +org.hibernate.validator.internal.util.classhierarchy=org.hibernate.validator.internal.util.classhierarchy +org.hibernate.validator.internal.util.logging=org.hibernate.validator.internal.util.logging +org.hibernate.validator.internal.util.privilegedactions=org.hibernate.validator.internal.util.privilegedactions +org.hibernate.validator.internal.util=org.hibernate.validator.internal.util +org.hibernate.validator.internal=org.hibernate.validator.internal +org.hibernate.validator.spi.properties=org.hibernate.validator.spi.properties +org.jboss.weld.annotated.enhanced=org.jboss.weld.annotated.enhanced +org.jboss.weld.bean.builtin=org.jboss.weld.bean.builtin +org.jboss.weld.bean.proxy=org.jboss.weld.bean.proxy +org.jboss.weld.bean.proxy.util=org.jboss.weld.bean.proxy.util +org.jboss.weld.bean=org.jboss.weld.bean +org.jboss.weld.bootstrap.api.helpers=org.jboss.weld.bootstrap.api.helpers +org.jboss.weld.bootstrap.api=org.jboss.weld.bootstrap.api +org.jboss.weld.bootstrap.spi.helpers=org.jboss.weld.bootstrap.spi.helpers +org.jboss.weld.bootstrap.spi=org.jboss.weld.bootstrap.spi +org.jboss.weld.bootstrap=org.jboss.weld.bootstrap +org.jboss.weld.config=org.jboss.weld.config +org.jboss.weld.construction.api=org.jboss.weld.construction.api +org.jboss.weld.context=org.jboss.weld.context +org.jboss.weld.context.api=org.jboss.weld.context.api +org.jboss.weld.context.bound=org.jboss.weld.context.bound +org.jboss.weld.context.http=org.jboss.weld.context.http +org.jboss.weld.contexts=org.jboss.weld.contexts +org.jboss.weld.ejb.api=org.jboss.weld.ejb.api +org.jboss.weld.ejb.spi=org.jboss.weld.ejb.spi +org.jboss.weld.exceptions=org.jboss.weld.exceptions +org.jboss.weld.executor=org.jboss.weld.executor +org.jboss.weld.injection.spi=org.jboss.weld.injection.spi +org.jboss.weld.injection=org.jboss.weld.injection +org.jboss.weld.interceptor.spi.model=org.jboss.weld.interceptor.spi.model +org.jboss.weld.manager.api=org.jboss.weld.manager.api +org.jboss.weld.manager=org.jboss.weld.manager +org.jboss.weld.metadata=org.jboss.weld.metadata +org.jboss.weld.module.ejb=org.jboss.weld.module.ejb +org.jboss.weld.module.jsf=org.jboss.weld.module.jsf +org.jboss.weld.module.web.el=org.jboss.weld.module.web.el +org.jboss.weld.module.web.servlet=org.jboss.weld.module.web.servlet +org.jboss.weld.probe=org.jboss.weld.probe +org.jboss.weld.resolution=org.jboss.weld.resolution +org.jboss.weld.resources.spi=org.jboss.weld.resources.spi +org.jboss.weld.resources=org.jboss.weld.resources +org.jboss.weld.security.spi=org.jboss.weld.security.spi +org.jboss.weld.serialization.spi=org.jboss.weld.serialization.spi +org.jboss.weld.transaction.spi=org.jboss.weld.transaction.spi +org.jboss.weld.util.collections=org.jboss.weld.util.collections +org.jboss.weld=org.jboss.weld + +org.eclipse.persistence.exceptions=org.eclipse.persistence.exceptions +org.eclipse.persistence.logging=org.eclipse.persistence.logging +org.eclipse.persistence.platform.server=org.eclipse.persistence.platform.server +org.eclipse.persistence.internal.databaseaccess=org.eclipse.persistence.internal.databaseaccess +org.eclipse.persistence.internal.helper=org.eclipse.persistence.internal.helper +org.eclipse.persistence.internal.security=org.eclipse.persistence.internal.security +org.eclipse.persistence.internal.sessions=org.eclipse.persistence.internal.sessions + +org.eclipse.persistence.annotations=org.eclipse.persistence.annotations +org.eclipse.persistence.descriptors=org.eclipse.persistence.descriptors +org.eclipse.persistence.descriptors.changetracking=org.eclipse.persistence.descriptors.changetracking +org.eclipse.persistence.queries=org.eclipse.persistence.queries +org.eclipse.persistence.indirection=org.eclipse.persistence.indirection +org.eclipse.persistence.internal.descriptors=org.eclipse.persistence.internal.descriptors +org.eclipse.persistence.internal.identitymaps=org.eclipse.persistence.internal.identitymaps +org.eclipse.persistence.internal.jpa=org.eclipse.persistence.internal.jpa +org.eclipse.persistence.internal.jpa.rs.metadata.model=org.eclipse.persistence.internal.jpa.rs.metadata.model +org.eclipse.persistence.internal.weaving=org.eclipse.persistence.internal.weaving +org.eclipse.persistence.jpa=org.eclipse.persistence.jpa +org.eclipse.persistence.platform.server.was=org.eclipse.persistence.platform.server.was +org.eclipse.persistence.internal.sessions.cdi=org.eclipse.persistence.internal.sessions.cdi +org.eclipse.persistence.platform.database=org.eclipse.persistence.platform.database +org.eclipse.persistence.sessions=org.eclipse.persistence.sessions +org.eclipse.persistence.tools.schemaframework=org.eclipse.persistence.tools.schemaframework +org.eclipse.persistence.transaction=org.eclipse.persistence.transaction + +com.sun.xml.internal.messaging.saaj.packaging.mime=com.sun.xml.messaging.saaj.packaging.mime +com.sun.xml.internal.messaging.saaj.packaging.mime.internet=com.sun.xml.messaging.saaj.packaging.mime.internet +com.sun.xml.internal.messaging.saaj.packaging.mime.util=com.sun.xml.messaging.saaj.packaging.mime.util +com.sun.xml.internal.messaging.saaj.soap=com.sun.xml.messaging.saaj.soap +com.sun.xml.internal.messaging.saaj.soap.dynamic=com.sun.xml.messaging.saaj.soap.dynamic +com.sun.xml.internal.messaging.saaj.soap.name=com.sun.xml.messaging.saaj.soap.name +com.sun.xml.internal.messaging.saaj.util=com.sun.xml.messaging.saaj.util +com.sun.xml.internal.messaging.saaj.util.stax=com.sun.xml.messaging.saaj.util.stax +com.sun.xml.internal.messaging.saaj.util.transform=com.sun.xml.messaging.saaj.util.transform diff --git a/rules/jakarta-versions.properties b/rules/jakarta-versions.properties new file mode 100644 index 000000000000..e43ebefeb412 --- /dev/null +++ b/rules/jakarta-versions.properties @@ -0,0 +1,223 @@ +# Taken from https://github.com/OpenLiberty/open-liberty/tree/30ca58383f9018227afd4b511bdedf33363b747e/dev/wlp-jakartaee-transform/rules + +com.ibm.wsspi.el=[4.0,5) +jakarta.activation=[2.0,3) +jakarta.annotation.security=[2.0,3) +jakarta.annotation.sql=[2.0,3) +jakarta.annotation=[2.0,3) +jakarta.batch.api=[2.0,3) +jakarta.batch.api.chunk=[2.0,3) +jakarta.batch.api.chunk.listener=[2.0,3) +jakarta.batch.api.listener=[2.0,3) +jakarta.batch.api.partition=[2.0,3) +jakarta.batch.operations=[2.0,3) +jakarta.batch.runtime=[2.0,3) +jakarta.batch.runtime.context=[2.0,3) +jakarta.decorator=[3.0,4.0) +jakarta.ejb=[4.0,5) +jakarta.ejb.embeddable=[4.0,5) +jakarta.ejb.spi=[4.0,5) +jakarta.el=[4.0,5) +jakarta.enterprise.concurrent=[2.0,3) +jakarta.enterprise.context.control=[3.0,4.0) +jakarta.enterprise.context.spi=[3.0,4.0) +jakarta.enterprise.context=[3.0,4.0) +jakarta.enterprise.event=[3.0,4.0) +jakarta.enterprise.inject.literal=[3.0,4.0) +jakarta.enterprise.inject.spi.configurator=[3.0,4.0) +jakarta.enterprise.inject.spi=[3.0,4.0) +jakarta.enterprise.inject=[3.0,4.0) +jakarta.enterprise.util=[3.0,4.0) +jakarta.faces=[3.0,4.0) +jakarta.faces.application=[3.0,4.0) +jakarta.faces.bean=[3.0,4.0) +jakarta.faces.component=[3.0,4.0) +jakarta.faces.component.behavior=[3.0,4.0) +jakarta.faces.context=[3.0,4.0) +jakarta.faces.convert=[3.0,4.0) +jakarta.faces.event=[3.0,4.0) +jakarta.faces.model=[3.0,4.0) +jakarta.faces.render=[3.0,4.0) +jakarta.faces.validator=[3.0,4.0) +jakarta.faces.view.facelets=[3.0,4.0) +jakarta.faces.webapp=[3.0,4.0) +jakarta.inject=[2.0,3.0) +jakarta.interceptor=[2.0,3.0) +jakarta.json.bind.adapter=[2.0,3.0) +jakarta.json.bind.annotation=[2.0,3.0) +jakarta.json.bind.config=[2.0,3.0) +jakarta.json.bind.serializer=[2.0,3.0) +jakarta.json.bind.spi=[2.0,3.0) +jakarta.json.bind=[2.0,3.0) +jakarta.json.spi=[2.0,3.0) +jakarta.json.stream=[2.0,3.0) +jakarta.json=[2.0,3.0) +jakarta.jms=[3.0,4) +jakarta.jws=[3.0,4) +jakarta.jws.soap=[3.0,4) +jakarta.persistence.criteria=[3.0,4) +jakarta.persistence.metamodel=[3.0,4) +jakarta.persistence.spi=[3.0,4) +jakarta.persistence=[3.0,4) +jakarta.resource.cci=[2.0,3) +jakarta.resource.spi.endpoint=[2.0,3) +jakarta.resource.spi.security=[2.0,3) +jakarta.resource.spi.work=[2.0,3) +jakarta.resource.spi=[2.0,3) +jakarta.resource=[2.0,3) +jakarta.security.auth.message=[2.0,3) +jakarta.security.auth.message.callback=[2.0,3) +jakarta.security.auth.message.config=[2.0,3) +jakarta.security.auth.message.module=[2.0,3) +jakarta.security.enterprise=[2.0,3) +jakarta.security.enterprise.authentication.mechanism.http=[2.0,3) +jakarta.security.enterprise.credential=[2.0,3) +jakarta.security.enterprise.identitystore=[2.0,3) +jakarta.security.jacc=[2.0,3) +jakarta.servlet.annotation=[5.0,6) +jakarta.servlet.descriptor=[5.0,6) +jakarta.servlet.http=[5.0,6) +jakarta.servlet.jsp.el=[3.0,4) +jakarta.servlet.jsp.jstl.core=[2.0,3) +jakarta.servlet.jsp.jstl.fmt=[2.0,3) +jakarta.servlet.jsp.jstl.sql=[2.0,3) +jakarta.servlet.jsp.jstl.tlv=[2.0,3) +jakarta.servlet.jsp.jstl=[2.0,3) +jakarta.servlet.jsp.resources=[3.0,4) +jakarta.servlet.jsp.tagext=[3.0,4) +jakarta.servlet.jsp=[3.0,4) +jakarta.servlet.resources=[5.0,6) +jakarta.servlet=[5.0,6) +jakarta.transaction=[2.0,3) +jakarta.validation=[3.0,4) +jakarta.validation.bootstrap=[3.0,4) +jakarta.validation.constraints=[3.0,4) +jakarta.validation.constraintvalidation=[3.0,4) +jakarta.validation.executable=[3.0,4) +jakarta.validation.groups=[3.0,4) +jakarta.validation.metadata=[3.0,4) +jakarta.validation.spi=[3.0,4) +jakarta.validation.valueextraction=[3.0,4) +jakarta.ws.rs=[3.0,4.0) +jakarta.ws.rs.client=[3.0,4.0) +jakarta.ws.rs.container=[3.0,4.0) +jakarta.ws.rs.core=[3.0,4.0) +jakarta.ws.rs.ext=[3.0,4.0) +jakarta.ws.rs.sse=[3.0,4.0) +jakarta.xml.bind.annotation.adapters=[3.0,4) +jakarta.xml.bind.annotation=[3.0,4) +jakarta.xml.bind.attachment=[3.0,4) +jakarta.xml.bind.helpers=[3.0,4) +jakarta.xml.bind.util=[3.0,4) +jakarta.xml.bind=[3.0,4) +jakarta.xml.soap=[3.0,4) +jakarta.xml.ws=[3.0,4) +jakarta.xml.ws.handler=[3.0,4) +jakarta.xml.ws.handler.soap=[3.0,4) +jakarta.xml.ws.http=[3.0,4) +jakarta.xml.ws.soap=[3.0,4) +jakarta.xml.ws.spi=[3.0,4) +jakarta.xml.ws.spi.http=[3.0,4) +jakarta.xml.ws.wsaddressing=[3.0,4) +jakarta.websocket=[2.0,3) +jakarta.websocket.server=[2.0,3) +org.apache.myfaces.cdi.util=[3.0,4) +org.apache.myfaces.config.annotation=[3.0,4) +org.apache.myfaces.ee=[3.0,4) +org.apache.myfaces.shared.util=[3.0,4) +org.apache.myfaces.spi=[3.0,4) +org.apache.myfaces.util=[3.0,4) +org.apache.myfaces.webapp=[3.0,4) +org.glassfish.jaxb.runtime=[3.0,4) +org.glassfish.jaxb.runtime.api=[3.0,4) +org.glassfish.jaxb.core.api.impl=[3.0,4) +org.glassfish.jaxb.core.marshaller=[3.0,4) +org.glassfish.jaxb.core.unmarshaller=[3.0,4) +org.glassfish.jaxb.runtime.util=[3.0,4) +org.glassfish.jaxb.core.v2.model.nav=[3.0,4) +org.glassfish.jaxb.runtime.v2=[3.0,4) +org.glassfish.jaxb.runtime.v2.model.annotation=[3.0,4) +org.glassfish.jaxb.runtime.v2.model.runtime=[3.0,4) +org.glassfish.jaxb.runtime.v2.runtime=[3.0,4) +org.glassfish.jaxb.runtime.v2.runtime.unmarshaller=[3.0,4) +org.glassfish.jaxb.runtime.v2.schemagen=[3.0,4) +org.glassfish.jaxb.runtime.v2.schemagen.xmlschema=[3.0,4) +org.glassfish.jaxb.runtime.v2.util=[3.0,4) +org.glassfish.jaxb=[3.0,4) +org.hibernate.validator=[7.0,8) +org.hibernate.validator.cdi.internal=[7.0,8) +org.hibernate.validator.cdi=[7.0,8) +org.hibernate.validator.internal.engine.valueextraction=[7.0,8) +org.hibernate.validator.internal.properties=[7.0,8) +org.hibernate.validator.internal.util.classhierarchy=[7.0,8) +org.hibernate.validator.internal.util.logging=[7.0,8) +org.hibernate.validator.internal.util.privilegedactions=[7.0,8) +org.hibernate.validator.internal.util=[7.0,8) +org.hibernate.validator.internal=[7.0,8) +org.hibernate.validator.spi.properties=[7.0,8) +org.jboss.weld.annotated.enhanced=[4.0,5) +org.jboss.weld.bean.builtin=[4.0,5) +org.jboss.weld.bean.proxy=[4.0,5) +org.jboss.weld.bean.proxy.util=[4.0,5) +org.jboss.weld.bean=[4.0,5) +org.jboss.weld.bootstrap.api.helpers=[4.0,5) +org.jboss.weld.bootstrap.api=[4.0,5) +org.jboss.weld.bootstrap.spi.helpers=[4.0,5) +org.jboss.weld.bootstrap.spi=[4.0,5) +org.jboss.weld.bootstrap=[4.0,5) +org.jboss.weld.config=[4.0,5) +org.jboss.weld.construction.api=[4.0,5) +org.jboss.weld.context=[4.0,5) +org.jboss.weld.context.api=[4.0,5) +org.jboss.weld.context.bound=[4.0,5) +org.jboss.weld.context.http=[4.0,5) +org.jboss.weld.contexts=[4.0,5) +org.jboss.weld.ejb.api=[4.0,5) +org.jboss.weld.ejb.spi=[4.0,5) +org.jboss.weld.exceptions=[4.0,5) +org.jboss.weld.executor=[4.0,5) +org.jboss.weld.injection.spi=[4.0,5) +org.jboss.weld.injection=[4.0,5) +org.jboss.weld.interceptor.spi.model=[4.0,5) +org.jboss.weld.manager.api=[4.0,5) +org.jboss.weld.manager=[4.0,5) +org.jboss.weld.metadata=[4.0,5) +org.jboss.weld.module.ejb=[4.0,5) +org.jboss.weld.module.jsf=[4.0,5) +org.jboss.weld.module.web.el=[4.0,5) +org.jboss.weld.module.web.servlet=[4.0,5) +org.jboss.weld.probe=[4.0,5) +org.jboss.weld.resolution=[4.0,5) +org.jboss.weld.resources.spi=[4.0,5) +org.jboss.weld.resources=[4.0,5) +org.jboss.weld.security.spi=[4.0,5) +org.jboss.weld.serialization.spi=[4.0,5) +org.jboss.weld.transaction.spi=[4.0,5) +org.jboss.weld.util.collections=[4.0,5) +org.jboss.weld=[4.0,5) + +org.eclipse.persistence.exceptions=[3.0,4) +org.eclipse.persistence.logging=[3.0,4) +org.eclipse.persistence.platform.server=[3.0,4) +org.eclipse.persistence.internal.databaseaccess=[3.0,4) +org.eclipse.persistence.internal.helper=[3.0,4) +org.eclipse.persistence.internal.security=[3.0,4) +org.eclipse.persistence.internal.sessions=[3.0,4) + +org.eclipse.persistence.annotations=[3.0,4) +org.eclipse.persistence.descriptors=[3.0,4) +org.eclipse.persistence.descriptors.changetracking=[3.0,4) +org.eclipse.persistence.queries=[3.0,4) +org.eclipse.persistence.indirection=[3.0,4) +org.eclipse.persistence.internal.descriptors=[3.0,4) +org.eclipse.persistence.internal.identitymaps=[3.0,4) +org.eclipse.persistence.internal.jpa=[3.0,4) +org.eclipse.persistence.internal.jpa.rs.metadata.model=[3.0,4) +org.eclipse.persistence.internal.weaving=[3.0,4) +org.eclipse.persistence.jpa=[3.0,4) +org.eclipse.persistence.platform.server.was=[3.0,4) +org.eclipse.persistence.internal.sessions.cdi=[3.0,4) +org.eclipse.persistence.platform.database=[3.0,4) +org.eclipse.persistence.sessions=[3.0,4) +org.eclipse.persistence.tools.schemaframework=[3.0,4) +org.eclipse.persistence.transaction=[3.0,4) diff --git a/settings.gradle b/settings.gradle index 54000713c5de..ca6903e25cb3 100644 --- a/settings.gradle +++ b/settings.gradle @@ -87,9 +87,17 @@ logger.lifecycle "Java versions for main code: " + gradle.ext.javaVersions.main logger.lifecycle "Java versions for tests: " + gradle.ext.javaVersions.test include 'hibernate-core' +include 'hibernate-core-jakarta' include 'hibernate-entitymanager' include 'hibernate-testing' +include 'hibernate-testing-jakarta' +// todo (jakarta): remove these three when the jakarta artifacts are released +include 'hibernate-jboss-jta' +include 'hibernate-transaction-client' +include 'hibernate-transaction-spi' + include 'hibernate-envers' +include 'hibernate-envers-jakarta' include 'hibernate-spatial' include 'hibernate-java8' @@ -127,6 +135,10 @@ include 'metamodel-generator' project(':metamodel-generator').projectDir = new File(rootProject.projectDir, "tooling/metamodel-generator") project(':metamodel-generator').name = 'hibernate-jpamodelgen' +include 'metamodel-generator-jakarta' +project(':metamodel-generator-jakarta').projectDir = new File(rootProject.projectDir, "tooling/metamodel-generator-jakarta") +project(':metamodel-generator-jakarta').name = 'hibernate-jpamodelgen-jakarta' + include 'hibernate-gradle-plugin' project(':hibernate-gradle-plugin').projectDir = new File(rootProject.projectDir, "tooling/hibernate-gradle-plugin") diff --git a/tooling/metamodel-generator-jakarta/hibernate-jpamodelgen-jakarta.gradle b/tooling/metamodel-generator-jakarta/hibernate-jpamodelgen-jakarta.gradle new file mode 100644 index 000000000000..13d32b668564 --- /dev/null +++ b/tooling/metamodel-generator-jakarta/hibernate-jpamodelgen-jakarta.gradle @@ -0,0 +1,68 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ + +description = 'Annotation Processor to generate JPA 3 static metamodel classes' + +apply from: rootProject.file( 'gradle/published-java-module.gradle' ) + +configurations { + jakartaeeTransformJars +} + +dependencies { + // JAXB + compile( libraries.jakarta_jaxb_api ) + compile( libraries.jakarta_jaxb_runtime ) + + jakartaeeTransformJars 'biz.aQute.bnd:biz.aQute.bnd.transform:5.1.1', + 'commons-cli:commons-cli:1.4', + 'org.slf4j:slf4j-simple:1.7.30', + 'org.slf4j:slf4j-api:1.7.26', + 'org.eclipse.transformer:org.eclipse.transformer:0.2.0', + 'org.eclipse.transformer:org.eclipse.transformer.cli:0.2.0' + testCompile fileTree(dir: 'libs', include: '*.jar') +} + +jar { + mustRunAfter project(':hibernate-jpamodelgen').tasks.jar + dependsOn project(':hibernate-jpamodelgen').tasks.jar + def baseDir = project(':hibernate-jpamodelgen').buildDir + def baseJars = fileTree(baseDir).matching {include 'libs/*.jar' } + inputs.files(baseJars).skipWhenEmpty() + outputs.dir project.buildDir + doLast { + new File(project.buildDir, "libs").mkdirs() + fileTree(project.buildDir).matching { include 'libs/*.jar' }.each { delete it } + + baseJars.each { bundleJar -> + def sourceJarPath = baseDir.path + '/libs/' + bundleJar.name + println 'Initial bundle jar name [ ' + sourceJarPath + ' ]' + + def finalBundleJarName = project.buildDir.path + '/libs/' + bundleJar.name.replaceAll( 'hibernate-jpamodelgen', 'hibernate-jpamodelgen-jakarta' ) + println 'Default jakarta final bundle jar name [ ' + finalBundleJarName + ' ]' + + def transformerArgs = [ + sourceJarPath, finalBundleJarName, + '-q', // quiet output + '-tr', new File(getProjectDir().getParentFile().getParentFile(), 'rules/jakarta-renames.properties').path, + '-tv', new File(getProjectDir().getParentFile().getParentFile(), 'rules/jakarta-versions.properties').path, + '-td', new File(getProjectDir().getParentFile().getParentFile(), 'rules/jakarta-direct-modelgen.properties').path, + ] + + println 'Transformer options:' + transformerArgs.each { + println ' [ ' + it + ' ]' + } + + javaexec { + classpath configurations.jakartaeeTransformJars + main = 'org.eclipse.transformer.jakarta.JakartaTransformer' + args = transformerArgs + } + } + } +} \ No newline at end of file diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/ClassWriter.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/ClassWriter.java index 245c9e3111a4..e97bfe3067b4 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/ClassWriter.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/ClassWriter.java @@ -199,7 +199,7 @@ private static String getFullyQualifiedClassName(MetaEntity entity, String metaM private static String writeGeneratedAnnotation(MetaEntity entity, Context context) { StringBuilder generatedAnnotation = new StringBuilder(); generatedAnnotation.append( "@" ) - .append( entity.importType( context.getGeneratedAnnotation().getQualifiedName().toString() ) ) + .append( entity.importType( context.getGeneratedAnnotationFqcn() ) ) .append( "(value = \"" ) .append( JPAMetaModelEntityProcessor.class.getName() ); if ( context.addGeneratedDate() ) { diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/Context.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/Context.java index da0d9a6f5523..c09ec34288cb 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/Context.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/Context.java @@ -50,7 +50,7 @@ public final class Context { private final boolean lazyXmlParsing; private final String persistenceXmlLocation; private final List ormXmlFiles; - private final TypeElement generatedAnnotation; + private final String generatedAnnotation; /** * Whether all mapping files are xml-mapping-metadata-complete. In this case no annotation processing will take @@ -96,14 +96,16 @@ public Context(ProcessingEnvironment pe) { lazyXmlParsing = Boolean.parseBoolean( pe.getOptions().get( JPAMetaModelEntityProcessor.LAZY_XML_PARSING ) ); logDebug = Boolean.parseBoolean( pe.getOptions().get( JPAMetaModelEntityProcessor.DEBUG_OPTION ) ); + // Workaround that Eclipse transformer tries to replace this constant which we don't want + String j = "j"; TypeElement java8AndBelowGeneratedAnnotation = - pe.getElementUtils().getTypeElement( "javax.annotation.Generated" ); + pe.getElementUtils().getTypeElement( j + "avax.annotation.Generated" ); if ( java8AndBelowGeneratedAnnotation != null ) { - generatedAnnotation = java8AndBelowGeneratedAnnotation; + generatedAnnotation = java8AndBelowGeneratedAnnotation.getQualifiedName().toString(); } else { // Using the new name for this annotation in Java 9 and above - generatedAnnotation = pe.getElementUtils().getTypeElement( "javax.annotation.processing.Generated" ); + generatedAnnotation = "javax.annotation.processing.Generated"; } } @@ -115,7 +117,7 @@ public boolean addGeneratedAnnotation() { return addGeneratedAnnotation; } - public TypeElement getGeneratedAnnotation() { + public String getGeneratedAnnotationFqcn() { return generatedAnnotation; } From c29b2d27ee66b0da2af2a640b5c2179c6454a983 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Fri, 23 Apr 2021 12:07:20 +0200 Subject: [PATCH 132/644] HHH-14577 Add Jenkinsfiles for running TCKs --- ci/jpa-2.2-tck.Jenkinsfile | 72 +++++++ ci/jpa-3.0-tck.Jenkinsfile | 72 +++++++ gradle/libraries.gradle | 1 + .../hibernate-core-jakarta.gradle | 179 +++++++++--------- .../hibernate-envers-jakarta.gradle | 58 +++--- .../hibernate-jboss-jta.gradle | 10 +- .../hibernate-testing-jakarta.gradle | 16 +- .../hibernate-transaction-client.gradle | 8 +- .../hibernate-transaction-spi.gradle | 62 ------ settings.gradle | 8 +- 10 files changed, 295 insertions(+), 191 deletions(-) create mode 100644 ci/jpa-2.2-tck.Jenkinsfile create mode 100644 ci/jpa-3.0-tck.Jenkinsfile delete mode 100644 hibernate-transaction-spi/hibernate-transaction-spi.gradle diff --git a/ci/jpa-2.2-tck.Jenkinsfile b/ci/jpa-2.2-tck.Jenkinsfile new file mode 100644 index 000000000000..fbc97668e0fd --- /dev/null +++ b/ci/jpa-2.2-tck.Jenkinsfile @@ -0,0 +1,72 @@ +@Library('hibernate-jenkins-pipeline-helpers@1.5') _ + +pipeline { + agent { + label 'LongDuration' + } + tools { + jdk 'OpenJDK 8 Latest' + } + stages { + stage('Build') { + steps { + script { + docker.withRegistry('https://index.docker.io/v1/', 'hibernateci.hub.docker.com') { + docker.image('openjdk:8-jdk').pull() + } + } + dir('hibernate') { + checkout scm + sh """ \ + ./gradlew publishToMavenLocal + """ + script { + env.HIBERNATE_VERSION = sh ( + script: "grep hibernateVersion gradle/version.properties|cut -d'=' -f2", + returnStdout: true + ).trim() + } + } + dir('tck') { + checkout changelog: false, poll: false, scm: [$class: 'GitSCM', branches: [[name: '*/main']], extensions: [], userRemoteConfigs: [[url: 'https://github.com/hibernate/jakarta-tck-runner.git']]] + sh """ \ + cd jpa-2.2; docker build -t jakarta-tck-runner . + """ + } + } + } + stage('Run TCK') { + steps { + sh """ \ + docker rm -f tck + docker run -v ~/.m2/repository/org/hibernate:/root/.m2/repository/org/hibernate:z -e NO_SLEEP=true -e HIBERNATE_VERSION=$HIBERNATE_VERSION --name tck jakarta-tck-runner + docker cp tck:/tck/persistence-tck/tmp/JTreport/ ./JTreport + """ + archiveArtifacts artifacts: 'JTreport/**' + script { + failures = sh ( + script: """ \ + while read line; do + if [[ "$line" != "*Passed." ]]; then + echo "$line" + fi + done = 9 ) { - // See org.hibernate.boot.model.naming.NamingHelperTest.DefaultCharset.set - jvmArgs( ['--add-opens', 'java.base/java.nio.charset=ALL-UNNAMED'] ) - // Weld needs this to generate proxies - jvmArgs( ['--add-opens', 'java.base/java.security=ALL-UNNAMED'] ) - jvmArgs( ['--add-opens', 'java.base/java.lang=ALL-UNNAMED'] ) - } -} \ No newline at end of file +// todo: enable again when we can finally use the Jakarta JARs from narayana +//task unpackTestJar(type: Copy) { +// dependsOn jar +// fileTree(project.buildDir).matching { include 'libs/*-test.jar' }.each { +// def outputDir = file("${buildDir}/unpacked/" + it.name) +// from zipTree(it) +// into outputDir +// } +//} +// +//task copyBundleResources (type: Copy) { +// dependsOn unpackTestJar +// File unpackedDir = new File(project.buildDir, "libs/hibernate-core-jakarta-${project.version}-test.jar") +// ext { +// bundlesTargetDir = file( "${buildDir}/bundles" ) +// bundleTokens = dbBundle[db] +// ext.bundleTokens['buildDirName'] = buildDir.absolutePath +// } +// +// from file("${buildDir}/unpacked/${unpackedDir.name}/templates") +// into ext.bundlesTargetDir +// filter( ReplaceTokens, tokens: ext.bundleTokens) +// doFirst { +// ext.bundlesTargetDir.mkdirs() +// } +//} +// +//processTestResources.dependsOn copyBundleResources +// +//artifacts { +// tests new File(project.buildDir, "libs/hibernate-core-jakarta-${project.version}-test.jar") +//} +// +//test { +// fileTree(project.buildDir).matching { include 'libs/*-test.jar' }.each { +// def outputDir = file("${buildDir}/unpacked/" + it.name) +// testClassesDirs += files(outputDir) +// classpath += files(outputDir) +// } +// systemProperty 'file.encoding', 'utf-8' +// +// if ( gradle.ext.javaVersions.test.launcher.asInt() >= 9 ) { +// // See org.hibernate.boot.model.naming.NamingHelperTest.DefaultCharset.set +// jvmArgs( ['--add-opens', 'java.base/java.nio.charset=ALL-UNNAMED'] ) +// // Weld needs this to generate proxies +// jvmArgs( ['--add-opens', 'java.base/java.security=ALL-UNNAMED'] ) +// jvmArgs( ['--add-opens', 'java.base/java.lang=ALL-UNNAMED'] ) +// } +//} \ No newline at end of file diff --git a/hibernate-envers-jakarta/hibernate-envers-jakarta.gradle b/hibernate-envers-jakarta/hibernate-envers-jakarta.gradle index 66f4b7449307..ac4963b0b4a5 100644 --- a/hibernate-envers-jakarta/hibernate-envers-jakarta.gradle +++ b/hibernate-envers-jakarta/hibernate-envers-jakarta.gradle @@ -28,9 +28,10 @@ dependencies { 'org.eclipse.transformer:org.eclipse.transformer:0.2.0', 'org.eclipse.transformer:org.eclipse.transformer.cli:0.2.0' - testCompile( project( ':hibernate-testing-jakarta' ) ) testCompile( project( ':hibernate-envers-jakarta' ) ) - testCompile( project( path: ':hibernate-core-jakarta', configuration: 'tests' ) ) +// todo: enable again when we can finally use the Jakarta JARs from narayana +// testCompile( project( ':hibernate-testing-jakarta' ) ) +// testCompile( project( path: ':hibernate-core-jakarta', configuration: 'tests' ) ) } jar { @@ -75,29 +76,30 @@ jar { } } -task unpackTestJar(type: Copy) { - dependsOn jar - fileTree(project.buildDir).matching { include 'libs/*-test.jar' }.each { - def outputDir = file("${buildDir}/unpacked/" + it.name) - from zipTree(it) - into outputDir - } -} - -test { - dependsOn unpackTestJar - fileTree(project.buildDir).matching { include 'libs/*-test.jar' }.each { - def outputDir = file("${buildDir}/unpacked/" + it.name) - testClassesDirs += files(outputDir) - classpath += files(outputDir) - } - systemProperty 'file.encoding', 'utf-8' - - if ( gradle.ext.javaVersions.test.launcher.asInt() >= 9 ) { - // See org.hibernate.boot.model.naming.NamingHelperTest.DefaultCharset.set - jvmArgs( ['--add-opens', 'java.base/java.nio.charset=ALL-UNNAMED'] ) - // Weld needs this to generate proxies - jvmArgs( ['--add-opens', 'java.base/java.security=ALL-UNNAMED'] ) - jvmArgs( ['--add-opens', 'java.base/java.lang=ALL-UNNAMED'] ) - } -} \ No newline at end of file +// todo: enable again when we can finally use the Jakarta JARs from narayana +//task unpackTestJar(type: Copy) { +// dependsOn jar +// fileTree(project.buildDir).matching { include 'libs/*-test.jar' }.each { +// def outputDir = file("${buildDir}/unpacked/" + it.name) +// from zipTree(it) +// into outputDir +// } +//} +// +//test { +// dependsOn unpackTestJar +// fileTree(project.buildDir).matching { include 'libs/*-test.jar' }.each { +// def outputDir = file("${buildDir}/unpacked/" + it.name) +// testClassesDirs += files(outputDir) +// classpath += files(outputDir) +// } +// systemProperty 'file.encoding', 'utf-8' +// +// if ( gradle.ext.javaVersions.test.launcher.asInt() >= 9 ) { +// // See org.hibernate.boot.model.naming.NamingHelperTest.DefaultCharset.set +// jvmArgs( ['--add-opens', 'java.base/java.nio.charset=ALL-UNNAMED'] ) +// // Weld needs this to generate proxies +// jvmArgs( ['--add-opens', 'java.base/java.security=ALL-UNNAMED'] ) +// jvmArgs( ['--add-opens', 'java.base/java.lang=ALL-UNNAMED'] ) +// } +//} \ No newline at end of file diff --git a/hibernate-jboss-jta/hibernate-jboss-jta.gradle b/hibernate-jboss-jta/hibernate-jboss-jta.gradle index e0331957af4a..bc3ebb694f56 100644 --- a/hibernate-jboss-jta/hibernate-jboss-jta.gradle +++ b/hibernate-jboss-jta/hibernate-jboss-jta.gradle @@ -7,7 +7,13 @@ description = 'JBoss JTA transformed to be JTA 2.0 compatible' -apply from: rootProject.file( 'gradle/java-module.gradle' ) +apply from: rootProject.file( 'gradle/published-java-module.gradle' ) + +tasks.withType(PublishToMavenRepository) { + onlyIf { + repository == publishing.repositories.mavenLocal + } +} configurations { jakartaeeTransformJars @@ -16,7 +22,7 @@ configurations { dependencies { compile( libraries.jakarta_jta ) compile( libraries.jakarta_resource ) - compile( project(':hibernate-transaction-spi') ) + compile( libraries.jboss_tx_spi_jakarta ) jakartaeeTransformJars 'biz.aQute.bnd:biz.aQute.bnd.transform:5.1.1', 'commons-cli:commons-cli:1.4', diff --git a/hibernate-testing-jakarta/hibernate-testing-jakarta.gradle b/hibernate-testing-jakarta/hibernate-testing-jakarta.gradle index 34aa2bed41b2..a0182448274b 100644 --- a/hibernate-testing-jakarta/hibernate-testing-jakarta.gradle +++ b/hibernate-testing-jakarta/hibernate-testing-jakarta.gradle @@ -7,9 +7,13 @@ description = 'Support for testing Hibernate ORM Jakarta functionality' -// todo (jakarta): replace this when the jakarta artifact is released -apply from: rootProject.file( 'gradle/java-module.gradle' ) -//apply from: rootProject.file( 'gradle/published-java-module.gradle' ) +apply from: rootProject.file( 'gradle/published-java-module.gradle' ) + +tasks.withType(PublishToMavenRepository) { + onlyIf { + repository == publishing.repositories.mavenLocal + } +} configurations { jakartaeeTransformJars @@ -26,9 +30,9 @@ dependencies { compile( libraries.log4j ) // todo (jakarta): replace this when the jakarta artifacts are released compile project( ':hibernate-jboss-jta' ) -// compile( libraries.jboss_tx_spi_jakarta ) { -// transitive=false; -// } + compile( libraries.jboss_tx_spi_jakarta ) { + transitive=false; + } // compile ( libraries.jboss_jta_jakarta ) { // transitive=false; // } diff --git a/hibernate-transaction-client/hibernate-transaction-client.gradle b/hibernate-transaction-client/hibernate-transaction-client.gradle index bd3cb0430b80..591d8367eac6 100644 --- a/hibernate-transaction-client/hibernate-transaction-client.gradle +++ b/hibernate-transaction-client/hibernate-transaction-client.gradle @@ -7,7 +7,13 @@ description = 'Wildfly Transaction Client transformed to be JTA 2.0 compatible' -apply from: rootProject.file( 'gradle/java-module.gradle' ) +apply from: rootProject.file( 'gradle/published-java-module.gradle' ) + +tasks.withType(PublishToMavenRepository) { + onlyIf { + repository == publishing.repositories.mavenLocal + } +} configurations { jakartaeeTransformJars diff --git a/hibernate-transaction-spi/hibernate-transaction-spi.gradle b/hibernate-transaction-spi/hibernate-transaction-spi.gradle deleted file mode 100644 index 57aced585fd6..000000000000 --- a/hibernate-transaction-spi/hibernate-transaction-spi.gradle +++ /dev/null @@ -1,62 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ - -description = 'Wildfly Transaction SPI transformed to be JTA 2.0 compatible' - -apply from: rootProject.file( 'gradle/java-module.gradle' ) - -configurations { - jakartaeeTransformJars -} - -dependencies { - compile( libraries.jakarta_jta ) - - jakartaeeTransformJars 'biz.aQute.bnd:biz.aQute.bnd.transform:5.1.1', - 'commons-cli:commons-cli:1.4', - 'org.slf4j:slf4j-simple:1.7.30', - 'org.slf4j:slf4j-api:1.7.26', - 'org.eclipse.transformer:org.eclipse.transformer:0.2.0', - 'org.eclipse.transformer:org.eclipse.transformer.cli:0.2.0' - testCompile ( libraries.jboss_tx_spi ) { - transitive=false; - } -} - -jar { - def sourceJarPath = project.configurations.testCompile.find { it.name.startsWith("jboss-transaction-spi-") } - inputs.files(sourceJarPath).skipWhenEmpty() - outputs.dir project.buildDir - doLast { - new File(project.buildDir, "libs").mkdirs() - fileTree(project.buildDir).matching { include 'libs/*.jar' }.each { delete it } - - println 'Initial bundle jar name [ ' + sourceJarPath + ' ]' - - def finalBundleJarName = project.buildDir.path + '/libs/hibernate-transaction-spi-' + project.version + ".jar" - println 'Default jakarta final bundle jar name [ ' + finalBundleJarName + ' ]' - - def transformerArgs = [ - sourceJarPath, finalBundleJarName, - '-q', // quiet output - '-tr', new File(getProjectDir().getParentFile(), 'rules/jakarta-renames.properties').path, - '-tv', new File(getProjectDir().getParentFile(), 'rules/jakarta-versions.properties').path, - '-td', new File(getProjectDir().getParentFile(), 'rules/jakarta-direct.properties').path, - ] - - println 'Transformer options:' - transformerArgs.each { - println ' [ ' + it + ' ]' - } - - javaexec { - classpath configurations.jakartaeeTransformJars - main = 'org.eclipse.transformer.jakarta.JakartaTransformer' - args = transformerArgs - } - } -} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index ca6903e25cb3..af1d875e26ed 100644 --- a/settings.gradle +++ b/settings.gradle @@ -90,11 +90,11 @@ include 'hibernate-core' include 'hibernate-core-jakarta' include 'hibernate-entitymanager' include 'hibernate-testing' -include 'hibernate-testing-jakarta' +// todo: enable again when we can finally use the Jakarta JARs from narayana +//include 'hibernate-testing-jakarta' // todo (jakarta): remove these three when the jakarta artifacts are released -include 'hibernate-jboss-jta' -include 'hibernate-transaction-client' -include 'hibernate-transaction-spi' +//include 'hibernate-jboss-jta' +//include 'hibernate-transaction-client' include 'hibernate-envers' include 'hibernate-envers-jakarta' From 8dabefd11153b80bad79dbe10ca874003647e24a Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Thu, 22 Apr 2021 17:14:22 +0200 Subject: [PATCH 133/644] HHH-14573 Remove useless call to EnhancementAsProxyLazinessInterceptor#isInitialized() --- .../hibernate/engine/internal/AbstractEntityEntry.java | 4 +--- .../java/org/hibernate/event/internal/WrapVisitor.java | 8 ++------ 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/AbstractEntityEntry.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/AbstractEntityEntry.java index c203ce250618..cfa74558cead 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/internal/AbstractEntityEntry.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/AbstractEntityEntry.java @@ -355,9 +355,7 @@ private boolean isUnequivocallyNonDirty(Object entity) { if ( enhancementAsProxyLazinessInterceptor.hasWrittenFieldNames() ) { return false; } - // When a proxy has dirty attributes, we have to treat it like a normal entity to flush changes - return !enhancementAsProxyLazinessInterceptor.isInitialized() - || !persister.hasCollections() && !( (SelfDirtinessTracker) entity ).$$_hibernate_hasDirtyAttributes(); + return true; } } else if ( entity instanceof HibernateProxy ) { diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/WrapVisitor.java b/hibernate-core/src/main/java/org/hibernate/event/internal/WrapVisitor.java index a7e038995699..bf6193aaa392 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/WrapVisitor.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/WrapVisitor.java @@ -15,7 +15,6 @@ import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.engine.spi.PersistenceContext; import org.hibernate.engine.spi.PersistentAttributeInterceptable; -import org.hibernate.engine.spi.PersistentAttributeInterceptor; import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.event.spi.EventSource; import org.hibernate.internal.CoreLogging; @@ -109,11 +108,8 @@ final Object processArrayOrNewCollection(Object collection, CollectionType colle } else { if ( entity instanceof PersistentAttributeInterceptable ) { - final PersistentAttributeInterceptor interceptor = ( (PersistentAttributeInterceptable) entity ).$$_hibernate_getInterceptor(); - if ( interceptor instanceof EnhancementAsProxyLazinessInterceptor ) { - if ( !( (EnhancementAsProxyLazinessInterceptor) interceptor ).isInitialized() ) { - return null; - } + if ( ( (PersistentAttributeInterceptable) entity ).$$_hibernate_getInterceptor() instanceof EnhancementAsProxyLazinessInterceptor ) { + return null; } } From 996debdc5410992fdfbbce5cf57492f4db69a367 Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Fri, 30 Apr 2021 12:24:18 +0000 Subject: [PATCH 134/644] 5.5.0.Alpha1 --- changelog.txt | 58 +++++++++++++++++++++++++++++++++++++++ gradle/version.properties | 2 +- 2 files changed, 59 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index e9aed989b0b1..3d8548993b5c 100644 --- a/changelog.txt +++ b/changelog.txt @@ -3,6 +3,64 @@ Hibernate 5 Changelog Note: Please refer to JIRA to learn more about each issue. +Changes in 5.5.0.Alpha1 (April 30, 2021) +------------------------------------------------------------------------------------------------------------------------ + +https://hibernate.atlassian.net/projects/HHH/versions/31844 + +** Bug + * [HHH-14571] - Hibernate.isPropertyInitialized( someEntity, "id" ) returns false + * [HHH-14567] - Filters are ignored if enabled after query creation but before execution + * [HHH-14557] - Connection leaked on rollback with mode DELAYED_ACQUISITION_AND_RELEASE_BEFORE_TRANSACTION_COMPLETION + * [HHH-14549] - Collection with default field initializer will always be empty + * [HHH-14537] - EntityNotFoundException thrown when non-existing association with @NotFound(IGNORE) mapped has proxy in PersistenceContext + * [HHH-14523] - Spatial Update Z axis of a org.locationtech.jts.geom.Point on Postgis + * [HHH-14475] - select indices from ternary relation is broken since 5.4.13 + * [HHH-14471] - Concurrency issue in DynamicBatchingEntityLoader + * [HHH-14467] - AnnotationException: A Foreign key refering from has the wrong number of column. should be 0 + * [HHH-14466] - StackOverflowError loading an entity with eager one-to-many if bidirectional and many-to-one side is the ID + * [HHH-14460] - NPE when setter is missing for persistent property + * [HHH-14449] - ResultStream closing is not properly handled + * [HHH-14445] - Javassist skip EntityWithMutableAttributesTest, LoadAndUpdateEntitiesWithCollectionsTest, SimpleDynamicUpdateTest, SimpleDynamicUpdateTest + * [HHH-14439] - QueryException: Unrecognized parameter label when executing the same query with subselects twice with different list parameters + * [HHH-14424] - When enhanced as a proxy with dirty checking is enabled, on flush uninitialized entities containing collections are updated setting all fields to null + * [HHH-14408] - SPI provided user types are not applied + * [HHH-14407] - NPE in Column.getSqlTypeCode(Mapping mapping) for column 'hib_sess_id' when using PersistentTableBulkIdStrategy + * [HHH-14404] - SessionBuilder.connectionHandlingMode is ignored + * [HHH-14390] - StackOverflowError with @Fetch(FetchMode.SELECT) mapped for entity with an ID that is a bidirectional one-to-one eager association + * [HHH-14389] - Add test case that throw IllegalArgumentException using EntityManager#find by ID when ID is a one-to-one association + * [HHH-14386] - Persistence.createEntityManagerFactory("testPU") fails, if persistence unit has config & CurrentTenantIdentifierResolver is not null. + * [HHH-14384] - Fix QueryProducer.createNativeQuery documentation + * [HHH-14380] - Join ordering logic wrongly pushes cross joins from subqueries to parent + * [HHH-14364] - UpdateDetachedTest#testUpdateDetachedWithAttachedPersistentSet failing when run on OracleDB + * [HHH-14363] - MutableTypeEnhancementTestCase failing when run on Oracle DB + * [HHH-14360] - NullPointerException on AbstractEntityPersister.resolveDirtyAttributeIndexes + * [HHH-14355] - NPE in Envers AdditionalJaxbMappingProducerImpl when XML mapping is disabled + * [HHH-14351] - Broken order by type + * [HHH-14350] - MariaDB103Dialect requires the lock wait timeout to be expressed in seconds + * [HHH-14348] - Lazy collection is fetched during dirty checking with bytecode enhancement + * [HHH-14346] - org.hibernate.metamodel.model.domain.internal.AbstractManagedType#getPluralAttributes NPE + * [HHH-14343] - Nested ID classes fail with AnnotationException: Column name game_id of x.x.PlayerStat not found in JoinColumns.referencedColumnName + * [HHH-14335] - Cache resolution of SimpleValue#getType + * [HHH-14333] - Pessimistic Lock causes FOR UPDATE on outer join statements + * [HHH-14329] - DirtinessTracker usage for enhanced entities doesn't respect mutable types + * [HHH-14322] - HBM many-to-one property-ref broken since 5.3.2 due to HHH-12684 + * [HHH-14319] - CollectionType#replaceElements may clear the original collection during merge + * [HHH-14317] - Avoid closing datasource in AgroalConnectionProvider if datasource is not initialized + * [HHH-14316] - Avoid accessing state in DriverManagerConnectionProviderImpl if null + * [HHH-14312] - Padded batch style entity loader ignores entity graph + * [HHH-14310] - Document hibernate.query.in_clause_parameter_padding + * [HHH-14288] - Complex batch insert query stopped to work + * [HHH-14279] - Broken 'with key(...)' operator on entity-key maps + * [HHH-14276] - Nested ID class using derived identifiers fails with strange AnnotationException: unable to find column reference in the @MapsId mapping: `game_id` + * [HHH-14275] - Broken link to Infinispan User Guide in Hibernate 5.3 User Guide + * [HHH-14264] - Entity graph cannot be applied to child class + * [HHH-14260] - Dead links in user guide + * [HHH-14257] - An Entity A with a map collection having as index an Embeddable with a an association to the Entity A fails with a NPE + * [HHH-14251] - Invalid SQL for @Embedded UPDATE + * [HHH-14249] - MultiLineImport fails when script contains blank spaces or tabs at the end of the last sql statement + + Changes in 5.4.14.Final (April 6, 2020) ------------------------------------------------------------------------------------------------------------------------ diff --git a/gradle/version.properties b/gradle/version.properties index 27307e6e59d0..f8f2cedadf1d 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -hibernateVersion=5.5.0-SNAPSHOT \ No newline at end of file +hibernateVersion=5.5.0.Alpha1 \ No newline at end of file From 830423422d357bfe374bae54ed6db39c3fb0daf1 Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Fri, 30 Apr 2021 12:30:04 +0000 Subject: [PATCH 135/644] 5.5.0-SNAPSHOT --- gradle/version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/version.properties b/gradle/version.properties index f8f2cedadf1d..27307e6e59d0 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -hibernateVersion=5.5.0.Alpha1 \ No newline at end of file +hibernateVersion=5.5.0-SNAPSHOT \ No newline at end of file From 41c71bfed7d8eb74bd0574ed7bd2552d055dcf46 Mon Sep 17 00:00:00 2001 From: Emmanuel Duchastenier Date: Tue, 23 Mar 2021 17:37:35 +0100 Subject: [PATCH 136/644] HHH-13779 (5.4) - Foreign key schema migrator should be case-insensitive This avoids re-creating existing foreign keys with a different name, after migrating from Hibernate 4 to Hibernate 5 (as implicit naming convention has changed). Actually, some RDBMS allow it (PostgreSQL, MySQL, MS SQL Server, ...) and duplicate the same key, whereas others (Oracle, ...) do not allow it and Schema update fails. This fix ignores the case of the table and column name when checking if a equivalent Foreign Key already exists (whatever its name) Closes https://hibernate.atlassian.net/browse/HHH-13779 (cherry picked from commit 0b819863f2cee41c7067d7e3656356f0b1221ef1) --- .../internal/AbstractSchemaMigrator.java | 21 +++--- .../internal/AbstractSchemaMigratorTest.java | 73 +++++++++++++++++++ 2 files changed, 85 insertions(+), 9 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/tool/schema/internal/AbstractSchemaMigratorTest.java diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/AbstractSchemaMigrator.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/AbstractSchemaMigrator.java index e38b3034b076..0f58cfee5099 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/AbstractSchemaMigrator.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/AbstractSchemaMigrator.java @@ -463,15 +463,7 @@ private boolean checkForExistingForeignKey(ForeignKey foreignKey, TableInformati * Find existing keys based on referencing column and referencedTable. "referencedColumnName" is not checked * because that always is the primary key of the "referencedTable". */ - Predicate mappingPredicate = m -> { - String existingReferencingColumn = m.getReferencingColumnMetadata().getColumnIdentifier().getText(); - String existingReferencedTable = m.getReferencedColumnMetadata().getContainingTableInformation().getName().getTableName().getCanonicalName(); - return referencingColumn.equals( existingReferencingColumn ) && referencedTable.equals( existingReferencedTable ); - }; - Stream keyStream = StreamSupport.stream( tableInformation.getForeignKeys().spliterator(), false ); - Stream mappingStream = keyStream.flatMap( k -> StreamSupport.stream( k.getColumnReferenceMappings().spliterator(), false ) ); - boolean found = mappingStream.anyMatch( mappingPredicate ); - if ( found ) { + if (equivalentForeignKeyExistsInDatabase(tableInformation, referencingColumn, referencedTable)) { return true; } @@ -480,6 +472,17 @@ private boolean checkForExistingForeignKey(ForeignKey foreignKey, TableInformati return tableInformation.getForeignKey( Identifier.toIdentifier( foreignKey.getName() ) ) != null; } + boolean equivalentForeignKeyExistsInDatabase(TableInformation tableInformation, String referencingColumn, String referencedTable) { + Predicate mappingPredicate = m -> { + String existingReferencingColumn = m.getReferencingColumnMetadata().getColumnIdentifier().getText(); + String existingReferencedTable = m.getReferencedColumnMetadata().getContainingTableInformation().getName().getTableName().getCanonicalName(); + return referencingColumn.equalsIgnoreCase( existingReferencingColumn ) && referencedTable.equalsIgnoreCase( existingReferencedTable ); + }; + Stream keyStream = StreamSupport.stream( tableInformation.getForeignKeys().spliterator(), false ); + Stream mappingStream = keyStream.flatMap( k -> StreamSupport.stream( k.getColumnReferenceMappings().spliterator(), false ) ); + return mappingStream.anyMatch( mappingPredicate ); + } + protected void checkExportIdentifier(Exportable exportable, Set exportIdentifiers) { final String exportIdentifier = exportable.getExportIdentifier(); if ( exportIdentifiers.contains( exportIdentifier ) ) { diff --git a/hibernate-core/src/test/java/org/hibernate/tool/schema/internal/AbstractSchemaMigratorTest.java b/hibernate-core/src/test/java/org/hibernate/tool/schema/internal/AbstractSchemaMigratorTest.java new file mode 100644 index 000000000000..8635fb788a83 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/tool/schema/internal/AbstractSchemaMigratorTest.java @@ -0,0 +1,73 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.tool.schema.internal; + +import java.util.ArrayList; +import java.util.Set; + +import org.hibernate.boot.Metadata; +import org.hibernate.boot.model.TruthValue; +import org.hibernate.boot.model.naming.Identifier; +import org.hibernate.boot.model.relational.Namespace; +import org.hibernate.boot.model.relational.QualifiedTableName; +import org.hibernate.dialect.Dialect; +import org.hibernate.engine.jdbc.internal.Formatter; +import org.hibernate.testing.TestForIssue; +import org.hibernate.tool.schema.extract.internal.ColumnInformationImpl; +import org.hibernate.tool.schema.extract.internal.ForeignKeyInformationImpl; +import org.hibernate.tool.schema.extract.spi.DatabaseInformation; +import org.hibernate.tool.schema.extract.spi.ForeignKeyInformation; +import org.hibernate.tool.schema.extract.spi.NameSpaceTablesInformation; +import org.hibernate.tool.schema.extract.spi.TableInformation; +import org.hibernate.tool.schema.internal.exec.GenerationTarget; +import org.hibernate.tool.schema.spi.ExecutionOptions; +import org.junit.Test; + +import static java.util.Collections.singletonList; +import static org.hamcrest.core.Is.is; +import static org.hibernate.boot.model.naming.Identifier.toIdentifier; +import static org.junit.Assert.assertThat; +import static org.mockito.Mockito.doReturn; +import static org.mockito.Mockito.mock; + +/** + * @author Emmanuel Duchastenier + */ +public class AbstractSchemaMigratorTest { + + @Test + @TestForIssue(jiraKey = "HHH-13779") + public void testForeignKeyPreExistenceDetectionIgnoresCaseForTableAndColumnName() { + final AbstractSchemaMigrator schemaMigrator = new AbstractSchemaMigrator(null, null) { + @Override + protected NameSpaceTablesInformation performTablesMigration(Metadata metadata, DatabaseInformation existingDatabase, ExecutionOptions options, Dialect dialect, Formatter formatter, Set exportIdentifiers, boolean tryToCreateCatalogs, boolean tryToCreateSchemas, Set exportedCatalogs, Namespace namespace, GenerationTarget[] targets) { return null; } + }; + + final TableInformation existingTableInformation = mock(TableInformation.class); + final ArrayList columnReferenceMappings = new ArrayList<>(); + + final TableInformation destinationTableInformation = mock(TableInformation.class); + doReturn(new QualifiedTableName(toIdentifier("catalog"), toIdentifier("schema"), + toIdentifier("referenced_table"))) // Table name is lower case + .when(destinationTableInformation).getName(); + columnReferenceMappings.add(new ForeignKeyInformationImpl.ColumnReferenceMappingImpl( + new ColumnInformationImpl(null, toIdentifier("referencing_column"), // column name is lower case + 0, "typeName", 255, 0, TruthValue.TRUE), + new ColumnInformationImpl(destinationTableInformation, null, 1, "typeName", 0, 0, TruthValue.TRUE))); + doReturn(singletonList(new ForeignKeyInformationImpl(toIdentifier("FKp8mpamfw2inhj88hwhty1eipm"), columnReferenceMappings))) + .when(existingTableInformation).getForeignKeys(); + + final boolean existInDatabase = schemaMigrator.equivalentForeignKeyExistsInDatabase( + existingTableInformation, + "REFERENCING_COLUMN", "REFERENCED_TABLE"); // Table and column names are UPPER-case here, to prove the test + + assertThat("Expected ForeignKey pre-existence check to be case-insensitive", + existInDatabase, + is(true)); + } + +} \ No newline at end of file From 7144af5990ca4a11abbafeff26a1ad957ad08d71 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Mon, 3 May 2021 17:50:38 +0200 Subject: [PATCH 137/644] HHH-12445 Auto-detect when discriminator columns are nullable --- .../DiscriminatorNotNullSingleTableTest.java | 6 --- .../org/hibernate/cfg/AnnotationBinder.java | 4 +- .../cfg/annotations/EntityBinder.java | 1 + ...NullableDiscriminatorColumnSecondPass.java | 53 +++++++++++++++++++ 4 files changed, 57 insertions(+), 7 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/cfg/internal/NullableDiscriminatorColumnSecondPass.java diff --git a/documentation/src/test/java/org/hibernate/userguide/inheritance/DiscriminatorNotNullSingleTableTest.java b/documentation/src/test/java/org/hibernate/userguide/inheritance/DiscriminatorNotNullSingleTableTest.java index 2c3bbf9ef3c5..16a503ef573f 100644 --- a/documentation/src/test/java/org/hibernate/userguide/inheritance/DiscriminatorNotNullSingleTableTest.java +++ b/documentation/src/test/java/org/hibernate/userguide/inheritance/DiscriminatorNotNullSingleTableTest.java @@ -45,12 +45,6 @@ protected Class[] getAnnotatedClasses() { @Test public void test() { doInJPA( this::entityManagerFactory, entityManager -> { - entityManager.unwrap( Session.class ).doWork( connection -> { - try(Statement statement = connection.createStatement()) { - statement.executeUpdate( "ALTER TABLE Account ALTER COLUMN DTYPE SET NULL" ); - } - } ); - //tag::entity-inheritance-single-table-discriminator-value-persist-example[] DebitAccount debitAccount = new DebitAccount(); debitAccount.setId( 1L ); diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java b/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java index a1e0f7c7799f..344b1e234c62 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java @@ -8,7 +8,6 @@ import java.util.ArrayList; import java.util.Arrays; -import java.util.Collection; import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; @@ -146,6 +145,7 @@ import org.hibernate.cfg.annotations.QueryBinder; import org.hibernate.cfg.annotations.SimpleValueBinder; 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; @@ -1484,6 +1484,8 @@ private static void bindDiscriminatorColumnToRootPersistentClass( if ( LOG.isTraceEnabled() ) { LOG.tracev( "Setting discriminator for entity {0}", rootClass.getEntityName() ); } + context.getMetadataCollector().addSecondPass( + new NullableDiscriminatorColumnSecondPass( rootClass.getEntityName() ) ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/EntityBinder.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/EntityBinder.java index ff12ec196cbd..b8a23e596e4e 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/EntityBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/EntityBinder.java @@ -71,6 +71,7 @@ import org.hibernate.cfg.AccessType; import org.hibernate.cfg.AnnotationBinder; import org.hibernate.cfg.BinderHelper; +import org.hibernate.cfg.Ejb3DiscriminatorColumn; import org.hibernate.cfg.Ejb3JoinColumn; import org.hibernate.cfg.InheritanceState; import org.hibernate.cfg.ObjectNameSource; diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/internal/NullableDiscriminatorColumnSecondPass.java b/hibernate-core/src/main/java/org/hibernate/cfg/internal/NullableDiscriminatorColumnSecondPass.java new file mode 100644 index 000000000000..989b8604cbe4 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/cfg/internal/NullableDiscriminatorColumnSecondPass.java @@ -0,0 +1,53 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.cfg.internal; + +import java.util.Iterator; +import java.util.Map; + +import org.hibernate.MappingException; +import org.hibernate.cfg.SecondPass; +import org.hibernate.mapping.Column; +import org.hibernate.mapping.PersistentClass; +import org.hibernate.mapping.Selectable; + +public class NullableDiscriminatorColumnSecondPass implements SecondPass { + private final String rootEntityName; + + public NullableDiscriminatorColumnSecondPass(String rootEntityName) { + this.rootEntityName = rootEntityName; + } + + @Override + @SuppressWarnings("rawtypes") + public void doSecondPass(Map persistentClasses) throws MappingException { + PersistentClass rootPersistenceClass = (PersistentClass) persistentClasses.get( rootEntityName ); + if ( hasNullDiscriminatorValue( rootPersistenceClass ) ) { + for ( Iterator iterator = rootPersistenceClass.getDiscriminator().getColumnIterator(); + iterator.hasNext(); ) { + Selectable selectable = iterator.next(); + if ( selectable instanceof Column ) { + ( (Column) selectable ).setNullable( true ); + } + } + } + } + + @SuppressWarnings({ "unchecked" }) + private boolean hasNullDiscriminatorValue(PersistentClass rootPersistenceClass) { + if ( rootPersistenceClass.isDiscriminatorValueNull() ) { + return true; + } + Iterator subclassIterator = rootPersistenceClass.getSubclassIterator(); + while ( subclassIterator.hasNext() ) { + if ( subclassIterator.next().isDiscriminatorValueNull() ) { + return true; + } + } + return false; + } +} From 1a2510df1604b9e8be10f543e2ea8f78f51768f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Mon, 3 May 2021 18:11:29 +0200 Subject: [PATCH 138/644] HHH-12445 Fix ORM not detecting "null"/"not null" discriminator values correctly for joined inheritance --- .../entity/JoinedSubclassEntityPersister.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java index 8fb627946786..862e91419cd8 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java @@ -106,7 +106,7 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister { // subclass discrimination works by assigning particular // values to certain combinations of null primary key // values in the outer join using an SQL CASE - private final Map subclassesByDiscriminatorValue = new HashMap(); + private final Map subclassesByDiscriminatorValue = new HashMap<>(); private final String[] discriminatorValues; private final String[] notNullColumnNames; private final int[] notNullColumnTableNumbers; @@ -801,7 +801,16 @@ public String getDiscriminatorAlias() { } public String getSubclassForDiscriminatorValue(Object value) { - return (String) subclassesByDiscriminatorValue.get( value ); + if ( value == null ) { + return subclassesByDiscriminatorValue.get( NULL_DISCRIMINATOR ); + } + else { + String result = subclassesByDiscriminatorValue.get( value ); + if ( result == null ) { + result = subclassesByDiscriminatorValue.get( NOT_NULL_DISCRIMINATOR ); + } + return result; + } } @Override From 662f86abe1c79c5e3fe9da86ee9d25cebd4beb61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Mon, 3 May 2021 18:12:13 +0200 Subject: [PATCH 139/644] HHH-12445 Test "null"/"not-null" discriminator values --- ...ngleTableNullNotNullDiscriminatorTest.java | 112 +++++++++++++++++ .../JoinedNullNotNullDiscriminatorTest.java | 114 ++++++++++++++++++ 2 files changed, 226 insertions(+) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/inheritance/discriminator/SingleTableNullNotNullDiscriminatorTest.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/inheritance/discriminator/joinedsubclass/JoinedNullNotNullDiscriminatorTest.java diff --git a/hibernate-core/src/test/java/org/hibernate/test/inheritance/discriminator/SingleTableNullNotNullDiscriminatorTest.java b/hibernate-core/src/test/java/org/hibernate/test/inheritance/discriminator/SingleTableNullNotNullDiscriminatorTest.java new file mode 100644 index 000000000000..71d48e40c65a --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/inheritance/discriminator/SingleTableNullNotNullDiscriminatorTest.java @@ -0,0 +1,112 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.inheritance.discriminator; + +import java.sql.Statement; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; +import javax.persistence.DiscriminatorValue; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Inheritance; +import javax.persistence.InheritanceType; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +@TestForIssue(jiraKey = "HHH-12445") +public class SingleTableNullNotNullDiscriminatorTest extends BaseCoreFunctionalTestCase { + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + RootEntity.class, + Val1Entity.class, + Val2Entity.class, + NotNullEntity.class + }; + } + + @Test + public void test() { + inTransaction( session -> { + Val1Entity val1 = new Val1Entity(); + val1.setId( 1L ); + + Val2Entity val2 = new Val2Entity(); + val2.setId( 2L ); + + RootEntity root = new RootEntity(); + root.setId( 3L ); + + session.persist( val1 ); + session.persist( val2 ); + session.persist( root ); + + session.doWork( connection -> { + try (Statement statement = connection.createStatement()) { + statement.executeUpdate( + "insert into root_ent (DTYPE, id) " + + "values ('other', 4)" + ); + } + } ); + } ); + + inTransaction( session -> { + Map entities = session.createQuery( + "select e from root_ent e", RootEntity.class ) + .getResultList() + .stream() + .collect( Collectors.toMap( RootEntity::getId, Function.identity() ) ); + + assertThat( entities ).extractingByKey( 1L ).isInstanceOf( Val1Entity.class ); + assertThat( entities ).extractingByKey( 2L ).isInstanceOf( Val2Entity.class ); + assertThat( entities ).extractingByKey( 3L ).isInstanceOf( RootEntity.class ); + assertThat( entities ).extractingByKey( 4L ).isInstanceOf( NotNullEntity.class ); + } ); + } + + @Entity(name = "root_ent") + @Inheritance(strategy = InheritanceType.SINGLE_TABLE) + @DiscriminatorValue("null") + public static class RootEntity { + + @Id + private Long id; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + } + + @Entity(name = "val1_ent") + @DiscriminatorValue("val1") + public static class Val1Entity extends RootEntity { + + } + + @Entity(name = "val2_ent") + @DiscriminatorValue("val2") + public static class Val2Entity extends RootEntity { + + } + + @Entity(name = "notnull_ent") + @DiscriminatorValue("not null") + public static class NotNullEntity extends RootEntity { + + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/inheritance/discriminator/joinedsubclass/JoinedNullNotNullDiscriminatorTest.java b/hibernate-core/src/test/java/org/hibernate/test/inheritance/discriminator/joinedsubclass/JoinedNullNotNullDiscriminatorTest.java new file mode 100644 index 000000000000..495ab9fff4fe --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/inheritance/discriminator/joinedsubclass/JoinedNullNotNullDiscriminatorTest.java @@ -0,0 +1,114 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.inheritance.discriminator.joinedsubclass; + +import java.sql.Statement; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; +import javax.persistence.DiscriminatorColumn; +import javax.persistence.DiscriminatorValue; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Inheritance; +import javax.persistence.InheritanceType; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.Test; + +import static org.assertj.core.api.Assertions.assertThat; + +@TestForIssue(jiraKey = "HHH-12445") +public class JoinedNullNotNullDiscriminatorTest extends BaseCoreFunctionalTestCase { + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + RootEntity.class, + Val1Entity.class, + Val2Entity.class, + NotNullEntity.class + }; + } + + @Test + public void test() { + inTransaction( session -> { + Val1Entity val1 = new Val1Entity(); + val1.setId( 1L ); + + Val2Entity val2 = new Val2Entity(); + val2.setId( 2L ); + + RootEntity root = new RootEntity(); + root.setId( 3L ); + + session.persist( val1 ); + session.persist( val2 ); + session.persist( root ); + + session.doWork( connection -> { + try (Statement statement = connection.createStatement()) { + statement.executeUpdate( + "insert into root_ent (DTYPE, id) " + + "values ('other', 4)" + ); + } + } ); + } ); + + inTransaction( session -> { + Map entities = session.createQuery( + "select e from root_ent e", RootEntity.class ) + .getResultList() + .stream() + .collect( Collectors.toMap( RootEntity::getId, Function.identity() ) ); + + assertThat( entities ).extractingByKey( 1L ).isInstanceOf( Val1Entity.class ); + assertThat( entities ).extractingByKey( 2L ).isInstanceOf( Val2Entity.class ); + assertThat( entities ).extractingByKey( 3L ).isInstanceOf( RootEntity.class ); + assertThat( entities ).extractingByKey( 4L ).isInstanceOf( NotNullEntity.class ); + } ); + } + + @Entity(name = "root_ent") + @Inheritance(strategy = InheritanceType.JOINED) + @DiscriminatorColumn() + @DiscriminatorValue("null") + public static class RootEntity { + + @Id + private Long id; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + } + + @Entity(name = "val1_ent") + @DiscriminatorValue("val1") + public static class Val1Entity extends RootEntity { + + } + + @Entity(name = "val2_ent") + @DiscriminatorValue("val2") + public static class Val2Entity extends RootEntity { + + } + + @Entity(name = "notnull_ent") + @DiscriminatorValue("not null") + public static class NotNullEntity extends RootEntity { + + } +} From 72f4a2f61017f1b45812874031ef7debff34fe9e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Mon, 3 May 2021 18:13:16 +0200 Subject: [PATCH 140/644] HHH-12445 Remove unused constants related to "null"/"not-null" discriminator values --- .../persister/entity/JoinedSubclassEntityPersister.java | 2 -- .../hibernate/persister/entity/SingleTableEntityPersister.java | 2 -- 2 files changed, 4 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java index 862e91419cd8..fa7f5cb30d88 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java @@ -62,8 +62,6 @@ public class JoinedSubclassEntityPersister extends AbstractEntityPersister { private static final String IMPLICIT_DISCRIMINATOR_ALIAS = "clazz_"; private static final Object NULL_DISCRIMINATOR = new MarkerObject(""); private static final Object NOT_NULL_DISCRIMINATOR = new MarkerObject(""); - private static final String NULL_STRING = "null"; - private static final String NOT_NULL_STRING = "not null"; // the class hierarchy structure private final int tableSpan; diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java index 494ce3f2437d..566d8d5a49c0 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java @@ -114,8 +114,6 @@ public class SingleTableEntityPersister extends AbstractEntityPersister { private static final Object NULL_DISCRIMINATOR = new MarkerObject( "" ); private static final Object NOT_NULL_DISCRIMINATOR = new MarkerObject( "" ); - private static final String NULL_STRING = "null"; - private static final String NOT_NULL_STRING = "not null"; //INITIALIZATION: From 129484557b3e92f2a59db6b41db107e2c78e6f41 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Wed, 5 May 2021 15:47:50 +0200 Subject: [PATCH 141/644] Re-include the temporary jakarta testing modules --- ci/jpa-2.2-tck.Jenkinsfile | 6 +++--- ci/jpa-3.0-tck.Jenkinsfile | 6 +++--- settings.gradle | 9 ++++----- 3 files changed, 10 insertions(+), 11 deletions(-) diff --git a/ci/jpa-2.2-tck.Jenkinsfile b/ci/jpa-2.2-tck.Jenkinsfile index fbc97668e0fd..87e9aa7bab20 100644 --- a/ci/jpa-2.2-tck.Jenkinsfile +++ b/ci/jpa-2.2-tck.Jenkinsfile @@ -38,7 +38,7 @@ pipeline { stage('Run TCK') { steps { sh """ \ - docker rm -f tck + docker rm -f tck || true docker run -v ~/.m2/repository/org/hibernate:/root/.m2/repository/org/hibernate:z -e NO_SLEEP=true -e HIBERNATE_VERSION=$HIBERNATE_VERSION --name tck jakarta-tck-runner docker cp tck:/tck/persistence-tck/tmp/JTreport/ ./JTreport """ @@ -47,8 +47,8 @@ pipeline { failures = sh ( script: """ \ while read line; do - if [[ "$line" != "*Passed." ]]; then - echo "$line" + if [[ "\$line" != *"Passed." ]]; then + echo "\$line" fi done Date: Thu, 6 May 2021 07:16:32 +0200 Subject: [PATCH 142/644] Fix publishing related issues in jakarta artifacts --- hibernate-jboss-jta/hibernate-jboss-jta.gradle | 2 +- hibernate-testing-jakarta/hibernate-testing-jakarta.gradle | 2 +- .../hibernate-transaction-client.gradle | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/hibernate-jboss-jta/hibernate-jboss-jta.gradle b/hibernate-jboss-jta/hibernate-jboss-jta.gradle index bc3ebb694f56..e1b30ccbd29c 100644 --- a/hibernate-jboss-jta/hibernate-jboss-jta.gradle +++ b/hibernate-jboss-jta/hibernate-jboss-jta.gradle @@ -11,7 +11,7 @@ apply from: rootProject.file( 'gradle/published-java-module.gradle' ) tasks.withType(PublishToMavenRepository) { onlyIf { - repository == publishing.repositories.mavenLocal + repository.name == "MavenLocal" } } diff --git a/hibernate-testing-jakarta/hibernate-testing-jakarta.gradle b/hibernate-testing-jakarta/hibernate-testing-jakarta.gradle index a0182448274b..10e119aab03a 100644 --- a/hibernate-testing-jakarta/hibernate-testing-jakarta.gradle +++ b/hibernate-testing-jakarta/hibernate-testing-jakarta.gradle @@ -11,7 +11,7 @@ apply from: rootProject.file( 'gradle/published-java-module.gradle' ) tasks.withType(PublishToMavenRepository) { onlyIf { - repository == publishing.repositories.mavenLocal + repository.name == "MavenLocal" } } diff --git a/hibernate-transaction-client/hibernate-transaction-client.gradle b/hibernate-transaction-client/hibernate-transaction-client.gradle index 591d8367eac6..2341fccedea0 100644 --- a/hibernate-transaction-client/hibernate-transaction-client.gradle +++ b/hibernate-transaction-client/hibernate-transaction-client.gradle @@ -11,7 +11,7 @@ apply from: rootProject.file( 'gradle/published-java-module.gradle' ) tasks.withType(PublishToMavenRepository) { onlyIf { - repository == publishing.repositories.mavenLocal + repository.name == "MavenLocal" } } From 0750c6784e6d92b8900b18d942d3faf7a4ba90cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Fri, 7 May 2021 08:37:02 +0200 Subject: [PATCH 143/644] Only apply --add-opens to compiler JVM options when using JDK9+ --- gradle.properties | 3 +-- gradle/java-module.gradle | 4 ++++ 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/gradle.properties b/gradle.properties index b8ec248b503f..a20f3a1cb4d7 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,6 @@ # Keep all these properties in sync unless you know what you are doing! org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=256m -XX:+HeapDumpOnOutOfMemoryError -Duser.language=en -Duser.country=US -Duser.timezone=UTC -Dfile.encoding=UTF-8 -# Needs add-opens because of https://github.com/gradle/gradle/issues/15538 -toolchain.compiler.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=256m -XX:+HeapDumpOnOutOfMemoryError -Duser.language=en -Duser.country=US -Duser.timezone=UTC -Dfile.encoding=UTF-8 --add-opens jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED +toolchain.compiler.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=256m -XX:+HeapDumpOnOutOfMemoryError -Duser.language=en -Duser.country=US -Duser.timezone=UTC -Dfile.encoding=UTF-8 toolchain.javadoc.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=256m -XX:+HeapDumpOnOutOfMemoryError -Duser.language=en -Duser.country=US -Duser.timezone=UTC -Dfile.encoding=UTF-8 toolchain.launcher.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=256m -XX:+HeapDumpOnOutOfMemoryError -Duser.language=en -Duser.country=US -Duser.timezone=UTC -Dfile.encoding=UTF-8 diff --git a/gradle/java-module.gradle b/gradle/java-module.gradle index e3d60db62364..85d5330adf3c 100644 --- a/gradle/java-module.gradle +++ b/gradle/java-module.gradle @@ -137,6 +137,8 @@ else { options.compilerArgs << gradle.ext.javaVersions.main.release.toString() } else { options.release = gradle.ext.javaVersions.main.release.asInt() + // Needs add-opens because of https://github.com/gradle/gradle/issues/15538 + options.forkOptions.jvmArgs.addAll( ["--add-opens", "jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED"] ) } } tasks.compileTestJava.configure { @@ -147,6 +149,8 @@ else { options.compilerArgs << gradle.ext.javaVersions.test.release.toString() } else { options.release = gradle.ext.javaVersions.test.release.asInt() + // Needs add-opens because of https://github.com/gradle/gradle/issues/15538 + options.forkOptions.jvmArgs.addAll( ["--add-opens", "jdk.compiler/com.sun.tools.javac.code=ALL-UNNAMED"] ) } } From a8f00b00aab67cfac886c7212dd94cb88eb0e14a Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Fri, 7 May 2021 09:50:35 +0200 Subject: [PATCH 144/644] Make use of narayana Jakarta artifacts --- gradle/libraries.gradle | 6 +- .../hibernate-core-jakarta.gradle | 180 +++++++++--------- .../hibernate-envers-jakarta.gradle | 58 +++--- .../hibernate-jboss-jta.gradle | 70 ------- .../hibernate-testing-jakarta.gradle | 8 +- settings.gradle | 2 - 6 files changed, 122 insertions(+), 202 deletions(-) delete mode 100644 hibernate-jboss-jta/hibernate-jboss-jta.gradle diff --git a/gradle/libraries.gradle b/gradle/libraries.gradle index 7c7f2e25e561..cf98d0a77bd1 100644 --- a/gradle/libraries.gradle +++ b/gradle/libraries.gradle @@ -141,10 +141,8 @@ ext { jodaTime: "joda-time:joda-time:${jodaTimeVersion}", informix: 'com.ibm.informix:jdbc:4.10.12', - jboss_jta: "org.jboss.narayana.jta:narayana-jta:5.11.1.Final", - // todo: update the version when the parent pom is published - jboss_tx_spi: "org.jboss:jboss-transaction-spi:7.6.0.Final", - // todo (jakarta): update the version when it is released + jboss_jta: "org.jboss.narayana.jta:narayana-jta:5.11.2.Final", + jboss_tx_spi: "org.jboss:jboss-transaction-spi:7.6.1.Final", jboss_jta_jakarta: "org.jboss.narayana.jta:narayana-jta-jakarta:5.11.2.Final", jboss_tx_spi_jakarta: "org.jboss:jboss-transaction-spi-jakarta:7.6.1.Final", xapool: "com.experlog:xapool:1.5.0", diff --git a/hibernate-core-jakarta/hibernate-core-jakarta.gradle b/hibernate-core-jakarta/hibernate-core-jakarta.gradle index c55a166042cd..6dbe272e27e8 100644 --- a/hibernate-core-jakarta/hibernate-core-jakarta.gradle +++ b/hibernate-core-jakarta/hibernate-core-jakarta.gradle @@ -48,48 +48,47 @@ dependencies { 'org.eclipse.transformer:org.eclipse.transformer:0.2.0', 'org.eclipse.transformer:org.eclipse.transformer.cli:0.2.0' -// todo: enable again when we can finally use the Jakarta JARs from narayana -// testCompile( project(':hibernate-testing-jakarta') ) -// testCompile fileTree(dir: 'libs', include: '*.jar') -// -// testCompile( libraries.shrinkwrap_api ) -// testCompile( libraries.shrinkwrap ) -// testCompile( libraries.jakarta_jacc ) -// testCompile( libraries.jakarta_validation ) -// testCompile( libraries.jandex ) -// testCompile( libraries.classmate ) -// testCompile( libraries.mockito ) -// testCompile( libraries.mockito_inline ) -// testCompile( libraries.jodaTime ) -// testCompile( libraries.assertj ) -// -// testCompile( libraries.jakarta_cdi ) -// -// testCompile( libraries.jakarta_validator ) { -// // for test runtime -// transitive = true -// } -// -// // for testing stored procedure support -// testCompile( libraries.derby ) -// -// testRuntime( "org.jboss.spec.javax.ejb:jboss-ejb-api_3.2_spec:1.0.0.Final" ) -// testRuntime( libraries.jakarta_el ) -// testRuntime( 'jaxen:jaxen:1.1' ) -// testRuntime( libraries.javassist ) -// testRuntime( libraries.byteBuddy ) -// testRuntime( libraries.jakarta_weld ) -// testRuntime( libraries.atomikos ) -// testRuntime( libraries.atomikos_jta ) -//// todo (jakarta): replace this when the jakarta artifact is released -// testRuntime( project(':hibernate-transaction-client') ) -//// testRuntime( libraries.wildfly_transaction_client_jakarta ) -// -// testCompile libraries.shrinkwrap_descriptors_api_javaee -// testCompile libraries.shrinkwrap_descriptors_impl_javaee -// -// testCompile libraries.jboss_ejb_spec_jar -// testCompile libraries.jboss_annotation_spec_jar + testCompile( project(':hibernate-testing-jakarta') ) + testCompile fileTree(dir: 'libs', include: '*.jar') + + testCompile( libraries.shrinkwrap_api ) + testCompile( libraries.shrinkwrap ) + testCompile( libraries.jakarta_jacc ) + testCompile( libraries.jakarta_validation ) + testCompile( libraries.jandex ) + testCompile( libraries.classmate ) + testCompile( libraries.mockito ) + testCompile( libraries.mockito_inline ) + testCompile( libraries.jodaTime ) + testCompile( libraries.assertj ) + + testCompile( libraries.jakarta_cdi ) + + testCompile( libraries.jakarta_validator ) { + // for test runtime + transitive = true + } + + // for testing stored procedure support + testCompile( libraries.derby ) + + testRuntime( "org.jboss.spec.javax.ejb:jboss-ejb-api_3.2_spec:1.0.0.Final" ) + testRuntime( libraries.jakarta_el ) + testRuntime( 'jaxen:jaxen:1.1' ) + testRuntime( libraries.javassist ) + testRuntime( libraries.byteBuddy ) + testRuntime( libraries.jakarta_weld ) + testRuntime( libraries.atomikos ) + testRuntime( libraries.atomikos_jta ) +// todo (jakarta): replace this when the jakarta artifact is released + testRuntime( project(':hibernate-transaction-client') ) +// testRuntime( libraries.wildfly_transaction_client_jakarta ) + + testCompile libraries.shrinkwrap_descriptors_api_javaee + testCompile libraries.shrinkwrap_descriptors_impl_javaee + + testCompile libraries.jboss_ejb_spec_jar + testCompile libraries.jboss_annotation_spec_jar } jar { @@ -134,52 +133,51 @@ jar { } } -// todo: enable again when we can finally use the Jakarta JARs from narayana -//task unpackTestJar(type: Copy) { -// dependsOn jar -// fileTree(project.buildDir).matching { include 'libs/*-test.jar' }.each { -// def outputDir = file("${buildDir}/unpacked/" + it.name) -// from zipTree(it) -// into outputDir -// } -//} -// -//task copyBundleResources (type: Copy) { -// dependsOn unpackTestJar -// File unpackedDir = new File(project.buildDir, "libs/hibernate-core-jakarta-${project.version}-test.jar") -// ext { -// bundlesTargetDir = file( "${buildDir}/bundles" ) -// bundleTokens = dbBundle[db] -// ext.bundleTokens['buildDirName'] = buildDir.absolutePath -// } -// -// from file("${buildDir}/unpacked/${unpackedDir.name}/templates") -// into ext.bundlesTargetDir -// filter( ReplaceTokens, tokens: ext.bundleTokens) -// doFirst { -// ext.bundlesTargetDir.mkdirs() -// } -//} -// -//processTestResources.dependsOn copyBundleResources -// -//artifacts { -// tests new File(project.buildDir, "libs/hibernate-core-jakarta-${project.version}-test.jar") -//} -// -//test { -// fileTree(project.buildDir).matching { include 'libs/*-test.jar' }.each { -// def outputDir = file("${buildDir}/unpacked/" + it.name) -// testClassesDirs += files(outputDir) -// classpath += files(outputDir) -// } -// systemProperty 'file.encoding', 'utf-8' -// -// if ( gradle.ext.javaVersions.test.launcher.asInt() >= 9 ) { -// // See org.hibernate.boot.model.naming.NamingHelperTest.DefaultCharset.set -// jvmArgs( ['--add-opens', 'java.base/java.nio.charset=ALL-UNNAMED'] ) -// // Weld needs this to generate proxies -// jvmArgs( ['--add-opens', 'java.base/java.security=ALL-UNNAMED'] ) -// jvmArgs( ['--add-opens', 'java.base/java.lang=ALL-UNNAMED'] ) -// } -//} \ No newline at end of file +task unpackTestJar(type: Copy) { + dependsOn jar + fileTree(project.buildDir).matching { include 'libs/*-test.jar' }.each { + def outputDir = file("${buildDir}/unpacked/" + it.name) + from zipTree(it) + into outputDir + } +} + +task copyBundleResources (type: Copy) { + dependsOn unpackTestJar + File unpackedDir = new File(project.buildDir, "libs/hibernate-core-jakarta-${project.version}-test.jar") + ext { + bundlesTargetDir = file( "${buildDir}/bundles" ) + bundleTokens = dbBundle[db] + ext.bundleTokens['buildDirName'] = buildDir.absolutePath + } + + from file("${buildDir}/unpacked/${unpackedDir.name}/templates") + into ext.bundlesTargetDir + filter( ReplaceTokens, tokens: ext.bundleTokens) + doFirst { + ext.bundlesTargetDir.mkdirs() + } +} + +processTestResources.dependsOn copyBundleResources + +artifacts { + tests new File(project.buildDir, "libs/hibernate-core-jakarta-${project.version}-test.jar") +} + +test { + fileTree(project.buildDir).matching { include 'libs/*-test.jar' }.each { + def outputDir = file("${buildDir}/unpacked/" + it.name) + testClassesDirs += files(outputDir) + classpath += files(outputDir) + } + systemProperty 'file.encoding', 'utf-8' + + if ( gradle.ext.javaVersions.test.launcher.asInt() >= 9 ) { + // See org.hibernate.boot.model.naming.NamingHelperTest.DefaultCharset.set + jvmArgs( ['--add-opens', 'java.base/java.nio.charset=ALL-UNNAMED'] ) + // Weld needs this to generate proxies + jvmArgs( ['--add-opens', 'java.base/java.security=ALL-UNNAMED'] ) + jvmArgs( ['--add-opens', 'java.base/java.lang=ALL-UNNAMED'] ) + } +} \ No newline at end of file diff --git a/hibernate-envers-jakarta/hibernate-envers-jakarta.gradle b/hibernate-envers-jakarta/hibernate-envers-jakarta.gradle index ac4963b0b4a5..9e1e109c9f40 100644 --- a/hibernate-envers-jakarta/hibernate-envers-jakarta.gradle +++ b/hibernate-envers-jakarta/hibernate-envers-jakarta.gradle @@ -29,9 +29,8 @@ dependencies { 'org.eclipse.transformer:org.eclipse.transformer.cli:0.2.0' testCompile( project( ':hibernate-envers-jakarta' ) ) -// todo: enable again when we can finally use the Jakarta JARs from narayana -// testCompile( project( ':hibernate-testing-jakarta' ) ) -// testCompile( project( path: ':hibernate-core-jakarta', configuration: 'tests' ) ) + testCompile( project( ':hibernate-testing-jakarta' ) ) + testCompile( project( path: ':hibernate-core-jakarta', configuration: 'tests' ) ) } jar { @@ -76,30 +75,29 @@ jar { } } -// todo: enable again when we can finally use the Jakarta JARs from narayana -//task unpackTestJar(type: Copy) { -// dependsOn jar -// fileTree(project.buildDir).matching { include 'libs/*-test.jar' }.each { -// def outputDir = file("${buildDir}/unpacked/" + it.name) -// from zipTree(it) -// into outputDir -// } -//} -// -//test { -// dependsOn unpackTestJar -// fileTree(project.buildDir).matching { include 'libs/*-test.jar' }.each { -// def outputDir = file("${buildDir}/unpacked/" + it.name) -// testClassesDirs += files(outputDir) -// classpath += files(outputDir) -// } -// systemProperty 'file.encoding', 'utf-8' -// -// if ( gradle.ext.javaVersions.test.launcher.asInt() >= 9 ) { -// // See org.hibernate.boot.model.naming.NamingHelperTest.DefaultCharset.set -// jvmArgs( ['--add-opens', 'java.base/java.nio.charset=ALL-UNNAMED'] ) -// // Weld needs this to generate proxies -// jvmArgs( ['--add-opens', 'java.base/java.security=ALL-UNNAMED'] ) -// jvmArgs( ['--add-opens', 'java.base/java.lang=ALL-UNNAMED'] ) -// } -//} \ No newline at end of file +task unpackTestJar(type: Copy) { + dependsOn jar + fileTree(project.buildDir).matching { include 'libs/*-test.jar' }.each { + def outputDir = file("${buildDir}/unpacked/" + it.name) + from zipTree(it) + into outputDir + } +} + +test { + dependsOn unpackTestJar + fileTree(project.buildDir).matching { include 'libs/*-test.jar' }.each { + def outputDir = file("${buildDir}/unpacked/" + it.name) + testClassesDirs += files(outputDir) + classpath += files(outputDir) + } + systemProperty 'file.encoding', 'utf-8' + + if ( gradle.ext.javaVersions.test.launcher.asInt() >= 9 ) { + // See org.hibernate.boot.model.naming.NamingHelperTest.DefaultCharset.set + jvmArgs( ['--add-opens', 'java.base/java.nio.charset=ALL-UNNAMED'] ) + // Weld needs this to generate proxies + jvmArgs( ['--add-opens', 'java.base/java.security=ALL-UNNAMED'] ) + jvmArgs( ['--add-opens', 'java.base/java.lang=ALL-UNNAMED'] ) + } +} \ No newline at end of file diff --git a/hibernate-jboss-jta/hibernate-jboss-jta.gradle b/hibernate-jboss-jta/hibernate-jboss-jta.gradle deleted file mode 100644 index e1b30ccbd29c..000000000000 --- a/hibernate-jboss-jta/hibernate-jboss-jta.gradle +++ /dev/null @@ -1,70 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ - -description = 'JBoss JTA transformed to be JTA 2.0 compatible' - -apply from: rootProject.file( 'gradle/published-java-module.gradle' ) - -tasks.withType(PublishToMavenRepository) { - onlyIf { - repository.name == "MavenLocal" - } -} - -configurations { - jakartaeeTransformJars -} - -dependencies { - compile( libraries.jakarta_jta ) - compile( libraries.jakarta_resource ) - compile( libraries.jboss_tx_spi_jakarta ) - - jakartaeeTransformJars 'biz.aQute.bnd:biz.aQute.bnd.transform:5.1.1', - 'commons-cli:commons-cli:1.4', - 'org.slf4j:slf4j-simple:1.7.30', - 'org.slf4j:slf4j-api:1.7.26', - 'org.eclipse.transformer:org.eclipse.transformer:0.2.0', - 'org.eclipse.transformer:org.eclipse.transformer.cli:0.2.0' - testCompile ( libraries.jboss_jta ) { - transitive=false; - } -} - -jar { - def sourceJarPath = project.configurations.testCompile.find { it.name.startsWith("narayana-jta-") } - inputs.files(sourceJarPath).skipWhenEmpty() - outputs.dir project.buildDir - doLast { - new File(project.buildDir, "libs").mkdirs() - fileTree(project.buildDir).matching { include 'libs/*.jar' }.each { delete it } - - println 'Initial bundle jar name [ ' + sourceJarPath + ' ]' - - def finalBundleJarName = project.buildDir.path + '/libs/hibernate-jboss-jta-' + project.version + ".jar" - println 'Default jakarta final bundle jar name [ ' + finalBundleJarName + ' ]' - - def transformerArgs = [ - sourceJarPath, finalBundleJarName, - '-q', // quiet output - '-tr', new File(getProjectDir().getParentFile(), 'rules/jakarta-renames.properties').path, - '-tv', new File(getProjectDir().getParentFile(), 'rules/jakarta-versions.properties').path, - '-td', new File(getProjectDir().getParentFile(), 'rules/jakarta-direct.properties').path, - ] - - println 'Transformer options:' - transformerArgs.each { - println ' [ ' + it + ' ]' - } - - javaexec { - classpath configurations.jakartaeeTransformJars - main = 'org.eclipse.transformer.jakarta.JakartaTransformer' - args = transformerArgs - } - } -} \ No newline at end of file diff --git a/hibernate-testing-jakarta/hibernate-testing-jakarta.gradle b/hibernate-testing-jakarta/hibernate-testing-jakarta.gradle index 10e119aab03a..7224a4a1d3e4 100644 --- a/hibernate-testing-jakarta/hibernate-testing-jakarta.gradle +++ b/hibernate-testing-jakarta/hibernate-testing-jakarta.gradle @@ -28,14 +28,12 @@ dependencies { compile( libraries.byteman_bmunit ) compile( libraries.xapool ) compile( libraries.log4j ) -// todo (jakarta): replace this when the jakarta artifacts are released - compile project( ':hibernate-jboss-jta' ) compile( libraries.jboss_tx_spi_jakarta ) { transitive=false; } -// compile ( libraries.jboss_jta_jakarta ) { -// transitive=false; -// } + compile ( libraries.jboss_jta_jakarta ) { + transitive=false; + } jakartaeeTransformJars 'biz.aQute.bnd:biz.aQute.bnd.transform:5.1.1', 'commons-cli:commons-cli:1.4', diff --git a/settings.gradle b/settings.gradle index fc6fac41619e..23d6def30615 100644 --- a/settings.gradle +++ b/settings.gradle @@ -91,8 +91,6 @@ include 'hibernate-core-jakarta' include 'hibernate-entitymanager' include 'hibernate-testing' include 'hibernate-testing-jakarta' -// todo (jakarta): remove these two when the jakarta artifacts are released -include 'hibernate-jboss-jta' include 'hibernate-transaction-client' include 'hibernate-envers' From 0c79d1d644600b5d82614dc21e59e2930103025f Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Fri, 7 May 2021 12:16:02 +0200 Subject: [PATCH 145/644] Fix service registry injection through connection provider delegate --- .../org/hibernate/testing/jdbc/ConnectionProviderDelegate.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/jdbc/ConnectionProviderDelegate.java b/hibernate-testing/src/main/java/org/hibernate/testing/jdbc/ConnectionProviderDelegate.java index c301c666882c..4044a71802d2 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/jdbc/ConnectionProviderDelegate.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/jdbc/ConnectionProviderDelegate.java @@ -68,6 +68,9 @@ public void configure(Map configurationValues) { serviceRegistry ); } + if ( connectionProvider instanceof ServiceRegistryAwareService ) { + ( (ServiceRegistryAwareService) connectionProvider ).injectServices( serviceRegistry ); + } if ( connectionProvider instanceof Configurable ) { Configurable configurableConnectionProvider = (Configurable) connectionProvider; configurableConnectionProvider.configure( configurationValues ); From 51529f5f204a8b32f1196e521299feb7bc7052d1 Mon Sep 17 00:00:00 2001 From: mrizzi Date: Fri, 7 May 2021 17:50:09 +0200 Subject: [PATCH 146/644] HHH-14585 size() HQL function discards '@Where' clause --- .../hql/size/WhereClauseOrderBySizeTest.java | 195 ++++++++++++++++++ 1 file changed, 195 insertions(+) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/hql/size/WhereClauseOrderBySizeTest.java diff --git a/hibernate-core/src/test/java/org/hibernate/test/hql/size/WhereClauseOrderBySizeTest.java b/hibernate-core/src/test/java/org/hibernate/test/hql/size/WhereClauseOrderBySizeTest.java new file mode 100644 index 000000000000..81d7170b0734 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/hql/size/WhereClauseOrderBySizeTest.java @@ -0,0 +1,195 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ + +package org.hibernate.test.hql.size; + +import org.hibernate.annotations.ResultCheckStyle; +import org.hibernate.annotations.SQLDelete; +import org.hibernate.annotations.Where; +import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; + +import org.hibernate.testing.TestForIssue; +import org.junit.After; +import org.junit.Test; + +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import javax.persistence.TypedQuery; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; +import static org.junit.Assert.assertEquals; + +@TestForIssue(jiraKey = "HHH-14585") +public class WhereClauseOrderBySizeTest extends BaseEntityManagerFunctionalTestCase { + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { Person.class, Book.class }; + } + + @Test + public void testSizeAsOrderByExpression() { + doInJPA( + this::entityManagerFactory, + entityManager -> { + // initial situation: Alice has 1 book, Bob none + final Person alice = new Person( "Alice" ); + entityManager.persist( alice ); + + final Book book1 = new Book(); + book1.setOwner( alice ); + entityManager.persist( book1 ); + + final Person bob = new Person( "Bob" ); + entityManager.persist( bob ); + + final TypedQuery orderByBroken = entityManager.createQuery( + "SELECT p FROM Person p ORDER BY size(p.books) DESC", + Person.class + ); + final TypedQuery orderByWorking = entityManager.createQuery( + "SELECT p FROM Person p ORDER BY p.books.size DESC", + Person.class + ); + + List dbPeopleBroken = orderByBroken.getResultList(); + List dbPeopleWorking = orderByWorking.getResultList(); + assertEquals( Arrays.asList( alice, bob ), dbPeopleWorking ); + assertEquals( dbPeopleWorking, dbPeopleBroken ); + + // add 2 books to Bob + final Book book2 = new Book(); + book2.setOwner( bob ); + entityManager.persist( book2 ); + + final Book book3 = new Book(); + book3.setOwner( bob ); + entityManager.persist( book3 ); + + dbPeopleBroken = orderByBroken.getResultList(); + dbPeopleWorking = orderByWorking.getResultList(); + assertEquals( Arrays.asList( bob, alice ), dbPeopleWorking ); + assertEquals( dbPeopleWorking, dbPeopleBroken ); + + // remove (soft-deleting) both Bob's books + entityManager.remove( book2 ); + entityManager.remove( book3 ); + + // result lists are not equal anymore + dbPeopleBroken = orderByBroken.getResultList(); + dbPeopleWorking = orderByWorking.getResultList(); + assertEquals( Arrays.asList( alice, bob ), dbPeopleWorking ); + assertEquals( dbPeopleWorking, dbPeopleBroken ); + } + ); + } + + @After + public void cleanupDatabase() { + doInJPA( + this::entityManagerFactory, + entityManager -> { + for ( Book book : entityManager.createQuery( "from Book", Book.class ).getResultList() ) { + entityManager.remove( book ); + } + for ( Person person : entityManager.createQuery( "from Person", Person.class ).getResultList() ) { + entityManager.remove( person ); + } + } + ); + } + + @Entity(name = "Person") + public static class Person { + @Id + @GeneratedValue + private Long id; + private String name; + @OneToMany(mappedBy = "owner", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE) + private List books = new ArrayList<>(); + + public Person(String name) { + this.name = name; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List getBooks() { + return books; + } + + public void setBooks(List books) { + this.books = books; + } + + @Override + public String toString() { + return "Person{" + + "id=" + id + + ", name='" + name + '\'' + + '}'; + } + } + + @Entity(name = "Book") + @SQLDelete(sql = "UPDATE Book SET deleted = true WHERE id = ?", check = ResultCheckStyle.COUNT) + @Where(clause = "deleted = false") + public static class Book { + @Id + @GeneratedValue + private Long id; + private Boolean deleted = false; + @ManyToOne + private Person owner; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Boolean getDeleted() { + return deleted; + } + + public void setDeleted(Boolean deleted) { + this.deleted = deleted; + } + + public Person getOwner() { + return owner; + } + + public void setOwner(Person owner) { + this.owner = owner; + } + } +} From 15d9eb4112019389d16e2f560d9d0b2202d71ae8 Mon Sep 17 00:00:00 2001 From: Fabio Massimo Ercoli Date: Tue, 11 May 2021 09:05:28 +0200 Subject: [PATCH 147/644] HHH-14585 Skip test for some dialects --- .../hql/size/WhereClauseOrderBySizeTest.java | 48 ++++++++----------- 1 file changed, 20 insertions(+), 28 deletions(-) diff --git a/hibernate-core/src/test/java/org/hibernate/test/hql/size/WhereClauseOrderBySizeTest.java b/hibernate-core/src/test/java/org/hibernate/test/hql/size/WhereClauseOrderBySizeTest.java index 81d7170b0734..f7baf77809e1 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/hql/size/WhereClauseOrderBySizeTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/hql/size/WhereClauseOrderBySizeTest.java @@ -7,15 +7,12 @@ package org.hibernate.test.hql.size; -import org.hibernate.annotations.ResultCheckStyle; -import org.hibernate.annotations.SQLDelete; -import org.hibernate.annotations.Where; -import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; - -import org.hibernate.testing.TestForIssue; -import org.junit.After; -import org.junit.Test; +import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; +import static org.junit.Assert.assertEquals; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; import javax.persistence.CascadeType; import javax.persistence.Entity; import javax.persistence.FetchType; @@ -24,14 +21,21 @@ import javax.persistence.ManyToOne; import javax.persistence.OneToMany; import javax.persistence.TypedQuery; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.List; -import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; -import static org.junit.Assert.assertEquals; +import org.hibernate.annotations.ResultCheckStyle; +import org.hibernate.annotations.SQLDelete; +import org.hibernate.annotations.Where; +import org.hibernate.dialect.H2Dialect; +import org.hibernate.dialect.PostgreSQL82Dialect; +import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; + +import org.hibernate.testing.RequiresDialect; +import org.hibernate.testing.TestForIssue; +import org.junit.Test; @TestForIssue(jiraKey = "HHH-14585") +@RequiresDialect(value = PostgreSQL82Dialect.class, comment = "Other databases may not support boolean data types") +@RequiresDialect(value = H2Dialect.class, comment = "Other databases may not support boolean data types") public class WhereClauseOrderBySizeTest extends BaseEntityManagerFunctionalTestCase { @Override @@ -96,21 +100,6 @@ public void testSizeAsOrderByExpression() { ); } - @After - public void cleanupDatabase() { - doInJPA( - this::entityManagerFactory, - entityManager -> { - for ( Book book : entityManager.createQuery( "from Book", Book.class ).getResultList() ) { - entityManager.remove( book ); - } - for ( Person person : entityManager.createQuery( "from Person", Person.class ).getResultList() ) { - entityManager.remove( person ); - } - } - ); - } - @Entity(name = "Person") public static class Person { @Id @@ -120,6 +109,9 @@ public static class Person { @OneToMany(mappedBy = "owner", fetch = FetchType.LAZY, cascade = CascadeType.REMOVE) private List books = new ArrayList<>(); + public Person() { + } + public Person(String name) { this.name = name; } From a106ce29dc7135357028454b6aba94459cc4bc3c Mon Sep 17 00:00:00 2001 From: Fabio Massimo Ercoli Date: Tue, 11 May 2021 09:06:56 +0200 Subject: [PATCH 148/644] HHH-14585 Handle filter fragment on CollectionSizeNode --- .../hibernate/hql/internal/ast/tree/CollectionSizeNode.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/CollectionSizeNode.java b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/CollectionSizeNode.java index b334e4b92587..b630be5f916c 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/CollectionSizeNode.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/tree/CollectionSizeNode.java @@ -12,6 +12,7 @@ import org.hibernate.internal.util.StringHelper; import org.hibernate.persister.collection.CollectionPropertyMapping; import org.hibernate.persister.collection.CollectionPropertyNames; +import org.hibernate.persister.collection.OneToManyPersister; import org.hibernate.persister.collection.QueryableCollection; import org.hibernate.type.StandardBasicTypes; @@ -89,6 +90,8 @@ public String toSqlExpression() { buffer.append( ownerKeyColumns[i] ).append( " = " ).append( collectionKeyColumns[i] ); } + buffer.append( collectionDescriptor.filterFragment( collectionTableAlias, + collectionOwnerFromElement.getWalker().getEnabledFilters() ) ); buffer.append( ")" ); if ( scalarName != null ) { From d0febfd0427e2179cee03a6b9d8fe9321493d199 Mon Sep 17 00:00:00 2001 From: Fabio Massimo Ercoli Date: Tue, 11 May 2021 09:42:19 +0200 Subject: [PATCH 149/644] HHH-14585 Test more size() cases In particular projections using a size function --- .../hibernate/test/hql/size/filter/City.java | 60 ++++++++ .../test/hql/size/filter/Region.java | 49 +++++++ .../WhereAnnotatedOneToManySizeTest.java | 133 ++++++++++++++++++ 3 files changed, 242 insertions(+) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/hql/size/filter/City.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/hql/size/filter/Region.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/hql/size/filter/WhereAnnotatedOneToManySizeTest.java diff --git a/hibernate-core/src/test/java/org/hibernate/test/hql/size/filter/City.java b/hibernate-core/src/test/java/org/hibernate/test/hql/size/filter/City.java new file mode 100644 index 000000000000..c60400e547f4 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/hql/size/filter/City.java @@ -0,0 +1,60 @@ +/* + * Hibernate Search, full-text search for your domain model + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.hql.size.filter; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.ManyToOne; + +import org.hibernate.annotations.Where; + +@Entity +@Where(clause = "deleted = false") +public class City { + + @Id + private Integer id; + + private String name; + + @ManyToOne + private Region region; + + private Boolean deleted; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Region getRegion() { + return region; + } + + public void setRegion(Region region) { + this.region = region; + } + + public Boolean getDeleted() { + return deleted; + } + + public void setDeleted(Boolean deleted) { + this.deleted = deleted; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/hql/size/filter/Region.java b/hibernate-core/src/test/java/org/hibernate/test/hql/size/filter/Region.java new file mode 100644 index 000000000000..59da4d4f355e --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/hql/size/filter/Region.java @@ -0,0 +1,49 @@ +/* + * Hibernate Search, full-text search for your domain model + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.hql.size.filter; + +import java.util.ArrayList; +import java.util.List; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.OneToMany; + +@Entity +public class Region { + + @Id + private Integer id; + + private String name; + + @OneToMany(mappedBy = "region") + private List cities = new ArrayList<>(); + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List getCities() { + return cities; + } + + public void setCities(List cities) { + this.cities = cities; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/hql/size/filter/WhereAnnotatedOneToManySizeTest.java b/hibernate-core/src/test/java/org/hibernate/test/hql/size/filter/WhereAnnotatedOneToManySizeTest.java new file mode 100644 index 000000000000..a5adb3af5b15 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/hql/size/filter/WhereAnnotatedOneToManySizeTest.java @@ -0,0 +1,133 @@ +/* + * Hibernate Search, full-text search for your domain model + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.hql.size.filter; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.List; + +import org.hibernate.dialect.DB2Dialect; +import org.hibernate.query.spi.QueryImplementor; + +import org.hibernate.testing.SkipForDialect; +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +@TestForIssue(jiraKey = "HHH-14585") +public class WhereAnnotatedOneToManySizeTest extends BaseCoreFunctionalTestCase { + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { Region.class, City.class }; + } + + @Before + public void before() { + Region lazio = new Region(); + lazio.setId( 1 ); + lazio.setName( "Lazio" ); + + Region lombardy = new Region(); + lombardy.setId( 2 ); + lombardy.setName( "Lombardy" ); + + City rome = new City(); + rome.setId( 1 ); + rome.setName( "Rome" ); + rome.setDeleted( false ); + rome.setRegion( lazio ); + + City gradoli = new City(); + gradoli.setId( 2 ); + gradoli.setName( "Gradoli" ); + gradoli.setDeleted( true ); + gradoli.setRegion( lazio ); + + City milan = new City(); + milan.setId( 3 ); + milan.setName( "Milan" ); + milan.setDeleted( false ); + milan.setRegion( lombardy ); + + City pavia = new City(); + pavia.setId( 4 ); + pavia.setName( "Pavia" ); + pavia.setDeleted( false ); + pavia.setRegion( lombardy ); + + lazio.getCities().add( rome ); + lazio.getCities().add( gradoli ); + + lombardy.getCities().add( milan ); + lombardy.getCities().add( pavia ); + + inTransaction( session -> { + session.persist( lazio ); + session.persist( lombardy ); + + session.persist( rome ); + session.persist( gradoli ); + session.persist( milan ); + session.persist( pavia ); + } ); + } + + @After + public void after() { + inTransaction( session -> { + session.createQuery( "DELETE FROM City c" ).executeUpdate(); + session.createQuery( "DELETE FROM Region c" ).executeUpdate(); + } ); + } + + @Test + @SkipForDialect(value = DB2Dialect.class, comment = "DB2 does not support correlated subqueries in the ORDER BY clause") + public void orderBy_sizeOf() { + inSession( session -> { + QueryImplementor query = session.createQuery( + "select r, size(r.cities) from Region r order by size(r.cities) desc" ); + List result = query.getResultList(); + assertThat( result ).extracting( f -> f[0] ).extracting( "name" ).containsExactly( "Lombardy", "Lazio" ); + assertThat( result ).extracting( f -> f[1] ).containsExactly( 2, 1 ); + } ); + } + + @Test + @SkipForDialect(value = DB2Dialect.class, comment = "DB2 does not support correlated subqueries in the ORDER BY clause") + public void orderBy_dotSize() { + inSession( session -> { + QueryImplementor query = session.createQuery( + "select r, r.cities.size from Region r order by r.cities.size desc" ); + List result = query.getResultList(); + assertThat( result ).extracting( f -> f[0] ).extracting( "name" ).containsExactly( "Lombardy", "Lazio" ); + assertThat( result ).extracting( f -> f[1] ).containsExactly( 2, 1 ); + } ); + } + + @Test + public void project_sizeOf() { + inSession( session -> { + QueryImplementor query = session.createQuery( + "SELECT size(r.cities) FROM Region r", Integer.class ); + List cityCounts = query.getResultList(); + assertThat( cityCounts ).containsExactlyInAnyOrder( 1, 2 ); + } ); + } + + @Test + public void project_dotSize() { + inSession( session -> { + QueryImplementor query = session.createQuery( + "SELECT r.cities.size FROM Region r", Integer.class ); + List cityCounts = query.getResultList(); + assertThat( cityCounts ).containsExactlyInAnyOrder( 1, 2 ); + } ); + } +} From b36b8e4d1c617c9b49be9be9450df2f60cbe1d30 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Wed, 12 May 2021 14:11:53 +0200 Subject: [PATCH 150/644] Enable publishing for hibernate-testing-jakarta --- .../hibernate-testing-jakarta.gradle | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/hibernate-testing-jakarta/hibernate-testing-jakarta.gradle b/hibernate-testing-jakarta/hibernate-testing-jakarta.gradle index 7224a4a1d3e4..716f96c9b027 100644 --- a/hibernate-testing-jakarta/hibernate-testing-jakarta.gradle +++ b/hibernate-testing-jakarta/hibernate-testing-jakarta.gradle @@ -9,12 +9,6 @@ description = 'Support for testing Hibernate ORM Jakarta functionality' apply from: rootProject.file( 'gradle/published-java-module.gradle' ) -tasks.withType(PublishToMavenRepository) { - onlyIf { - repository.name == "MavenLocal" - } -} - configurations { jakartaeeTransformJars } @@ -82,4 +76,4 @@ jar { } } } -} \ No newline at end of file +} From 7f152c36f7c70a1970a7d7d443076cc4a0a308ee Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Fri, 30 Apr 2021 14:32:41 +0200 Subject: [PATCH 151/644] HHH-14541 Test that the session factory is still open in SessionFactoryObserver#sessionFactoryClosing --- .../java/org/hibernate/test/events/CallbackTest.java | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/hibernate-core/src/test/java/org/hibernate/test/events/CallbackTest.java b/hibernate-core/src/test/java/org/hibernate/test/events/CallbackTest.java index 14e1e72a2e9f..5d37fa7a8cfd 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/events/CallbackTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/events/CallbackTest.java @@ -22,9 +22,11 @@ import org.hibernate.integrator.spi.Integrator; import org.hibernate.service.spi.SessionFactoryServiceRegistry; +import org.hibernate.testing.TestForIssue; import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; import org.junit.Test; +import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.assertEquals; @@ -33,6 +35,7 @@ * * @author Steve Ebersole */ +@TestForIssue(jiraKey = {"HHH-2884", "HHH-10674", "HHH-14541"}) public class CallbackTest extends BaseCoreFunctionalTestCase { private TestingObserver observer = new TestingObserver(); private TestingListener listener = new TestingListener(); @@ -97,16 +100,22 @@ private static class TestingObserver implements SessionFactoryObserver { private int closedCount = 0; private int closingCount = 0; + @Override public void sessionFactoryCreated(SessionFactory factory) { + assertThat( factory.isClosed() ).isFalse(); creationCount++; } @Override public void sessionFactoryClosing(SessionFactory factory) { + // Test for HHH-14541 + assertThat( factory.isClosed() ).isFalse(); closingCount++; } + @Override public void sessionFactoryClosed(SessionFactory factory) { + assertThat( factory.isClosed() ).isTrue(); closedCount++; } } From eb4e397a048ca6013ac02c09c1ce4a834a65ad8a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Fri, 30 Apr 2021 14:42:05 +0200 Subject: [PATCH 152/644] HHH-14541 Only mark the session factory as closed *after* SessionFactoryObserver#sessionFactoryClosing was called --- .../internal/SessionFactoryImpl.java | 75 +++++++++++-------- 1 file changed, 45 insertions(+), 30 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java index 2c8bf16f09fd..17e3a258e050 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java @@ -160,7 +160,7 @@ public class SessionFactoryImpl implements SessionFactoryImplementor { private final String name; private final String uuid; - private transient volatile boolean isClosed; + private transient volatile Status status = Status.OPEN; private final transient SessionFactoryObserverChain observer = new SessionFactoryObserverChain(); @@ -535,7 +535,7 @@ public Map getProperties() { } protected void validateNotClosed() { - if ( isClosed ) { + if ( Status.CLOSED == status ) { throw new IllegalStateException( "EntityManagerFactory is closed" ); } } @@ -625,7 +625,7 @@ public Session createEntityManager() { } private Session buildEntityManager(final SynchronizationType synchronizationType, final Map map) { - assert !isClosed; + assert Status.CLOSED != status; SessionBuilderImplementor builder = withOptions(); if ( synchronizationType == SynchronizationType.SYNCHRONIZED ) { @@ -694,7 +694,7 @@ public MetamodelImplementor getMetamodel() { @Override public boolean isOpen() { - return !isClosed; + return Status.CLOSED != status; } @Override @@ -789,9 +789,10 @@ public Type getReferencedPropertyType(String className, String propertyName) * collector release the memory. * @throws HibernateException */ + @Override public void close() throws HibernateException { synchronized (this) { - if ( isClosed ) { + if ( Status.OPEN != status ) { if ( getSessionFactoryOptions().getJpaCompliance().isJpaClosedComplianceEnabled() ) { throw new IllegalStateException( "EntityManagerFactory is already closed" ); } @@ -800,39 +801,47 @@ public void close() throws HibernateException { return; } - isClosed = true; + status = Status.CLOSING; } - LOG.closing(); - observer.sessionFactoryClosing( this ); + try { + LOG.closing(); + observer.sessionFactoryClosing( this ); - settings.getMultiTableBulkIdStrategy().release( serviceRegistry.getService( JdbcServices.class ), buildLocalConnectionAccess() ); + settings.getMultiTableBulkIdStrategy().release( + serviceRegistry.getService( JdbcServices.class ), + buildLocalConnectionAccess() + ); - // NOTE : the null checks below handle cases where close is called from - // a failed attempt to create the SessionFactory + // NOTE : the null checks below handle cases where close is called from + // a failed attempt to create the SessionFactory - if ( cacheAccess != null ) { - cacheAccess.close(); - } + if ( cacheAccess != null ) { + cacheAccess.close(); + } - if ( metamodel != null ) { - metamodel.close(); - } + if ( metamodel != null ) { + metamodel.close(); + } - if ( queryPlanCache != null ) { - queryPlanCache.cleanup(); - } + if ( queryPlanCache != null ) { + queryPlanCache.cleanup(); + } - if ( delayedDropAction != null ) { - delayedDropAction.perform( serviceRegistry ); - } + if ( delayedDropAction != null ) { + delayedDropAction.perform( serviceRegistry ); + } - SessionFactoryRegistry.INSTANCE.removeSessionFactory( - getUuid(), - name, - settings.isSessionFactoryNameAlsoJndiName(), - serviceRegistry.getService( JndiService.class ) - ); + SessionFactoryRegistry.INSTANCE.removeSessionFactory( + getUuid(), + name, + settings.isSessionFactoryNameAlsoJndiName(), + serviceRegistry.getService( JndiService.class ) + ); + } + finally { + status = Status.CLOSED; + } observer.sessionFactoryClosed( this ); serviceRegistry.destroy(); @@ -977,8 +986,9 @@ public void addNamedEntityGraph(String graphName, EntityGraph entityGraph getMetamodel().addNamedEntityGraph( graphName, (RootGraphImplementor) entityGraph ); } + @Override public boolean isClosed() { - return isClosed; + return Status.CLOSED == status; } private transient StatisticsImplementor statistics; @@ -1688,4 +1698,9 @@ public FastSessionServices getFastSessionServices() { return this.fastSessionServices; } + private enum Status { + OPEN, + CLOSING, + CLOSED; + } } From f7ab5f315dcdbe60310a347982671f031e6d88c8 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Wed, 12 May 2021 17:27:14 +0200 Subject: [PATCH 153/644] HHH-14541 Only mark the session factory as closed *after* SessionFactoryObserver#sessionFactoryClosing was called --- .../org/hibernate/internal/SessionFactoryImpl.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java index 17e3a258e050..ef50a2b8ec00 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java @@ -535,7 +535,7 @@ public Map getProperties() { } protected void validateNotClosed() { - if ( Status.CLOSED == status ) { + if ( status == Status.CLOSED ) { throw new IllegalStateException( "EntityManagerFactory is closed" ); } } @@ -625,7 +625,7 @@ public Session createEntityManager() { } private Session buildEntityManager(final SynchronizationType synchronizationType, final Map map) { - assert Status.CLOSED != status; + assert status != Status.CLOSED; SessionBuilderImplementor builder = withOptions(); if ( synchronizationType == SynchronizationType.SYNCHRONIZED ) { @@ -694,7 +694,7 @@ public MetamodelImplementor getMetamodel() { @Override public boolean isOpen() { - return Status.CLOSED != status; + return status != Status.CLOSED; } @Override @@ -792,7 +792,7 @@ public Type getReferencedPropertyType(String className, String propertyName) @Override public void close() throws HibernateException { synchronized (this) { - if ( Status.OPEN != status ) { + if ( status != Status.OPEN ) { if ( getSessionFactoryOptions().getJpaCompliance().isJpaClosedComplianceEnabled() ) { throw new IllegalStateException( "EntityManagerFactory is already closed" ); } @@ -988,7 +988,7 @@ public void addNamedEntityGraph(String graphName, EntityGraph entityGraph @Override public boolean isClosed() { - return Status.CLOSED == status; + return status == Status.CLOSED; } private transient StatisticsImplementor statistics; From 0dbffcc0685d83153e5ee33e3ba6eaa57cf24ead Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Wed, 12 May 2021 15:56:40 +0000 Subject: [PATCH 154/644] 5.5.0.Beta1 --- changelog.txt | 13 +++++++++++++ gradle/version.properties | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 3d8548993b5c..05f4fdf969cb 100644 --- a/changelog.txt +++ b/changelog.txt @@ -3,6 +3,19 @@ Hibernate 5 Changelog Note: Please refer to JIRA to learn more about each issue. +Changes in 5.5.0.Beta1 (May 12, 2021) +------------------------------------------------------------------------------------------------------------------------ + +https://hibernate.atlassian.net/projects/HHH/versions/31938 + +** Bug + * [HHH-14541] - SessionFactoryObserver#sessionFactoryClosing() gets called after the session factory is marked as closed + * [HHH-13779] - Schema migrator should use case insensitive column comparison of foreign keys + +** Improvement + * [HHH-12445] - Discriminator column should be nullable when using @DiscriminatorValue( "null" ) + + Changes in 5.5.0.Alpha1 (April 30, 2021) ------------------------------------------------------------------------------------------------------------------------ diff --git a/gradle/version.properties b/gradle/version.properties index 27307e6e59d0..9277b6240d65 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -hibernateVersion=5.5.0-SNAPSHOT \ No newline at end of file +hibernateVersion=5.5.0.Beta1 \ No newline at end of file From 43539f0399636cf90b9f35d6c5efd807f37440f6 Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Wed, 12 May 2021 16:03:47 +0000 Subject: [PATCH 155/644] 5.5.0-SNAPSHOT --- gradle/version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/version.properties b/gradle/version.properties index 9277b6240d65..27307e6e59d0 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -hibernateVersion=5.5.0.Beta1 \ No newline at end of file +hibernateVersion=5.5.0-SNAPSHOT \ No newline at end of file From 40851fc50da7edac397175dfc41a6d3a97adeb28 Mon Sep 17 00:00:00 2001 From: Nathan Xu Date: Wed, 13 Jan 2021 18:07:48 -0500 Subject: [PATCH 156/644] HHH-14406 fix Architecture svg image in user guide --- .../images/architecture/JPA_Hibernate.svg | 4869 ++++++++--------- 1 file changed, 2149 insertions(+), 2720 deletions(-) diff --git a/documentation/src/main/asciidoc/userguide/images/architecture/JPA_Hibernate.svg b/documentation/src/main/asciidoc/userguide/images/architecture/JPA_Hibernate.svg index b6a240a85a97..173e51135226 100644 --- a/documentation/src/main/asciidoc/userguide/images/architecture/JPA_Hibernate.svg +++ b/documentation/src/main/asciidoc/userguide/images/architecture/JPA_Hibernate.svg @@ -1,2891 +1,2320 @@ - - - - image/svg+xml - - - - - - + xmlns="http://www.w3.org/2000/svg" + xmlns:xlink="http://www.w3.org/1999/xlink" + fill-opacity="1" + stroke="black" + stroke-linecap="square" + width="885" + stroke-miterlimit="10" + stroke-opacity="1" + fill="black" + stroke-dasharray="none" + stroke-width="1" + height="438" + font-family="'Dialog'" + font-size="12" + stroke-dashoffset="0" + version="1.1" + id="svg699" +> + id="genericDefs"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + id="g697"> - - - - - - - - - - - - - - - - + id="defs1"> + x1="0" + gradientUnits="userSpaceOnUse" + x2="0" + y1="0" + y2="33" + id="linearGradient5"> + stop-opacity="1" + stop-color="rgb(255,255,240)" + offset="0" + id="stop23"/> + stop-opacity="1" + stop-color="rgb(255,255,168)" + offset="1" + id="stop25"/> + x1="0" + gradientUnits="userSpaceOnUse" + x2="0" + y1="0" + y2="33" + id="linearGradient6"> + stop-opacity="1" + stop-color="rgb(255,255,240)" + offset="0" + id="stop28"/> + stop-opacity="1" + stop-color="rgb(255,255,168)" + offset="1" + id="stop30"/> + x1="0" + gradientUnits="userSpaceOnUse" + x2="0" + y1="0" + y2="33" + id="linearGradient7"> + stop-opacity="1" + stop-color="rgb(255,255,245)" + offset="0" + id="stop33"/> + stop-opacity="1" + stop-color="rgb(215,213,172)" + offset="1" + id="stop35"/> + x1="0" + gradientUnits="userSpaceOnUse" + x2="0" + y1="0" + y2="33" + id="linearGradient8"> + stop-opacity="1" + stop-color="rgb(255,255,245)" + offset="0" + id="stop38"/> + stop-opacity="1" + stop-color="rgb(215,213,172)" + offset="1" + id="stop40"/> + x1="0" + gradientUnits="userSpaceOnUse" + x2="0" + y1="0" + y2="33" + id="linearGradient9"> + stop-opacity="1" + stop-color="rgb(255,255,245)" + offset="0" + id="stop43"/> + stop-opacity="1" + stop-color="rgb(215,213,172)" + offset="1" + id="stop45"/> + x1="0" + gradientUnits="userSpaceOnUse" + x2="0" + y1="0" + y2="33" + id="linearGradient10"> + stop-opacity="1" + stop-color="rgb(255,255,245)" + offset="0" + id="stop48"/> + stop-opacity="1" + stop-color="rgb(215,213,172)" + offset="1" + id="stop50"/> + x1="0" + gradientUnits="userSpaceOnUse" + x2="0" + y1="0" + y2="33" + id="linearGradient13"> + stop-opacity="1" + stop-color="rgb(255,255,240)" + offset="0" + id="stop63"/> + stop-opacity="1" + stop-color="rgb(255,255,168)" + offset="1" + id="stop65"/> + x1="0" + gradientUnits="userSpaceOnUse" + x2="0" + y1="0" + y2="33" + id="linearGradient14"> + stop-opacity="1" + stop-color="rgb(255,255,240)" + offset="0" + id="stop68"/> + stop-opacity="1" + stop-color="rgb(255,255,168)" + offset="1" + id="stop70"/> + x1="0" + gradientUnits="userSpaceOnUse" + x2="0" + y1="0" + y2="33" + id="linearGradient15"> + stop-opacity="1" + stop-color="rgb(255,255,245)" + offset="0" + id="stop73"/> + stop-opacity="1" + stop-color="rgb(215,213,172)" + offset="1" + id="stop75"/> + x1="0" + gradientUnits="userSpaceOnUse" + x2="0" + y1="0" + y2="33" + id="linearGradient16"> + stop-opacity="1" + stop-color="rgb(255,255,245)" + offset="0" + id="stop78"/> + stop-opacity="1" + stop-color="rgb(215,213,172)" + offset="1" + id="stop80"/> + x1="0" + gradientUnits="userSpaceOnUse" + x2="0" + y1="0" + y2="33" + id="linearGradient17"> + stop-opacity="1" + stop-color="rgb(255,255,245)" + offset="0" + id="stop83"/> + stop-opacity="1" + stop-color="rgb(215,213,172)" + offset="1" + id="stop85"/> + x1="0" + gradientUnits="userSpaceOnUse" + x2="0" + y1="0" + y2="33" + id="linearGradient18"> + stop-opacity="1" + stop-color="rgb(255,255,245)" + offset="0" + id="stop88"/> + stop-opacity="1" + stop-color="rgb(215,213,172)" + offset="1" + id="stop90"/> - - - - - - - - - - - - - - - - - - + + d="M-649 -37 L236 -37 L236 401 L-649 401 L-649 -37 Z" + id="path96"/> - + + d="M0 0 L0 37 L207 37 L207 0 Z" + id="path132"/> - + + d="M0 0 L0 35 L205 35 L205 0 Z" + id="path135"/> - + + d="M0 0 L0 33 L203 33 L203 0 Z" + id="path138"/> - + + d="M0 0 L0 25 L195 25 L195 0 Z" + id="path141"/> - + + d="M0 0 L0 37 L160 37 L160 0 Z" + id="path147"/> - + + d="M0 0 L0 35 L158 35 L158 0 Z" + id="path150"/> - + + d="M0 0 L0 33 L156 33 L156 0 Z" + id="path153"/> - + + d="M0 0 L0 25 L148 25 L148 0 Z" + id="path156"/> - + + d="M0 0 L0 37 L190 37 L190 0 Z" + id="path162"/> - + + d="M0 0 L0 35 L188 35 L188 0 Z" + id="path165"/> - + + d="M0 0 L0 33 L186 33 L186 0 Z" + id="path168"/> - + + d="M0 0 L0 25 L178 25 L178 0 Z" + id="path171"/> - + + d="M0 0 L0 37 L176 37 L176 0 Z" + id="path192"/> - + + d="M0 0 L0 35 L174 35 L174 0 Z" + id="path195"/> - + + d="M0 0 L0 33 L172 33 L172 0 Z" + id="path198"/> - + + d="M0 0 L0 25 L164 25 L164 0 Z" + id="path201"/> - + + d="M0 0 L0 37 L139 37 L139 0 Z" + id="path207"/> - + + d="M0 0 L0 35 L137 35 L137 0 Z" + id="path210"/> - + + d="M0 0 L0 33 L135 33 L135 0 Z" + id="path213"/> - + + d="M0 0 L0 25 L127 25 L127 0 Z" + id="path216"/> - + + d="M0 0 L0 37 L169 37 L169 0 Z" + id="path222"/> - + + d="M0 0 L0 35 L167 35 L167 0 Z" + id="path225"/> - + + d="M0 0 L0 33 L165 33 L165 0 Z" + id="path228"/> - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + d="M0 0 L0 25 L157 25 L157 0 Z" + id="path231"/> - - - - - - - - - - + fill="white" + transform="translate(649,37)" + stroke="white" + id="g237"/> + + + + + + + + - - - - - - - - + d="M0 0 L205 0 L205 35 L0 35 L0 0 ZM1 1 L204 1 L204 34 L1 34 L1 1 Z" + fill-rule="evenodd" + clip-path="url(#clipPath15)" + stroke="none" + id="path345"/> + + + + + + + + + x="3" + y="3" + clip-path="url(#clipPath17)" + width="20" + height="20" + preserveAspectRatio="none" + id="image357" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAACCklEQVR42q1UMUsc QRSeN7N72VOiBINwTbSQdJrCQgMpvAQJWMQqKIJwf8BOA0EDacRCCxttk3hBCHYW ghEVhGhCqmghIkgQgjaKYJZd73bnOW91l53bU068gQe7b95+++Z73zeMVXnBTRuo 9kbWBt4gYqdgzKKcz5gLAD8nX84vQlBSAWBuPWc1SvetRPYKAgzmlZQYyEBwwNUa bi18zH52bwQcXh6sBeGNq5+nKzygg74xOvU6b4cZHu+MwBCwplK+qJa+GdofepAA pGNSZ4A6NyLFZTy0/oJaTFt/T/oiPqIBXHF2Ef/ArDW8lfd/eoTJAx79ojS6J54t FW3P0FrlMqsw8jQoQe/22kAvID5Vj1oHUiLwFHfO/zmPQIBs7mrcrc+kbcTEMOF7 ro1tftnZC45M0igzTdUSwpOOhqPUQ8OhoGepcmXo9BjK5xGHoc7uJWgESxtKtRYP HXBfICUhNwIkO4UT15YAPPx9mimce2mKw18nGa5yZfAMBnwrAiRvkp1Kq0xL+AfL R62y4JsUByvHrULlyvheEIZmvXer/YNKDi8STZaI2S/IJO/If0x2z89pQyGjB94E XWMEEA+dN1UL4LjNDd+qczkoMJt7Y7PZhf/RieL7m1+3i+0fsuvGmVvHOLZc/1Am ry9mAvINt+nx9Ez7J+dOFyw5IBRtIA01zdsu2KqvS/ZN5gVE2Ks6AAAAAElFTkSu QmCC"/> + x="23" + y="3" + clip-path="url(#clipPath17)" + width="20" + height="20" + preserveAspectRatio="none" + id="image359" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAABKklEQVR42u2Uv0oD QRDGZ3Y9Q/6ghdhZ26RMKVhoEYxaay8GrHyFe4lUIUlhr4WKEomgD+Az+ABWipFc LvM5e96ByIWsnUIGjtmbvfn43TfLEs3jzwXnFY+utzbB3CQgIOYxyLR7jbsHH0GT V3Rihum227g/dJlJjn0JcwUd2cjYC+WHiUvnCalnLEzbKEYFuBxV3hbt0Cbr5uV+ yeXyyguW+/VRGIbi5+HN9lVk7EEg4zUGn4LYKnZASJuYAdBTd3fQmv3L2t3ZGeyd 1fvvKrb+JZYYKylCrLqxFjb8POSMg0jA6RoBs/TKXDjRD55TTPmVhz/GLjCmOkS0 qi9LU5yaLWiUMIFkmuika/hmu9oo/scmA5t8PILwqrIVN9zsUbGiwHbm98I/iU+D oGuHyXAGnwAAAABJRU5ErkJggg=="/> EntityManager - - - - - - - - + x="47" + y="19" + clip-path="url(#clipPath17)" + stroke="none" + id="text361" + style="white-space: pre;">EntityManagerFactory + + + + + + + + + + x="3" + y="3" + clip-path="url(#clipPath17)" + width="20" + height="20" + preserveAspectRatio="none" + id="image373" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAACCklEQVR42q1UMUsc QRSeN7N72VOiBINwTbSQdJrCQgMpvAQJWMQqKIJwf8BOA0EDacRCCxttk3hBCHYW ghEVhGhCqmghIkgQgjaKYJZd73bnOW91l53bU068gQe7b95+++Z73zeMVXnBTRuo 9kbWBt4gYqdgzKKcz5gLAD8nX84vQlBSAWBuPWc1SvetRPYKAgzmlZQYyEBwwNUa bi18zH52bwQcXh6sBeGNq5+nKzygg74xOvU6b4cZHu+MwBCwplK+qJa+GdofepAA pGNSZ4A6NyLFZTy0/oJaTFt/T/oiPqIBXHF2Ef/ArDW8lfd/eoTJAx79ojS6J54t FW3P0FrlMqsw8jQoQe/22kAvID5Vj1oHUiLwFHfO/zmPQIBs7mrcrc+kbcTEMOF7 ro1tftnZC45M0igzTdUSwpOOhqPUQ8OhoGepcmXo9BjK5xGHoc7uJWgESxtKtRYP HXBfICUhNwIkO4UT15YAPPx9mimce2mKw18nGa5yZfAMBnwrAiRvkp1Kq0xL+AfL R62y4JsUByvHrULlyvheEIZmvXer/YNKDi8STZaI2S/IJO/If0x2z89pQyGjB94E XWMEEA+dN1UL4LjNDd+qczkoMJt7Y7PZhf/RieL7m1+3i+0fsuvGmVvHOLZc/1Am ry9mAvINt+nx9Ez7J+dOFyw5IBRtIA01zdsu2KqvS/ZN5gVE2Ks6AAAAAElFTkSu QmCC"/> + x="23" + y="3" + clip-path="url(#clipPath17)" + width="20" + height="20" + preserveAspectRatio="none" + id="image375" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAABKklEQVR42u2Uv0oD QRDGZ3Y9Q/6ghdhZ26RMKVhoEYxaay8GrHyFe4lUIUlhr4WKEomgD+Az+ABWipFc LvM5e96ByIWsnUIGjtmbvfn43TfLEs3jzwXnFY+utzbB3CQgIOYxyLR7jbsHH0GT V3Rihum227g/dJlJjn0JcwUd2cjYC+WHiUvnCalnLEzbKEYFuBxV3hbt0Cbr5uV+ yeXyyguW+/VRGIbi5+HN9lVk7EEg4zUGn4LYKnZASJuYAdBTd3fQmv3L2t3ZGeyd 1fvvKrb+JZYYKylCrLqxFjb8POSMg0jA6RoBs/TKXDjRD55TTPmVhz/GLjCmOkS0 qi9LU5yaLWiUMIFkmuika/hmu9oo/scmA5t8PILwqrIVN9zsUbGiwHbm98I/iU+D oGuHyXAGnwAAAABJRU5ErkJggg=="/> EntityManager - - - - - - - - - + x="47" + y="19" + clip-path="url(#clipPath17)" + stroke="none" + id="text377" + style="white-space: pre;">EntityManagerFactory + + + + + + + + + + - - - - - - - - + d="M0 0 L158 0 L158 35 L0 35 L0 0 ZM1 1 L157 1 L157 34 L1 34 L1 1 Z" + fill-rule="evenodd" + clip-path="url(#clipPath20)" + stroke="none" + id="path391"/> + + + + + + + + + x="3" + y="3" + clip-path="url(#clipPath22)" + width="20" + height="20" + preserveAspectRatio="none" + id="image403" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAACCklEQVR42q1UMUsc QRSeN7N72VOiBINwTbSQdJrCQgMpvAQJWMQqKIJwf8BOA0EDacRCCxttk3hBCHYW ghEVhGhCqmghIkgQgjaKYJZd73bnOW91l53bU068gQe7b95+++Z73zeMVXnBTRuo 9kbWBt4gYqdgzKKcz5gLAD8nX84vQlBSAWBuPWc1SvetRPYKAgzmlZQYyEBwwNUa bi18zH52bwQcXh6sBeGNq5+nKzygg74xOvU6b4cZHu+MwBCwplK+qJa+GdofepAA pGNSZ4A6NyLFZTy0/oJaTFt/T/oiPqIBXHF2Ef/ArDW8lfd/eoTJAx79ojS6J54t FW3P0FrlMqsw8jQoQe/22kAvID5Vj1oHUiLwFHfO/zmPQIBs7mrcrc+kbcTEMOF7 ro1tftnZC45M0igzTdUSwpOOhqPUQ8OhoGepcmXo9BjK5xGHoc7uJWgESxtKtRYP HXBfICUhNwIkO4UT15YAPPx9mimce2mKw18nGa5yZfAMBnwrAiRvkp1Kq0xL+AfL R62y4JsUByvHrULlyvheEIZmvXer/YNKDi8STZaI2S/IJO/If0x2z89pQyGjB94E XWMEEA+dN1UL4LjNDd+qczkoMJt7Y7PZhf/RieL7m1+3i+0fsuvGmVvHOLZc/1Am ry9mAvINt+nx9Ez7J+dOFyw5IBRtIA01zdsu2KqvS/ZN5gVE2Ks6AAAAAElFTkSu QmCC"/> + x="23" + y="3" + clip-path="url(#clipPath22)" + width="20" + height="20" + preserveAspectRatio="none" + id="image405" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAABKklEQVR42u2Uv0oD QRDGZ3Y9Q/6ghdhZ26RMKVhoEYxaay8GrHyFe4lUIUlhr4WKEomgD+Az+ABWipFc LvM5e96ByIWsnUIGjtmbvfn43TfLEs3jzwXnFY+utzbB3CQgIOYxyLR7jbsHH0GT V3Rihum227g/dJlJjn0JcwUd2cjYC+WHiUvnCalnLEzbKEYFuBxV3hbt0Cbr5uV+ yeXyyguW+/VRGIbi5+HN9lVk7EEg4zUGn4LYKnZASJuYAdBTd3fQmv3L2t3ZGeyd 1fvvKrb+JZYYKylCrLqxFjb8POSMg0jA6RoBs/TKXDjRD55TTPmVhz/GLjCmOkS0 qi9LU5yaLWiUMIFkmuika/hmu9oo/scmA5t8PILwqrIVN9zsUbGiwHbm98I/iU+D oGuHyXAGnwAAAABJRU5ErkJggg=="/> Session - - - - - - - - + x="47" + y="19" + clip-path="url(#clipPath22)" + stroke="none" + id="text407" + style="white-space: pre;">SessionFactory + + + + + + + + + + x="3" + y="3" + clip-path="url(#clipPath22)" + width="20" + height="20" + preserveAspectRatio="none" + id="image419" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAACCklEQVR42q1UMUsc QRSeN7N72VOiBINwTbSQdJrCQgMpvAQJWMQqKIJwf8BOA0EDacRCCxttk3hBCHYW ghEVhGhCqmghIkgQgjaKYJZd73bnOW91l53bU068gQe7b95+++Z73zeMVXnBTRuo 9kbWBt4gYqdgzKKcz5gLAD8nX84vQlBSAWBuPWc1SvetRPYKAgzmlZQYyEBwwNUa bi18zH52bwQcXh6sBeGNq5+nKzygg74xOvU6b4cZHu+MwBCwplK+qJa+GdofepAA pGNSZ4A6NyLFZTy0/oJaTFt/T/oiPqIBXHF2Ef/ArDW8lfd/eoTJAx79ojS6J54t FW3P0FrlMqsw8jQoQe/22kAvID5Vj1oHUiLwFHfO/zmPQIBs7mrcrc+kbcTEMOF7 ro1tftnZC45M0igzTdUSwpOOhqPUQ8OhoGepcmXo9BjK5xGHoc7uJWgESxtKtRYP HXBfICUhNwIkO4UT15YAPPx9mimce2mKw18nGa5yZfAMBnwrAiRvkp1Kq0xL+AfL R62y4JsUByvHrULlyvheEIZmvXer/YNKDi8STZaI2S/IJO/If0x2z89pQyGjB94E XWMEEA+dN1UL4LjNDd+qczkoMJt7Y7PZhf/RieL7m1+3i+0fsuvGmVvHOLZc/1Am ry9mAvINt+nx9Ez7J+dOFyw5IBRtIA01zdsu2KqvS/ZN5gVE2Ks6AAAAAElFTkSu QmCC"/> + x="23" + y="3" + clip-path="url(#clipPath22)" + width="20" + height="20" + preserveAspectRatio="none" + id="image421" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAABKklEQVR42u2Uv0oD QRDGZ3Y9Q/6ghdhZ26RMKVhoEYxaay8GrHyFe4lUIUlhr4WKEomgD+Az+ABWipFc LvM5e96ByIWsnUIGjtmbvfn43TfLEs3jzwXnFY+utzbB3CQgIOYxyLR7jbsHH0GT V3Rihum227g/dJlJjn0JcwUd2cjYC+WHiUvnCalnLEzbKEYFuBxV3hbt0Cbr5uV+ yeXyyguW+/VRGIbi5+HN9lVk7EEg4zUGn4LYKnZASJuYAdBTd3fQmv3L2t3ZGeyd 1fvvKrb+JZYYKylCrLqxFjb8POSMg0jA6RoBs/TKXDjRD55TTPmVhz/GLjCmOkS0 qi9LU5yaLWiUMIFkmuika/hmu9oo/scmA5t8PILwqrIVN9zsUbGiwHbm98I/iU+D oGuHyXAGnwAAAABJRU5ErkJggg=="/> Session - - - - - - - - - + x="47" + y="19" + clip-path="url(#clipPath22)" + stroke="none" + id="text423" + style="white-space: pre;">SessionFactory + + + + + + + + + + - - - - - - - - + d="M0 0 L188 0 L188 35 L0 35 L0 0 ZM1 1 L187 1 L187 34 L1 34 L1 1 Z" + fill-rule="evenodd" + clip-path="url(#clipPath25)" + stroke="none" + id="path437"/> + + + + + + + + + + x="3" + y="3" + clip-path="url(#clipPath27)" + width="20" + height="20" + preserveAspectRatio="none" + id="image451" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAA2klEQVR42mNkgILa 3hn6/xkYJzIxMdn/+//v5CtuBttZ6em/GUgELCCiumdmGgMj40yG//8Z/v37x8DA yCDN/fUrSI50A0EuAxn2H2gYHPz//5D/86efDGQAJpA3kQ1jZmFh+P/9f3hDQ8M/ sgwEhRmyYf/+/tVh5GTUT5s5k5UsA0ERAAyzJ0B/Hv3z+ZfM////5Dm5eLaKfWbo J8dAZo0g34UMv79O5fr8dk5zXeknjWDfB+xffguxsLFlO7gFLDywc+MHBmqAhv75 CrUTZpozjIJRMApGJAAA4itU2q7mkFUAAAAASUVORK5CYII="/> + x="23" + y="3" + clip-path="url(#clipPath27)" + width="20" + height="20" + preserveAspectRatio="none" + id="image453" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAABKklEQVR42u2Uv0oD QRDGZ3Y9Q/6ghdhZ26RMKVhoEYxaay8GrHyFe4lUIUlhr4WKEomgD+Az+ABWipFc LvM5e96ByIWsnUIGjtmbvfn43TfLEs3jzwXnFY+utzbB3CQgIOYxyLR7jbsHH0GT V3Rihum227g/dJlJjn0JcwUd2cjYC+WHiUvnCalnLEzbKEYFuBxV3hbt0Cbr5uV+ yeXyyguW+/VRGIbi5+HN9lVk7EEg4zUGn4LYKnZASJuYAdBTd3fQmv3L2t3ZGeyd 1fvvKrb+JZYYKylCrLqxFjb8POSMg0jA6RoBs/TKXDjRD55TTPmVhz/GLjCmOkS0 qi9LU5yaLWiUMIFkmuika/hmu9oo/scmA5t8PILwqrIVN9zsUbGiwHbm98I/iU+D oGuHyXAGnwAAAABJRU5ErkJggg=="/> EntityManagerFactory - - - - - - - - + x="47" + y="19" + clip-path="url(#clipPath27)" + stroke="none" + id="text455" + style="white-space: pre;">SessionFactoryImpl + + + + + + + + + + + x="3" + y="3" + clip-path="url(#clipPath27)" + width="20" + height="20" + preserveAspectRatio="none" + id="image469" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAA2klEQVR42mNkgILa 3hn6/xkYJzIxMdn/+//v5CtuBttZ6em/GUgELCCiumdmGgMj40yG//8Z/v37x8DA yCDN/fUrSI50A0EuAxn2H2gYHPz//5D/86efDGQAJpA3kQ1jZmFh+P/9f3hDQ8M/ sgwEhRmyYf/+/tVh5GTUT5s5k5UsA0ERAAyzJ0B/Hv3z+ZfM////5Dm5eLaKfWbo J8dAZo0g34UMv79O5fr8dk5zXeknjWDfB+xffguxsLFlO7gFLDywc+MHBmqAhv75 CrUTZpozjIJRMApGJAAA4itU2q7mkFUAAAAASUVORK5CYII="/> + x="23" + y="3" + clip-path="url(#clipPath27)" + width="20" + height="20" + preserveAspectRatio="none" + id="image471" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAABKklEQVR42u2Uv0oD QRDGZ3Y9Q/6ghdhZ26RMKVhoEYxaay8GrHyFe4lUIUlhr4WKEomgD+Az+ABWipFc LvM5e96ByIWsnUIGjtmbvfn43TfLEs3jzwXnFY+utzbB3CQgIOYxyLR7jbsHH0GT V3Rihum227g/dJlJjn0JcwUd2cjYC+WHiUvnCalnLEzbKEYFuBxV3hbt0Cbr5uV+ yeXyyguW+/VRGIbi5+HN9lVk7EEg4zUGn4LYKnZASJuYAdBTd3fQmv3L2t3ZGeyd 1fvvKrb+JZYYKylCrLqxFjb8POSMg0jA6RoBs/TKXDjRD55TTPmVhz/GLjCmOkS0 qi9LU5yaLWiUMIFkmuika/hmu9oo/scmA5t8PILwqrIVN9zsUbGiwHbm98I/iU+D oGuHyXAGnwAAAABJRU5ErkJggg=="/> EntityManagerFactory - - - - - - - - - + x="47" + y="19" + clip-path="url(#clipPath27)" + stroke="none" + id="text473" + style="white-space: pre;">SessionFactoryImpl + + + + + + + + + + - - - - - - - - + d="M0 0 L174 0 L174 35 L0 35 L0 0 ZM1 1 L173 1 L173 34 L1 34 L1 1 Z" + fill-rule="evenodd" + clip-path="url(#clipPath35)" + stroke="none" + id="path537"/> + + + + + + + + + x="3" + y="3" + clip-path="url(#clipPath37)" + width="20" + height="20" + preserveAspectRatio="none" + id="image549" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAACCklEQVR42q1UMUsc QRSeN7N72VOiBINwTbSQdJrCQgMpvAQJWMQqKIJwf8BOA0EDacRCCxttk3hBCHYW ghEVhGhCqmghIkgQgjaKYJZd73bnOW91l53bU068gQe7b95+++Z73zeMVXnBTRuo 9kbWBt4gYqdgzKKcz5gLAD8nX84vQlBSAWBuPWc1SvetRPYKAgzmlZQYyEBwwNUa bi18zH52bwQcXh6sBeGNq5+nKzygg74xOvU6b4cZHu+MwBCwplK+qJa+GdofepAA pGNSZ4A6NyLFZTy0/oJaTFt/T/oiPqIBXHF2Ef/ArDW8lfd/eoTJAx79ojS6J54t FW3P0FrlMqsw8jQoQe/22kAvID5Vj1oHUiLwFHfO/zmPQIBs7mrcrc+kbcTEMOF7 ro1tftnZC45M0igzTdUSwpOOhqPUQ8OhoGepcmXo9BjK5xGHoc7uJWgESxtKtRYP HXBfICUhNwIkO4UT15YAPPx9mimce2mKw18nGa5yZfAMBnwrAiRvkp1Kq0xL+AfL R62y4JsUByvHrULlyvheEIZmvXer/YNKDi8STZaI2S/IJO/If0x2z89pQyGjB94E XWMEEA+dN1UL4LjNDd+qczkoMJt7Y7PZhf/RieL7m1+3i+0fsuvGmVvHOLZc/1Am ry9mAvINt+nx9Ez7J+dOFyw5IBRtIA01zdsu2KqvS/ZN5gVE2Ks6AAAAAElFTkSu QmCC"/> + x="23" + y="3" + clip-path="url(#clipPath37)" + width="20" + height="20" + preserveAspectRatio="none" + id="image551" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAABKklEQVR42u2Uv0oD QRDGZ3Y9Q/6ghdhZ26RMKVhoEYxaay8GrHyFe4lUIUlhr4WKEomgD+Az+ABWipFc LvM5e96ByIWsnUIGjtmbvfn43TfLEs3jzwXnFY+utzbB3CQgIOYxyLR7jbsHH0GT V3Rihum227g/dJlJjn0JcwUd2cjYC+WHiUvnCalnLEzbKEYFuBxV3hbt0Cbr5uV+ yeXyyguW+/VRGIbi5+HN9lVk7EEg4zUGn4LYKnZASJuYAdBTd3fQmv3L2t3ZGeyd 1fvvKrb+JZYYKylCrLqxFjb8POSMg0jA6RoBs/TKXDjRD55TTPmVhz/GLjCmOkS0 qi9LU5yaLWiUMIFkmuika/hmu9oo/scmA5t8PILwqrIVN9zsUbGiwHbm98I/iU+D oGuHyXAGnwAAAABJRU5ErkJggg=="/> SessionFactory - - - - - - - - + x="47" + y="19" + clip-path="url(#clipPath37)" + stroke="none" + id="text553" + style="white-space: pre;">EntityTransaction + + + + + + + + + + x="3" + y="3" + clip-path="url(#clipPath37)" + width="20" + height="20" + preserveAspectRatio="none" + id="image565" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAACCklEQVR42q1UMUsc QRSeN7N72VOiBINwTbSQdJrCQgMpvAQJWMQqKIJwf8BOA0EDacRCCxttk3hBCHYW ghEVhGhCqmghIkgQgjaKYJZd73bnOW91l53bU068gQe7b95+++Z73zeMVXnBTRuo 9kbWBt4gYqdgzKKcz5gLAD8nX84vQlBSAWBuPWc1SvetRPYKAgzmlZQYyEBwwNUa bi18zH52bwQcXh6sBeGNq5+nKzygg74xOvU6b4cZHu+MwBCwplK+qJa+GdofepAA pGNSZ4A6NyLFZTy0/oJaTFt/T/oiPqIBXHF2Ef/ArDW8lfd/eoTJAx79ojS6J54t FW3P0FrlMqsw8jQoQe/22kAvID5Vj1oHUiLwFHfO/zmPQIBs7mrcrc+kbcTEMOF7 ro1tftnZC45M0igzTdUSwpOOhqPUQ8OhoGepcmXo9BjK5xGHoc7uJWgESxtKtRYP HXBfICUhNwIkO4UT15YAPPx9mimce2mKw18nGa5yZfAMBnwrAiRvkp1Kq0xL+AfL R62y4JsUByvHrULlyvheEIZmvXer/YNKDi8STZaI2S/IJO/If0x2z89pQyGjB94E XWMEEA+dN1UL4LjNDd+qczkoMJt7Y7PZhf/RieL7m1+3i+0fsuvGmVvHOLZc/1Am ry9mAvINt+nx9Ez7J+dOFyw5IBRtIA01zdsu2KqvS/ZN5gVE2Ks6AAAAAElFTkSu QmCC"/> + x="23" + y="3" + clip-path="url(#clipPath37)" + width="20" + height="20" + preserveAspectRatio="none" + id="image567" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAABKklEQVR42u2Uv0oD QRDGZ3Y9Q/6ghdhZ26RMKVhoEYxaay8GrHyFe4lUIUlhr4WKEomgD+Az+ABWipFc LvM5e96ByIWsnUIGjtmbvfn43TfLEs3jzwXnFY+utzbB3CQgIOYxyLR7jbsHH0GT V3Rihum227g/dJlJjn0JcwUd2cjYC+WHiUvnCalnLEzbKEYFuBxV3hbt0Cbr5uV+ yeXyyguW+/VRGIbi5+HN9lVk7EEg4zUGn4LYKnZASJuYAdBTd3fQmv3L2t3ZGeyd 1fvvKrb+JZYYKylCrLqxFjb8POSMg0jA6RoBs/TKXDjRD55TTPmVhz/GLjCmOkS0 qi9LU5yaLWiUMIFkmuika/hmu9oo/scmA5t8PILwqrIVN9zsUbGiwHbm98I/iU+D oGuHyXAGnwAAAABJRU5ErkJggg=="/> SessionFactory - - - - - - - - - + x="47" + y="19" + clip-path="url(#clipPath37)" + stroke="none" + id="text569" + style="white-space: pre;">EntityTransaction + + + + + + + + + + - - - - - - - - + d="M0 0 L137 0 L137 35 L0 35 L0 0 ZM1 1 L136 1 L136 34 L1 34 L1 1 Z" + fill-rule="evenodd" + clip-path="url(#clipPath40)" + stroke="none" + id="path583"/> + + + + + + + + + x="3" + y="3" + clip-path="url(#clipPath42)" + width="20" + height="20" + preserveAspectRatio="none" + id="image595" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAACCklEQVR42q1UMUsc QRSeN7N72VOiBINwTbSQdJrCQgMpvAQJWMQqKIJwf8BOA0EDacRCCxttk3hBCHYW ghEVhGhCqmghIkgQgjaKYJZd73bnOW91l53bU068gQe7b95+++Z73zeMVXnBTRuo 9kbWBt4gYqdgzKKcz5gLAD8nX84vQlBSAWBuPWc1SvetRPYKAgzmlZQYyEBwwNUa bi18zH52bwQcXh6sBeGNq5+nKzygg74xOvU6b4cZHu+MwBCwplK+qJa+GdofepAA pGNSZ4A6NyLFZTy0/oJaTFt/T/oiPqIBXHF2Ef/ArDW8lfd/eoTJAx79ojS6J54t FW3P0FrlMqsw8jQoQe/22kAvID5Vj1oHUiLwFHfO/zmPQIBs7mrcrc+kbcTEMOF7 ro1tftnZC45M0igzTdUSwpOOhqPUQ8OhoGepcmXo9BjK5xGHoc7uJWgESxtKtRYP HXBfICUhNwIkO4UT15YAPPx9mimce2mKw18nGa5yZfAMBnwrAiRvkp1Kq0xL+AfL R62y4JsUByvHrULlyvheEIZmvXer/YNKDi8STZaI2S/IJO/If0x2z89pQyGjB94E XWMEEA+dN1UL4LjNDd+qczkoMJt7Y7PZhf/RieL7m1+3i+0fsuvGmVvHOLZc/1Am ry9mAvINt+nx9Ez7J+dOFyw5IBRtIA01zdsu2KqvS/ZN5gVE2Ks6AAAAAElFTkSu QmCC"/> - + x="23" + y="3" + clip-path="url(#clipPath42)" + width="20" + height="20" + preserveAspectRatio="none" + id="image597" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAABKklEQVR42u2Uv0oD QRDGZ3Y9Q/6ghdhZ26RMKVhoEYxaay8GrHyFe4lUIUlhr4WKEomgD+Az+ABWipFc LvM5e96ByIWsnUIGjtmbvfn43TfLEs3jzwXnFY+utzbB3CQgIOYxyLR7jbsHH0GT V3Rihum227g/dJlJjn0JcwUd2cjYC+WHiUvnCalnLEzbKEYFuBxV3hbt0Cbr5uV+ yeXyyguW+/VRGIbi5+HN9lVk7EEg4zUGn4LYKnZASJuYAdBTd3fQmv3L2t3ZGeyd 1fvvKrb+JZYYKylCrLqxFjb8POSMg0jA6RoBs/TKXDjRD55TTPmVhz/GLjCmOkS0 qi9LU5yaLWiUMIFkmuika/hmu9oo/scmA5t8PILwqrIVN9zsUbGiwHbm98I/iU+D oGuHyXAGnwAAAABJRU5ErkJggg=="/> SessionFactoryImpl - - - - - - - - + x="47" + y="19" + clip-path="url(#clipPath42)" + stroke="none" + id="text599" + style="white-space: pre;">Transaction + + + + + + + + + + x="3" + y="3" + clip-path="url(#clipPath42)" + width="20" + height="20" + preserveAspectRatio="none" + id="image611" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAACCklEQVR42q1UMUsc QRSeN7N72VOiBINwTbSQdJrCQgMpvAQJWMQqKIJwf8BOA0EDacRCCxttk3hBCHYW ghEVhGhCqmghIkgQgjaKYJZd73bnOW91l53bU068gQe7b95+++Z73zeMVXnBTRuo 9kbWBt4gYqdgzKKcz5gLAD8nX84vQlBSAWBuPWc1SvetRPYKAgzmlZQYyEBwwNUa bi18zH52bwQcXh6sBeGNq5+nKzygg74xOvU6b4cZHu+MwBCwplK+qJa+GdofepAA pGNSZ4A6NyLFZTy0/oJaTFt/T/oiPqIBXHF2Ef/ArDW8lfd/eoTJAx79ojS6J54t FW3P0FrlMqsw8jQoQe/22kAvID5Vj1oHUiLwFHfO/zmPQIBs7mrcrc+kbcTEMOF7 ro1tftnZC45M0igzTdUSwpOOhqPUQ8OhoGepcmXo9BjK5xGHoc7uJWgESxtKtRYP HXBfICUhNwIkO4UT15YAPPx9mimce2mKw18nGa5yZfAMBnwrAiRvkp1Kq0xL+AfL R62y4JsUByvHrULlyvheEIZmvXer/YNKDi8STZaI2S/IJO/If0x2z89pQyGjB94E XWMEEA+dN1UL4LjNDd+qczkoMJt7Y7PZhf/RieL7m1+3i+0fsuvGmVvHOLZc/1Am ry9mAvINt+nx9Ez7J+dOFyw5IBRtIA01zdsu2KqvS/ZN5gVE2Ks6AAAAAElFTkSu QmCC"/> - + x="23" + y="3" + clip-path="url(#clipPath42)" + width="20" + height="20" + preserveAspectRatio="none" + id="image613" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAABKklEQVR42u2Uv0oD QRDGZ3Y9Q/6ghdhZ26RMKVhoEYxaay8GrHyFe4lUIUlhr4WKEomgD+Az+ABWipFc LvM5e96ByIWsnUIGjtmbvfn43TfLEs3jzwXnFY+utzbB3CQgIOYxyLR7jbsHH0GT V3Rihum227g/dJlJjn0JcwUd2cjYC+WHiUvnCalnLEzbKEYFuBxV3hbt0Cbr5uV+ yeXyyguW+/VRGIbi5+HN9lVk7EEg4zUGn4LYKnZASJuYAdBTd3fQmv3L2t3ZGeyd 1fvvKrb+JZYYKylCrLqxFjb8POSMg0jA6RoBs/TKXDjRD55TTPmVhz/GLjCmOkS0 qi9LU5yaLWiUMIFkmuika/hmu9oo/scmA5t8PILwqrIVN9zsUbGiwHbm98I/iU+D oGuHyXAGnwAAAABJRU5ErkJggg=="/> SessionFactoryImpl - - - - - - - - - + x="47" + y="19" + clip-path="url(#clipPath42)" + stroke="none" + id="text615" + style="white-space: pre;">Transaction + + + + + + + + + + - - - - - - - - + d="M0 0 L167 0 L167 35 L0 35 L0 0 ZM1 1 L166 1 L166 34 L1 34 L1 1 Z" + fill-rule="evenodd" + clip-path="url(#clipPath45)" + stroke="none" + id="path629"/> + + + + + + + + + x="3" + y="3" + clip-path="url(#clipPath47)" + width="20" + height="20" + preserveAspectRatio="none" + id="image641" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAACrElEQVR42q1UXUgU URS+587sn4qZ6RZIqGSrYmRQSUVFKCT4UEFED5UUQfQQRI+SPQhFL0GJ9FAvldhD hKSGgZHarmRFUEQPKlmrlWgi5t+62+7ce7p3Z3eb62Kt4IVh7pw78813zne+Q8gq L1juABGh8tnIISR0FwHuNIM0BIS/6akp6AAATAnwwD2/k7rpMQ68CgkwgWIs+UQH ghpF2s0n+eOXZwpDywIe7PqYHjYyryEQV4rpBe2a6/Lz6g2BeEyzMmMux3UESFtB xeycR/aXnrzQO/ywickIjR/JNE1mqNQGNA3B5uCJCzRUK01cIWI/rjCU4fvDvy6J LVMIMITZ1ttlc50Ptgb6nm5a/ODN07Pc81q2O6QShSJ/y82OhoYGE9BXcfqwSNUj ttwKNnW3fo8x5s9N21n12eEpnxDs2ILvyRZX+b5v4HByC1No/jpDRloah/Too2wN wg1rmjOtTWVsajxr3dkrXlte0TwikwKOrzl6fgAjv+mSYhrI6W5xbzcP4n2WKKiO 4dGh9bp747Qtv2QuBmZySQaLHZgY9N8qclipU2jcASqOAfb84p/G5NjayOhgplVZ DCzoqtLxOpkYUVEKT1zMEKKUJkQRqjuLd0yFBt7lLr7t2syDAWTTE87ge2/ebNud irTtlX6w2y2iEJ1S7JaiRBlGvSnspPxRA8w5d7Xf4dn2PfSpvyDgbSsL/xjOya6t 80F6hrHEMVpPdUGHYr3KztFTDPjepEyE4lKkv3pGAFGtLSX0VW9NfrMiijS69Kbs UkU8xkAqm7gUMJAvB50k/CjJyyPtjYantq5PelPwtqU6HMjCYv2LIyXBJEC5vrTc iEijM6JnSjtJByjuiQkggjaRps9FIresYP8fsF1iwEoHxJpWtgZQ/loKsNyAXfX1 BxclLeZjw8WpAAAAAElFTkSuQmCC"/> - + x="23" + y="3" + clip-path="url(#clipPath47)" + width="20" + height="20" + preserveAspectRatio="none" + id="image643" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAABKklEQVR42u2Uv0oD QRDGZ3Y9Q/6ghdhZ26RMKVhoEYxaay8GrHyFe4lUIUlhr4WKEomgD+Az+ABWipFc LvM5e96ByIWsnUIGjtmbvfn43TfLEs3jzwXnFY+utzbB3CQgIOYxyLR7jbsHH0GT V3Rihum227g/dJlJjn0JcwUd2cjYC+WHiUvnCalnLEzbKEYFuBxV3hbt0Cbr5uV+ yeXyyguW+/VRGIbi5+HN9lVk7EEg4zUGn4LYKnZASJuYAdBTd3fQmv3L2t3ZGeyd 1fvvKrb+JZYYKylCrLqxFjb8POSMg0jA6RoBs/TKXDjRD55TTPmVhz/GLjCmOkS0 qi9LU5yaLWiUMIFkmuika/hmu9oo/scmA5t8PILwqrIVN9zsUbGiwHbm98I/iU+D oGuHyXAGnwAAAABJRU5ErkJggg=="/> SessionImpl - - - - - - - - + x="47" + y="19" + clip-path="url(#clipPath47)" + stroke="none" + id="text645" + style="white-space: pre;">TransactionImpl + + + + + + + + + + x="3" + y="3" + clip-path="url(#clipPath47)" + width="20" + height="20" + preserveAspectRatio="none" + id="image657" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAACrElEQVR42q1UXUgU URS+587sn4qZ6RZIqGSrYmRQSUVFKCT4UEFED5UUQfQQRI+SPQhFL0GJ9FAvldhD hKSGgZHarmRFUEQPKlmrlWgi5t+62+7ce7p3Z3eb62Kt4IVh7pw78813zne+Q8gq L1juABGh8tnIISR0FwHuNIM0BIS/6akp6AAATAnwwD2/k7rpMQ68CgkwgWIs+UQH ghpF2s0n+eOXZwpDywIe7PqYHjYyryEQV4rpBe2a6/Lz6g2BeEyzMmMux3UESFtB xeycR/aXnrzQO/ywickIjR/JNE1mqNQGNA3B5uCJCzRUK01cIWI/rjCU4fvDvy6J LVMIMITZ1ttlc50Ptgb6nm5a/ODN07Pc81q2O6QShSJ/y82OhoYGE9BXcfqwSNUj ttwKNnW3fo8x5s9N21n12eEpnxDs2ILvyRZX+b5v4HByC1No/jpDRloah/Too2wN wg1rmjOtTWVsajxr3dkrXlte0TwikwKOrzl6fgAjv+mSYhrI6W5xbzcP4n2WKKiO 4dGh9bp747Qtv2QuBmZySQaLHZgY9N8qclipU2jcASqOAfb84p/G5NjayOhgplVZ DCzoqtLxOpkYUVEKT1zMEKKUJkQRqjuLd0yFBt7lLr7t2syDAWTTE87ge2/ebNud irTtlX6w2y2iEJ1S7JaiRBlGvSnspPxRA8w5d7Xf4dn2PfSpvyDgbSsL/xjOya6t 80F6hrHEMVpPdUGHYr3KztFTDPjepEyE4lKkv3pGAFGtLSX0VW9NfrMiijS69Kbs UkU8xkAqm7gUMJAvB50k/CjJyyPtjYantq5PelPwtqU6HMjCYv2LIyXBJEC5vrTc iEijM6JnSjtJByjuiQkggjaRps9FIresYP8fsF1iwEoHxJpWtgZQ/loKsNyAXfX1 BxclLeZjw8WpAAAAAElFTkSuQmCC"/> - + x="23" + y="3" + clip-path="url(#clipPath47)" + width="20" + height="20" + preserveAspectRatio="none" + id="image659" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAABKklEQVR42u2Uv0oD QRDGZ3Y9Q/6ghdhZ26RMKVhoEYxaay8GrHyFe4lUIUlhr4WKEomgD+Az+ABWipFc LvM5e96ByIWsnUIGjtmbvfn43TfLEs3jzwXnFY+utzbB3CQgIOYxyLR7jbsHH0GT V3Rihum227g/dJlJjn0JcwUd2cjYC+WHiUvnCalnLEzbKEYFuBxV3hbt0Cbr5uV+ yeXyyguW+/VRGIbi5+HN9lVk7EEg4zUGn4LYKnZASJuYAdBTd3fQmv3L2t3ZGeyd 1fvvKrb+JZYYKylCrLqxFjb8POSMg0jA6RoBs/TKXDjRD55TTPmVhz/GLjCmOkS0 qi9LU5yaLWiUMIFkmuika/hmu9oo/scmA5t8PILwqrIVN9zsUbGiwHbm98I/iU+D oGuHyXAGnwAAAABJRU5ErkJggg=="/> SessionImpl - - - - - - - - - + x="47" + y="19" + clip-path="url(#clipPath47)" + stroke="none" + id="text661" + style="white-space: pre;">TransactionImpl + + + - - - - - - - - + fill="none" + d="M-525 20.5405 L-525 92.4595" + clip-path="url(#clipPath2)" + id="path679"/> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + x="3" + y="3" + clip-path="url(#clip-4)" + width="20" + height="20" + preserveAspectRatio="none" + id="image-1" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAACCklEQVR42q1UMUsc QRSeN7N72VOiBINwTbSQdJrCQgMpvAQJWMQqKIJwf8BOA0EDacRCCxttk3hBCHYW ghEVhGhCqmghIkgQgjaKYJZd73bnOW91l53bU068gQe7b95+++Z73zeMVXnBTRuo 9kbWBt4gYqdgzKKcz5gLAD8nX84vQlBSAWBuPWc1SvetRPYKAgzmlZQYyEBwwNUa bi18zH52bwQcXh6sBeGNq5+nKzygg74xOvU6b4cZHu+MwBCwplK+qJa+GdofepAA pGNSZ4A6NyLFZTy0/oJaTFt/T/oiPqIBXHF2Ef/ArDW8lfd/eoTJAx79ojS6J54t FW3P0FrlMqsw8jQoQe/22kAvID5Vj1oHUiLwFHfO/zmPQIBs7mrcrc+kbcTEMOF7 ro1tftnZC45M0igzTdUSwpOOhqPUQ8OhoGepcmXo9BjK5xGHoc7uJWgESxtKtRYP HXBfICUhNwIkO4UT15YAPPx9mimce2mKw18nGa5yZfAMBnwrAiRvkp1Kq0xL+AfL R62y4JsUByvHrULlyvheEIZmvXer/YNKDi8STZaI2S/IJO/If0x2z89pQyGjB94E XWMEEA+dN1UL4LjNDd+qczkoMJt7Y7PZhf/RieL7m1+3i+0fsuvGmVvHOLZc/1Am ry9mAvINt+nx9Ez7J+dOFyw5IBRtIA01zdsu2KqvS/ZN5gVE2Ks6AAAAAElFTkSu QmCC"/> + x="23" + y="3" + clip-path="url(#clip-4)" + width="20" + height="20" + preserveAspectRatio="none" + id="image-2" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAABKklEQVR42u2Uv0oD QRDGZ3Y9Q/6ghdhZ26RMKVhoEYxaay8GrHyFe4lUIUlhr4WKEomgD+Az+ABWipFc LvM5e96ByIWsnUIGjtmbvfn43TfLEs3jzwXnFY+utzbB3CQgIOYxyLR7jbsHH0GT V3Rihum227g/dJlJjn0JcwUd2cjYC+WHiUvnCalnLEzbKEYFuBxV3hbt0Cbr5uV+ yeXyyguW+/VRGIbi5+HN9lVk7EEg4zUGn4LYKnZASJuYAdBTd3fQmv3L2t3ZGeyd 1fvvKrb+JZYYKylCrLqxFjb8POSMg0jA6RoBs/TKXDjRD55TTPmVhz/GLjCmOkS0 qi9LU5yaLWiUMIFkmuika/hmu9oo/scmA5t8PILwqrIVN9zsUbGiwHbm98I/iU+D oGuHyXAGnwAAAABJRU5ErkJggg=="/> EntityTransaction - - - - - - - - + x="47" + y="19" + clip-path="url(#clip-4)" + stroke="none" + id="text-1" + style="white-space: pre;">EntityManagerFactory + + + + + + + + + + x="3" + y="3" + clip-path="url(#clip-4)" + width="20" + height="20" + preserveAspectRatio="none" + id="image-3" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAACCklEQVR42q1UMUsc QRSeN7N72VOiBINwTbSQdJrCQgMpvAQJWMQqKIJwf8BOA0EDacRCCxttk3hBCHYW ghEVhGhCqmghIkgQgjaKYJZd73bnOW91l53bU068gQe7b95+++Z73zeMVXnBTRuo 9kbWBt4gYqdgzKKcz5gLAD8nX84vQlBSAWBuPWc1SvetRPYKAgzmlZQYyEBwwNUa bi18zH52bwQcXh6sBeGNq5+nKzygg74xOvU6b4cZHu+MwBCwplK+qJa+GdofepAA pGNSZ4A6NyLFZTy0/oJaTFt/T/oiPqIBXHF2Ef/ArDW8lfd/eoTJAx79ojS6J54t FW3P0FrlMqsw8jQoQe/22kAvID5Vj1oHUiLwFHfO/zmPQIBs7mrcrc+kbcTEMOF7 ro1tftnZC45M0igzTdUSwpOOhqPUQ8OhoGepcmXo9BjK5xGHoc7uJWgESxtKtRYP HXBfICUhNwIkO4UT15YAPPx9mimce2mKw18nGa5yZfAMBnwrAiRvkp1Kq0xL+AfL R62y4JsUByvHrULlyvheEIZmvXer/YNKDi8STZaI2S/IJO/If0x2z89pQyGjB94E XWMEEA+dN1UL4LjNDd+qczkoMJt7Y7PZhf/RieL7m1+3i+0fsuvGmVvHOLZc/1Am ry9mAvINt+nx9Ez7J+dOFyw5IBRtIA01zdsu2KqvS/ZN5gVE2Ks6AAAAAElFTkSu QmCC"/> + x="23" + y="3" + clip-path="url(#clip-4)" + width="20" + height="20" + preserveAspectRatio="none" + id="image-4" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAABKklEQVR42u2Uv0oD QRDGZ3Y9Q/6ghdhZ26RMKVhoEYxaay8GrHyFe4lUIUlhr4WKEomgD+Az+ABWipFc LvM5e96ByIWsnUIGjtmbvfn43TfLEs3jzwXnFY+utzbB3CQgIOYxyLR7jbsHH0GT V3Rihum227g/dJlJjn0JcwUd2cjYC+WHiUvnCalnLEzbKEYFuBxV3hbt0Cbr5uV+ yeXyyguW+/VRGIbi5+HN9lVk7EEg4zUGn4LYKnZASJuYAdBTd3fQmv3L2t3ZGeyd 1fvvKrb+JZYYKylCrLqxFjb8POSMg0jA6RoBs/TKXDjRD55TTPmVhz/GLjCmOkS0 qi9LU5yaLWiUMIFkmuika/hmu9oo/scmA5t8PILwqrIVN9zsUbGiwHbm98I/iU+D oGuHyXAGnwAAAABJRU5ErkJggg=="/> EntityTransaction - - - - - - - - - + x="47" + y="19" + clip-path="url(#clip-4)" + stroke="none" + id="text-2" + style="white-space:pre">EntityManager + + + + + + + + + + - - - - - - - - + d="M0 0 L158 0 L158 35 L0 35 L0 0 ZM1 1 L157 1 L157 34 L1 34 L1 1 Z" + fill-rule="evenodd" + clip-path="url(#clip-6)" + stroke="none" + id="path-14"/> + + + + + + + + + x="3" + y="3" + clip-path="url(#clip-8)" + width="20" + height="20" + preserveAspectRatio="none" + id="image-5" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAACCklEQVR42q1UMUsc QRSeN7N72VOiBINwTbSQdJrCQgMpvAQJWMQqKIJwf8BOA0EDacRCCxttk3hBCHYW ghEVhGhCqmghIkgQgjaKYJZd73bnOW91l53bU068gQe7b95+++Z73zeMVXnBTRuo 9kbWBt4gYqdgzKKcz5gLAD8nX84vQlBSAWBuPWc1SvetRPYKAgzmlZQYyEBwwNUa bi18zH52bwQcXh6sBeGNq5+nKzygg74xOvU6b4cZHu+MwBCwplK+qJa+GdofepAA pGNSZ4A6NyLFZTy0/oJaTFt/T/oiPqIBXHF2Ef/ArDW8lfd/eoTJAx79ojS6J54t FW3P0FrlMqsw8jQoQe/22kAvID5Vj1oHUiLwFHfO/zmPQIBs7mrcrc+kbcTEMOF7 ro1tftnZC45M0igzTdUSwpOOhqPUQ8OhoGepcmXo9BjK5xGHoc7uJWgESxtKtRYP HXBfICUhNwIkO4UT15YAPPx9mimce2mKw18nGa5yZfAMBnwrAiRvkp1Kq0xL+AfL R62y4JsUByvHrULlyvheEIZmvXer/YNKDi8STZaI2S/IJO/If0x2z89pQyGjB94E XWMEEA+dN1UL4LjNDd+qczkoMJt7Y7PZhf/RieL7m1+3i+0fsuvGmVvHOLZc/1Am ry9mAvINt+nx9Ez7J+dOFyw5IBRtIA01zdsu2KqvS/ZN5gVE2Ks6AAAAAElFTkSu QmCC"/> + x="23" + y="3" + clip-path="url(#clip-8)" + width="20" + height="20" + preserveAspectRatio="none" + id="image-6" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAABKklEQVR42u2Uv0oD QRDGZ3Y9Q/6ghdhZ26RMKVhoEYxaay8GrHyFe4lUIUlhr4WKEomgD+Az+ABWipFc LvM5e96ByIWsnUIGjtmbvfn43TfLEs3jzwXnFY+utzbB3CQgIOYxyLR7jbsHH0GT V3Rihum227g/dJlJjn0JcwUd2cjYC+WHiUvnCalnLEzbKEYFuBxV3hbt0Cbr5uV+ yeXyyguW+/VRGIbi5+HN9lVk7EEg4zUGn4LYKnZASJuYAdBTd3fQmv3L2t3ZGeyd 1fvvKrb+JZYYKylCrLqxFjb8POSMg0jA6RoBs/TKXDjRD55TTPmVhz/GLjCmOkS0 qi9LU5yaLWiUMIFkmuika/hmu9oo/scmA5t8PILwqrIVN9zsUbGiwHbm98I/iU+D oGuHyXAGnwAAAABJRU5ErkJggg=="/> Transaction - - - - - - - - + x="47" + y="19" + clip-path="url(#clip-8)" + stroke="none" + id="text-3" + style="white-space: pre;">SessionFactory + + + + + + + + + + x="3" + y="3" + clip-path="url(#clip-8)" + width="20" + height="20" + preserveAspectRatio="none" + id="image-7" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAACCklEQVR42q1UMUsc QRSeN7N72VOiBINwTbSQdJrCQgMpvAQJWMQqKIJwf8BOA0EDacRCCxttk3hBCHYW ghEVhGhCqmghIkgQgjaKYJZd73bnOW91l53bU068gQe7b95+++Z73zeMVXnBTRuo 9kbWBt4gYqdgzKKcz5gLAD8nX84vQlBSAWBuPWc1SvetRPYKAgzmlZQYyEBwwNUa bi18zH52bwQcXh6sBeGNq5+nKzygg74xOvU6b4cZHu+MwBCwplK+qJa+GdofepAA pGNSZ4A6NyLFZTy0/oJaTFt/T/oiPqIBXHF2Ef/ArDW8lfd/eoTJAx79ojS6J54t FW3P0FrlMqsw8jQoQe/22kAvID5Vj1oHUiLwFHfO/zmPQIBs7mrcrc+kbcTEMOF7 ro1tftnZC45M0igzTdUSwpOOhqPUQ8OhoGepcmXo9BjK5xGHoc7uJWgESxtKtRYP HXBfICUhNwIkO4UT15YAPPx9mimce2mKw18nGa5yZfAMBnwrAiRvkp1Kq0xL+AfL R62y4JsUByvHrULlyvheEIZmvXer/YNKDi8STZaI2S/IJO/If0x2z89pQyGjB94E XWMEEA+dN1UL4LjNDd+qczkoMJt7Y7PZhf/RieL7m1+3i+0fsuvGmVvHOLZc/1Am ry9mAvINt+nx9Ez7J+dOFyw5IBRtIA01zdsu2KqvS/ZN5gVE2Ks6AAAAAElFTkSu QmCC"/> + x="23" + y="3" + clip-path="url(#clip-8)" + width="20" + height="20" + preserveAspectRatio="none" + id="image-8" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAABKklEQVR42u2Uv0oD QRDGZ3Y9Q/6ghdhZ26RMKVhoEYxaay8GrHyFe4lUIUlhr4WKEomgD+Az+ABWipFc LvM5e96ByIWsnUIGjtmbvfn43TfLEs3jzwXnFY+utzbB3CQgIOYxyLR7jbsHH0GT V3Rihum227g/dJlJjn0JcwUd2cjYC+WHiUvnCalnLEzbKEYFuBxV3hbt0Cbr5uV+ yeXyyguW+/VRGIbi5+HN9lVk7EEg4zUGn4LYKnZASJuYAdBTd3fQmv3L2t3ZGeyd 1fvvKrb+JZYYKylCrLqxFjb8POSMg0jA6RoBs/TKXDjRD55TTPmVhz/GLjCmOkS0 qi9LU5yaLWiUMIFkmuika/hmu9oo/scmA5t8PILwqrIVN9zsUbGiwHbm98I/iU+D oGuHyXAGnwAAAABJRU5ErkJggg=="/> Transaction - - - - - - - - - + x="47" + y="19" + clip-path="url(#clip-8)" + stroke="none" + id="text-4" + style="white-space:pre">Session + + + + + + + + + + - - - - - - - - + d="M0 0 L188 0 L188 35 L0 35 L0 0 ZM1 1 L187 1 L187 34 L1 34 L1 1 Z" + fill-rule="evenodd" + clip-path="url(#clip-10)" + stroke="none" + id="path-15"/> + + + + + + + + + + x="3" + y="3" + clip-path="url(#clip-12)" + width="20" + height="20" + preserveAspectRatio="none" + id="image-10" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAA2klEQVR42mNkgILa 3hn6/xkYJzIxMdn/+//v5CtuBttZ6em/GUgELCCiumdmGgMj40yG//8Z/v37x8DA yCDN/fUrSI50A0EuAxn2H2gYHPz//5D/86efDGQAJpA3kQ1jZmFh+P/9f3hDQ8M/ sgwEhRmyYf/+/tVh5GTUT5s5k5UsA0ERAAyzJ0B/Hv3z+ZfM////5Dm5eLaKfWbo J8dAZo0g34UMv79O5fr8dk5zXeknjWDfB+xffguxsLFlO7gFLDywc+MHBmqAhv75 CrUTZpozjIJRMApGJAAA4itU2q7mkFUAAAAASUVORK5CYII="/> + x="23" + y="3" + clip-path="url(#clip-12)" + width="20" + height="20" + preserveAspectRatio="none" + id="image-11" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAABKklEQVR42u2Uv0oD QRDGZ3Y9Q/6ghdhZ26RMKVhoEYxaay8GrHyFe4lUIUlhr4WKEomgD+Az+ABWipFc LvM5e96ByIWsnUIGjtmbvfn43TfLEs3jzwXnFY+utzbB3CQgIOYxyLR7jbsHH0GT V3Rihum227g/dJlJjn0JcwUd2cjYC+WHiUvnCalnLEzbKEYFuBxV3hbt0Cbr5uV+ yeXyyguW+/VRGIbi5+HN9lVk7EEg4zUGn4LYKnZASJuYAdBTd3fQmv3L2t3ZGeyd 1fvvKrb+JZYYKylCrLqxFjb8POSMg0jA6RoBs/TKXDjRD55TTPmVhz/GLjCmOkS0 qi9LU5yaLWiUMIFkmuika/hmu9oo/scmA5t8PILwqrIVN9zsUbGiwHbm98I/iU+D oGuHyXAGnwAAAABJRU5ErkJggg=="/> TransactionImpl - - - - - - - - + x="47" + y="19" + clip-path="url(#clip-12)" + stroke="none" + id="text-5" + style="white-space: pre;">SessionFactoryImpl + + + + + + + + + + + x="3" + y="3" + clip-path="url(#clip-12)" + width="20" + height="20" + preserveAspectRatio="none" + id="image-13" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAA2klEQVR42mNkgILa 3hn6/xkYJzIxMdn/+//v5CtuBttZ6em/GUgELCCiumdmGgMj40yG//8Z/v37x8DA yCDN/fUrSI50A0EuAxn2H2gYHPz//5D/86efDGQAJpA3kQ1jZmFh+P/9f3hDQ8M/ sgwEhRmyYf/+/tVh5GTUT5s5k5UsA0ERAAyzJ0B/Hv3z+ZfM////5Dm5eLaKfWbo J8dAZo0g34UMv79O5fr8dk5zXeknjWDfB+xffguxsLFlO7gFLDywc+MHBmqAhv75 CrUTZpozjIJRMApGJAAA4itU2q7mkFUAAAAASUVORK5CYII="/> + x="23" + y="3" + clip-path="url(#clip-12)" + width="20" + height="20" + preserveAspectRatio="none" + id="image-14" + xlink:href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAABKklEQVR42u2Uv0oD QRDGZ3Y9Q/6ghdhZ26RMKVhoEYxaay8GrHyFe4lUIUlhr4WKEomgD+Az+ABWipFc LvM5e96ByIWsnUIGjtmbvfn43TfLEs3jzwXnFY+utzbB3CQgIOYxyLR7jbsHH0GT V3Rihum227g/dJlJjn0JcwUd2cjYC+WHiUvnCalnLEzbKEYFuBxV3hbt0Cbr5uV+ yeXyyguW+/VRGIbi5+HN9lVk7EEg4zUGn4LYKnZASJuYAdBTd3fQmv3L2t3ZGeyd 1fvvKrb+JZYYKylCrLqxFjb8POSMg0jA6RoBs/TKXDjRD55TTPmVhz/GLjCmOkS0 qi9LU5yaLWiUMIFkmuika/hmu9oo/scmA5t8PILwqrIVN9zsUbGiwHbm98I/iU+D oGuHyXAGnwAAAABJRU5ErkJggg=="/> TransactionImpl - - - - - - - - - - - - - - - - - - + x="47" + y="19" + clip-path="url(#clip-12)" + stroke="none" + id="text-6" + style="white-space:pre">SessionImpl + From b30a68f5be8aeef7e8b1f8110fabfe08b4caf0b3 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Thu, 13 May 2021 09:49:14 +0200 Subject: [PATCH 157/644] HHH-14596 WhereAnnotatedOneToManySizeTest fails on HANA database --- .../test/hql/size/filter/WhereAnnotatedOneToManySizeTest.java | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hibernate-core/src/test/java/org/hibernate/test/hql/size/filter/WhereAnnotatedOneToManySizeTest.java b/hibernate-core/src/test/java/org/hibernate/test/hql/size/filter/WhereAnnotatedOneToManySizeTest.java index a5adb3af5b15..a3ec5d5a3587 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/hql/size/filter/WhereAnnotatedOneToManySizeTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/hql/size/filter/WhereAnnotatedOneToManySizeTest.java @@ -10,6 +10,7 @@ import java.util.List; +import org.hibernate.dialect.AbstractHANADialect; import org.hibernate.dialect.DB2Dialect; import org.hibernate.query.spi.QueryImplementor; @@ -89,6 +90,7 @@ public void after() { @Test @SkipForDialect(value = DB2Dialect.class, comment = "DB2 does not support correlated subqueries in the ORDER BY clause") + @SkipForDialect(value = AbstractHANADialect.class, comment = "HANA db does not support correlated subqueries in the ORDER BY clause") public void orderBy_sizeOf() { inSession( session -> { QueryImplementor query = session.createQuery( @@ -101,6 +103,7 @@ public void orderBy_sizeOf() { @Test @SkipForDialect(value = DB2Dialect.class, comment = "DB2 does not support correlated subqueries in the ORDER BY clause") + @SkipForDialect(value = AbstractHANADialect.class, comment = "HANA db does not support correlated subqueries in the ORDER BY clause") public void orderBy_dotSize() { inSession( session -> { QueryImplementor query = session.createQuery( From 8b9b5e7e68893dc9c84120c8295d7afad8371290 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Sun, 16 May 2021 14:55:57 +0100 Subject: [PATCH 158/644] HHH-14610 Upgrade to Byte Buddy 1.10.22 --- gradle/libraries.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libraries.gradle b/gradle/libraries.gradle index cf98d0a77bd1..9fc6ca1d61b7 100644 --- a/gradle/libraries.gradle +++ b/gradle/libraries.gradle @@ -25,7 +25,7 @@ ext { jakartaWeldVersion = '4.0.1.SP1' javassistVersion = '3.27.0-GA' - byteBuddyVersion = '1.10.21' + byteBuddyVersion = '1.10.22' agroalVersion = '1.9' From eb6c68cdc608ba90cd9deeb654a4e3dccde03ccc Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Tue, 18 May 2021 22:05:17 +0100 Subject: [PATCH 159/644] HHH-14621 Introduce new methods on EventListenerGroup which allow Hibernate Reactive to fire events more efficiently --- .../internal/EventListenerGroupImpl.java | 54 +++++++++++++++++++ .../event/service/spi/EventListenerGroup.java | 52 ++++++++++++++++++ 2 files changed, 106 insertions(+) diff --git a/hibernate-core/src/main/java/org/hibernate/event/service/internal/EventListenerGroupImpl.java b/hibernate-core/src/main/java/org/hibernate/event/service/internal/EventListenerGroupImpl.java index 8bdcf3710ff0..fb6255eb8464 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/service/internal/EventListenerGroupImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/event/service/internal/EventListenerGroupImpl.java @@ -11,8 +11,12 @@ import java.util.Collections; import java.util.LinkedHashSet; import java.util.Set; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; import java.util.function.BiConsumer; +import java.util.function.BiFunction; import java.util.function.Consumer; +import java.util.function.Function; import java.util.function.Supplier; import org.hibernate.event.service.spi.DuplicationStrategy; @@ -33,8 +37,10 @@ * @author Sanne Grinovero */ class EventListenerGroupImpl implements EventListenerGroup { + private static final Logger log = Logger.getLogger( EventListenerGroupImpl.class ); private static final Set DEFAULT_DUPLICATION_STRATEGIES = Collections.unmodifiableSet( makeDefaultDuplicationStrategy() ); + private static final CompletableFuture COMPLETED = CompletableFuture.completedFuture( null ); private final EventType eventType; private final CallbackRegistry callbackRegistry; @@ -114,6 +120,54 @@ public void fireEventOnEachListener(final U event, final X parameter, fina } } + @Override + public CompletionStage fireEventOnEachListener( + final U event, + final Function>> fun) { + CompletionStage ret = COMPLETED; + final T[] ls = listeners; + if ( ls != null && ls.length != 0 ) { + for ( T listener : ls ) { + //to preserve atomicity of the Session methods + //call apply() from within the arg of thenCompose() + ret = ret.thenCompose( v -> fun.apply( (RL) listener ).apply( event ) ); + } + } + return ret; + } + + @Override + public CompletionStage fireEventOnEachListener( + U event, X param, Function>> fun) { + CompletionStage ret = COMPLETED; + final T[] ls = listeners; + if ( ls != null && ls.length != 0 ) { + for ( T listener : ls ) { + //to preserve atomicity of the Session methods + //call apply() from within the arg of thenCompose() + ret = ret.thenCompose( v -> fun.apply( (RL) listener ).apply( event, param ) ); + } + } + return ret; + } + + @Override + public CompletionStage fireLazyEventOnEachListener( + final Supplier eventSupplier, + final Function>> fun) { + CompletionStage ret = COMPLETED; + final T[] ls = listeners; + if ( ls != null && ls.length != 0 ) { + final U event = eventSupplier.get(); + for ( T listener : ls ) { + //to preserve atomicity of the Session methods + //call apply() from within the arg of thenCompose() + ret = ret.thenCompose( v -> fun.apply( (RL) listener ).apply( event ) ); + } + } + return ret; + } + @Override public void addDuplicationStrategy(DuplicationStrategy strategy) { if ( duplicationStrategies == DEFAULT_DUPLICATION_STRATEGIES ) { diff --git a/hibernate-core/src/main/java/org/hibernate/event/service/spi/EventListenerGroup.java b/hibernate-core/src/main/java/org/hibernate/event/service/spi/EventListenerGroup.java index df62868c4894..84872efe28c8 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/service/spi/EventListenerGroup.java +++ b/hibernate-core/src/main/java/org/hibernate/event/service/spi/EventListenerGroup.java @@ -8,7 +8,10 @@ import java.io.Serializable; import java.util.Map; +import java.util.concurrent.CompletionStage; import java.util.function.BiConsumer; +import java.util.function.BiFunction; +import java.util.function.Function; import java.util.function.Supplier; import org.hibernate.Incubating; @@ -113,4 +116,53 @@ public interface EventListenerGroup extends Serializable { @Incubating void fireEventOnEachListener(final U event, X param, final EventActionWithParameter actionOnEvent); + /** + * Similar to {@link #fireEventOnEachListener(Object, Function)}, but Reactive friendly: it chains + * processing of the same event on each Reactive Listener, and returns a {@link CompletionStage} of type R. + * The various generic types allow using this for each concrete event type and flexible return types. + *

    Used by Hibernate Reactive

    + * @param event The event being fired + * @param fun The function combining each event listener with the event + * @param the return type of the returned CompletionStage + * @param the type of the event being fired on each listener + * @param the type of ReactiveListener: each listener of type T will be casted to it. + * @return the composite completion stage of invoking fun(event) on each listener. + */ + @Incubating + CompletionStage fireEventOnEachListener(final U event, final Function>> fun); + + /** + * Similar to {@link #fireEventOnEachListener(Object, Object, Function)}, but Reactive friendly: it chains + * processing of the same event on each Reactive Listener, and returns a {@link CompletionStage} of type R. + * The various generic types allow using this for each concrete event type and flexible return types. + *

    Used by Hibernate Reactive

    + * @param event The event being fired + * @param fun The function combining each event listener with the event + * @param the return type of the returned CompletionStage + * @param the type of the event being fired on each listener + * @param the type of ReactiveListener: each listener of type T will be casted to it. + * @param an additional parameter to be passed to the function fun + * @return the composite completion stage of invoking fun(event) on each listener. + */ + @Incubating + public CompletionStage fireEventOnEachListener(U event, X param, Function>> fun); + + /** + * Similar to {@link #fireLazyEventOnEachListener(Supplier, BiConsumer)}, but Reactive friendly: it chains + * processing of the same event on each Reactive Listener, and returns a {@link CompletionStage} of type R. + * The various generic types allow using this for each concrete event type and flexible return types. + *

    This variant expects a Supplier of the event, rather than the event directly; this is useful for the + * event types which are commonly configured with no listeners at all, so to allow skipping creating the + * event; use only for event types which are known to be expensive while the listeners are commonly empty.

    + *

    Used by Hibernate Reactive

    + * @param eventSupplier A supplier able to produce the actual event + * @param fun The function combining each event listener with the event + * @param the return type of the returned CompletionStage + * @param the type of the event being fired on each listener + * @param the type of ReactiveListener: each listener of type T will be casted to it. + * @return the composite completion stage of invoking fun(event) on each listener. + */ + @Incubating + CompletionStage fireLazyEventOnEachListener(final Supplier eventSupplier, final Function>> fun); + } From b9270e44b186dd0f2eb9821e1c766e01249d4bd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Wed, 19 May 2021 16:25:35 +0200 Subject: [PATCH 160/644] HHH-14620 Do not initialize collections just to take a snapshot of their size As far as I can tell this is safe enough for dirty tracking: * The collection tracker will return a size of -1 for that collection * Which is exactly the behavior we currently get after $$_hibernane_clearDirtyCollectionNames is called if a collection has been "retrieved" (getter called) but was not initialized. * This will mainly prevent some optimizations because we will no longer be able to tell whether a collection is "dirty" or not. I think we should be able to restore those optimizations: for PersistentCollection instances, we would store the "initial" size inside the collection itself upon initialization, and we would compare THAT size to the current size in implementations of $$_hibernate_areCollectionFieldsDirty (see org.hibernate.bytecode.enhance.internal.bytebuddy.CodeTemplates). Alternatively we could store the CollectionTracker inside the PersistentCollection so that the collection can update the tracker upon initialization. However, that's outside the scope of this bug, that would require significant testing, and that may cause conflicts with ORM 6, so I won't do it here. --- .../LazyAttributeLoadingInterceptor.java | 8 ++++++ .../ondemandload/OnDemandLoadTest.java | 26 ++++++++++--------- 2 files changed, 22 insertions(+), 12 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/LazyAttributeLoadingInterceptor.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/LazyAttributeLoadingInterceptor.java index 7880edbb578f..1b084cccd223 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/LazyAttributeLoadingInterceptor.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/spi/interceptor/LazyAttributeLoadingInterceptor.java @@ -16,6 +16,7 @@ import org.hibernate.LockMode; import org.hibernate.bytecode.enhance.spi.CollectionTracker; import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer; +import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.engine.spi.SelfDirtinessTracker; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.spi.Status; @@ -152,11 +153,18 @@ public String toString() { private void takeCollectionSizeSnapshot(Object target, String fieldName, Object value) { if ( value instanceof Collection && target instanceof SelfDirtinessTracker ) { + // This must be called first, so that we remember that there is a collection out there, + // even if we don't know its size (see below). CollectionTracker tracker = ( (SelfDirtinessTracker) target ).$$_hibernate_getCollectionTracker(); if ( tracker == null ) { ( (SelfDirtinessTracker) target ).$$_hibernate_clearDirtyAttributes(); tracker = ( (SelfDirtinessTracker) target ).$$_hibernate_getCollectionTracker(); } + + if ( value instanceof PersistentCollection && !( (PersistentCollection) value ).wasInitialized() ) { + // Cannot take a snapshot of an un-initialized collection. + return; + } tracker.add( fieldName, ( (Collection) value ).size() ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/ondemandload/OnDemandLoadTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/ondemandload/OnDemandLoadTest.java index e242c1c3a036..68642adeb095 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/ondemandload/OnDemandLoadTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/ondemandload/OnDemandLoadTest.java @@ -119,16 +119,17 @@ public void testClearedSession() { store.getInventories().size(); assertTrue( isPropertyInitialized( store, "inventories" ) ); - // the extra Session is the temp Session needed to perform the init - assertEquals( 2, sessionFactory().getStatistics().getSessionOpenCount() ); - assertEquals( 1, sessionFactory().getStatistics().getSessionCloseCount() ); + // the extra Sessions are the temp Sessions needed to perform the init: + // first the entity, then the collection (since it's lazy) + assertEquals( 3, sessionFactory().getStatistics().getSessionOpenCount() ); + assertEquals( 2, sessionFactory().getStatistics().getSessionCloseCount() ); // clear Session again. The collection should still be recognized as initialized from above s.clear(); assertNotNull( store ); assertTrue( isPropertyInitialized( store, "inventories" ) ); - assertEquals( 2, sessionFactory().getStatistics().getSessionOpenCount() ); - assertEquals( 1, sessionFactory().getStatistics().getSessionCloseCount() ); + assertEquals( 3, sessionFactory().getStatistics().getSessionOpenCount() ); + assertEquals( 2, sessionFactory().getStatistics().getSessionCloseCount() ); // lets clear the Session again and this time reload the Store s.clear(); @@ -138,21 +139,22 @@ public void testClearedSession() { // collection should be back to uninitialized since we have a new entity instance assertFalse( isPropertyInitialized( store, "inventories" ) ); - assertEquals( 2, sessionFactory().getStatistics().getSessionOpenCount() ); - assertEquals( 1, sessionFactory().getStatistics().getSessionCloseCount() ); + assertEquals( 3, sessionFactory().getStatistics().getSessionOpenCount() ); + assertEquals( 2, sessionFactory().getStatistics().getSessionCloseCount() ); store.getInventories().size(); assertTrue( isPropertyInitialized( store, "inventories" ) ); - // the extra Session is the temp Session needed to perform the init - assertEquals( 3, sessionFactory().getStatistics().getSessionOpenCount() ); - assertEquals( 2, sessionFactory().getStatistics().getSessionCloseCount() ); + // the extra Sessions are the temp Sessions needed to perform the init: + // first the entity, then the collection (since it's lazy) + assertEquals( 5, sessionFactory().getStatistics().getSessionOpenCount() ); + assertEquals( 4, sessionFactory().getStatistics().getSessionCloseCount() ); // clear Session again. The collection should still be recognized as initialized from above s.clear(); assertNotNull( store ); assertTrue( isPropertyInitialized( store, "inventories" ) ); - assertEquals( 3, sessionFactory().getStatistics().getSessionOpenCount() ); - assertEquals( 2, sessionFactory().getStatistics().getSessionCloseCount() ); + assertEquals( 5, sessionFactory().getStatistics().getSessionOpenCount() ); + assertEquals( 4, sessionFactory().getStatistics().getSessionCloseCount() ); } ); } From 12cb577f9f7febf0cfcd709289495aa7be8c799a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Wed, 19 May 2021 16:10:03 +0200 Subject: [PATCH 161/644] HHH-14620 Test incorrect initialization of a collection with extended bytecode enhancement --- .../lazy/LazyCollectionLoadingTest.java | 37 +++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/LazyCollectionLoadingTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/LazyCollectionLoadingTest.java index f61895cd5d22..ab4bd313663b 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/LazyCollectionLoadingTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/LazyCollectionLoadingTest.java @@ -36,6 +36,7 @@ import static org.hamcrest.CoreMatchers.notNullValue; import static org.hamcrest.CoreMatchers.sameInstance; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hibernate.Hibernate.isInitialized; import static org.hibernate.Hibernate.isPropertyInitialized; import static org.hibernate.testing.bytecode.enhancement.EnhancerTestUtils.checkDirtyTracking; import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; @@ -101,7 +102,40 @@ public void testTransaction() { checkDirtyTracking( parent ); assertThat( children1, sameInstance( children2 ) ); + + assertFalse( isInitialized( children1 ) ); + assertThat( children1.size(), equalTo( CHILDREN_SIZE ) ); + assertTrue( isInitialized( children1 ) ); + } ); + } + + @Test + @TestForIssue( jiraKey = "HHH-14620" ) + public void testTransaction_noProxy() { + doInHibernate( this::sessionFactory, s -> { + // find will not return a proxy, which is exactly what we want here. + Parent parent = s.find( Parent.class, parentID ); + assertThat( parent, notNullValue() ); + assertThat( parent, not( instanceOf( HibernateProxy.class ) ) ); + assertThat( parent, not( instanceOf( HibernateProxy.class ) ) ); + assertFalse( isPropertyInitialized( parent, "children" ) ); + checkDirtyTracking( parent ); + + List children1 = parent.children; + List children2 = parent.children; + + assertTrue( isPropertyInitialized( parent, "children" ) ); + checkDirtyTracking( parent ); + + assertThat( children1, sameInstance( children2 ) ); + + // This check is important: a bug used to cause the collection to be initialized + // during the call to parent.children above. + // Note the same problem would occur if we were using getters: + // we only need extended enhancement to be enabled. + assertFalse( isInitialized( children1 ) ); assertThat( children1.size(), equalTo( CHILDREN_SIZE ) ); + assertTrue( isInitialized( children1 ) ); } ); } @@ -122,7 +156,10 @@ public void testNoTransaction() { checkDirtyTracking( parent ); assertThat( children1, sameInstance( children2 ) ); + + assertFalse( isInitialized( children1 ) ); assertThat( children1.size(), equalTo( CHILDREN_SIZE ) ); + assertTrue( isInitialized( children1 ) ); } // --- // From ccc5eb13054af130f9132fcf1c7808901fa9e2c9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Thu, 20 May 2021 08:46:36 +0200 Subject: [PATCH 162/644] HHH-14620 Remove duplicate assertions in LazyCollectionLoadingTest --- .../bytecode/enhancement/lazy/LazyCollectionLoadingTest.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/LazyCollectionLoadingTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/LazyCollectionLoadingTest.java index ab4bd313663b..1433a80e20b2 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/LazyCollectionLoadingTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/LazyCollectionLoadingTest.java @@ -91,7 +91,6 @@ public void testTransaction() { Parent parent = s.load( Parent.class, parentID ); assertThat( parent, notNullValue() ); assertThat( parent, not( instanceOf( HibernateProxy.class ) ) ); - assertThat( parent, not( instanceOf( HibernateProxy.class ) ) ); assertFalse( isPropertyInitialized( parent, "children" ) ); checkDirtyTracking( parent ); @@ -117,7 +116,6 @@ public void testTransaction_noProxy() { Parent parent = s.find( Parent.class, parentID ); assertThat( parent, notNullValue() ); assertThat( parent, not( instanceOf( HibernateProxy.class ) ) ); - assertThat( parent, not( instanceOf( HibernateProxy.class ) ) ); assertFalse( isPropertyInitialized( parent, "children" ) ); checkDirtyTracking( parent ); @@ -145,7 +143,6 @@ public void testNoTransaction() { parent = s.load( Parent.class, parentID ); assertThat( parent, notNullValue() ); assertThat( parent, not( instanceOf( HibernateProxy.class ) ) ); - assertThat( parent, not( instanceOf( HibernateProxy.class ) ) ); assertFalse( isPropertyInitialized( parent, "children" ) ); } ); From e6688f8ebc83b5562225a1969d2967f28ddf5a0d Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Wed, 19 May 2021 21:00:28 +0100 Subject: [PATCH 163/644] HHH-14622 Improved iteration of PreLoadEventListener --- .../engine/internal/TwoPhaseLoad.java | 43 +++---------------- .../java/org/hibernate/loader/Loader.java | 8 +--- .../process/internal/AbstractRowReader.java | 8 +--- 3 files changed, 9 insertions(+), 50 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/TwoPhaseLoad.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/TwoPhaseLoad.java index 8dfc849ed5ed..20b94278bd89 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/internal/TwoPhaseLoad.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/TwoPhaseLoad.java @@ -105,29 +105,6 @@ public static void postHydrate( } } - /** - * @deprecated This method will be removed. Use {@link #initializeEntity(Object, boolean, SharedSessionContractImplementor, PreLoadEvent, Iterable)} instead. - * - * @param entity The entity being loaded - * @param readOnly Is the entity being loaded as read-only - * @param session The Session - * @param preLoadEvent The (re-used) pre-load event - */ - @Deprecated - public static void initializeEntity( - final Object entity, - final boolean readOnly, - final SharedSessionContractImplementor session, - final PreLoadEvent preLoadEvent) { - final EventListenerGroup listenerGroup = session - .getFactory() - .getServiceRegistry() - .getService( EventListenerRegistry.class ) - .getEventListenerGroup( EventType.PRE_LOAD ); - final Iterable listeners = listenerGroup.listeners(); - initializeEntity( entity, readOnly, session, preLoadEvent, listeners, EntityResolver.DEFAULT ); - } - /** * Perform the second step of 2-phase load. Fully initialize the entity * instance. @@ -140,15 +117,13 @@ public static void initializeEntity( * @param readOnly Is the entity being loaded as read-only * @param session The Session * @param preLoadEvent The (re-used) pre-load event - * @param preLoadEventListeners the pre-load event listeners */ public static void initializeEntity( final Object entity, final boolean readOnly, final SharedSessionContractImplementor session, - final PreLoadEvent preLoadEvent, - final Iterable preLoadEventListeners) { - initializeEntity( entity, readOnly, session, preLoadEvent, preLoadEventListeners, EntityResolver.DEFAULT ); + final PreLoadEvent preLoadEvent) { + initializeEntity( entity, readOnly, session, preLoadEvent, EntityResolver.DEFAULT ); } /** @@ -163,7 +138,6 @@ public static void initializeEntity( * @param readOnly Is the entity being loaded as read-only * @param session The Session * @param preLoadEvent The (re-used) pre-load event - * @param preLoadEventListeners the pre-load event listeners * @param entityResolver the resolver used for to-one entity associations * (not used when an entity is a bytecode-enhanced lazy entity) */ @@ -172,7 +146,6 @@ public static void initializeEntity( final boolean readOnly, final SharedSessionContractImplementor session, final PreLoadEvent preLoadEvent, - final Iterable preLoadEventListeners, final EntityResolver entityResolver) { final PersistenceContext persistenceContext = session.getPersistenceContextInternal(); final EntityEntry entityEntry = persistenceContext.getEntry( entity ); @@ -180,7 +153,7 @@ public static void initializeEntity( throw new AssertionFailure( "possible non-threadsafe access to the session" ); } initializeEntityEntryLoadedState( entity, entityEntry, session, entityResolver ); - initializeEntityFromEntityEntryLoadedState( entity, entityEntry, readOnly, session, preLoadEvent, preLoadEventListeners ); + initializeEntityFromEntityEntryLoadedState( entity, entityEntry, readOnly, session, preLoadEvent ); } public static void initializeEntityEntryLoadedState( @@ -261,8 +234,7 @@ public static void initializeEntityFromEntityEntryLoadedState( final EntityEntry entityEntry, final boolean readOnly, final SharedSessionContractImplementor session, - final PreLoadEvent preLoadEvent, - final Iterable preLoadEventListeners) throws HibernateException { + final PreLoadEvent preLoadEvent) throws HibernateException { final PersistenceContext persistenceContext = session.getPersistenceContextInternal(); final EntityPersister persister = entityEntry.getPersister(); @@ -274,9 +246,8 @@ public static void initializeEntityFromEntityEntryLoadedState( //Must occur after resolving identifiers! if ( session.isEventSource() ) { preLoadEvent.setEntity( entity ).setState( hydratedState ).setId( id ).setPersister( persister ); - for ( PreLoadEventListener listener : preLoadEventListeners ) { - listener.onPreLoad( preLoadEvent ); - } + session.getFactory().getFastSessionServices() + .eventListenerGroup_PRE_LOAD.fireEventOnEachListener( preLoadEvent, PreLoadEventListener::onPreLoad ); } persister.setPropertyValues( entity, hydratedState ); @@ -589,7 +560,7 @@ public static void addUninitializedCachedEntity( /** * Implementations determine how a to-one associations is resolved. * - * @see #initializeEntity(Object, boolean, SharedSessionContractImplementor, PreLoadEvent, Iterable, EntityResolver) + * @see #initializeEntity(Object, boolean, SharedSessionContractImplementor, PreLoadEvent, EntityResolver) */ public interface EntityResolver { diff --git a/hibernate-core/src/main/java/org/hibernate/loader/Loader.java b/hibernate-core/src/main/java/org/hibernate/loader/Loader.java index 2095ecc0f6a9..db8e0e2fbeb4 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/Loader.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/Loader.java @@ -1184,14 +1184,8 @@ private void initializeEntitiesAndCollections( LOG.tracev( "Total objects hydrated: {0}", hydratedObjectsSize ); if ( hydratedObjectsSize != 0 ) { - final Iterable listeners = session - .getFactory() - .getFastSessionServices() - .eventListenerGroup_PRE_LOAD - .listeners(); - for ( Object hydratedObject : hydratedObjects ) { - TwoPhaseLoad.initializeEntity( hydratedObject, readOnly, session, pre, listeners ); + TwoPhaseLoad.initializeEntity( hydratedObject, readOnly, session, pre ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/process/internal/AbstractRowReader.java b/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/process/internal/AbstractRowReader.java index 4e640e41e11f..32f8b01870ea 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/process/internal/AbstractRowReader.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/process/internal/AbstractRowReader.java @@ -237,19 +237,13 @@ private void performTwoPhaseLoad( } final SharedSessionContractImplementor session = context.getSession(); - final Iterable listeners = session - .getFactory() - .getFastSessionServices() - .eventListenerGroup_PRE_LOAD - .listeners(); for ( HydratedEntityRegistration registration : hydratedEntityRegistrations ) { TwoPhaseLoad.initializeEntity( registration.getInstance(), context.isReadOnly(), session, - preLoadEvent, - listeners + preLoadEvent ); } } From 6dc3b4a7263ffce501544499fe4c443b3f871228 Mon Sep 17 00:00:00 2001 From: gavin Date: Wed, 19 May 2021 11:17:02 +0200 Subject: [PATCH 164/644] make logFlushResults() protected for the benefit of HR --- .../event/internal/AbstractFlushingEventListener.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractFlushingEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractFlushingEventListener.java index d596c6e8e613..b70a6166652d 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractFlushingEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractFlushingEventListener.java @@ -104,8 +104,8 @@ protected void flushEverythingToExecutions(FlushEvent event) throws HibernateExc logFlushResults( event ); } - @SuppressWarnings( value = {"unchecked"} ) - private void logFlushResults(FlushEvent event) { + @SuppressWarnings("unchecked") + protected void logFlushResults(FlushEvent event) { if ( !LOG.isDebugEnabled() ) { return; } From bf19f98c2d59fb60cf4043cab322dfd68a9e5101 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Wed, 19 May 2021 15:50:24 +0200 Subject: [PATCH 165/644] HHH-14619 Test and fix ClassCastException because collection of uninitialized proxy is dirty checked --- .../AbstractFlushingEventListener.java | 1 - .../DefaultFlushEntityEventListener.java | 1 + .../DirtyCollectionSearchVisitor.java | 17 +- .../lazy/LazyProxyWithCollectionTest.java | 166 ++++++++++++++++++ 4 files changed, 182 insertions(+), 3 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/LazyProxyWithCollectionTest.java diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractFlushingEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractFlushingEventListener.java index b70a6166652d..98502d8c6877 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractFlushingEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/AbstractFlushingEventListener.java @@ -219,7 +219,6 @@ private int flushEntities(final FlushEvent event, final PersistenceContext persi final int count = entityEntries.length; for ( Map.Entry me : entityEntries ) { - // Update the status of the object and if necessary, schedule an update EntityEntry entry = me.getValue(); diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultFlushEntityEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultFlushEntityEventListener.java index 23e4955d5f5c..ef9815b00c09 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultFlushEntityEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultFlushEntityEventListener.java @@ -485,6 +485,7 @@ protected final boolean isUpdateNecessary(FlushEntityEvent event) throws Hiberna private boolean hasDirtyCollections(FlushEntityEvent event, EntityPersister persister, Status status) { if ( isCollectionDirtyCheckNecessary( persister, status ) ) { DirtyCollectionSearchVisitor visitor = new DirtyCollectionSearchVisitor( + event.getEntity(), event.getSession(), persister.getPropertyVersionability() ); diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DirtyCollectionSearchVisitor.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DirtyCollectionSearchVisitor.java index 73fb564b6ee5..3cfcd164171e 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DirtyCollectionSearchVisitor.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DirtyCollectionSearchVisitor.java @@ -7,7 +7,9 @@ package org.hibernate.event.internal; import org.hibernate.HibernateException; +import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor; import org.hibernate.collection.spi.PersistentCollection; +import org.hibernate.engine.spi.PersistentAttributeInterceptable; import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.event.spi.EventSource; import org.hibernate.type.CollectionType; @@ -22,11 +24,19 @@ */ public class DirtyCollectionSearchVisitor extends AbstractVisitor { + private final EnhancementAsProxyLazinessInterceptor interceptor; + private final boolean[] propertyVersionability; private boolean dirty; - private boolean[] propertyVersionability; - public DirtyCollectionSearchVisitor(EventSource session, boolean[] propertyVersionability) { + public DirtyCollectionSearchVisitor(Object entity, EventSource session, boolean[] propertyVersionability) { super( session ); + EnhancementAsProxyLazinessInterceptor interceptor = null; + if ( entity instanceof PersistentAttributeInterceptable ) { + if ( ( (PersistentAttributeInterceptable) entity ).$$_hibernate_getInterceptor() instanceof EnhancementAsProxyLazinessInterceptor ) { + interceptor = (EnhancementAsProxyLazinessInterceptor) ( (PersistentAttributeInterceptable) entity ).$$_hibernate_getInterceptor(); + } + } + this.interceptor = interceptor; this.propertyVersionability = propertyVersionability; } @@ -45,6 +55,9 @@ Object processCollection(Object collection, CollectionType type) throws Hibernat // return (ah==null) ? true : searchForDirtyCollections(ah, type); } else { + if ( interceptor != null && !interceptor.isAttributeLoaded( type.getName() ) ) { + return null; + } // if not wrapped yet, its dirty (this can't occur, because // we now always call wrap() before getting to here) // return ( ! (obj instanceof PersistentCollection) ) ? diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/LazyProxyWithCollectionTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/LazyProxyWithCollectionTest.java new file mode 100644 index 000000000000..d818fa52e845 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/LazyProxyWithCollectionTest.java @@ -0,0 +1,166 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.bytecode.enhancement.lazy; + +import java.util.HashSet; +import java.util.Set; + +import org.hibernate.HibernateException; +import org.hibernate.bytecode.enhance.spi.UnloadedClass; +import org.hibernate.event.service.spi.EventListenerRegistry; +import org.hibernate.event.spi.EventType; +import org.hibernate.event.spi.LoadEvent; +import org.hibernate.event.spi.LoadEventListener; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; +import org.hibernate.testing.bytecode.enhancement.CustomEnhancementContext; +import org.hibernate.testing.bytecode.enhancement.EnhancerTestContext; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.OneToMany; +import javax.persistence.OneToOne; +import javax.persistence.Table; +import javax.persistence.Version; + +import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; + +/** + * @author Christian Beikov + */ +@TestForIssue( jiraKey = "HHH-14619" ) +@RunWith( BytecodeEnhancerRunner.class ) +public class LazyProxyWithCollectionTest extends BaseCoreFunctionalTestCase { + + private Long childId; + + @Override + public Class[] getAnnotatedClasses() { + return new Class[]{Parent.class, Child.class}; + } + + @Before + public void prepare() { + doInJPA( this::sessionFactory, em -> { + Child c = new Child(); + em.persist( c ); + childId = c.getId(); + } ); + } + + @Test + public void testReference() { + doInJPA( this::sessionFactory, em -> { + Child child = em.getReference( Child.class, childId ); + Parent parent = new Parent(); + parent.child = child; + em.persist( parent ); + // Class cast exception occurs during auto-flush + em.find( Parent.class, parent.getId() ); + } ); + } + + @Test + public void testLazyCollection() { + doInJPA( this::sessionFactory, em -> { + Child child = em.find( Child.class, childId ); + Parent parent = new Parent(); + parent.child = child; + em.persist( parent ); + child.children = new HashSet<>(); + // Class cast exception occurs during auto-flush + em.find( Parent.class, parent.getId() ); + } ); + } + + // --- // + + @Entity + @Table( name = "PARENT" ) + private static class Parent { + + @Id + @GeneratedValue( strategy = GenerationType.AUTO ) + Long id; + + @OneToOne( fetch = FetchType.LAZY ) + Child child; + + public Long getId() { + return id; + } + + public Child getChild() { + return child; + } + + public void setChild(Child child) { + this.child = child; + } + } + + @Entity + @Table( name = "CHILD" ) + private static class Child { + + @Id + @GeneratedValue( strategy = GenerationType.AUTO ) + Long id; + @Version + Long version; + + String name; + + @OneToMany + Set children = new HashSet<>(); + + Child() { + // No-arg constructor necessary for proxy factory + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Long getVersion() { + return version; + } + + public void setVersion(Long version) { + this.version = version; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public Set getChildren() { + return children; + } + + public void setChildren(Set children) { + this.children = children; + } + } + +} From a57c0e34ff99dc77d4b372e225fdd65d1373b82a Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Thu, 20 May 2021 14:27:01 +0200 Subject: [PATCH 166/644] HHH-14618 Allow passing multiple script source files separated by comma --- .../tool/schema/internal/Helper.java | 47 ++++++---- .../exec/ScriptSourceInputAggregate.java | 87 +++++++++++++++++++ .../schemagen/JpaFileSchemaGeneratorTest.java | 4 - .../schemagen/JpaSchemaGeneratorTest.java | 36 ++++++-- ...maGeneratorWithHbm2DdlCharsetNameTest.java | 4 - .../test/schemagen/create-script-source2.sql | 1 + .../test/schemagen/drop-script-source2.sql | 1 + .../iso8859/create-script-source2.sql | 1 + .../schemagen/iso8859/drop-script-source2.sql | 1 + .../schemagen/iso8859/load-script-source2.sql | 1 + .../test/schemagen/load-script-source2.sql | 1 + 11 files changed, 153 insertions(+), 31 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/tool/schema/internal/exec/ScriptSourceInputAggregate.java create mode 100644 hibernate-core/src/test/resources/org/hibernate/jpa/test/schemagen/create-script-source2.sql create mode 100644 hibernate-core/src/test/resources/org/hibernate/jpa/test/schemagen/drop-script-source2.sql create mode 100644 hibernate-core/src/test/resources/org/hibernate/jpa/test/schemagen/iso8859/create-script-source2.sql create mode 100644 hibernate-core/src/test/resources/org/hibernate/jpa/test/schemagen/iso8859/drop-script-source2.sql create mode 100644 hibernate-core/src/test/resources/org/hibernate/jpa/test/schemagen/iso8859/load-script-source2.sql create mode 100644 hibernate-core/src/test/resources/org/hibernate/jpa/test/schemagen/load-script-source2.sql diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/Helper.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/Helper.java index 1701ed4e4813..49c66cff1756 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/Helper.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/Helper.java @@ -12,6 +12,7 @@ import java.net.URL; import java.sql.SQLException; import java.util.Map; +import java.util.regex.Pattern; import org.hibernate.boot.model.relational.Namespace; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; @@ -24,6 +25,7 @@ import org.hibernate.service.ServiceRegistry; import org.hibernate.tool.schema.extract.spi.DatabaseInformation; import org.hibernate.tool.schema.extract.internal.DatabaseInformationImpl; +import org.hibernate.tool.schema.internal.exec.ScriptSourceInputAggregate; import org.hibernate.tool.schema.internal.exec.ScriptSourceInputFromFile; import org.hibernate.tool.schema.internal.exec.ScriptSourceInputFromReader; import org.hibernate.tool.schema.internal.exec.ScriptSourceInputFromUrl; @@ -33,8 +35,6 @@ import org.hibernate.tool.schema.spi.ScriptSourceInput; import org.hibernate.tool.schema.spi.ScriptTargetOutput; -import org.jboss.logging.Logger; - /** * Helper methods. * @@ -43,6 +43,7 @@ public class Helper { private static final CoreMessageLogger log = CoreLogging.messageLogger( Helper.class ); + private static final Pattern COMMA_PATTERN = Pattern.compile( "\\s*,\\s*" ); public static ScriptSourceInput interpretScriptSourceSetting( Object scriptSourceSetting, @@ -55,22 +56,38 @@ public static ScriptSourceInput interpretScriptSourceSetting( final String scriptSourceSettingString = scriptSourceSetting.toString(); log.debugf( "Attempting to resolve script source setting : %s", scriptSourceSettingString ); - // setting could be either: - // 1) string URL representation (i.e., "file://...") - // 2) relative file path (resource lookup) - // 3) absolute file path - - log.trace( "Trying as URL..." ); - // ClassLoaderService.locateResource() first tries the given resource name as url form... - final URL url = classLoaderService.locateResource( scriptSourceSettingString ); - if ( url != null ) { - return new ScriptSourceInputFromUrl( url, charsetName ); + final String[] paths = COMMA_PATTERN.split( scriptSourceSettingString ); + if ( paths.length == 1 ) { + return interpretScriptSourceSetting( scriptSourceSettingString, classLoaderService, charsetName ); + } + final ScriptSourceInput[] inputs = new ScriptSourceInput[paths.length]; + for ( int i = 0; i < paths.length; i++ ) { + inputs[i] = interpretScriptSourceSetting( paths[i], classLoaderService, charsetName ) ; } - // assume it is a File path - final File file = new File( scriptSourceSettingString ); - return new ScriptSourceInputFromFile( file, charsetName ); + return new ScriptSourceInputAggregate( inputs ); + } + } + + private static ScriptSourceInput interpretScriptSourceSetting( + String scriptSourceSettingString, + ClassLoaderService classLoaderService, + String charsetName) { + // setting could be either: + // 1) string URL representation (i.e., "file://...") + // 2) relative file path (resource lookup) + // 3) absolute file path + + log.trace( "Trying as URL..." ); + // ClassLoaderService.locateResource() first tries the given resource name as url form... + final URL url = classLoaderService.locateResource( scriptSourceSettingString ); + if ( url != null ) { + return new ScriptSourceInputFromUrl( url, charsetName ); } + + // assume it is a File path + final File file = new File( scriptSourceSettingString ); + return new ScriptSourceInputFromFile( file, charsetName ); } public static ScriptTargetOutput interpretScriptTargetSetting( diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/exec/ScriptSourceInputAggregate.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/exec/ScriptSourceInputAggregate.java new file mode 100644 index 000000000000..6981f60f9046 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/exec/ScriptSourceInputAggregate.java @@ -0,0 +1,87 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.tool.schema.internal.exec; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.hibernate.tool.hbm2ddl.ImportSqlCommandExtractor; +import org.hibernate.tool.schema.spi.ScriptSourceInput; + +/** + * A script source input that aggregates over multiple other {@link ScriptSourceInput}. + * + * @author Christian Beikov + */ +public class ScriptSourceInputAggregate implements ScriptSourceInput { + + private final ScriptSourceInput[] inputs; + + /** + * Constructs a ScriptSourceInputAggregate + * + * @param inputs The script source inputs + */ + public ScriptSourceInputAggregate(ScriptSourceInput[] inputs) { + this.inputs = inputs; + } + + @Override + public void prepare() { + for ( ScriptSourceInput input : inputs ) { + input.prepare(); + } + } + + @Override + public void release() { + Throwable t = null; + for ( ScriptSourceInput input : inputs ) { + try { + input.release(); + } + catch (Throwable t2) { + if ( t == null ) { + t = t2; + } + else { + t.addSuppressed( t2 ); + } + } + } + if ( t != null ) { + doThrow( t ); + } + } + + @SuppressWarnings("unchecked") + private static void doThrow(Throwable e) throws T { + throw (T) e; + } + + @Override + public List read(ImportSqlCommandExtractor commandExtractor) { + final List[] lists = new List[inputs.length]; + int size = 0; + for ( int i = 0; i < inputs.length; i++ ) { + lists[i] = inputs[i].read( commandExtractor ); + size += lists[i].size(); + } + + final List list = new ArrayList<>( size ); + for ( List strings : lists ) { + list.addAll( strings ); + } + return list; + } + + @Override + public String toString() { + return "ScriptSourceInputAggregate(" + Arrays.toString( inputs ) + ")"; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/schemagen/JpaFileSchemaGeneratorTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/schemagen/JpaFileSchemaGeneratorTest.java index 324b399b7af1..8f1452032390 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/schemagen/JpaFileSchemaGeneratorTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/schemagen/JpaFileSchemaGeneratorTest.java @@ -30,10 +30,6 @@ protected String getDropSqlScript() { return toFilePath(super.getDropSqlScript()); } - protected String toFilePath(String relativePath) { - return Thread.currentThread().getContextClassLoader().getResource( relativePath ).getFile(); - } - @Override protected String getResourceUrlString(String resource) { return resource; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/schemagen/JpaSchemaGeneratorTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/schemagen/JpaSchemaGeneratorTest.java index 8ebb3cbb808c..51aa15989987 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/schemagen/JpaSchemaGeneratorTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/schemagen/JpaSchemaGeneratorTest.java @@ -8,6 +8,7 @@ import java.net.URL; import java.util.Map; +import java.util.function.Function; import javax.persistence.EntityManager; import javax.persistence.EntityManagerFactory; @@ -20,6 +21,7 @@ import org.hibernate.testing.RequiresDialect; import org.hibernate.testing.TestForIssue; +import org.hibernate.test.legacy.S; import org.junit.Assert; import org.junit.Test; @@ -29,9 +31,9 @@ @RequiresDialect( H2Dialect.class ) public class JpaSchemaGeneratorTest extends BaseEntityManagerFunctionalTestCase { - private final String LOAD_SQL = getScriptFolderPath() + "load-script-source.sql"; - private final String CREATE_SQL = getScriptFolderPath() + "create-script-source.sql"; - private final String DROP_SQL = getScriptFolderPath() + "drop-script-source.sql"; + private final String LOAD_SQL = getScriptFolderPath() + "load-script-source.sql , " + getScriptFolderPath() + "load-script-source2.sql"; + private final String CREATE_SQL = getScriptFolderPath() + "create-script-source.sql , " + getScriptFolderPath() + "create-script-source2.sql"; + private final String DROP_SQL = getScriptFolderPath() + "drop-script-source.sql , " + getScriptFolderPath() + "drop-script-source2.sql"; private static int schemagenNumber = 0; @@ -65,12 +67,29 @@ public void testSqlLoadScriptSourceUrl() throws Exception { doTest( settings ); } - protected String getResourceUrlString(String resource) { - final URL url = getClass().getClassLoader().getResource( resource ); - if ( url == null ) { - throw new RuntimeException( "Unable to locate requested resource [" + resource + "]" ); + protected String getResourceUrlString(String string) { + return getResourceUrlString( getClass().getClassLoader(), string, URL::toString ); + } + + protected String getResourceUrlString(ClassLoader classLoader, String string, Function transformer) { + final String[] strings = string.split( "\\s*,\\s*" ); + final StringBuilder sb = new StringBuilder( string.length() ); + for ( int i = 0; i < strings.length; i++ ) { + if ( i != 0 ) { + sb.append( ',' ); + } + final String resource = strings[i]; + final URL url = classLoader.getResource( resource ); + if ( url == null ) { + throw new RuntimeException( "Unable to locate requested resource [" + resource + "]" ); + } + sb.append( transformer.apply( url ) ); } - return url.toString(); + return sb.toString(); + } + + protected String toFilePath(String relativePath) { + return getResourceUrlString( Thread.currentThread().getContextClassLoader(), relativePath, URL::getFile ); } @SuppressWarnings("unchecked") @@ -143,6 +162,7 @@ private void doTest(Map settings) { EntityManager em = emf.createEntityManager(); try { Assert.assertNotNull( em.find( Item.class, encodedName() ) ); + Assert.assertNotNull( em.find( Item.class, "multi-file-test" ) ); } finally { em.close(); diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/schemagen/iso8859/JpaFileSchemaGeneratorWithHbm2DdlCharsetNameTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/schemagen/iso8859/JpaFileSchemaGeneratorWithHbm2DdlCharsetNameTest.java index 908c50c93e7c..9b5e0a6748b9 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/schemagen/iso8859/JpaFileSchemaGeneratorWithHbm2DdlCharsetNameTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/schemagen/iso8859/JpaFileSchemaGeneratorWithHbm2DdlCharsetNameTest.java @@ -45,10 +45,6 @@ protected String getDropSqlScript() { return toFilePath(super.getDropSqlScript()); } - protected String toFilePath(String relativePath) { - return Thread.currentThread().getContextClassLoader().getResource( relativePath ).getFile(); - } - @Override protected String getResourceUrlString(String resource) { return resource; diff --git a/hibernate-core/src/test/resources/org/hibernate/jpa/test/schemagen/create-script-source2.sql b/hibernate-core/src/test/resources/org/hibernate/jpa/test/schemagen/create-script-source2.sql new file mode 100644 index 000000000000..4fec78b40852 --- /dev/null +++ b/hibernate-core/src/test/resources/org/hibernate/jpa/test/schemagen/create-script-source2.sql @@ -0,0 +1 @@ +INSERT INTO Item(name) VALUES('multi-file-test'); diff --git a/hibernate-core/src/test/resources/org/hibernate/jpa/test/schemagen/drop-script-source2.sql b/hibernate-core/src/test/resources/org/hibernate/jpa/test/schemagen/drop-script-source2.sql new file mode 100644 index 000000000000..4fec78b40852 --- /dev/null +++ b/hibernate-core/src/test/resources/org/hibernate/jpa/test/schemagen/drop-script-source2.sql @@ -0,0 +1 @@ +INSERT INTO Item(name) VALUES('multi-file-test'); diff --git a/hibernate-core/src/test/resources/org/hibernate/jpa/test/schemagen/iso8859/create-script-source2.sql b/hibernate-core/src/test/resources/org/hibernate/jpa/test/schemagen/iso8859/create-script-source2.sql new file mode 100644 index 000000000000..ae16517d82bd --- /dev/null +++ b/hibernate-core/src/test/resources/org/hibernate/jpa/test/schemagen/iso8859/create-script-source2.sql @@ -0,0 +1 @@ +INSERT INTO Item(name) VALUES('multi-file-test'); \ No newline at end of file diff --git a/hibernate-core/src/test/resources/org/hibernate/jpa/test/schemagen/iso8859/drop-script-source2.sql b/hibernate-core/src/test/resources/org/hibernate/jpa/test/schemagen/iso8859/drop-script-source2.sql new file mode 100644 index 000000000000..ae16517d82bd --- /dev/null +++ b/hibernate-core/src/test/resources/org/hibernate/jpa/test/schemagen/iso8859/drop-script-source2.sql @@ -0,0 +1 @@ +INSERT INTO Item(name) VALUES('multi-file-test'); \ No newline at end of file diff --git a/hibernate-core/src/test/resources/org/hibernate/jpa/test/schemagen/iso8859/load-script-source2.sql b/hibernate-core/src/test/resources/org/hibernate/jpa/test/schemagen/iso8859/load-script-source2.sql new file mode 100644 index 000000000000..4fec78b40852 --- /dev/null +++ b/hibernate-core/src/test/resources/org/hibernate/jpa/test/schemagen/iso8859/load-script-source2.sql @@ -0,0 +1 @@ +INSERT INTO Item(name) VALUES('multi-file-test'); diff --git a/hibernate-core/src/test/resources/org/hibernate/jpa/test/schemagen/load-script-source2.sql b/hibernate-core/src/test/resources/org/hibernate/jpa/test/schemagen/load-script-source2.sql new file mode 100644 index 000000000000..4fec78b40852 --- /dev/null +++ b/hibernate-core/src/test/resources/org/hibernate/jpa/test/schemagen/load-script-source2.sql @@ -0,0 +1 @@ +INSERT INTO Item(name) VALUES('multi-file-test'); From 75bcb6bc0c77dd5742e007eeda4009631060a19f Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Tue, 18 May 2021 10:13:49 +0200 Subject: [PATCH 167/644] HHH-14616 Add test for issue --- ...cLockWithGloballyQuotedIdentifierTest.java | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/optlock/OptimisticLockWithGloballyQuotedIdentifierTest.java diff --git a/hibernate-core/src/test/java/org/hibernate/test/optlock/OptimisticLockWithGloballyQuotedIdentifierTest.java b/hibernate-core/src/test/java/org/hibernate/test/optlock/OptimisticLockWithGloballyQuotedIdentifierTest.java new file mode 100644 index 000000000000..109b0fc0c462 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/optlock/OptimisticLockWithGloballyQuotedIdentifierTest.java @@ -0,0 +1,92 @@ +package org.hibernate.test.optlock; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.LockModeType; +import javax.persistence.Version; + +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.cfg.Configuration; + +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class OptimisticLockWithGloballyQuotedIdentifierTest extends BaseCoreFunctionalTestCase { + + @Override + protected void configure(Configuration configuration) { + configuration.setProperty( AvailableSettings.GLOBALLY_QUOTED_IDENTIFIERS, "true" ); + } + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { Person.class }; + } + + @Before + public void setUp() { + inTransaction( + session -> { + Person person = new Person( "1", "Fabiana" ); + session.persist( person ); + } + ); + } + + @After + public void tearDown() { + inTransaction( + session -> { + session.createQuery( "delete from Person" ).executeUpdate(); + } + ); + } + + @Test + public void testHqlQueryWithOptimisticLock() { + inTransaction( + session -> { + session.createQuery( "from Person e", Person.class ) + .setLockMode( LockModeType.OPTIMISTIC ) + .getResultList().get( 0 ); + } + ); + } + + @Entity(name = "Person") + public static class Person { + @Id + private String id; + + @Version + private long version; + + private String name; + + public Person() { + } + + public Person(String id, String name) { + this.id = id; + this.name = name; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } +} From e76a60cbfc0d556e16301140ba8dbd525a17f813 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Tue, 18 May 2021 10:14:22 +0200 Subject: [PATCH 168/644] HHH-14616 Oprimistic Lock throws org.hibernate.exception.SQLGrammarException: could not retrieve version --- .../hibernate/persister/entity/AbstractEntityPersister.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index 1a3a43a1c804..a64545ce76b7 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -166,6 +166,7 @@ public abstract class AbstractEntityPersister private static final CoreMessageLogger LOG = CoreLogging.messageLogger( AbstractEntityPersister.class ); public static final String ENTITY_CLASS = "class"; + public static final String VERSION_COLUMN_ALIAS = "v"; private final NavigableRole navigableRole; @@ -1721,7 +1722,7 @@ public String generateSelectVersionString() { SimpleSelect select = new SimpleSelect( getFactory().getDialect() ) .setTableName( getVersionedTableName() ); if ( isVersioned() ) { - select.addColumn( versionColumnName ); + select.addColumn( getVersionColumnName(), VERSION_COLUMN_ALIAS ); } else { select.addColumns( rootTableKeyColumnNames ); @@ -1947,7 +1948,7 @@ public Object getCurrentVersion(Serializable id, SharedSessionContractImplemento if ( !isVersioned() ) { return this; } - return getVersionType().nullSafeGet( rs, getVersionColumnName(), session, null ); + return getVersionType().nullSafeGet( rs, VERSION_COLUMN_ALIAS, session, null ); } finally { session.getJdbcCoordinator().getLogicalConnection().getResourceRegistry().release( rs, st ); From 6bb1900495b25aa2d14faa98c2d00b0b24d1f37e Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Wed, 19 May 2021 17:08:08 -0700 Subject: [PATCH 169/644] HHH-14616 : Add test case with default hibernate.globally_quoted_identifiers (=false) and version column quoted --- .../OptimisticLockWithQuotedVersionTest.java | 89 +++++++++++++++++++ 1 file changed, 89 insertions(+) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/optlock/OptimisticLockWithQuotedVersionTest.java diff --git a/hibernate-core/src/test/java/org/hibernate/test/optlock/OptimisticLockWithQuotedVersionTest.java b/hibernate-core/src/test/java/org/hibernate/test/optlock/OptimisticLockWithQuotedVersionTest.java new file mode 100644 index 000000000000..6d1bb39a87d1 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/optlock/OptimisticLockWithQuotedVersionTest.java @@ -0,0 +1,89 @@ +package org.hibernate.test.optlock; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.LockModeType; +import javax.persistence.Version; + +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.cfg.Configuration; + +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +public class OptimisticLockWithQuotedVersionTest extends BaseCoreFunctionalTestCase { + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { Person.class }; + } + + @Before + public void setUp() { + inTransaction( + session -> { + Person person = new Person( "1", "Fabiana" ); + session.persist( person ); + } + ); + } + + @After + public void tearDown() { + inTransaction( + session -> { + session.createQuery( "delete from Person" ).executeUpdate(); + } + ); + } + + @Test + public void testHqlQueryWithOptimisticLock() { + inTransaction( + session -> { + session.createQuery( "from Person e", Person.class ) + .setLockMode( LockModeType.OPTIMISTIC ) + .getResultList().get( 0 ); + } + ); + } + + @Entity(name = "Person") + public static class Person { + @Id + private String id; + + @Version + @Column(name = "`version`") + private long version; + + private String name; + + public Person() { + } + + public Person(String id, String name) { + this.id = id; + this.name = name; + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } +} From 26e858c78b303cbb2a0c5539d8a25f879cd3c1c7 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Sat, 22 May 2021 09:12:40 +0200 Subject: [PATCH 170/644] HHH-14616 Change VERSION_COLUMN_ALIAS from v to version_ --- .../org/hibernate/persister/entity/AbstractEntityPersister.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index a64545ce76b7..53924d8dc9ed 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -166,7 +166,7 @@ public abstract class AbstractEntityPersister private static final CoreMessageLogger LOG = CoreLogging.messageLogger( AbstractEntityPersister.class ); public static final String ENTITY_CLASS = "class"; - public static final String VERSION_COLUMN_ALIAS = "v"; + public static final String VERSION_COLUMN_ALIAS = "version_"; private final NavigableRole navigableRole; From fc3accfbd1b8596a440837ba7b7c29a875968e68 Mon Sep 17 00:00:00 2001 From: Christoph Dreis Date: Fri, 23 Apr 2021 16:43:04 +0200 Subject: [PATCH 171/644] HHH-14574 Avoid NPEs from LoadContexts.cleanup(ResultSet) --- .../hibernate/engine/loading/internal/LoadContexts.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/engine/loading/internal/LoadContexts.java b/hibernate-core/src/main/java/org/hibernate/engine/loading/internal/LoadContexts.java index 53e6452c2786..8c53e64b629a 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/loading/internal/LoadContexts.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/loading/internal/LoadContexts.java @@ -78,11 +78,15 @@ private SharedSessionContractImplementor getSession() { public void cleanup(ResultSet resultSet) { if ( collectionLoadContexts != null ) { final CollectionLoadContext collectionLoadContext = collectionLoadContexts.remove( resultSet ); - collectionLoadContext.cleanup(); + if ( collectionLoadContext != null ) { + collectionLoadContext.cleanup(); + } } if ( entityLoadContexts != null ) { final EntityLoadContext entityLoadContext = entityLoadContexts.remove( resultSet ); - entityLoadContext.cleanup(); + if ( entityLoadContext != null ) { + entityLoadContext.cleanup(); + } } } From ad57a1dde26e6e683a941e50206bd8d746ed0e8c Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Mon, 24 May 2021 11:24:50 +0000 Subject: [PATCH 172/644] 5.5.0.CR1 --- changelog.txt | 21 +++++++++++++++++++++ gradle/version.properties | 2 +- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 05f4fdf969cb..45a2b4052b5d 100644 --- a/changelog.txt +++ b/changelog.txt @@ -3,6 +3,27 @@ Hibernate 5 Changelog Note: Please refer to JIRA to learn more about each issue. +Changes in 5.5.0.CR1 (May 24, 2021) +------------------------------------------------------------------------------------------------------------------------ + +https://hibernate.atlassian.net/projects/HHH/versions/31942 + +** Bug + * [HHH-14620] - Retrieving a collection from an entity triggers collection initialization (with extended bytecode enhancement enabled) + * [HHH-14619] - ClassCastException because collection of uninitialized proxy is dirty checked + * [HHH-14616] - Optimistic Lock throws org.hibernate.exception.SQLGrammarException: could not retrieve version + * [HHH-14596] - WhereAnnotatedOneToManySizeTest fails on HANA database + +** Improvement + * [HHH-14622] - Improved iteration of PreLoadEventListener + * [HHH-14621] - Introduce new methods on EventListenerGroup which allow Hibernate Reactive to fire events more efficiently + * [HHH-14618] - Having the possibility to include several SQL files into the import.sql file + * [HHH-14574] - Avoid NullPointerExceptions from LoadContexts.cleanup(ResultSet) + +** Task + * [HHH-14610] - Upgrade to Byte Buddy 1.10.22 + + Changes in 5.5.0.Beta1 (May 12, 2021) ------------------------------------------------------------------------------------------------------------------------ diff --git a/gradle/version.properties b/gradle/version.properties index 27307e6e59d0..fdc8aad41e85 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -hibernateVersion=5.5.0-SNAPSHOT \ No newline at end of file +hibernateVersion=5.5.0.CR1 \ No newline at end of file From 7570f39d10db832f443db6f0b8b87a10cd6bfec1 Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Mon, 24 May 2021 11:31:12 +0000 Subject: [PATCH 173/644] 5.5.0-SNAPSHOT --- gradle/version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/version.properties b/gradle/version.properties index fdc8aad41e85..27307e6e59d0 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -hibernateVersion=5.5.0.CR1 \ No newline at end of file +hibernateVersion=5.5.0-SNAPSHOT \ No newline at end of file From cea044ec698291b3f69b3298498fac5beafe72d0 Mon Sep 17 00:00:00 2001 From: Vlad Mihalcea Date: Mon, 24 May 2021 11:30:59 +0300 Subject: [PATCH 174/644] HHH-14632 - Call statistics.queryPlanCacheHit and statistics.queryPlanCacheMiss for FilterQueryPlan and NativeSQLQueryPlan --- .../engine/query/spi/QueryPlanCache.java | 18 ++++++ .../stat/internal/QueryStatisticsImpl.java | 4 ++ .../stat/internal/StatisticsImpl.java | 15 ++++- .../stat/spi/StatisticsImplementor.java | 13 ++++- .../QueryPlanCacheStatisticsTest.java | 58 +++++++++++++++++-- 5 files changed, 99 insertions(+), 9 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/engine/query/spi/QueryPlanCache.java b/hibernate-core/src/main/java/org/hibernate/engine/query/spi/QueryPlanCache.java index 6a738937e4ea..9e3e00232662 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/query/spi/QueryPlanCache.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/query/spi/QueryPlanCache.java @@ -200,6 +200,8 @@ public FilterQueryPlan getFilterQueryPlan( Map enabledFilters) throws QueryException, MappingException { final FilterQueryPlanKey key = new FilterQueryPlanKey( filterString, collectionRole, shallow, enabledFilters ); FilterQueryPlan value = (FilterQueryPlan) queryPlanCache.get( key ); + final StatisticsImplementor statistics = factory.getStatistics(); + boolean stats = statistics.isStatisticsEnabled(); if ( value == null ) { LOG.tracev( "Unable to locate collection-filter query plan in cache; generating ({0} : {1} )", @@ -207,10 +209,17 @@ public FilterQueryPlan getFilterQueryPlan( filterString ); value = new FilterQueryPlan( filterString, collectionRole, shallow, enabledFilters,factory ); + if ( stats ) { + statistics.queryPlanCacheMiss( key.query ); + } queryPlanCache.putIfAbsent( key, value ); } else { LOG.tracev( "Located collection-filter query plan in cache ({0} : {1})", collectionRole, filterString ); + + if ( stats ) { + statistics.queryPlanCacheHit( key.query ); + } } return value; } @@ -228,13 +237,22 @@ public FilterQueryPlan getFilterQueryPlan( @SuppressWarnings("unchecked") public NativeSQLQueryPlan getNativeSQLQueryPlan(final NativeSQLQuerySpecification spec) { NativeSQLQueryPlan value = (NativeSQLQueryPlan) queryPlanCache.get( spec ); + final StatisticsImplementor statistics = factory.getStatistics(); + boolean stats = statistics.isStatisticsEnabled(); if ( value == null ) { LOG.tracev( "Unable to locate native-sql query plan in cache; generating ({0})", spec.getQueryString() ); value = nativeQueryInterpreter.createQueryPlan( spec, factory ); + if ( stats ) { + statistics.queryPlanCacheMiss( spec.getQueryString() ); + } queryPlanCache.putIfAbsent( spec, value ); } else { LOG.tracev( "Located native-sql query plan in cache ({0})", spec.getQueryString() ); + + if ( stats ) { + statistics.queryPlanCacheHit( spec.getQueryString() ); + } } return value; } diff --git a/hibernate-core/src/main/java/org/hibernate/stat/internal/QueryStatisticsImpl.java b/hibernate-core/src/main/java/org/hibernate/stat/internal/QueryStatisticsImpl.java index fb78dd497547..360b7271844a 100644 --- a/hibernate-core/src/main/java/org/hibernate/stat/internal/QueryStatisticsImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/stat/internal/QueryStatisticsImpl.java @@ -202,6 +202,10 @@ void incrementPlanCacheHitCount() { planCacheHitCount.increment(); } + void incrementPlanCacheMissCount() { + planCacheMissCount.increment(); + } + public String toString() { return "QueryStatistics" + "[query=" + query diff --git a/hibernate-core/src/main/java/org/hibernate/stat/internal/StatisticsImpl.java b/hibernate-core/src/main/java/org/hibernate/stat/internal/StatisticsImpl.java index 9fb2c21e2fdc..62d4e95121d0 100644 --- a/hibernate-core/src/main/java/org/hibernate/stat/internal/StatisticsImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/stat/internal/StatisticsImpl.java @@ -805,11 +805,20 @@ public void queryCompiled(String hql, long microseconds) { } @Override - public void queryPlanCacheHit(String hql) { + public void queryPlanCacheHit(String query) { queryPlanCacheHitCount.increment(); - if ( hql != null ) { - getQueryStatistics( hql ).incrementPlanCacheHitCount(); + if ( query != null ) { + getQueryStatistics( query ).incrementPlanCacheHitCount(); + } + } + + @Override + public void queryPlanCacheMiss(String query) { + queryPlanCacheMissCount.increment(); + + if ( query != null ) { + getQueryStatistics( query ).incrementPlanCacheMissCount(); } } diff --git a/hibernate-core/src/main/java/org/hibernate/stat/spi/StatisticsImplementor.java b/hibernate-core/src/main/java/org/hibernate/stat/spi/StatisticsImplementor.java index efdd6a7cd5cf..12294128436a 100644 --- a/hibernate-core/src/main/java/org/hibernate/stat/spi/StatisticsImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/stat/spi/StatisticsImplementor.java @@ -251,9 +251,18 @@ public interface StatisticsImplementor extends Statistics, Service { /** * Callback indicating a get from the query plan cache resulted in a hit. * - * @param hql The query + * @param query The query + */ + default void queryPlanCacheHit(String query) { + //For backward compatibility + } + + /** + * Callback indicating a get from the query plan cache resulted in a miss. + * + * @param query The query */ - default void queryPlanCacheHit(String hql) { + default void queryPlanCacheMiss(String query) { //For backward compatibility } diff --git a/hibernate-core/src/test/java/org/hibernate/stat/internal/QueryPlanCacheStatisticsTest.java b/hibernate-core/src/test/java/org/hibernate/stat/internal/QueryPlanCacheStatisticsTest.java index 5974b976b012..9f3bac412a40 100644 --- a/hibernate-core/src/test/java/org/hibernate/stat/internal/QueryPlanCacheStatisticsTest.java +++ b/hibernate-core/src/test/java/org/hibernate/stat/internal/QueryPlanCacheStatisticsTest.java @@ -14,6 +14,7 @@ import javax.persistence.Id; import javax.persistence.LockModeType; import javax.persistence.NamedQuery; +import javax.persistence.Table; import javax.persistence.Tuple; import javax.persistence.TypedQuery; @@ -150,7 +151,7 @@ public void testCreateQueryHitCount() { assertEquals( 5, employees.size() ); - //The miss count is still 1, as no we got the query plan from the cache + //The miss count is still 1, as now we got the query plan from the cache assertEquals( 1, statistics.getQueryPlanCacheMissCount() ); //And the cache hit count increases. assertEquals( 1, statistics.getQueryPlanCacheHitCount() ); @@ -164,7 +165,55 @@ public void testCreateQueryHitCount() { assertEquals( 5, employees.size() ); - //The miss count is still 1, as no we got the query plan from the cache + //The miss count is still 1, as now we got the query plan from the cache + assertEquals( 1, statistics.getQueryPlanCacheMissCount() ); + //And the cache hit count increases. + assertEquals( 2, statistics.getQueryPlanCacheHitCount() ); + } ); + } + + @Test + @TestForIssue( jiraKey = "HHH-14632" ) + public void testCreateNativeQueryHitCount() { + statistics.clear(); + + doInJPA( this::entityManagerFactory, entityManager -> { + + List employees = entityManager.createNativeQuery( + "select * from employee e", Employee.class ) + .getResultList(); + + assertEquals( 5, employees.size() ); + + //First time, we get a cache miss, so the query is compiled + assertEquals( 1, statistics.getQueryPlanCacheMissCount() ); + //The hit count should be 0 as we don't need to go to the cache after we already compiled the query + assertEquals( 0, statistics.getQueryPlanCacheHitCount() ); + } ); + + doInJPA( this::entityManagerFactory, entityManager -> { + + List employees = entityManager.createNativeQuery( + "select * from employee e", Employee.class ) + .getResultList(); + + assertEquals( 5, employees.size() ); + + //The miss count is still 1, as now we got the query plan from the cache + assertEquals( 1, statistics.getQueryPlanCacheMissCount() ); + //And the cache hit count increases. + assertEquals( 1, statistics.getQueryPlanCacheHitCount() ); + } ); + + doInJPA( this::entityManagerFactory, entityManager -> { + + List employees = entityManager.createNativeQuery( + "select * from employee e", Employee.class ) + .getResultList(); + + assertEquals( 5, employees.size() ); + + //The miss count is still 1, as now we got the query plan from the cache assertEquals( 1, statistics.getQueryPlanCacheMissCount() ); //And the cache hit count increases. assertEquals( 2, statistics.getQueryPlanCacheHitCount() ); @@ -232,7 +281,7 @@ public void testCreateQueryTupleHitCount() { assertEquals( 5, employees.size() ); - //The miss count is still 1, as no we got the query plan from the cache + //The miss count is still 1, as now we got the query plan from the cache assertEquals( 1, statistics.getQueryPlanCacheMissCount() ); //And the cache hit count increases. assertEquals( 1, statistics.getQueryPlanCacheHitCount() ); @@ -246,7 +295,7 @@ public void testCreateQueryTupleHitCount() { assertEquals( 5, employees.size() ); - //The miss count is still 1, as no we got the query plan from the cache + //The miss count is still 1, as now we got the query plan from the cache assertEquals( 1, statistics.getQueryPlanCacheMissCount() ); //And the cache hit count increases. assertEquals( 2, statistics.getQueryPlanCacheHitCount() ); @@ -292,6 +341,7 @@ private void assertQueryStatistics(String hql, int hitCount) { } @Entity(name = "Employee") + @Table(name = "employee") @NamedQuery( name = "find_employee_by_name", query = "select e from Employee e where e.name = :name" From 0c74a9263c154515eb97fe4df4dcc1f965901892 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Tue, 25 May 2021 12:12:49 +0200 Subject: [PATCH 175/644] HHH-14635 Update to latest JUnit --- gradle/libraries.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libraries.gradle b/gradle/libraries.gradle index 9fc6ca1d61b7..a2240e9d9a7f 100644 --- a/gradle/libraries.gradle +++ b/gradle/libraries.gradle @@ -9,7 +9,7 @@ // use. In that respect it serves a role similar to in Maven ext { - junitVersion = '4.12' + junitVersion = '4.13.2' h2Version = '1.4.197' bytemanVersion = '4.0.13' //Compatible with JDK16 jnpVersion = '5.0.6.CR1' From 07eca3883d13e4f5f898de15c8506c0fd2eecf1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Tue, 25 May 2021 12:46:19 +0200 Subject: [PATCH 176/644] HHH-14635 Upgrade to log4j 2 --- .../tutorials/osgi/managed-jpa/features.xml | 1 - .../tutorials/osgi/unmanaged-jpa/features.xml | 1 - .../osgi/unmanaged-native/features.xml | 1 - .../src/test/resources/log4j.properties | 56 ------ .../src/test/resources/log4j2.properties | 75 ++++++++ etc/log4j.properties | 54 ------ etc/log4j2.properties | 66 ++++++++ gradle/java-module.gradle | 2 +- gradle/libraries.gradle | 2 +- .../src/test/resources/log4j.properties | 60 ------- .../src/test/resources/log4j2.properties | 83 +++++++++ .../src/test/resources/log4j.properties | 16 -- .../src/test/resources/log4j2.properties | 19 +++ .../jpa/test/JpaProxyComplianceWithDebug.java | 19 ++- .../ImmutableNaturalKeyLookupTest.java | 18 +- .../JoinedSubclassBatchingTest.java | 4 - .../ImplicitCompositeKeyJoinTest.java | 2 +- .../src/test/resources/log4j.properties | 62 ------- .../src/test/resources/log4j2.properties | 89 ++++++++++ .../src/test/resources/log4j.properties | 17 -- .../src/test/resources/log4j2.properties | 20 +++ .../src/test/resources/log4j.properties | 23 --- .../src/test/resources/log4j2.properties | 30 ++++ .../src/test/resources/log4j.properties | 60 ------- .../src/test/resources/log4j2.properties | 83 +++++++++ .../src/test/resources/logging.properties | 30 ++-- .../src/test/resources/log4j.properties | 17 -- .../src/test/resources/log4j2.properties | 20 +++ .../src/test/resources/log4j.properties | 19 --- .../src/test/resources/log4j2.properties | 25 +++ .../src/test/resources/logging.properties | 30 ++-- .../src/test/resources/log4j.properties | 16 -- .../src/test/resources/log4j2.properties | 19 +++ .../src/test/resources/log4j.properties | 13 -- .../src/test/resources/log4j2.properties | 16 ++ .../hibernate-testing-jakarta.gradle | 2 +- hibernate-testing/hibernate-testing.gradle | 2 +- .../testing/logger/Log4DelegatingLogger.java | 129 -------------- .../logger/Log4J2DelegatingLogger.java | 160 ++++++++++++++++++ .../testing/logger/LogInspectionHelper.java | 8 +- .../logger/TestableLoggerProvider.java | 66 +++++--- .../testing/logger/LogDelegationTest.java | 2 +- .../src/test/resources/log4j.properties | 60 ------- .../src/test/resources/log4j2.properties | 83 +++++++++ .../src/test/resources/log4j.properties | 31 ---- .../src/test/resources/log4j2.properties | 28 +++ 46 files changed, 919 insertions(+), 720 deletions(-) delete mode 100644 documentation/src/test/resources/log4j.properties create mode 100644 documentation/src/test/resources/log4j2.properties delete mode 100644 etc/log4j.properties create mode 100644 etc/log4j2.properties delete mode 100644 hibernate-agroal/src/test/resources/log4j.properties create mode 100644 hibernate-agroal/src/test/resources/log4j2.properties delete mode 100644 hibernate-c3p0/src/test/resources/log4j.properties create mode 100644 hibernate-c3p0/src/test/resources/log4j2.properties delete mode 100644 hibernate-core/src/test/resources/log4j.properties create mode 100644 hibernate-core/src/test/resources/log4j2.properties delete mode 100644 hibernate-ehcache/src/test/resources/log4j.properties create mode 100644 hibernate-ehcache/src/test/resources/log4j2.properties delete mode 100644 hibernate-envers/src/test/resources/log4j.properties create mode 100644 hibernate-envers/src/test/resources/log4j2.properties delete mode 100644 hibernate-hikaricp/src/test/resources/log4j.properties create mode 100644 hibernate-hikaricp/src/test/resources/log4j2.properties delete mode 100644 hibernate-jcache/src/test/resources/log4j.properties create mode 100644 hibernate-jcache/src/test/resources/log4j2.properties delete mode 100644 hibernate-micrometer/src/test/resources/log4j.properties create mode 100644 hibernate-micrometer/src/test/resources/log4j2.properties delete mode 100644 hibernate-proxool/src/test/resources/log4j.properties create mode 100644 hibernate-proxool/src/test/resources/log4j2.properties delete mode 100644 hibernate-spatial/src/test/resources/log4j.properties create mode 100644 hibernate-spatial/src/test/resources/log4j2.properties delete mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/logger/Log4DelegatingLogger.java create mode 100644 hibernate-testing/src/main/java/org/hibernate/testing/logger/Log4J2DelegatingLogger.java delete mode 100644 hibernate-vibur/src/test/resources/log4j.properties create mode 100644 hibernate-vibur/src/test/resources/log4j2.properties delete mode 100644 tooling/metamodel-generator/src/test/resources/log4j.properties create mode 100644 tooling/metamodel-generator/src/test/resources/log4j2.properties diff --git a/documentation/src/main/asciidoc/quickstart/tutorials/osgi/managed-jpa/features.xml b/documentation/src/main/asciidoc/quickstart/tutorials/osgi/managed-jpa/features.xml index c712d512f406..1df06fe5b907 100644 --- a/documentation/src/main/asciidoc/quickstart/tutorials/osgi/managed-jpa/features.xml +++ b/documentation/src/main/asciidoc/quickstart/tutorials/osgi/managed-jpa/features.xml @@ -59,7 +59,6 @@ mvn:com.fasterxml/classmate/0.8.0 mvn:org.apache.logging.log4j/log4j-api/2.0 - mvn:log4j/log4j/1.2.17 mvn:org.jboss.logging/jboss-logging/3.2.1.Final mvn:org.javassist/javassist/3.18.1-GA diff --git a/documentation/src/main/asciidoc/quickstart/tutorials/osgi/unmanaged-jpa/features.xml b/documentation/src/main/asciidoc/quickstart/tutorials/osgi/unmanaged-jpa/features.xml index 3252004918ee..f3f240a28223 100644 --- a/documentation/src/main/asciidoc/quickstart/tutorials/osgi/unmanaged-jpa/features.xml +++ b/documentation/src/main/asciidoc/quickstart/tutorials/osgi/unmanaged-jpa/features.xml @@ -32,7 +32,6 @@ mvn:com.fasterxml/classmate/0.8.0 mvn:org.apache.logging.log4j/log4j-api/2.0 - mvn:log4j/log4j/1.2.17 mvn:org.jboss.logging/jboss-logging/3.2.1.Final mvn:org.javassist/javassist/3.18.1-GA diff --git a/documentation/src/main/asciidoc/quickstart/tutorials/osgi/unmanaged-native/features.xml b/documentation/src/main/asciidoc/quickstart/tutorials/osgi/unmanaged-native/features.xml index 3adcef2c307a..cd4d665d40cc 100644 --- a/documentation/src/main/asciidoc/quickstart/tutorials/osgi/unmanaged-native/features.xml +++ b/documentation/src/main/asciidoc/quickstart/tutorials/osgi/unmanaged-native/features.xml @@ -40,7 +40,6 @@ mvn:com.fasterxml/classmate/0.8.0 mvn:org.apache.logging.log4j/log4j-api/2.0 - mvn:log4j/log4j/1.2.17 mvn:org.jboss.logging/jboss-logging/3.2.1.Final mvn:org.javassist/javassist/3.18.1-GA diff --git a/documentation/src/test/resources/log4j.properties b/documentation/src/test/resources/log4j.properties deleted file mode 100644 index 49358a1a2d75..000000000000 --- a/documentation/src/test/resources/log4j.properties +++ /dev/null @@ -1,56 +0,0 @@ -# -# Hibernate, Relational Persistence for Idiomatic Java -# -# License: GNU Lesser General Public License (LGPL), version 2.1 or later. -# See the lgpl.txt file in the root directory or . -# -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.Target=System.out -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n - -log4j.rootLogger=info, stdout - -log4j.logger.org.hibernate=info -#log4j.logger.org.hibernate=warn - -log4j.logger.org.hibernate.ejb=info -log4j.logger.org.hibernate.ejb.packaging=info -log4j.logger.org.hibernate.reflection=info - -#log4j.logger.org.hibernate.engine.Cascades=warn -#log4j.logger.org.hibernate.hql=warn - -### log just the SQL -log4j.logger.org.hibernate.SQL=debug - -### log JDBC bind parameters ### -log4j.logger.org.hibernate.type=trace -log4j.logger.org.hibernate.type.descriptor.sql=trace -log4j.logger.org.hibernate.id.enhanced.TableGenerator=trace -log4j.logger.org.hibernate.id.IdentifierGeneratorHelper=trace -log4j.logger.org.hibernate.persister.entity.AbstractEntityPersister=trace -log4j.logger.org.hibernate.loader.plan.exec.process.internal.EntityReferenceInitializerImpl=trace - -### log schema export/update ### -log4j.logger.org.hibernate.tool.hbm2ddl=info - -### log HQL parse trees -#log4j.logger.org.hibernate.hql=warn - -### log cache activity ### -#log4j.logger.org.hibernate.cache=warn - -### log JDBC resource acquisition -#log4j.logger.org.hibernate.jdbc=warn - -### enable the following line if you want to track down connection ### -### leakages when using DriverManagerConnectionProvider ### -#log4j.logger.org.hibernate.connection.DriverManagerConnectionProvider=trace - -### When entity copy merge functionality is enabled using: -### hibernate.event.merge.entity_copy_observer=log, the following will -### provide information about merged entity copies. -#log4j.logger.org.hibernate.event.internal.EntityCopyAllowedLoggedObserver=warn - -log4j.logger.org.hibernate.userguide=debug diff --git a/documentation/src/test/resources/log4j2.properties b/documentation/src/test/resources/log4j2.properties new file mode 100644 index 000000000000..bcca35fbe733 --- /dev/null +++ b/documentation/src/test/resources/log4j2.properties @@ -0,0 +1,75 @@ +# +# Hibernate, Relational Persistence for Idiomatic Java +# +# License: GNU Lesser General Public License (LGPL), version 2.1 or later. +# See the lgpl.txt file in the root directory or . +# +appender.stdout.type=Console +appender.stdout.name=STDOUT +appender.stdout.layout.type=PatternLayout +appender.stdout.layout.pattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n + +rootLogger.level=info +rootLogger.appenderRef.stdout.ref=STDOUT + +logger.hibernate.name=org.hibernate +logger.hibernate.level=info +#logger.hibernate.level=warn + +logger.ejb.name=org.hibernate.ejb +logger.ejb.level=info +logger.ejb-packaging.name=org.hibernate.ejb.packaging +logger.ejb-packaging.level=info +logger.reflection.name=org.hibernate.reflection +logger.reflection.level=info + +logger.cascades.name=org.hibernate.engine.Cascades +#logger.cascades.level=warn + +### log just the SQL +logger.sql.name=org.hibernate.SQL +logger.sql.level=debug + +### log JDBC bind parameters ### +logger.hibernate-type.name=org.hibernate.type +logger.hibernate-type.level=trace +logger.type-sql.name=org.hibernate.type.descriptor.sql +logger.type-sql.level=trace +logger.table-generator.name=org.hibernate.id.enhanced.TableGenerator +logger.table-generator.level=trace +logger.identifier-generator-helper.name=org.hibernate.id.IdentifierGeneratorHelper +logger.identifier-generator-helper.level=trace +logger.abstract-entity-persister.name=org.hibernate.persister.entity.AbstractEntityPersister +logger.abstract-entity-persister.level=trace +logger.entity-reference-initializer-impl.name=org.hibernate.loader.plan.exec.process.internal.EntityReferenceInitializerImpl +logger.entity-reference-initializer-impl.level=trace + +### log schema export/update ### +logger.hbm2ddl.name=org.hibernate.tool.hbm2ddl +logger.hbm2ddl.level=info + +### log HQL parse trees +logger.hql.name=org.hibernate.hql +#logger.hql.level=warn + +### log cache activity ### +logger.cache.name=org.hibernate.cache +#logger.cache.level=warn + +### log JDBC resource acquisition +logger.hibernate-jdbc.name=org.hibernate.jdbc +#logger.hibernate-jdbc.level=warn + +### enable the following line if you want to track down connection ### +### leakages when using DriverManagerConnectionProvider ### +logger.driver-manager-connection-provider.name=org.hibernate.connection.DriverManagerConnectionProvider +#logger.driver-manager-connection-provider.level=trace + +### When entity copy merge functionality is enabled using: +### hibernate.event.merge.entity_copy_observer=log, the following will +### provide information about merged entity copies. +logger.entity-copy-allowed-logged-observer.name=org.hibernate.event.internal.EntityCopyAllowedLoggedObserver +#logger.entity-copy-allowed-logged-observer.level=warn + +logger.userguide.name=org.hibernate.userguide +logger.userguide.level=debug diff --git a/etc/log4j.properties b/etc/log4j.properties deleted file mode 100644 index d0b320610af5..000000000000 --- a/etc/log4j.properties +++ /dev/null @@ -1,54 +0,0 @@ -# -# Hibernate, Relational Persistence for Idiomatic Java -# -# License: GNU Lesser General Public License (LGPL), version 2.1 or later. -# See the lgpl.txt file in the root directory or . -# - -### direct log messages to stdout ### -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.Target=System.out -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n - -### direct messages to file hibernate.log ### -#log4j.appender.file=org.apache.log4j.FileAppender -#log4j.appender.file.File=hibernate.log -#log4j.appender.file.layout=org.apache.log4j.PatternLayout -#log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n - -### set log levels - for more verbose logging change 'info' to 'debug' ### - -log4j.rootLogger=warn, stdout - -#log4j.logger.org.hibernate=info -log4j.logger.org.hibernate=debug - -### log HQL query parser activity -#log4j.logger.org.hibernate.hql.ast.AST=debug - -### log just the SQL -#log4j.logger.org.hibernate.SQL=debug - -### log JDBC bind parameters ### -log4j.logger.org.hibernate.type=info -#log4j.logger.org.hibernate.type=debug - -### log schema export/update ### -log4j.logger.org.hibernate.tool.hbm2ddl=debug - -### log HQL parse trees -#log4j.logger.org.hibernate.hql=debug - -### log cache activity ### -#log4j.logger.org.hibernate.cache=debug - -### log transaction activity -#log4j.logger.org.hibernate.transaction=debug - -### log JDBC resource acquisition -#log4j.logger.org.hibernate.jdbc=debug - -### enable the following line if you want to track down connection ### -### leakages when using DriverManagerConnectionProvider ### -#log4j.logger.org.hibernate.connection.DriverManagerConnectionProvider=trace diff --git a/etc/log4j2.properties b/etc/log4j2.properties new file mode 100644 index 000000000000..e12215cd7299 --- /dev/null +++ b/etc/log4j2.properties @@ -0,0 +1,66 @@ +# +# Hibernate, Relational Persistence for Idiomatic Java +# +# License: GNU Lesser General Public License (LGPL), version 2.1 or later. +# See the lgpl.txt file in the root directory or . +# + +### direct log messages to stdout ### +appender.stdout.type=Console +appender.stdout.name=STDOUT +appender.stdout.layout.type=PatternLayout +appender.stdout.layout.pattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n + +### direct messages to file hibernate.log ### +#appender.file.type=File +#appender.file.name=file +#appender.file.fileName=hibernate.log +#appender.file.layout.type=PatternLayout +#appender.file.layout.pattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n + +### set log levels - for more verbose logging change 'info' to 'debug' ### + +rootLogger.level=warn +rootLogger.appenderRef.stdout.ref=STDOUT + +logger.hibernate.name=org.hibernate +#logger.hibernate.level=info +logger.hibernate.level=debug + +### log HQL query parser activity +logger.hql-ast.name=org.hibernate.hql.ast.AST +#logger.hql-ast.level=debug + +### log just the SQL +logger.sql.name=org.hibernate.SQL +#logger.sql.level=debug + +### log JDBC bind parameters ### +logger.hibernate-type.name=org.hibernate.type +logger.hibernate-type.level=info +#logger.hibernate-type.level=debug + +### log schema export/update ### +logger.hbm2ddl.name=org.hibernate.tool.hbm2ddl +logger.hbm2ddl.level=debug + +### log HQL parse trees +logger.hql.name=org.hibernate.hql +#logger.hql.level=debug + +### log cache activity ### +logger.cache.name=org.hibernate.cache +#logger.cache.level=debug + +### log transaction activity +logger.hibernate-transaction.name=org.hibernate.transaction +#logger.hibernate-transaction.level=debug + +### log JDBC resource acquisition +logger.hibernate-jdbc.name=org.hibernate.jdbc +#logger.hibernate-jdbc.level=debug + +### enable the following line if you want to track down connection ### +### leakages when using DriverManagerConnectionProvider ### +logger.driver-manager-connection-provider.name=org.hibernate.connection.DriverManagerConnectionProvider +#logger.driver-manager-connection-provider.level=trace diff --git a/gradle/java-module.gradle b/gradle/java-module.gradle index 85d5330adf3c..582c5078d8b2 100644 --- a/gradle/java-module.gradle +++ b/gradle/java-module.gradle @@ -71,7 +71,7 @@ dependencies { testCompile( libraries.byteman_install ) testCompile( libraries.byteman_bmunit ) - testRuntime( libraries.log4j ) + testRuntime( libraries.log4j2 ) testRuntime( libraries.javassist ) testRuntime( libraries.byteBuddy ) diff --git a/gradle/libraries.gradle b/gradle/libraries.gradle index a2240e9d9a7f..a317e76e8ab7 100644 --- a/gradle/libraries.gradle +++ b/gradle/libraries.gradle @@ -120,7 +120,7 @@ ext { // ~~~~~~~~~~~~~~~~~~~~~~~~~~ testing - log4j: "log4j:log4j:1.2.17", + log4j2: "org.apache.logging.log4j:log4j-core:2.14.1", junit: "junit:junit:${junitVersion}", byteman: "org.jboss.byteman:byteman:${bytemanVersion}", byteman_install: "org.jboss.byteman:byteman-install:${bytemanVersion}", diff --git a/hibernate-agroal/src/test/resources/log4j.properties b/hibernate-agroal/src/test/resources/log4j.properties deleted file mode 100644 index eb96581a28b5..000000000000 --- a/hibernate-agroal/src/test/resources/log4j.properties +++ /dev/null @@ -1,60 +0,0 @@ -# -# Hibernate, Relational Persistence for Idiomatic Java -# -# License: GNU Lesser General Public License (LGPL), version 2.1 or later. -# See the lgpl.txt file in the root directory or . -# -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.Target=System.out -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n -#log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L (hibernateLoadPlanWalkPath->%X{hibernateLoadPlanWalkPath}) - %m%n - -#log4j.appender.stdout-mdc=org.apache.log4j.ConsoleAppender -#log4j.appender.stdout-mdc.Target=System.out -#log4j.appender.stdout-mdc.layout=org.apache.log4j.PatternLayout -#log4j.appender.stdout-mdc.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L (walk path -> %X{hibernateLoadPlanWalkPath}) - %m%n - -log4j.appender.unclosedSessionFactoryFile=org.apache.log4j.FileAppender -log4j.appender.unclosedSessionFactoryFile.append=true -log4j.appender.unclosedSessionFactoryFile.file=target/tmp/log/UnclosedSessionFactoryWarnings.log -log4j.appender.unclosedSessionFactoryFile.layout=org.apache.log4j.PatternLayout -log4j.appender.unclosedSessionFactoryFile.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n - -log4j.rootLogger=info, stdout - -#log4j.logger.org.hibernate.loader.plan=trace, stdout-mdc -#log4j.additivity.org.hibernate.loader.plan=false -#log4j.logger.org.hibernate.persister.walking=trace, stdout-mdc -#log4j.additivity.org.hibernate.persister.walking=false - -log4j.logger.org.hibernate.tool.hbm2ddl=trace -log4j.logger.org.hibernate.testing.cache=debug - -# SQL Logging - HHH-6833 -log4j.logger.org.hibernate.SQL=debug - -log4j.logger.org.hibernate.type.descriptor.sql.BasicBinder=trace -log4j.logger.org.hibernate.type.descriptor.sql.BasicExtractor=trace - -log4j.logger.org.hibernate.hql.internal.ast=debug - -log4j.logger.org.hibernate.sql.ordering.antlr=debug - -log4j.logger.org.hibernate.loader.plan2.build.internal.LoadPlanImpl=debug -log4j.logger.org.hibernate.loader.plan2.build.spi.LoadPlanTreePrinter=debug -log4j.logger.org.hibernate.loader.plan2.exec.spi.EntityLoadQueryDetails=debug - -log4j.logger.org.hibernate.engine.internal.StatisticalLoggingSessionEventListener=info - -log4j.logger.org.hibernate.boot.model.source.internal.hbm.ModelBinder=debug -log4j.logger.org.hibernate.type.descriptor.java.JavaTypeDescriptorRegistry=debug - - -### When entity copy merge functionality is enabled using: -### hibernate.event.merge.entity_copy_observer=log, the following will -### provide information about merged entity copies. -### log4j.logger.org.hibernate.event.internal.EntityCopyAllowedLoggedObserver=debug - -log4j.logger.org.hibernate.testing.junit4.TestClassMetadata=info, unclosedSessionFactoryFile -log4j.logger.org.hibernate.boot.model.process.internal.ScanningCoordinator=debug diff --git a/hibernate-agroal/src/test/resources/log4j2.properties b/hibernate-agroal/src/test/resources/log4j2.properties new file mode 100644 index 000000000000..c9a2a7cad77d --- /dev/null +++ b/hibernate-agroal/src/test/resources/log4j2.properties @@ -0,0 +1,83 @@ +# +# Hibernate, Relational Persistence for Idiomatic Java +# +# License: GNU Lesser General Public License (LGPL), version 2.1 or later. +# See the lgpl.txt file in the root directory or . +# +appender.stdout.type=Console +appender.stdout.name=STDOUT +appender.stdout.layout.type=PatternLayout +appender.stdout.layout.pattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n +appender.stdout.layout.pattern=%d{ABSOLUTE} %5p %c{1}:%L (hibernateLoadPlanWalkPath->%X{hibernateLoadPlanWalkPath}) - %m%n + +appender.stdout-mdc.type=Console +appender.stdout-mdc.name=stdout-mdc +appender.stdout-mdc.layout.type=PatternLayout +appender.stdout-mdc.layout.pattern=%d{ABSOLUTE} %5p %c{1}:%L (walk path -> %X{hibernateLoadPlanWalkPath}) - %m%n + +appender.unclosedSessionFactoryFile.type=File +appender.unclosedSessionFactoryFile.name=unclosedSessionFactoryFile +appender.unclosedSessionFactoryFile.append=true +appender.unclosedSessionFactoryFile.fileName=target/tmp/log/UnclosedSessionFactoryWarnings.log +appender.unclosedSessionFactoryFile.layout.type=PatternLayout +appender.unclosedSessionFactoryFile.layout.pattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n + +rootLogger.level=info +rootLogger.appenderRef.stdout.ref=STDOUT + +logger.loader-plan.name=org.hibernate.loader.plan +#logger.loader-plan.level=trace +#logger.loader-plan.appenderRef.stdout-mdc.ref=stdout-mdc +#logger.loader-plan.additivity=false +logger.persister-walking.name=org.hibernate.persister.walking +#logger.persister-walking.level=trace +#logger.persister-walking.appenderRef.stdout-mdc.ref=stdout-mdc +#logger.persister-walking.additivity=false + +logger.hbm2ddl.name=org.hibernate.tool.hbm2ddl +logger.hbm2ddl.level=trace +logger.testing-cache.name=org.hibernate.testing.cache +logger.testing-cache.level=debug + +# SQL Logging - HHH-6833 +logger.sql.name=org.hibernate.SQL +logger.sql.level=debug + +logger.type-basic-binder.name=org.hibernate.type.descriptor.sql.BasicBinder +logger.type-basic-binder.level=trace +logger.type-basic-extractor.name=org.hibernate.type.descriptor.sql.BasicExtractor +logger.type-basic-extractor.level=trace + +logger.hql-internal-ast.name=org.hibernate.hql.internal.ast +logger.hql-internal-ast.level=debug + +logger.sql-ordering-antlr.name=org.hibernate.sql.ordering.antlr +logger.sql-ordering-antlr.level=debug + +logger.load-plan-impl.name=org.hibernate.loader.plan2.build.internal.LoadPlanImpl +logger.load-plan-impl.level=debug +logger.load-plan-tree-printer.name=org.hibernate.loader.plan2.build.spi.LoadPlanTreePrinter +logger.load-plan-tree-printer.level=debug +logger.entity-load-query-details.name=org.hibernate.loader.plan2.exec.spi.EntityLoadQueryDetails +logger.entity-load-query-details.level=debug + +logger.statistical-logging-session-event-listener.name=org.hibernate.engine.internal.StatisticalLoggingSessionEventListener +logger.statistical-logging-session-event-listener.level=info + +logger.model-binder.name=org.hibernate.boot.model.source.internal.hbm.ModelBinder +logger.model-binder.level=debug +logger.java-type-descriptor-registry.name=org.hibernate.type.descriptor.java.JavaTypeDescriptorRegistry +logger.java-type-descriptor-registry.level=debug + + +logger.merged-entity-copies.name=org.hibernate.event.internal.EntityCopyAllowedLoggedObserver +### When entity copy merge functionality is enabled using: +### hibernate.event.merge.entity_copy_observer=log, the following will +### provide information about merged entity copies. +#logger.merged-entity-copies.level=debug + +logger.test-class-metadata.name=org.hibernate.testing.junit4.TestClassMetadata +logger.test-class-metadata.level=info +logger.test-class-metadata.appenderRef.unclosedSessionFactoryFile.ref=unclosedSessionFactoryFile +logger.scanning-coordinator.name=org.hibernate.boot.model.process.internal.ScanningCoordinator +logger.scanning-coordinator.level=debug diff --git a/hibernate-c3p0/src/test/resources/log4j.properties b/hibernate-c3p0/src/test/resources/log4j.properties deleted file mode 100644 index 86c5d9be55e6..000000000000 --- a/hibernate-c3p0/src/test/resources/log4j.properties +++ /dev/null @@ -1,16 +0,0 @@ -# -# Hibernate, Relational Persistence for Idiomatic Java -# -# License: GNU Lesser General Public License (LGPL), version 2.1 or later. -# See the lgpl.txt file in the root directory or . -# -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.Target=System.out -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n - - -log4j.rootLogger=info, stdout - -log4j.logger.org.hibernate.tool.hbm2ddl=debug -log4j.logger.org.hibernate.testing.cache=debug diff --git a/hibernate-c3p0/src/test/resources/log4j2.properties b/hibernate-c3p0/src/test/resources/log4j2.properties new file mode 100644 index 000000000000..d4da0b21a5e8 --- /dev/null +++ b/hibernate-c3p0/src/test/resources/log4j2.properties @@ -0,0 +1,19 @@ +# +# Hibernate, Relational Persistence for Idiomatic Java +# +# License: GNU Lesser General Public License (LGPL), version 2.1 or later. +# See the lgpl.txt file in the root directory or . +# +appender.stdout.type=Console +appender.stdout.name=STDOUT +appender.stdout.layout.type=PatternLayout +appender.stdout.layout.pattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n + + +rootLogger.level=info +rootLogger.appenderRef.stdout.ref=STDOUT + +logger.hbm2ddl.name=org.hibernate.tool.hbm2ddl +logger.hbm2ddl.level=debug +logger.testing-cache.name=org.hibernate.testing.cache +logger.testing-cache.level=debug diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/JpaProxyComplianceWithDebug.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/JpaProxyComplianceWithDebug.java index a619e6a9e15d..d4d04b23e9d2 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/JpaProxyComplianceWithDebug.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/JpaProxyComplianceWithDebug.java @@ -25,14 +25,17 @@ import javax.persistence.ManyToOne; import javax.persistence.Table; -import org.apache.log4j.Level; -import org.apache.log4j.LogManager; -import org.apache.log4j.Logger; import org.hibernate.cfg.AvailableSettings; import org.hibernate.testing.TestForIssue; import org.junit.Before; import org.junit.Test; +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.core.LoggerContext; +import org.apache.logging.log4j.core.config.Configuration; +import org.apache.logging.log4j.core.config.LoggerConfig; + @TestForIssue(jiraKey = "HHH-13244") public class JpaProxyComplianceWithDebug extends BaseEntityManagerFunctionalTestCase { @@ -82,17 +85,19 @@ public void setUp() { @Test @TestForIssue(jiraKey = "HHH-13244") public void testJpaComplianceProxyWithDebug() { + LoggerContext context = (LoggerContext) LogManager.getContext( false ); + Configuration configuration = context.getConfiguration(); //This could be replaced with setting the root logger level, or the "org.hibernate" logger to debug. //These are simply the narrowest log settings that trigger the bug - Logger entityLogger = LogManager.getLogger("org.hibernate.internal.util.EntityPrinter"); - Logger listenerLogger = LogManager.getLogger("org.hibernate.event.internal.AbstractFlushingEventListener"); + LoggerConfig entityLogger = configuration.getLoggerConfig( "org.hibernate.internal.util.EntityPrinter"); + LoggerConfig listenerLogger = configuration.getLoggerConfig("org.hibernate.event.internal.AbstractFlushingEventListener"); Level oldEntityLogLevel = entityLogger.getLevel(); Level oldListenerLogLevel = listenerLogger.getLevel(); - entityLogger.setLevel((Level) Level.DEBUG); - listenerLogger.setLevel((Level) Level.DEBUG); + entityLogger.setLevel(Level.DEBUG); + listenerLogger.setLevel(Level.DEBUG); try { doInJPA(this::entityManagerFactory, entityManager -> { entityManager.find(MvnoBillingAgreement.class, 1); diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/naturalid/ImmutableNaturalKeyLookupTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/naturalid/ImmutableNaturalKeyLookupTest.java index 58ea046c3e05..1ce438654c74 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/naturalid/ImmutableNaturalKeyLookupTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/naturalid/ImmutableNaturalKeyLookupTest.java @@ -132,8 +132,10 @@ public void testCriteriaWithFetchModeJoinCollection() { newTx = s.beginTransaction(); // please enable - // log4j.logger.org.hibernate.cache.StandardQueryCache=DEBUG - // log4j.logger.org.hibernate.cache.UpdateTimestampsCache=DEBUG + // logger.standard-query-cache.name=org.hibernate.cache.StandardQueryCache + // logger.standard-query-cache.level=debug + // logger.update-timestamps-cache.name=org.hibernate.cache.UpdateTimestampsCache + // logger.update-timestamps-cache.level=debug // to see that isUpToDate is called where not appropriated Assert.assertTrue( s.getSessionFactory().getStatistics().isStatisticsEnabled() ); @@ -228,8 +230,10 @@ public void testCriteriaWithAliasOneToOneJoin() { newTx = s.beginTransaction(); // please enable - // log4j.logger.org.hibernate.cache.StandardQueryCache=DEBUG - // log4j.logger.org.hibernate.cache.UpdateTimestampsCache=DEBUG + // logger.standard-query-cache.name=org.hibernate.cache.StandardQueryCache + // logger.standard-query-cache.level=debug + // logger.update-timestamps-cache.name=org.hibernate.cache.UpdateTimestampsCache + // logger.update-timestamps-cache.level=debug // to see that isUpToDate is called where not appropriated Assert.assertTrue( s.getSessionFactory().getStatistics().isStatisticsEnabled() ); @@ -274,8 +278,10 @@ public void testSubCriteriaOneToOneJoin() { newTx = s.beginTransaction(); // please enable - // log4j.logger.org.hibernate.cache.StandardQueryCache=DEBUG - // log4j.logger.org.hibernate.cache.UpdateTimestampsCache=DEBUG + // logger.standard-query-cache.name=org.hibernate.cache.StandardQueryCache + // logger.standard-query-cache.level=debug + // logger.update-timestamps-cache.name=org.hibernate.cache.UpdateTimestampsCache + // logger.update-timestamps-cache.level=debug // to see that isUpToDate is called where not appropriated Assert.assertTrue( s.getSessionFactory().getStatistics().isStatisticsEnabled() ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/joinedsubclassbatch/JoinedSubclassBatchingTest.java b/hibernate-core/src/test/java/org/hibernate/test/joinedsubclassbatch/JoinedSubclassBatchingTest.java index faab782487c3..522c6798375a 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/joinedsubclassbatch/JoinedSubclassBatchingTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/joinedsubclassbatch/JoinedSubclassBatchingTest.java @@ -32,10 +32,6 @@ import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; import org.junit.Test; -import org.apache.log4j.Level; -import org.apache.log4j.LogManager; -import org.apache.log4j.Logger; - import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; /** diff --git a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/ImplicitCompositeKeyJoinTest.java b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/ImplicitCompositeKeyJoinTest.java index 4f59647bebbf..1771db572697 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/ImplicitCompositeKeyJoinTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/ImplicitCompositeKeyJoinTest.java @@ -24,7 +24,7 @@ import org.hibernate.testing.TestForIssue; import org.junit.Test; -import org.apache.log4j.Logger; +import org.jboss.logging.Logger; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; diff --git a/hibernate-core/src/test/resources/log4j.properties b/hibernate-core/src/test/resources/log4j.properties deleted file mode 100644 index 498bbeddd638..000000000000 --- a/hibernate-core/src/test/resources/log4j.properties +++ /dev/null @@ -1,62 +0,0 @@ -# -# Hibernate, Relational Persistence for Idiomatic Java -# -# License: GNU Lesser General Public License (LGPL), version 2.1 or later. -# See the lgpl.txt file in the root directory or . -# -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.Target=System.out -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n - -log4j.appender.unclosedSessionFactoryFile=org.apache.log4j.FileAppender -log4j.appender.unclosedSessionFactoryFile.append=true -log4j.appender.unclosedSessionFactoryFile.file=target/tmp/log/UnclosedSessionFactoryWarnings.log -log4j.appender.unclosedSessionFactoryFile.layout=org.apache.log4j.PatternLayout -log4j.appender.unclosedSessionFactoryFile.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n - -log4j.rootLogger=info, stdout - -log4j.logger.org.hibernate.orm.graph=debug - -#log4j.logger.org.hibernate.orm.tooling.schema.script=trace -#log4j.logger.org.hibernate.orm.tooling.schema.script.graph=trace - - -log4j.logger.org.hibernate.tool.hbm2ddl=trace -log4j.logger.org.hibernate.testing.cache=debug - -# SQL Logging - HHH-6833 -log4j.logger.org.hibernate.SQL=debug - -log4j.logger.org.hibernate.type.descriptor.sql.BasicBinder=trace -log4j.logger.org.hibernate.type.descriptor.sql.BasicExtractor=trace - -log4j.logger.org.hibernate.hql.internal.ast=debug - -log4j.logger.org.hibernate.sql.ordering.antlr=debug - -log4j.logger.org.hibernate.loader.plan2.build.internal.LoadPlanImpl=debug -log4j.logger.org.hibernate.loader.plan2.build.spi.LoadPlanTreePrinter=debug -log4j.logger.org.hibernate.loader.plan2.exec.spi.EntityLoadQueryDetails=debug - -log4j.logger.org.hibernate.engine.internal.StatisticalLoggingSessionEventListener=info - -log4j.logger.org.hibernate.boot.model.source.internal.hbm.ModelBinder=debug -log4j.logger.org.hibernate.type.descriptor.java.JavaTypeDescriptorRegistry=debug - -#log4j.logger.org.hibernate.action.internal.EntityAction=debug -#log4j.logger.org.hibernate.engine.internal.Cascade=trace - - -### When entity copy merge functionality is enabled using: -### hibernate.event.merge.entity_copy_observer=log, the following will -### provide information about merged entity copies. -### log4j.logger.org.hibernate.event.internal.EntityCopyAllowedLoggedObserver=debug - -log4j.logger.org.hibernate.testing.junit4.TestClassMetadata=info, unclosedSessionFactoryFile -log4j.logger.org.hibernate.boot.model.process.internal.ScanningCoordinator=debug -log4j.logger.org.hibernate.collection.internal.AbstractPersistentCollection=debug - -log4j.logger.org.hibernate.cache trace -log4j.logger.org.hibernate.stat trace \ No newline at end of file diff --git a/hibernate-core/src/test/resources/log4j2.properties b/hibernate-core/src/test/resources/log4j2.properties new file mode 100644 index 000000000000..f21f8c8748fc --- /dev/null +++ b/hibernate-core/src/test/resources/log4j2.properties @@ -0,0 +1,89 @@ +# +# Hibernate, Relational Persistence for Idiomatic Java +# +# License: GNU Lesser General Public License (LGPL), version 2.1 or later. +# See the lgpl.txt file in the root directory or . +# +appender.stdout.type=Console +appender.stdout.name=STDOUT +appender.stdout.layout.type=PatternLayout +appender.stdout.layout.pattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n + +appender.unclosedSessionFactoryFile.type=File +appender.unclosedSessionFactoryFile.name=unclosedSessionFactoryFile +appender.unclosedSessionFactoryFile.append=true +appender.unclosedSessionFactoryFile.fileName=target/tmp/log/UnclosedSessionFactoryWarnings.log +appender.unclosedSessionFactoryFile.layout.type=PatternLayout +appender.unclosedSessionFactoryFile.layout.pattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n + +rootLogger.level=info +rootLogger.appenderRef.stdout.ref=STDOUT + +logger.graph.name=org.hibernate.orm.graph +logger.graph.level=debug + +logger.tooling-schema-script.name=org.hibernate.orm.tooling.schema.script +#logger.tooling-schema-script.level=trace +logger.tooling-schema-script-graph.name=org.hibernate.orm.tooling.schema.script.graph +#logger.tooling-schema-script-graph.level=trace + + +logger.hbm2ddl.name=org.hibernate.tool.hbm2ddl +logger.hbm2ddl.level=trace +logger.testing-cache.name=org.hibernate.testing.cache +logger.testing-cache.level=debug + +# SQL Logging - HHH-6833 +logger.sql.name=org.hibernate.SQL +logger.sql.level=debug + +logger.type-basic-binder.name=org.hibernate.type.descriptor.sql.BasicBinder +logger.type-basic-binder.level=trace +logger.type-basic-extractor.name=org.hibernate.type.descriptor.sql.BasicExtractor +logger.type-basic-extractor.level=trace + +logger.hql-internal-ast.name=org.hibernate.hql.internal.ast +logger.hql-internal-ast.level=debug + +logger.sql-ordering-antlr.name=org.hibernate.sql.ordering.antlr +logger.sql-ordering-antlr.level=debug + +logger.load-plan-impl.name=org.hibernate.loader.plan2.build.internal.LoadPlanImpl +logger.load-plan-impl.level=debug +logger.load-plan-tree-printer.name=org.hibernate.loader.plan2.build.spi.LoadPlanTreePrinter +logger.load-plan-tree-printer.level=debug +logger.entity-load-query-details.name=org.hibernate.loader.plan2.exec.spi.EntityLoadQueryDetails +logger.entity-load-query-details.level=debug + +logger.statistical-logging-session-event-listener.name=org.hibernate.engine.internal.StatisticalLoggingSessionEventListener +logger.statistical-logging-session-event-listener.level=info + +logger.model-binder.name=org.hibernate.boot.model.source.internal.hbm.ModelBinder +logger.model-binder.level=debug +logger.java-type-descriptor-registry.name=org.hibernate.type.descriptor.java.JavaTypeDescriptorRegistry +logger.java-type-descriptor-registry.level=debug + +logger.entity-action.name=org.hibernate.action.internal.EntityAction +#logger.entity-action.level=debug +logger.cascade.name=org.hibernate.engine.internal.Cascade +#logger.cascade.level=trace + + +logger.merged-entity-copies.name=org.hibernate.event.internal.EntityCopyAllowedLoggedObserver +### When entity copy merge functionality is enabled using: +### hibernate.event.merge.entity_copy_observer=log, the following will +### provide information about merged entity copies. +#logger.merged-entity-copies.level=debug + +logger.test-class-metadata.name=org.hibernate.testing.junit4.TestClassMetadata +logger.test-class-metadata.level=info +logger.test-class-metadata.appenderRef.unclosedSessionFactoryFile.ref=unclosedSessionFactoryFile +logger.scanning-coordinator.name=org.hibernate.boot.model.process.internal.ScanningCoordinator +logger.scanning-coordinator.level=debug +logger.abstract-persistent-collection.name=org.hibernate.collection.internal.AbstractPersistentCollection +logger.abstract-persistent-collection.level=debug + +logger.cache.name=org.hibernate.cache +logger.cache.level=trace +logger.stat.name=org.hibernate.stat +logger.stat.level=trace \ No newline at end of file diff --git a/hibernate-ehcache/src/test/resources/log4j.properties b/hibernate-ehcache/src/test/resources/log4j.properties deleted file mode 100644 index cc2eb6d040f1..000000000000 --- a/hibernate-ehcache/src/test/resources/log4j.properties +++ /dev/null @@ -1,17 +0,0 @@ -# -# Hibernate, Relational Persistence for Idiomatic Java -# -# License: GNU Lesser General Public License (LGPL), version 2.1 or later -# See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html -# -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.Target=System.out -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n - -log4j.rootLogger=info, stdout - -log4j.logger.org.hibernate.test=info - -# SQL Logging - HHH-6833 -log4j.logger.org.hibernate.SQL=debug \ No newline at end of file diff --git a/hibernate-ehcache/src/test/resources/log4j2.properties b/hibernate-ehcache/src/test/resources/log4j2.properties new file mode 100644 index 000000000000..636a2e63b8fc --- /dev/null +++ b/hibernate-ehcache/src/test/resources/log4j2.properties @@ -0,0 +1,20 @@ +# +# Hibernate, Relational Persistence for Idiomatic Java +# +# License: GNU Lesser General Public License (LGPL), version 2.1 or later +# See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html +# +appender.stdout.type=Console +appender.stdout.name=STDOUT +appender.stdout.layout.type=PatternLayout +appender.stdout.layout.pattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n + +rootLogger.level=info +rootLogger.appenderRef.stdout.ref=STDOUT + +logger.test.name=org.hibernate.test +logger.test.level=info + +# SQL Logging - HHH-6833 +logger.sql.name=org.hibernate.SQL +logger.sql.level=debug \ No newline at end of file diff --git a/hibernate-envers/src/test/resources/log4j.properties b/hibernate-envers/src/test/resources/log4j.properties deleted file mode 100644 index e516e460d1d8..000000000000 --- a/hibernate-envers/src/test/resources/log4j.properties +++ /dev/null @@ -1,23 +0,0 @@ -# -# Hibernate, Relational Persistence for Idiomatic Java -# -# License: GNU Lesser General Public License (LGPL), version 2.1 or later. -# See the lgpl.txt file in the root directory or . -# -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.Target=System.out -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n - -log4j.rootLogger=info, stdout - -log4j.logger.org.hibernate.test=info - -# SQL Logging - HHH-6833 -log4j.logger.org.hibernate.SQL=debug -log4j.logger.org.hibernate.tool.hbm2ddl=debug - -log4j.logger.org.hibernate.type.descriptor.sql.BasicBinder=trace -log4j.logger.org.hibernate.type.descriptor.sql.BasicExtractor=trace - -log4j.logger.org.hibernate.envers.boot.internal.AdditionalJaxbMappingProducerImpl=trace \ No newline at end of file diff --git a/hibernate-envers/src/test/resources/log4j2.properties b/hibernate-envers/src/test/resources/log4j2.properties new file mode 100644 index 000000000000..77dcbca11fc4 --- /dev/null +++ b/hibernate-envers/src/test/resources/log4j2.properties @@ -0,0 +1,30 @@ +# +# Hibernate, Relational Persistence for Idiomatic Java +# +# License: GNU Lesser General Public License (LGPL), version 2.1 or later. +# See the lgpl.txt file in the root directory or . +# +appender.stdout.type=Console +appender.stdout.name=STDOUT +appender.stdout.layout.type=PatternLayout +appender.stdout.layout.pattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n + +rootLogger.level=info +rootLogger.appenderRef.stdout.ref=STDOUT + +logger.test.name=org.hibernate.test +logger.test.level=info + +# SQL Logging - HHH-6833 +logger.sql.name=org.hibernate.SQL +logger.sql.level=debug +logger.hbm2ddl.name=org.hibernate.tool.hbm2ddl +logger.hbm2ddl.level=debug + +logger.type-basic-binder.name=org.hibernate.type.descriptor.sql.BasicBinder +logger.type-basic-binder.level=trace +logger.type-basic-extractor.name=org.hibernate.type.descriptor.sql.BasicExtractor +logger.type-basic-extractor.level=trace + +logger.additional-jaxb-mapping-producer-impl.name=org.hibernate.envers.boot.internal.AdditionalJaxbMappingProducerImpl +logger.additional-jaxb-mapping-producer-impl.level=trace \ No newline at end of file diff --git a/hibernate-hikaricp/src/test/resources/log4j.properties b/hibernate-hikaricp/src/test/resources/log4j.properties deleted file mode 100644 index eb96581a28b5..000000000000 --- a/hibernate-hikaricp/src/test/resources/log4j.properties +++ /dev/null @@ -1,60 +0,0 @@ -# -# Hibernate, Relational Persistence for Idiomatic Java -# -# License: GNU Lesser General Public License (LGPL), version 2.1 or later. -# See the lgpl.txt file in the root directory or . -# -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.Target=System.out -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n -#log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L (hibernateLoadPlanWalkPath->%X{hibernateLoadPlanWalkPath}) - %m%n - -#log4j.appender.stdout-mdc=org.apache.log4j.ConsoleAppender -#log4j.appender.stdout-mdc.Target=System.out -#log4j.appender.stdout-mdc.layout=org.apache.log4j.PatternLayout -#log4j.appender.stdout-mdc.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L (walk path -> %X{hibernateLoadPlanWalkPath}) - %m%n - -log4j.appender.unclosedSessionFactoryFile=org.apache.log4j.FileAppender -log4j.appender.unclosedSessionFactoryFile.append=true -log4j.appender.unclosedSessionFactoryFile.file=target/tmp/log/UnclosedSessionFactoryWarnings.log -log4j.appender.unclosedSessionFactoryFile.layout=org.apache.log4j.PatternLayout -log4j.appender.unclosedSessionFactoryFile.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n - -log4j.rootLogger=info, stdout - -#log4j.logger.org.hibernate.loader.plan=trace, stdout-mdc -#log4j.additivity.org.hibernate.loader.plan=false -#log4j.logger.org.hibernate.persister.walking=trace, stdout-mdc -#log4j.additivity.org.hibernate.persister.walking=false - -log4j.logger.org.hibernate.tool.hbm2ddl=trace -log4j.logger.org.hibernate.testing.cache=debug - -# SQL Logging - HHH-6833 -log4j.logger.org.hibernate.SQL=debug - -log4j.logger.org.hibernate.type.descriptor.sql.BasicBinder=trace -log4j.logger.org.hibernate.type.descriptor.sql.BasicExtractor=trace - -log4j.logger.org.hibernate.hql.internal.ast=debug - -log4j.logger.org.hibernate.sql.ordering.antlr=debug - -log4j.logger.org.hibernate.loader.plan2.build.internal.LoadPlanImpl=debug -log4j.logger.org.hibernate.loader.plan2.build.spi.LoadPlanTreePrinter=debug -log4j.logger.org.hibernate.loader.plan2.exec.spi.EntityLoadQueryDetails=debug - -log4j.logger.org.hibernate.engine.internal.StatisticalLoggingSessionEventListener=info - -log4j.logger.org.hibernate.boot.model.source.internal.hbm.ModelBinder=debug -log4j.logger.org.hibernate.type.descriptor.java.JavaTypeDescriptorRegistry=debug - - -### When entity copy merge functionality is enabled using: -### hibernate.event.merge.entity_copy_observer=log, the following will -### provide information about merged entity copies. -### log4j.logger.org.hibernate.event.internal.EntityCopyAllowedLoggedObserver=debug - -log4j.logger.org.hibernate.testing.junit4.TestClassMetadata=info, unclosedSessionFactoryFile -log4j.logger.org.hibernate.boot.model.process.internal.ScanningCoordinator=debug diff --git a/hibernate-hikaricp/src/test/resources/log4j2.properties b/hibernate-hikaricp/src/test/resources/log4j2.properties new file mode 100644 index 000000000000..1563522cc763 --- /dev/null +++ b/hibernate-hikaricp/src/test/resources/log4j2.properties @@ -0,0 +1,83 @@ +# +# Hibernate, Relational Persistence for Idiomatic Java +# +# License: GNU Lesser General Public License (LGPL), version 2.1 or later. +# See the lgpl.txt file in the root directory or . +# +appender.stdout.type=Console +appender.stdout.name=STDOUT +appender.stdout.layout.type=PatternLayout +appender.stdout.layout.pattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n +appender.stdout.layout.pattern=%d{ABSOLUTE} %5p %c{1}:%L (hibernateLoadPlanWalkPath->%X{hibernateLoadPlanWalkPath}) - %m%n + +appender.stdout-mdc.type=Console +appender.stdout-mdc.name=stdout-mdc +appender.stdout-mdc.layout.type=PatternLayout +appender.stdout-mdc.layout.pattern=%d{ABSOLUTE} %5p %c{1}:%L (walk path -> %X{hibernateLoadPlanWalkPath}) - %m%n + +appender.unclosedSessionFactoryFile.type=File +appender.unclosedSessionFactoryFile.name=unclosedSessionFactoryFile +appender.unclosedSessionFactoryFile.append=true +appender.unclosedSessionFactoryFile.fileName=target/tmp/log/UnclosedSessionFactoryWarnings.log +appender.unclosedSessionFactoryFile.layout.type=PatternLayout +appender.unclosedSessionFactoryFile.layout.pattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n + +rootLogger.level=info +rootLogger.appenderRef.stdout.ref=STDOUT + +logger.loader-plan.name=org.hibernate.loader.plan +#logger.loader-plan.level=trace +#logger.loader-plan.appenderRef.stdout-mdc.ref=stdout-mdc +#logger.loader-plan.additivity=false +logger.persister-walking.name=org.hibernate.persister.walking +#logger.persister-walking.level=trace +#logger.persister-walking.appenderRef.stdout-mdc.ref=stdout-mdc +#logger.persister-walking.additivity=false + +logger.hbm2ddl.name=org.hibernate.tool.hbm2ddl +logger.hbm2ddl.level=trace +logger.testing-cache.name=org.hibernate.testing.cache +logger.testing-cache.level=debug + +# SQL Logging - HHH-6833 +logger.sql.name=org.hibernate.SQL +logger.sql.level=debug + +logger.type-basic-binder.name=org.hibernate.type.descriptor.sql.BasicBinder +logger.type-basic-binder.level=trace +logger.type-basic-extractor.name=org.hibernate.type.descriptor.sql.BasicExtractor +logger.type-basic-extractor.level=trace + +logger.hql-internal-ast.name=org.hibernate.hql.internal.ast +logger.hql-internal-ast.level=debug + +logger.sql-ordering-antlr.name=org.hibernate.sql.ordering.antlr +logger.sql-ordering-antlr.level=debug + +logger.load-plan-impl.name=org.hibernate.loader.plan2.build.internal.LoadPlanImpl +logger.load-plan-impl.level=debug +logger.load-plan-tree-printer.name=org.hibernate.loader.plan2.build.spi.LoadPlanTreePrinter +logger.load-plan-tree-printer.level=debug +logger.entity-load-query-details.name=org.hibernate.loader.plan2.exec.spi.EntityLoadQueryDetails +logger.entity-load-query-details.level=debug + +logger.statistical-logging-session-event-listener.name=org.hibernate.engine.internal.StatisticalLoggingSessionEventListener +logger.statistical-logging-session-event-listener.level=info + +logger.model-binder.name=org.hibernate.boot.model.source.internal.hbm.ModelBinder +logger.model-binder.level=debug +logger.java-type-descriptor-registry.name=org.hibernate.type.descriptor.java.JavaTypeDescriptorRegistry +logger.java-type-descriptor-registry.level=debug + + +logger.merged-entity-copies.name=org.hibernate.event.internal.EntityCopyAllowedLoggedObserver +### When entity copy merge functionality is enabled using: +### hibernate.event.merge.entity_copy_observer=log, the following will +### provide information about merged entity copies. +#logger.merged-entity-copies.level=debug + +logger.test-class-metadata.name=org.hibernate.testing.junit4.TestClassMetadata +logger.test-class-metadata.level=info +logger.test-class-metadata.appenderRef.unclosedSessionFactoryFile.ref=unclosedSessionFactoryFile +logger.scanning-coordinator.name=org.hibernate.boot.model.process.internal.ScanningCoordinator +logger.scanning-coordinator.level=debug diff --git a/hibernate-integrationtest-java-modules/src/test/resources/logging.properties b/hibernate-integrationtest-java-modules/src/test/resources/logging.properties index f96639aaf09b..545fb493cae2 100644 --- a/hibernate-integrationtest-java-modules/src/test/resources/logging.properties +++ b/hibernate-integrationtest-java-modules/src/test/resources/logging.properties @@ -5,19 +5,19 @@ # See the lgpl.txt file in the root directory or . # -# Root logger option -log4j.rootLogger=DEBUG, file - -# Direct log messages to a log file -log4j.appender.file=org.apache.log4j.FileAppender -log4j.appender.file.File=target/test.log -log4j.appender.file.layout=org.apache.log4j.PatternLayout -log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p [%c] (%t) - %m%n -log4j.appender.file.Threshold=DEBUG - # Direct log messages to console -log4j.appender.console=org.apache.log4j.ConsoleAppender -log4j.appender.console.Target=System.out -log4j.appender.console.layout=org.apache.log4j.PatternLayout -log4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p [%c] (%t) - %m%n -log4j.appender.console.Threshold=WARN \ No newline at end of file +appender.stdout.type=Console +appender.stdout.name=STDOUT +appender.stdout.layout.type=PatternLayout +appender.stdout.layout.pattern=%d{yyyy-MM-dd HH:mm:ss} %-5p [%c] (%t) - %m%n + +# Direct log messages to a log file +appender.file.type=File +appender.file.name=file +appender.file.fileName=target/test.log +appender.file.layout.type=PatternLayout +appender.file.layout.pattern=%d{yyyy-MM-dd HH:mm:ss} %-5p [%c] (%t) - %m%n + +# Root logger option +rootLogger.level=debug +rootLogger.appenderRef.file.ref=file diff --git a/hibernate-jcache/src/test/resources/log4j.properties b/hibernate-jcache/src/test/resources/log4j.properties deleted file mode 100644 index f29002cc37c1..000000000000 --- a/hibernate-jcache/src/test/resources/log4j.properties +++ /dev/null @@ -1,17 +0,0 @@ -# -# Hibernate, Relational Persistence for Idiomatic Java -# -# License: GNU Lesser General Public License (LGPL), version 2.1 or later. -# See the lgpl.txt file in the root directory or . -# -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.Target=System.out -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n - -log4j.rootLogger=info, stdout - -log4j.logger.org.hibernate.test=info - -# SQL Logging - HHH-6833 -log4j.logger.org.hibernate.SQL=debug \ No newline at end of file diff --git a/hibernate-jcache/src/test/resources/log4j2.properties b/hibernate-jcache/src/test/resources/log4j2.properties new file mode 100644 index 000000000000..a348845e890f --- /dev/null +++ b/hibernate-jcache/src/test/resources/log4j2.properties @@ -0,0 +1,20 @@ +# +# Hibernate, Relational Persistence for Idiomatic Java +# +# License: GNU Lesser General Public License (LGPL), version 2.1 or later. +# See the lgpl.txt file in the root directory or . +# +appender.stdout.type=Console +appender.stdout.name=STDOUT +appender.stdout.layout.type=PatternLayout +appender.stdout.layout.pattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n + +rootLogger.level=info +rootLogger.appenderRef.stdout.ref=STDOUT + +logger.test.name=org.hibernate.test +logger.test.level=info + +# SQL Logging - HHH-6833 +logger.sql.name=org.hibernate.SQL +logger.sql.level=debug \ No newline at end of file diff --git a/hibernate-micrometer/src/test/resources/log4j.properties b/hibernate-micrometer/src/test/resources/log4j.properties deleted file mode 100644 index 4567cb1105cb..000000000000 --- a/hibernate-micrometer/src/test/resources/log4j.properties +++ /dev/null @@ -1,19 +0,0 @@ -# -# Hibernate, Relational Persistence for Idiomatic Java -# -# License: GNU Lesser General Public License (LGPL), version 2.1 or later. -# See the lgpl.txt file in the root directory or . -# -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.Target=System.out -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n - -log4j.rootLogger=info, stdout - -log4j.logger.org.hibernate.stat=trace - -log4j.logger.org.hibernate.tool.hbm2ddl=trace -log4j.logger.org.hibernate.SQL=debug -log4j.logger.org.hibernate.type.descriptor.sql.BasicBinder=trace -log4j.logger.org.hibernate.type.descriptor.sql.BasicExtractor=trace \ No newline at end of file diff --git a/hibernate-micrometer/src/test/resources/log4j2.properties b/hibernate-micrometer/src/test/resources/log4j2.properties new file mode 100644 index 000000000000..15a8605c8b3c --- /dev/null +++ b/hibernate-micrometer/src/test/resources/log4j2.properties @@ -0,0 +1,25 @@ +# +# Hibernate, Relational Persistence for Idiomatic Java +# +# License: GNU Lesser General Public License (LGPL), version 2.1 or later. +# See the lgpl.txt file in the root directory or . +# +appender.stdout.type=Console +appender.stdout.name=STDOUT +appender.stdout.layout.type=PatternLayout +appender.stdout.layout.pattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n + +rootLogger.level=info +rootLogger.appenderRef.stdout.ref=STDOUT + +logger.stat.name=org.hibernate.stat +logger.stat.level=trace + +logger.hbm2ddl.name=org.hibernate.tool.hbm2ddl +logger.hbm2ddl.level=trace +logger.sql.name=org.hibernate.SQL +logger.sql.level=debug +logger.type-basic-binder.name=org.hibernate.type.descriptor.sql.BasicBinder +logger.type-basic-binder.level=trace +logger.type-basic-extractor.name=org.hibernate.type.descriptor.sql.BasicExtractor +logger.type-basic-extractor.level=trace \ No newline at end of file diff --git a/hibernate-osgi/src/test/resources/logging.properties b/hibernate-osgi/src/test/resources/logging.properties index f96639aaf09b..545fb493cae2 100644 --- a/hibernate-osgi/src/test/resources/logging.properties +++ b/hibernate-osgi/src/test/resources/logging.properties @@ -5,19 +5,19 @@ # See the lgpl.txt file in the root directory or . # -# Root logger option -log4j.rootLogger=DEBUG, file - -# Direct log messages to a log file -log4j.appender.file=org.apache.log4j.FileAppender -log4j.appender.file.File=target/test.log -log4j.appender.file.layout=org.apache.log4j.PatternLayout -log4j.appender.file.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p [%c] (%t) - %m%n -log4j.appender.file.Threshold=DEBUG - # Direct log messages to console -log4j.appender.console=org.apache.log4j.ConsoleAppender -log4j.appender.console.Target=System.out -log4j.appender.console.layout=org.apache.log4j.PatternLayout -log4j.appender.console.layout.ConversionPattern=%d{yyyy-MM-dd HH:mm:ss} %-5p [%c] (%t) - %m%n -log4j.appender.console.Threshold=WARN \ No newline at end of file +appender.stdout.type=Console +appender.stdout.name=STDOUT +appender.stdout.layout.type=PatternLayout +appender.stdout.layout.pattern=%d{yyyy-MM-dd HH:mm:ss} %-5p [%c] (%t) - %m%n + +# Direct log messages to a log file +appender.file.type=File +appender.file.name=file +appender.file.fileName=target/test.log +appender.file.layout.type=PatternLayout +appender.file.layout.pattern=%d{yyyy-MM-dd HH:mm:ss} %-5p [%c] (%t) - %m%n + +# Root logger option +rootLogger.level=debug +rootLogger.appenderRef.file.ref=file diff --git a/hibernate-proxool/src/test/resources/log4j.properties b/hibernate-proxool/src/test/resources/log4j.properties deleted file mode 100644 index 86c5d9be55e6..000000000000 --- a/hibernate-proxool/src/test/resources/log4j.properties +++ /dev/null @@ -1,16 +0,0 @@ -# -# Hibernate, Relational Persistence for Idiomatic Java -# -# License: GNU Lesser General Public License (LGPL), version 2.1 or later. -# See the lgpl.txt file in the root directory or . -# -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.Target=System.out -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n - - -log4j.rootLogger=info, stdout - -log4j.logger.org.hibernate.tool.hbm2ddl=debug -log4j.logger.org.hibernate.testing.cache=debug diff --git a/hibernate-proxool/src/test/resources/log4j2.properties b/hibernate-proxool/src/test/resources/log4j2.properties new file mode 100644 index 000000000000..d4da0b21a5e8 --- /dev/null +++ b/hibernate-proxool/src/test/resources/log4j2.properties @@ -0,0 +1,19 @@ +# +# Hibernate, Relational Persistence for Idiomatic Java +# +# License: GNU Lesser General Public License (LGPL), version 2.1 or later. +# See the lgpl.txt file in the root directory or . +# +appender.stdout.type=Console +appender.stdout.name=STDOUT +appender.stdout.layout.type=PatternLayout +appender.stdout.layout.pattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n + + +rootLogger.level=info +rootLogger.appenderRef.stdout.ref=STDOUT + +logger.hbm2ddl.name=org.hibernate.tool.hbm2ddl +logger.hbm2ddl.level=debug +logger.testing-cache.name=org.hibernate.testing.cache +logger.testing-cache.level=debug diff --git a/hibernate-spatial/src/test/resources/log4j.properties b/hibernate-spatial/src/test/resources/log4j.properties deleted file mode 100644 index 5156e0d55e13..000000000000 --- a/hibernate-spatial/src/test/resources/log4j.properties +++ /dev/null @@ -1,13 +0,0 @@ -# -# Hibernate, Relational Persistence for Idiomatic Java -# -# License: GNU Lesser General Public License (LGPL), version 2.1 or later. -# See the lgpl.txt file in the root directory or . -# -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.Target=System.out -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n -log4j.rootLogger=info, stdout -log4j.logger.org.hibernate.SQL=DEBUG -log4j.logger.org.hibernate.spatial=debug diff --git a/hibernate-spatial/src/test/resources/log4j2.properties b/hibernate-spatial/src/test/resources/log4j2.properties new file mode 100644 index 000000000000..6b2e5ea0a11f --- /dev/null +++ b/hibernate-spatial/src/test/resources/log4j2.properties @@ -0,0 +1,16 @@ +# +# Hibernate, Relational Persistence for Idiomatic Java +# +# License: GNU Lesser General Public License (LGPL), version 2.1 or later. +# See the lgpl.txt file in the root directory or . +# +appender.stdout.type=Console +appender.stdout.name=STDOUT +appender.stdout.layout.type=PatternLayout +appender.stdout.layout.pattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n +rootLogger.level=info +rootLogger.appenderRef.stdout.ref=STDOUT +logger.sql.name=org.hibernate.SQL +logger.sql.level=DEBUG +logger.spatial.name=org.hibernate.spatial +logger.spatial.level=debug diff --git a/hibernate-testing-jakarta/hibernate-testing-jakarta.gradle b/hibernate-testing-jakarta/hibernate-testing-jakarta.gradle index 716f96c9b027..e734d0acbddd 100644 --- a/hibernate-testing-jakarta/hibernate-testing-jakarta.gradle +++ b/hibernate-testing-jakarta/hibernate-testing-jakarta.gradle @@ -21,7 +21,7 @@ dependencies { compile( libraries.byteman_install ) compile( libraries.byteman_bmunit ) compile( libraries.xapool ) - compile( libraries.log4j ) + compile( libraries.log4j2 ) compile( libraries.jboss_tx_spi_jakarta ) { transitive=false; } diff --git a/hibernate-testing/hibernate-testing.gradle b/hibernate-testing/hibernate-testing.gradle index abd8e3a5def9..0f39d04069a5 100644 --- a/hibernate-testing/hibernate-testing.gradle +++ b/hibernate-testing/hibernate-testing.gradle @@ -18,7 +18,7 @@ dependencies { compile( libraries.byteman_install ) compile( libraries.byteman_bmunit ) compile( libraries.xapool ) - compile( libraries.log4j ) + compile( libraries.log4j2 ) compile( libraries.jboss_tx_spi ) { transitive=false; } diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/logger/Log4DelegatingLogger.java b/hibernate-testing/src/main/java/org/hibernate/testing/logger/Log4DelegatingLogger.java deleted file mode 100644 index b6f14dd59781..000000000000 --- a/hibernate-testing/src/main/java/org/hibernate/testing/logger/Log4DelegatingLogger.java +++ /dev/null @@ -1,129 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.testing.logger; - -import java.text.MessageFormat; -import java.util.LinkedList; -import java.util.List; -import java.util.concurrent.atomic.AtomicBoolean; - -import org.jboss.logging.Logger; - -/** - * A {@code Logger} implementation which delegates to Log4J but makes it possible - * to test for events being logged (not logged). - * - * @author Sanne Grinovero (C) 2015 Red Hat Inc. - */ -public final class Log4DelegatingLogger extends Logger { - - private final org.apache.log4j.Logger logger; - - // Synchronize access on the field - private final List enabledListeners = new LinkedList(); - private final AtomicBoolean interceptEnabled = new AtomicBoolean( false ); - - Log4DelegatingLogger(final String name) { - super( name ); - logger = org.apache.log4j.Logger.getLogger( name ); - } - - void registerListener(LogListener newListener) { - synchronized ( enabledListeners ) { - if ( newListener != null ) { - enabledListeners.add( newListener ); - interceptEnabled.set( true ); - } - } - } - - void clearAllListeners() { - synchronized ( enabledListeners ) { - enabledListeners.clear(); - interceptEnabled.set( false ); - } - } - - public boolean isEnabled(final Level level) { - final org.apache.log4j.Level l = translate( level ); - return logger.isEnabledFor( l ) && l.isGreaterOrEqual( logger.getEffectiveLevel() ); - } - - protected void doLog(final Level level, final String loggerClassName, final Object message, final Object[] parameters, final Throwable thrown) { - final org.apache.log4j.Level translatedLevel = translate( level ); - if ( interceptEnabled.get() ) { - intercept( level, parameters == null || parameters.length == 0 ? String.valueOf( message ) : MessageFormat.format( String.valueOf( message ), parameters ), thrown ); - } - if ( !logger.isEnabledFor( translatedLevel ) ) { - return; - } - try { - logger.log( - loggerClassName, - translatedLevel, - parameters == null || parameters.length == 0 - ? String.valueOf( message ) - : MessageFormat.format(String.valueOf( message ), parameters ), - thrown - ); - } - catch (Throwable ignored) { - } - } - - private void intercept(Level level, String renderedMessage, Throwable thrown) { - synchronized ( enabledListeners ) { - for ( LogListener listener : enabledListeners ) { - listener.loggedEvent( level, renderedMessage, thrown ); - } - } - } - - protected void doLogf(final Level level, final String loggerClassName, final String format, final Object[] parameters, final Throwable thrown) { - final org.apache.log4j.Level translatedLevel = translate( level ); - if ( interceptEnabled.get() ) { - intercept( level, parameters == null ? format : String.format( format, parameters ), thrown ); - } - if ( !logger.isEnabledFor( translatedLevel ) ) { - return; - } - try { - logger.log( - loggerClassName, - translatedLevel, - parameters == null ? format : String.format( format, parameters ), - thrown - ); - } - catch (Throwable ignored) { - } - } - - private static org.apache.log4j.Level translate(final Level level) { - if ( level == null ) { - return org.apache.log4j.Level.ALL; - } - - switch ( level ) { - case FATAL: - return org.apache.log4j.Level.FATAL; - case ERROR: - return org.apache.log4j.Level.ERROR; - case WARN: - return org.apache.log4j.Level.WARN; - case INFO: - return org.apache.log4j.Level.INFO; - case DEBUG: - return org.apache.log4j.Level.DEBUG; - case TRACE: - return org.apache.log4j.Level.TRACE; - } - - return org.apache.log4j.Level.ALL; - } - -} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/logger/Log4J2DelegatingLogger.java b/hibernate-testing/src/main/java/org/hibernate/testing/logger/Log4J2DelegatingLogger.java new file mode 100644 index 000000000000..7341e5d3a26b --- /dev/null +++ b/hibernate-testing/src/main/java/org/hibernate/testing/logger/Log4J2DelegatingLogger.java @@ -0,0 +1,160 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.testing.logger; + +import java.text.MessageFormat; +import java.util.LinkedList; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.jboss.logging.Logger; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.LoggingException; +import org.apache.logging.log4j.message.MessageFormatMessageFactory; +import org.apache.logging.log4j.message.StringFormattedMessage; +import org.apache.logging.log4j.spi.AbstractLogger; + +/** + * A {@code Logger} implementation which delegates to Log4J2 but makes it possible + * to test for events being logged (not logged). + * + * @author Sanne Grinovero (C) 2015 Red Hat Inc. + */ +public final class Log4J2DelegatingLogger extends Logger { + + private final AbstractLogger logger; + private final MessageFormatMessageFactory messageFactory; + + // Synchronize access on the field + private final List enabledListeners = new LinkedList<>(); + private final AtomicBoolean interceptEnabled = new AtomicBoolean( false ); + + Log4J2DelegatingLogger(final String name) { + super( name ); + org.apache.logging.log4j.Logger logger = LogManager.getLogger( name ); + if ( !( logger instanceof AbstractLogger ) ) { + throw new LoggingException( "The logger for [" + name + "] does not extend AbstractLogger. Actual logger: " + logger + .getClass() + .getName() ); + } + this.logger = (AbstractLogger) logger; + this.messageFactory = new MessageFormatMessageFactory(); + } + + void registerListener(LogListener newListener) { + synchronized (enabledListeners) { + if ( newListener != null ) { + enabledListeners.add( newListener ); + interceptEnabled.set( true ); + } + } + } + + void clearAllListeners() { + synchronized (enabledListeners) { + enabledListeners.clear(); + interceptEnabled.set( false ); + } + } + + @Override + public boolean isEnabled(final Level level) { + return this.logger.isEnabled( translate( level ) ); + } + + @Override + protected void doLog( + final Level level, + final String loggerClassName, + final Object message, + final Object[] parameters, + final Throwable thrown) { + final org.apache.logging.log4j.Level translatedLevel = translate( level ); + if ( interceptEnabled.get() ) { + intercept( + level, + parameters == null || parameters.length == 0 ? + String.valueOf( message ) : + MessageFormat.format( String.valueOf( message ), parameters ), + thrown + ); + } + if ( !this.logger.isEnabled( translatedLevel ) ) { + return; + } + try { + this.logger.logMessage( loggerClassName, translatedLevel, null, + ( parameters == null || parameters.length == 0 ) ? + this.messageFactory.newMessage( message ) : + this.messageFactory.newMessage( String.valueOf( message ), parameters ), + thrown + ); + } + catch (Throwable ignored) { + } + } + + private void intercept(Level level, String renderedMessage, Throwable thrown) { + synchronized (enabledListeners) { + for ( LogListener listener : enabledListeners ) { + listener.loggedEvent( level, renderedMessage, thrown ); + } + } + } + + @Override + protected void doLogf( + final Level level, + final String loggerClassName, + final String format, + final Object[] parameters, + final Throwable thrown) { + final org.apache.logging.log4j.Level translatedLevel = translate( level ); + if ( interceptEnabled.get() ) { + intercept( level, parameters == null ? format : String.format( format, parameters ), thrown ); + } + if ( !logger.isEnabled( translatedLevel ) ) { + return; + } + try { + this.logger.logMessage( + loggerClassName, + translatedLevel, + null, + new StringFormattedMessage( format, parameters ), + thrown + ); + } + catch (Throwable ignored) { + } + } + + private static org.apache.logging.log4j.Level translate(final Level level) { + if ( level == null ) { + return org.apache.logging.log4j.Level.ALL; + } + + switch ( level ) { + case FATAL: + return org.apache.logging.log4j.Level.FATAL; + case ERROR: + return org.apache.logging.log4j.Level.ERROR; + case WARN: + return org.apache.logging.log4j.Level.WARN; + case INFO: + return org.apache.logging.log4j.Level.INFO; + case DEBUG: + return org.apache.logging.log4j.Level.DEBUG; + case TRACE: + return org.apache.logging.log4j.Level.TRACE; + } + + return org.apache.logging.log4j.Level.ALL; + } + +} diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/logger/LogInspectionHelper.java b/hibernate-testing/src/main/java/org/hibernate/testing/logger/LogInspectionHelper.java index b189410a39eb..a81e78bbf9a7 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/logger/LogInspectionHelper.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/logger/LogInspectionHelper.java @@ -32,7 +32,7 @@ static void clearAllListeners(BasicLogger log) { convertType( log ).clearAllListeners(); } - private static Log4DelegatingLogger convertType(BasicLogger log) { + private static Log4J2DelegatingLogger convertType(BasicLogger log) { if ( log instanceof DelegatingBasicLogger) { //Most loggers generated via the annotation processor are of this type DelegatingBasicLogger wrapper = (DelegatingBasicLogger) log; @@ -43,13 +43,13 @@ private static Log4DelegatingLogger convertType(BasicLogger log) { throw new RuntimeException( cause ); } } - if ( ! ( log instanceof Log4DelegatingLogger ) ) { + if ( ! ( log instanceof Log4J2DelegatingLogger ) ) { throw new AssertionFailure( "Unexpected log type: JBoss Logger didn't register the custom TestableLoggerProvider as logger provider" ); } - return (Log4DelegatingLogger) log; + return (Log4J2DelegatingLogger) log; } - private static Log4DelegatingLogger extractFromWrapper(DelegatingBasicLogger wrapper) throws Exception { + private static Log4J2DelegatingLogger extractFromWrapper(DelegatingBasicLogger wrapper) throws Exception { Field field = DelegatingBasicLogger.class.getDeclaredField( "log" ); field.setAccessible( true ); Object object = field.get( wrapper ); diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/logger/TestableLoggerProvider.java b/hibernate-testing/src/main/java/org/hibernate/testing/logger/TestableLoggerProvider.java index 50979d8d48f6..5f0fa3ca5d36 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/logger/TestableLoggerProvider.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/logger/TestableLoggerProvider.java @@ -6,14 +6,15 @@ */ package org.hibernate.testing.logger; +import java.util.HashMap; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import org.apache.log4j.MDC; -import org.apache.log4j.NDC; import org.jboss.logging.Logger; +import org.apache.logging.log4j.ThreadContext; + /** * A {@code LoggerProvider} for JBoss Logger. * See also META-INF/services/org.jboss.logging.LoggerProvider @@ -23,17 +24,18 @@ public class TestableLoggerProvider implements org.jboss.logging.LoggerProvider { //We LEAK Logger instances: good only for testing as we know the set of categories is limited in practice - private static final ConcurrentMap reuseLoggerInstances = new ConcurrentHashMap(); + private static final ConcurrentMap reuseLoggerInstances = new ConcurrentHashMap<>(); // Maintainer note: // Except the next method, which is adjusted to return our own Log4DelegatingLogger // this class is a verbatim copy of org.jboss.logging.Log4jLoggerProvider // (which is a final class) + @Override public Logger getLogger(final String name) { Logger logger = reuseLoggerInstances.get( name ); if ( logger == null ) { - logger = new Log4DelegatingLogger( "".equals( name ) ? "ROOT" : name ); + logger = new Log4J2DelegatingLogger( "".equals( name ) ? "ROOT" : name ); Logger previous = reuseLoggerInstances.putIfAbsent( name, logger ); if ( previous != null ) { return previous; @@ -44,57 +46,67 @@ public Logger getLogger(final String name) { @Override public void clearMdc() { - MDC.clear(); - } - - public Object getMdc(String key) { - return MDC.get( key ); - } - - @SuppressWarnings("unchecked") - public Map getMdcMap() { - return MDC.getContext(); + ThreadContext.clearMap(); } - public Object putMdc(String key, Object val) { + @Override + public Object putMdc(String key, Object value) { try { - return MDC.get( key ); + return ThreadContext.get( key ); } finally { - MDC.put( key, val ); + ThreadContext.put( key, String.valueOf( value ) ); } } + @Override + public Object getMdc(String key) { + return ThreadContext.get( key ); + } + + @Override public void removeMdc(String key) { - MDC.remove( key ); + ThreadContext.remove( key ); } + @Override + public Map getMdcMap() { + return new HashMap<>( ThreadContext.getImmutableContext() ); + } + + @Override public void clearNdc() { - NDC.remove(); + ThreadContext.clearStack(); } + @Override public String getNdc() { - return NDC.get(); + return ThreadContext.peek(); } + @Override public int getNdcDepth() { - return NDC.getDepth(); + return ThreadContext.getDepth(); } - public String peekNdc() { - return NDC.peek(); + @Override + public String popNdc() { + return ThreadContext.pop(); } - public String popNdc() { - return NDC.pop(); + @Override + public String peekNdc() { + return ThreadContext.peek(); } + @Override public void pushNdc(String message) { - NDC.push( message ); + ThreadContext.push( message ); } + @Override public void setNdcMaxDepth(int maxDepth) { - NDC.setMaxDepth( maxDepth ); + ThreadContext.trim( maxDepth ); } } diff --git a/hibernate-testing/src/test/java/org/hibernate/testing/logger/LogDelegationTest.java b/hibernate-testing/src/test/java/org/hibernate/testing/logger/LogDelegationTest.java index 9509646e6655..34d9e9c9eebf 100644 --- a/hibernate-testing/src/test/java/org/hibernate/testing/logger/LogDelegationTest.java +++ b/hibernate-testing/src/test/java/org/hibernate/testing/logger/LogDelegationTest.java @@ -30,7 +30,7 @@ public class LogDelegationTest { @Test public void testLogDelegationIsActivated() { - assertThat( LOG, instanceOf( Log4DelegatingLogger.class ) ); + assertThat( LOG, instanceOf( Log4J2DelegatingLogger.class ) ); } @Test diff --git a/hibernate-vibur/src/test/resources/log4j.properties b/hibernate-vibur/src/test/resources/log4j.properties deleted file mode 100644 index eb96581a28b5..000000000000 --- a/hibernate-vibur/src/test/resources/log4j.properties +++ /dev/null @@ -1,60 +0,0 @@ -# -# Hibernate, Relational Persistence for Idiomatic Java -# -# License: GNU Lesser General Public License (LGPL), version 2.1 or later. -# See the lgpl.txt file in the root directory or . -# -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.Target=System.out -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n -#log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L (hibernateLoadPlanWalkPath->%X{hibernateLoadPlanWalkPath}) - %m%n - -#log4j.appender.stdout-mdc=org.apache.log4j.ConsoleAppender -#log4j.appender.stdout-mdc.Target=System.out -#log4j.appender.stdout-mdc.layout=org.apache.log4j.PatternLayout -#log4j.appender.stdout-mdc.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L (walk path -> %X{hibernateLoadPlanWalkPath}) - %m%n - -log4j.appender.unclosedSessionFactoryFile=org.apache.log4j.FileAppender -log4j.appender.unclosedSessionFactoryFile.append=true -log4j.appender.unclosedSessionFactoryFile.file=target/tmp/log/UnclosedSessionFactoryWarnings.log -log4j.appender.unclosedSessionFactoryFile.layout=org.apache.log4j.PatternLayout -log4j.appender.unclosedSessionFactoryFile.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n - -log4j.rootLogger=info, stdout - -#log4j.logger.org.hibernate.loader.plan=trace, stdout-mdc -#log4j.additivity.org.hibernate.loader.plan=false -#log4j.logger.org.hibernate.persister.walking=trace, stdout-mdc -#log4j.additivity.org.hibernate.persister.walking=false - -log4j.logger.org.hibernate.tool.hbm2ddl=trace -log4j.logger.org.hibernate.testing.cache=debug - -# SQL Logging - HHH-6833 -log4j.logger.org.hibernate.SQL=debug - -log4j.logger.org.hibernate.type.descriptor.sql.BasicBinder=trace -log4j.logger.org.hibernate.type.descriptor.sql.BasicExtractor=trace - -log4j.logger.org.hibernate.hql.internal.ast=debug - -log4j.logger.org.hibernate.sql.ordering.antlr=debug - -log4j.logger.org.hibernate.loader.plan2.build.internal.LoadPlanImpl=debug -log4j.logger.org.hibernate.loader.plan2.build.spi.LoadPlanTreePrinter=debug -log4j.logger.org.hibernate.loader.plan2.exec.spi.EntityLoadQueryDetails=debug - -log4j.logger.org.hibernate.engine.internal.StatisticalLoggingSessionEventListener=info - -log4j.logger.org.hibernate.boot.model.source.internal.hbm.ModelBinder=debug -log4j.logger.org.hibernate.type.descriptor.java.JavaTypeDescriptorRegistry=debug - - -### When entity copy merge functionality is enabled using: -### hibernate.event.merge.entity_copy_observer=log, the following will -### provide information about merged entity copies. -### log4j.logger.org.hibernate.event.internal.EntityCopyAllowedLoggedObserver=debug - -log4j.logger.org.hibernate.testing.junit4.TestClassMetadata=info, unclosedSessionFactoryFile -log4j.logger.org.hibernate.boot.model.process.internal.ScanningCoordinator=debug diff --git a/hibernate-vibur/src/test/resources/log4j2.properties b/hibernate-vibur/src/test/resources/log4j2.properties new file mode 100644 index 000000000000..1563522cc763 --- /dev/null +++ b/hibernate-vibur/src/test/resources/log4j2.properties @@ -0,0 +1,83 @@ +# +# Hibernate, Relational Persistence for Idiomatic Java +# +# License: GNU Lesser General Public License (LGPL), version 2.1 or later. +# See the lgpl.txt file in the root directory or . +# +appender.stdout.type=Console +appender.stdout.name=STDOUT +appender.stdout.layout.type=PatternLayout +appender.stdout.layout.pattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n +appender.stdout.layout.pattern=%d{ABSOLUTE} %5p %c{1}:%L (hibernateLoadPlanWalkPath->%X{hibernateLoadPlanWalkPath}) - %m%n + +appender.stdout-mdc.type=Console +appender.stdout-mdc.name=stdout-mdc +appender.stdout-mdc.layout.type=PatternLayout +appender.stdout-mdc.layout.pattern=%d{ABSOLUTE} %5p %c{1}:%L (walk path -> %X{hibernateLoadPlanWalkPath}) - %m%n + +appender.unclosedSessionFactoryFile.type=File +appender.unclosedSessionFactoryFile.name=unclosedSessionFactoryFile +appender.unclosedSessionFactoryFile.append=true +appender.unclosedSessionFactoryFile.fileName=target/tmp/log/UnclosedSessionFactoryWarnings.log +appender.unclosedSessionFactoryFile.layout.type=PatternLayout +appender.unclosedSessionFactoryFile.layout.pattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n + +rootLogger.level=info +rootLogger.appenderRef.stdout.ref=STDOUT + +logger.loader-plan.name=org.hibernate.loader.plan +#logger.loader-plan.level=trace +#logger.loader-plan.appenderRef.stdout-mdc.ref=stdout-mdc +#logger.loader-plan.additivity=false +logger.persister-walking.name=org.hibernate.persister.walking +#logger.persister-walking.level=trace +#logger.persister-walking.appenderRef.stdout-mdc.ref=stdout-mdc +#logger.persister-walking.additivity=false + +logger.hbm2ddl.name=org.hibernate.tool.hbm2ddl +logger.hbm2ddl.level=trace +logger.testing-cache.name=org.hibernate.testing.cache +logger.testing-cache.level=debug + +# SQL Logging - HHH-6833 +logger.sql.name=org.hibernate.SQL +logger.sql.level=debug + +logger.type-basic-binder.name=org.hibernate.type.descriptor.sql.BasicBinder +logger.type-basic-binder.level=trace +logger.type-basic-extractor.name=org.hibernate.type.descriptor.sql.BasicExtractor +logger.type-basic-extractor.level=trace + +logger.hql-internal-ast.name=org.hibernate.hql.internal.ast +logger.hql-internal-ast.level=debug + +logger.sql-ordering-antlr.name=org.hibernate.sql.ordering.antlr +logger.sql-ordering-antlr.level=debug + +logger.load-plan-impl.name=org.hibernate.loader.plan2.build.internal.LoadPlanImpl +logger.load-plan-impl.level=debug +logger.load-plan-tree-printer.name=org.hibernate.loader.plan2.build.spi.LoadPlanTreePrinter +logger.load-plan-tree-printer.level=debug +logger.entity-load-query-details.name=org.hibernate.loader.plan2.exec.spi.EntityLoadQueryDetails +logger.entity-load-query-details.level=debug + +logger.statistical-logging-session-event-listener.name=org.hibernate.engine.internal.StatisticalLoggingSessionEventListener +logger.statistical-logging-session-event-listener.level=info + +logger.model-binder.name=org.hibernate.boot.model.source.internal.hbm.ModelBinder +logger.model-binder.level=debug +logger.java-type-descriptor-registry.name=org.hibernate.type.descriptor.java.JavaTypeDescriptorRegistry +logger.java-type-descriptor-registry.level=debug + + +logger.merged-entity-copies.name=org.hibernate.event.internal.EntityCopyAllowedLoggedObserver +### When entity copy merge functionality is enabled using: +### hibernate.event.merge.entity_copy_observer=log, the following will +### provide information about merged entity copies. +#logger.merged-entity-copies.level=debug + +logger.test-class-metadata.name=org.hibernate.testing.junit4.TestClassMetadata +logger.test-class-metadata.level=info +logger.test-class-metadata.appenderRef.unclosedSessionFactoryFile.ref=unclosedSessionFactoryFile +logger.scanning-coordinator.name=org.hibernate.boot.model.process.internal.ScanningCoordinator +logger.scanning-coordinator.level=debug diff --git a/tooling/metamodel-generator/src/test/resources/log4j.properties b/tooling/metamodel-generator/src/test/resources/log4j.properties deleted file mode 100644 index 319af3375c71..000000000000 --- a/tooling/metamodel-generator/src/test/resources/log4j.properties +++ /dev/null @@ -1,31 +0,0 @@ -# -# Hibernate, Relational Persistence for Idiomatic Java -# -# License: GNU Lesser General Public License (LGPL), version 2.1 or later. -# See the lgpl.txt file in the root directory or . -# - -### direct log messages to stdout ### -log4j.appender.stdout=org.apache.log4j.ConsoleAppender -log4j.appender.stdout.Target=System.out -log4j.appender.stdout.layout=org.apache.log4j.PatternLayout -log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n - -### direct messages to file hibernate.log ### -log4j.appender.file=org.apache.log4j.FileAppender -log4j.appender.file.File=hibernate.log -log4j.appender.file.layout=org.apache.log4j.PatternLayout -log4j.appender.file.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n - -### direct messages to socket - chainsaw ### -log4j.appender.socket=org.apache.log4j.net.SocketAppender -log4j.appender.socket.remoteHost=localhost -log4j.appender.socket.port=4560 -log4j.appender.socket.locationInfo=true - - -### set log levels - for more verbose logging change 'info' to 'debug' ### -log4j.rootLogger=warn, stdout - -#log4j.logger.org.hibernate.jpamodelgen.test.util.CompilationTest=trace - diff --git a/tooling/metamodel-generator/src/test/resources/log4j2.properties b/tooling/metamodel-generator/src/test/resources/log4j2.properties new file mode 100644 index 000000000000..096dfc1d710d --- /dev/null +++ b/tooling/metamodel-generator/src/test/resources/log4j2.properties @@ -0,0 +1,28 @@ +# +# Hibernate, Relational Persistence for Idiomatic Java +# +# License: GNU Lesser General Public License (LGPL), version 2.1 or later. +# See the lgpl.txt file in the root directory or . +# + +### direct log messages to stdout ### +appender.stdout.type=Console +appender.stdout.name=STDOUT +appender.stdout.layout.type=PatternLayout +appender.stdout.layout.pattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n + +### direct messages to file hibernate.log ### +appender.file.type=File +appender.file.name=file +appender.file.fileName=hibernate.log +appender.file.layout.type=PatternLayout +appender.file.layout.pattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n + + +### set log levels - for more verbose logging change 'info' to 'debug' ### +rootLogger.level=warn +rootLogger.appenderRef.stdout.ref=STDOUT + +logger.compilation-test.name=org.hibernate.jpamodelgen.test.util.CompilationTest +#logger.compilation-test.level=trace + From 19c774831cb5929024683cd1fa6e27318b48c120 Mon Sep 17 00:00:00 2001 From: Nathan Xu Date: Thu, 27 May 2021 12:48:12 -0400 Subject: [PATCH 177/644] HHH-14139 BasicBinder Trace Logging Causes Duplicated Message --- gradle/libraries.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libraries.gradle b/gradle/libraries.gradle index a317e76e8ab7..bbc3df82aa78 100644 --- a/gradle/libraries.gradle +++ b/gradle/libraries.gradle @@ -92,7 +92,7 @@ ext { jakarta_cdi: 'jakarta.enterprise:jakarta.enterprise.cdi-api:3.0.0', // logging - logging: 'org.jboss.logging:jboss-logging:3.4.1.Final', + logging: 'org.jboss.logging:jboss-logging:3.4.2.Final', logging_annotations: 'org.jboss.logging:jboss-logging-annotations:2.1.0.Final', logging_processor: 'org.jboss.logging:jboss-logging-processor:2.1.0.Final', From fa261190ecee6ad4e094fb4ae29523ef8f02a9d0 Mon Sep 17 00:00:00 2001 From: Gavin King Date: Thu, 17 Sep 2020 14:10:38 +0200 Subject: [PATCH 178/644] HHH-14240 Stop generating fragments of uppercase SQL Hibernate generates lowercase SQL. (Note that I already fixed all this in H6, but not in H5.) --- .../hibernate/dialect/InterbaseDialect.java | 8 +- .../hibernate/dialect/MariaDB103Dialect.java | 2 +- .../hibernate/dialect/Oracle8iDialect.java | 2 +- .../dialect/SQLServer2012Dialect.java | 2 +- .../hibernate/dialect/SQLServerDialect.java | 2 +- .../dialect/hint/IndexQueryHintHandler.java | 2 +- .../pagination/Informix10LimitHandler.java | 114 ++++---- .../pagination/SQLServer2005LimitHandler.java | 18 +- .../dialect/InformixLimitHandlerTestCase.java | 10 +- .../dialect/SQLServer2005DialectTestCase.java | 258 +++++++++--------- .../dialect/SQLServer2012DialectTestCase.java | 4 +- .../jpa/test/query/NamedQueryCommentTest.java | 2 +- 12 files changed, 212 insertions(+), 212 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/InterbaseDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/InterbaseDialect.java index 89958c5142e7..418753ed7608 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/InterbaseDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/InterbaseDialect.java @@ -77,7 +77,7 @@ public String getAddColumnString() { @Override public String getSequenceNextValString(String sequenceName) { - return "select " + getSelectSequenceNextValString( sequenceName ) + " from RDB$DATABASE"; + return "select " + getSelectSequenceNextValString( sequenceName ) + " from rdb$database"; } @Override @@ -92,12 +92,12 @@ public String getCreateSequenceString(String sequenceName) { @Override public String getDropSequenceString(String sequenceName) { - return "delete from RDB$GENERATORS where RDB$GENERATOR_NAME = '" + sequenceName.toUpperCase(Locale.ROOT) + "'"; + return "delete from rdb$generators where rdb$generator_name = '" + sequenceName.toUpperCase(Locale.ROOT) + "'"; } @Override public String getQuerySequencesString() { - return "select RDB$GENERATOR_NAME from RDB$GENERATORS"; + return "select rdb$generator_name from rdb$generators"; } @Override @@ -150,7 +150,7 @@ public String getCurrentTimestampSelectString() { // TODO : not sure which (either?) is correct, could not find docs on how to do this. // did find various blogs and forums mentioning that select CURRENT_TIMESTAMP // does not work... - return "{?= call CURRENT_TIMESTAMP }"; + return "{?= call current_timestamp }"; // return "select CURRENT_TIMESTAMP from RDB$DATABASE"; } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/MariaDB103Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/MariaDB103Dialect.java index a2e0de9dcaa5..b0731980aebe 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/MariaDB103Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/MariaDB103Dialect.java @@ -76,7 +76,7 @@ public String getSelectSequenceNextValString(String sequenceName) { @Override public String getQuerySequencesString() { - return "select table_name from information_schema.TABLES where table_schema = database() and table_type = 'SEQUENCE'"; + return "select table_name from information_schema.tables where table_schema = database() and table_type = 'SEQUENCE'"; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/Oracle8iDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/Oracle8iDialect.java index 5f0c25bac255..8cba9cff5922 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/Oracle8iDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/Oracle8iDialect.java @@ -745,7 +745,7 @@ public boolean canCreateSchema() { @Override public String getCurrentSchemaCommand() { - return "SELECT SYS_CONTEXT('USERENV', 'CURRENT_SCHEMA') FROM DUAL"; + return "select sys_context('USERENV', 'CURRENT_SCHEMA') from dual"; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServer2012Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServer2012Dialect.java index 90c461ac4609..5ecc7b3b8113 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServer2012Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServer2012Dialect.java @@ -49,7 +49,7 @@ public String getSequenceNextValString(String sequenceName) { @Override public String getQuerySequencesString() { // The upper-case name should work on both case-sensitive and case-insensitive collations. - return "select * from INFORMATION_SCHEMA.SEQUENCES"; + return "select * from information_schema.sequences"; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java index 7ac92fe1ac07..2c9542a003c7 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java @@ -124,7 +124,7 @@ public char closeQuote() { @Override public String getCurrentSchemaCommand() { - return "SELECT SCHEMA_NAME()"; + return "select schema_name()"; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/hint/IndexQueryHintHandler.java b/hibernate-core/src/main/java/org/hibernate/dialect/hint/IndexQueryHintHandler.java index 36ce81083a9a..26c004c008b2 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/hint/IndexQueryHintHandler.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/hint/IndexQueryHintHandler.java @@ -35,7 +35,7 @@ public String addQueryHints(String query, String hints) { String endToken = matcher.group( 2 ); return new StringBuilder( startToken ) - .append( " USE INDEX (" ) + .append( " use index (" ) .append( hints ) .append( ") " ) .append( endToken ) diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/pagination/Informix10LimitHandler.java b/hibernate-core/src/main/java/org/hibernate/dialect/pagination/Informix10LimitHandler.java index eecf677f4273..3943b483f732 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/pagination/Informix10LimitHandler.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/pagination/Informix10LimitHandler.java @@ -1,57 +1,57 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.dialect.pagination; - -import java.util.Locale; - -import org.hibernate.engine.spi.RowSelection; - -public class Informix10LimitHandler extends AbstractLimitHandler { - - public static final Informix10LimitHandler INSTANCE = new Informix10LimitHandler(); - - private Informix10LimitHandler() { - // Disallow instantiation - } - - @Override - public String processSql(String sql, RowSelection selection) { - final boolean hasOffset = LimitHelper.hasFirstRow( selection ); - String sqlOffset = hasOffset ? " SKIP " + selection.getFirstRow() : ""; - String sqlLimit = " FIRST " + getMaxOrLimit( selection ); - String sqlOffsetLimit = sqlOffset + sqlLimit; - String result = new StringBuilder( sql.length() + 10 ) - .append( sql ) - .insert( sql.toLowerCase( Locale.ROOT ).indexOf( "select" ) + 6, sqlOffsetLimit ).toString(); - return result; - } - - @Override - public boolean supportsLimit() { - return true; - } - - @Override - public boolean bindLimitParametersFirst() { - return true; - } - - @Override - public boolean useMaxForLimit() { - return false; - } - - @Override - public boolean supportsLimitOffset() { - return true; - } - - @Override - public boolean supportsVariableLimit() { - return false; - } -} +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.dialect.pagination; + +import java.util.Locale; + +import org.hibernate.engine.spi.RowSelection; + +public class Informix10LimitHandler extends AbstractLimitHandler { + + public static final Informix10LimitHandler INSTANCE = new Informix10LimitHandler(); + + private Informix10LimitHandler() { + // Disallow instantiation + } + + @Override + public String processSql(String sql, RowSelection selection) { + final boolean hasOffset = LimitHelper.hasFirstRow( selection ); + String sqlOffset = hasOffset ? " skip " + selection.getFirstRow() : ""; + String sqlLimit = " first " + getMaxOrLimit( selection ); + String sqlOffsetLimit = sqlOffset + sqlLimit; + String result = new StringBuilder( sql.length() + 10 ) + .append( sql ) + .insert( sql.toLowerCase( Locale.ROOT ).indexOf( "select" ) + 6, sqlOffsetLimit ).toString(); + return result; + } + + @Override + public boolean supportsLimit() { + return true; + } + + @Override + public boolean bindLimitParametersFirst() { + return true; + } + + @Override + public boolean useMaxForLimit() { + return false; + } + + @Override + public boolean supportsLimitOffset() { + return true; + } + + @Override + public boolean supportsVariableLimit() { + return false; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/pagination/SQLServer2005LimitHandler.java b/hibernate-core/src/main/java/org/hibernate/dialect/pagination/SQLServer2005LimitHandler.java index 789f6c3c221b..147488cdb0a3 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/pagination/SQLServer2005LimitHandler.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/pagination/SQLServer2005LimitHandler.java @@ -97,10 +97,10 @@ public int convertToFirstRowValue(int zeroBasedFirstResult) { *
     	 * WITH query AS (
     	 *   SELECT inner_query.*
    -	 *        , ROW_NUMBER() OVER (ORDER BY CURRENT_TIMESTAMP) as __hibernate_row_nr__
    +	 *        , ROW_NUMBER() OVER (ORDER BY CURRENT_TIMESTAMP) as __row__
     	 *     FROM ( original_query_with_top_if_order_by_present_and_all_aliased_columns ) inner_query
     	 * )
    -	 * SELECT alias_list FROM query WHERE __hibernate_row_nr__ >= offset AND __hibernate_row_nr__ < offset + last
    +	 * SELECT alias_list FROM query WHERE __row__ >= offset AND __row__ < offset + last
     	 * 
    * * When offset equals {@literal 0}, only TOP(?) expression is added to the original query. @@ -131,9 +131,9 @@ public String processSql(String sql, RowSelection selection) { encloseWithOuterQuery( sb, offset ); - sb.insert( offset, !isCTE ? "WITH query AS (" : ", query AS (" ); - sb.append( ") SELECT " ).append( selectClause ).append( " FROM query " ); - sb.append( "WHERE __hibernate_row_nr__ >= ? AND __hibernate_row_nr__ < ?" ); + sb.insert( offset, !isCTE ? "with query as (" : ", query as (" ); + sb.append( ") select " ).append( selectClause ).append( " from query " ); + sb.append( "where __row__ >= ? and __row__ < ?" ); } return sb.toString(); @@ -298,13 +298,13 @@ private String getAlias(String expression) { } /** - * Encloses original SQL statement with outer query that provides {@literal __hibernate_row_nr__} column. + * Encloses original SQL statement with outer query that provides {@literal __row__} column. * * @param sql SQL query. * @param offset SQL query offset. */ protected void encloseWithOuterQuery(StringBuilder sql, int offset) { - sql.insert( offset, "SELECT inner_query.*, ROW_NUMBER() OVER (ORDER BY CURRENT_TIMESTAMP) as __hibernate_row_nr__ FROM ( " ); + sql.insert( offset, "select inner_query.*, row_number() over (order by current_timestamp) as __row__ from ( " ); sql.append( " ) inner_query " ); } @@ -321,11 +321,11 @@ protected void addTopExpression(StringBuilder sql, int offset) { final int selectDistinctPos = shallowIndexOfPattern( sql, SELECT_DISTINCT_PATTERN, offset ); if ( selectPos == selectDistinctPos ) { // Place TOP after SELECT DISTINCT - sql.insert( selectDistinctPos + SELECT_DISTINCT.length(), " TOP(?)" ); + sql.insert( selectDistinctPos + SELECT_DISTINCT.length(), " top(?)" ); } else { // Place TOP after SELECT - sql.insert( selectPos + SELECT.length(), " TOP(?)" ); + sql.insert( selectPos + SELECT.length(), " top(?)" ); } topAdded = true; } diff --git a/hibernate-core/src/test/java/org/hibernate/dialect/InformixLimitHandlerTestCase.java b/hibernate-core/src/test/java/org/hibernate/dialect/InformixLimitHandlerTestCase.java index 2633fbe14a29..32f017488d0e 100644 --- a/hibernate-core/src/test/java/org/hibernate/dialect/InformixLimitHandlerTestCase.java +++ b/hibernate-core/src/test/java/org/hibernate/dialect/InformixLimitHandlerTestCase.java @@ -19,7 +19,7 @@ public class InformixLimitHandlerTestCase extends private Informix10LimitHandler informixLimitHandler; - private final String TEST_SQL = "SELECT field FROM table"; + private final String TEST_SQL = "select field from table"; @Before public void setup() { @@ -29,10 +29,10 @@ public void setup() { @Test @TestForIssue(jiraKey = "HHH-11509") public void testCorrectLimit() { - assertLimitHandlerEquals( "SELECT FIRST 10 field FROM table", 0, 10 ); - assertLimitHandlerEquals( "SELECT SKIP 3 FIRST 5 field FROM table", 3, 5 ); - assertLimitHandlerEquals( "SELECT SKIP 10 FIRST 5 field FROM table", 10, 5 ); - assertLimitHandlerEquals( "SELECT SKIP 55 FIRST 12 field FROM table", 55, 12 ); + assertLimitHandlerEquals( "select first 10 field from table", 0, 10 ); + assertLimitHandlerEquals( "select skip 3 first 5 field from table", 3, 5 ); + assertLimitHandlerEquals( "select skip 10 first 5 field from table", 10, 5 ); + assertLimitHandlerEquals( "select skip 55 first 12 field from table", 55, 12 ); } private void assertLimitHandlerEquals(String sql, int firstRow, int maxRows) { diff --git a/hibernate-core/src/test/java/org/hibernate/dialect/SQLServer2005DialectTestCase.java b/hibernate-core/src/test/java/org/hibernate/dialect/SQLServer2005DialectTestCase.java index e84df4a5bcc6..474dd7aa8393 100644 --- a/hibernate-core/src/test/java/org/hibernate/dialect/SQLServer2005DialectTestCase.java +++ b/hibernate-core/src/test/java/org/hibernate/dialect/SQLServer2005DialectTestCase.java @@ -45,19 +45,19 @@ public void testGetLimitString() { String input = "select distinct f1 as f53245 from table849752 order by f234, f67 desc"; assertEquals( - "with query as (select inner_query.*, row_number() over (order by current_timestamp) as __hibernate_row_nr__ from ( " + + "with query as (select inner_query.*, row_number() over (order by current_timestamp) as __row__ from ( " + "select distinct top(?) f1 as f53245 from table849752 order by f234, f67 desc ) inner_query )" + - " select f53245 from query where __hibernate_row_nr__ >= ? and __hibernate_row_nr__ < ?", + " select f53245 from query where __row__ >= ? and __row__ < ?", dialect.getLimitHandler().processSql( input, toRowSelection( 10, 15 ) ).toLowerCase(Locale.ROOT) ); } @Test @TestForIssue(jiraKey = "HHH-10736") public void testGetLimitStringWithNewlineAfterSelect() { - final String query = "select" + System.lineSeparator() + "* FROM Employee E WHERE E.firstName = :firstName"; + final String query = "select" + System.lineSeparator() + "* from Employee E where E.firstName = :firstName"; assertEquals( - "WITH query AS (SELECT inner_query.*, ROW_NUMBER() OVER (ORDER BY CURRENT_TIMESTAMP) as __hibernate_row_nr__ FROM ( " + - query + " ) inner_query ) SELECT * FROM query WHERE __hibernate_row_nr__ >= ? AND __hibernate_row_nr__ < ?", + "with query as (select inner_query.*, row_number() over (order by current_timestamp) as __row__ from ( " + + query + " ) inner_query ) select * from query where __row__ >= ? and __row__ < ?", dialect.getLimitHandler().processSql( query, toRowSelection( 1, 25 ) ) ); } @@ -65,10 +65,10 @@ public void testGetLimitStringWithNewlineAfterSelect() { @Test @TestForIssue(jiraKey = "HHH-10736") public void testGetLimitStringWithNewlineAfterSelectWithMultipleSpaces() { - final String query = "select " + System.lineSeparator() + "* FROM Employee E WHERE E.firstName = :firstName"; + final String query = "select " + System.lineSeparator() + "* from employee e where e.firstName = :firstName"; assertEquals( - "WITH query AS (SELECT inner_query.*, ROW_NUMBER() OVER (ORDER BY CURRENT_TIMESTAMP) as __hibernate_row_nr__ FROM ( " + - query + " ) inner_query ) SELECT * FROM query WHERE __hibernate_row_nr__ >= ? AND __hibernate_row_nr__ < ?", + "with query as (select inner_query.*, row_number() over (order by current_timestamp) as __row__ from ( " + + query + " ) inner_query ) select * from query where __row__ >= ? and __row__ < ?", dialect.getLimitHandler().processSql( query, toRowSelection( 1, 25 ) ) ); } @@ -76,12 +76,12 @@ public void testGetLimitStringWithNewlineAfterSelectWithMultipleSpaces() { @Test @TestForIssue(jiraKey = "HHH-8507") public void testGetLimitStringWithNewlineAfterColumnList() { - final String query = "select E.fieldA,E.fieldB\r\nFROM Employee E WHERE E.firstName = :firstName"; + final String query = "select e.fielda,e.fieldb\r\nfrom employee e where e.firstname = :firstname"; assertEquals( - "WITH query AS (SELECT inner_query.*, ROW_NUMBER() OVER (ORDER BY CURRENT_TIMESTAMP) as __hibernate_row_nr__ FROM ( " + - "select E.fieldA as page0_,E.fieldB as page1_\r\n" + - "FROM Employee E WHERE E.firstName = :firstName ) inner_query ) SELECT page0_, page1_ FROM query " + - "WHERE __hibernate_row_nr__ >= ? AND __hibernate_row_nr__ < ?", + "with query as (select inner_query.*, row_number() over (order by current_timestamp) as __row__ from ( " + + "select e.fielda as page0_,e.fieldb as page1_\r\n" + + "from employee e where e.firstname = :firstname ) inner_query ) select page0_, page1_ from query " + + "where __row__ >= ? and __row__ < ?", dialect.getLimitHandler().processSql( query, toRowSelection( 1, 25 ) ) ); } @@ -96,9 +96,9 @@ public void testGetLimitStringWithFromColumnName() { "where persistent0_.customerid=?"; assertEquals( - "WITH query AS (SELECT inner_query.*, ROW_NUMBER() OVER (ORDER BY CURRENT_TIMESTAMP) as __hibernate_row_nr__ FROM ( " + + "with query as (select inner_query.*, row_number() over (order by current_timestamp) as __row__ from ( " + fromColumnNameSQL + " ) inner_query ) " + - "SELECT rid1688_, deviati16_1688_, sortindex1688_ FROM query WHERE __hibernate_row_nr__ >= ? AND __hibernate_row_nr__ < ?", + "select rid1688_, deviati16_1688_, sortindex1688_ from query where __row__ >= ? and __row__ < ?", dialect.getLimitHandler().processSql( fromColumnNameSQL, toRowSelection( 1, 10 ) ) ); } @@ -109,9 +109,9 @@ public void testGetLimitStringAliasGeneration() { final String notAliasedSQL = "select column1, column2, column3, column4 from table1"; assertEquals( - "WITH query AS (SELECT inner_query.*, ROW_NUMBER() OVER (ORDER BY CURRENT_TIMESTAMP) as __hibernate_row_nr__ FROM ( " + + "with query as (select inner_query.*, row_number() over (order by current_timestamp) as __row__ from ( " + "select column1 as page0_, column2 as page1_, column3 as page2_, column4 as page3_ from table1 ) inner_query ) " + - "SELECT page0_, page1_, page2_, page3_ FROM query WHERE __hibernate_row_nr__ >= ? AND __hibernate_row_nr__ < ?", + "select page0_, page1_, page2_, page3_ from query where __row__ >= ? and __row__ < ?", dialect.getLimitHandler().processSql( notAliasedSQL, toRowSelection( 3, 5 ) ) ); } @@ -121,9 +121,9 @@ public void testGetLimitStringAliasGeneration() { public void testGetLimitStringAliasGenerationWithAliasesNoAs() { final String aliasedSQLNoAs = "select column1 c1, column c2, column c3, column c4 from table1"; assertEquals( - "WITH query AS (SELECT inner_query.*, ROW_NUMBER() OVER (ORDER BY CURRENT_TIMESTAMP) as __hibernate_row_nr__ FROM ( " + + "with query as (select inner_query.*, row_number() over (order by current_timestamp) as __row__ from ( " + "select column1 c1, column c2, column c3, column c4 from table1 ) inner_query ) " + - "SELECT c1, c2, c3, c4 FROM query WHERE __hibernate_row_nr__ >= ? AND __hibernate_row_nr__ < ?", + "select c1, c2, c3, c4 from query where __row__ >= ? and __row__ < ?", dialect.getLimitHandler().processSql( aliasedSQLNoAs, toRowSelection( 3, 5 ) ) ); } @@ -132,9 +132,9 @@ public void testGetLimitStringAliasGenerationWithAliasesNoAs() { @TestForIssue(jiraKey = "HHH-11352") public void testPagingWithColumnNameStartingWithFrom() { final String sql = "select column1 c1, from_column c2 from table1"; - assertEquals( "WITH query AS (SELECT inner_query.*, ROW_NUMBER() OVER (ORDER BY CURRENT_TIMESTAMP) as __hibernate_row_nr__ FROM ( " + + assertEquals( "with query as (select inner_query.*, row_number() over (order by current_timestamp) as __row__ from ( " + "select column1 c1, from_column c2 from table1 ) inner_query ) " + - "SELECT c1, c2 FROM query WHERE __hibernate_row_nr__ >= ? AND __hibernate_row_nr__ < ?", + "select c1, c2 from query where __row__ >= ? and __row__ < ?", dialect.getLimitHandler().processSql(sql, toRowSelection(3, 5))); } @@ -149,9 +149,9 @@ public void testGetLimitStringWithSubselect() { "where persistent0_.type='v'"; assertEquals( - "WITH query AS (SELECT inner_query.*, ROW_NUMBER() OVER (ORDER BY CURRENT_TIMESTAMP) as __hibernate_row_nr__ FROM ( " + + "with query as (select inner_query.*, row_number() over (order by current_timestamp) as __row__ from ( " + subselectInSelectClauseSQL + " ) inner_query ) " + - "SELECT col_0_0_, col_1_0_ FROM query WHERE __hibernate_row_nr__ >= ? AND __hibernate_row_nr__ < ?", + "select col_0_0_, col_1_0_ from query where __row__ >= ? and __row__ < ?", dialect.getLimitHandler().processSql( subselectInSelectClauseSQL, toRowSelection( 2, 5 ) ) ); } @@ -159,14 +159,14 @@ public void testGetLimitStringWithSubselect() { @Test @TestForIssue(jiraKey = "HHH-11084") public void testGetLimitStringWithSelectDistinctSubselect() { - final String selectDistinctSubselectSQL = "select page0_.CONTENTID as CONTENT1_12_ " + - "where page0_.CONTENTTYPE='PAGE' and (page0_.CONTENTID in " + - "(select distinct page2_.PREVVER from CONTENT page2_ where (page2_.PREVVER is not null)))"; + final String selectDistinctSubselectSQL = "select page0_.contentid as content1_12_ " + + "where page0_.contenttype='page' and (page0_.contentid in " + + "(select distinct page2_.prevver from content page2_ where (page2_.prevver is not null)))"; assertEquals( - "select TOP(?) page0_.CONTENTID as CONTENT1_12_ " + - "where page0_.CONTENTTYPE='PAGE' and (page0_.CONTENTID in " + - "(select distinct page2_.PREVVER from CONTENT page2_ where (page2_.PREVVER is not null)))", + "select top(?) page0_.contentid as content1_12_ " + + "where page0_.contenttype='page' and (page0_.contentid in " + + "(select distinct page2_.prevver from content page2_ where (page2_.prevver is not null)))", dialect.getLimitHandler().processSql( selectDistinctSubselectSQL, toRowSelection( 0, 5 ) ) ); } @@ -174,14 +174,14 @@ public void testGetLimitStringWithSelectDistinctSubselect() { @Test @TestForIssue(jiraKey = "HHH-11084") public void testGetLimitStringWithSelectDistinctSubselectNotFirst() { - final String selectDistinctSubselectSQL = "select page0_.CONTENTID as CONTENT1_12_ FROM CONTEXT page0_ " + - "where page0_.CONTENTTYPE='PAGE' and (page0_.CONTENTID in " + - "(select distinct page2_.PREVVER from CONTENT page2_ where (page2_.PREVVER is not null)))"; + final String selectDistinctSubselectSQL = "select page0_.contentid as content1_12_ from context page0_ " + + "where page0_.contenttype='page' and (page0_.contentid in " + + "(select distinct page2_.prevver from content page2_ where (page2_.prevver is not null)))"; assertEquals( - "WITH query AS (SELECT inner_query.*, ROW_NUMBER() OVER (ORDER BY CURRENT_TIMESTAMP) as __hibernate_row_nr__ " + - "FROM ( " + selectDistinctSubselectSQL + " ) inner_query ) " + - "SELECT CONTENT1_12_ FROM query WHERE __hibernate_row_nr__ >= ? AND __hibernate_row_nr__ < ?", + "with query as (select inner_query.*, row_number() over (order by current_timestamp) as __row__ " + + "from ( " + selectDistinctSubselectSQL + " ) inner_query ) " + + "select content1_12_ from query where __row__ >= ? and __row__ < ?", dialect.getLimitHandler().processSql( selectDistinctSubselectSQL, toRowSelection( 1, 5 ) ) ); } @@ -189,18 +189,18 @@ public void testGetLimitStringWithSelectDistinctSubselectNotFirst() { @Test @TestForIssue(jiraKey = "HHH-6728") public void testGetLimitStringCaseSensitive() { - final String caseSensitiveSQL = "select persistent0_.id, persistent0_.uid AS tmp1, " + + final String caseSensitiveSQL = "select persistent0_.id, persistent0_.uid as tmp1, " + "(select case when persistent0_.name = 'Smith' then 'Neo' else persistent0_.id end) " + - "from C_Customer persistent0_ " + + "from c_customer persistent0_ " + "where persistent0_.type='Va' " + "order by persistent0_.Order"; assertEquals( - "WITH query AS (SELECT inner_query.*, ROW_NUMBER() OVER (ORDER BY CURRENT_TIMESTAMP) as __hibernate_row_nr__ FROM ( " + - "select TOP(?) persistent0_.id as page0_, persistent0_.uid AS tmp1, " + + "with query as (select inner_query.*, row_number() over (order by current_timestamp) as __row__ from ( " + + "select top(?) persistent0_.id as page0_, persistent0_.uid as tmp1, " + "(select case when persistent0_.name = 'Smith' then 'Neo' else persistent0_.id end) as page1_ " + - "from C_Customer persistent0_ where persistent0_.type='Va' order by persistent0_.Order ) " + - "inner_query ) SELECT page0_, tmp1, page1_ FROM query WHERE __hibernate_row_nr__ >= ? AND __hibernate_row_nr__ < ?", + "from c_customer persistent0_ where persistent0_.type='Va' order by persistent0_.Order ) " + + "inner_query ) select page0_, tmp1, page1_ from query where __row__ >= ? and __row__ < ?", dialect.getLimitHandler().processSql( caseSensitiveSQL, toRowSelection( 1, 2 ) ) ); } @@ -211,9 +211,9 @@ public void testGetLimitStringDistinctWithinAggregation() { final String distinctInAggregateSQL = "select aggregate_function(distinct p.n) as f1 from table849752 p order by f1"; assertEquals( - "WITH query AS (SELECT inner_query.*, ROW_NUMBER() OVER (ORDER BY CURRENT_TIMESTAMP) as __hibernate_row_nr__ FROM ( " + - "select TOP(?) aggregate_function(distinct p.n) as f1 from table849752 p order by f1 ) inner_query ) " + - "SELECT f1 FROM query WHERE __hibernate_row_nr__ >= ? AND __hibernate_row_nr__ < ?", + "with query as (select inner_query.*, row_number() over (order by current_timestamp) as __row__ from ( " + + "select top(?) aggregate_function(distinct p.n) as f1 from table849752 p order by f1 ) inner_query ) " + + "select f1 from query where __row__ >= ? and __row__ < ?", dialect.getLimitHandler().processSql( distinctInAggregateSQL, toRowSelection( 2, 5 ) ) ); } @@ -224,9 +224,9 @@ public void testGetLimitStringDistinctWithinAggregationWithoutAlias() { final String distinctInAggregateSQL = "select aggregate_function(distinct p.n) from table849752 p order by f1"; assertEquals( - "WITH query AS (SELECT inner_query.*, ROW_NUMBER() OVER (ORDER BY CURRENT_TIMESTAMP) as __hibernate_row_nr__ FROM ( " + - "select TOP(?) aggregate_function(distinct p.n) as page0_ from table849752 p order by f1 ) inner_query ) " + - "SELECT page0_ FROM query WHERE __hibernate_row_nr__ >= ? AND __hibernate_row_nr__ < ?", + "with query as (select inner_query.*, row_number() over (order by current_timestamp) as __row__ from ( " + + "select top(?) aggregate_function(distinct p.n) as page0_ from table849752 p order by f1 ) inner_query ) " + + "select page0_ from query where __row__ >= ? and __row__ < ?", dialect.getLimitHandler().processSql( distinctInAggregateSQL, toRowSelection( 2, 5 ) ) ); } @@ -237,9 +237,9 @@ public void testGetLimitStringDistinctWithinAggregationWithAliasNoAs() { final String distinctInAggregateSQL = "select aggregate_function(distinct p.n) f1 from table849752 p order by f1"; assertEquals( - "WITH query AS (SELECT inner_query.*, ROW_NUMBER() OVER (ORDER BY CURRENT_TIMESTAMP) as __hibernate_row_nr__ FROM ( " + - "select TOP(?) aggregate_function(distinct p.n) f1 from table849752 p order by f1 ) inner_query ) " + - "SELECT f1 FROM query WHERE __hibernate_row_nr__ >= ? AND __hibernate_row_nr__ < ?", + "with query as (select inner_query.*, row_number() over (order by current_timestamp) as __row__ from ( " + + "select top(?) aggregate_function(distinct p.n) f1 from table849752 p order by f1 ) inner_query ) " + + "select f1 from query where __row__ >= ? and __row__ < ?", dialect.getLimitHandler().processSql( distinctInAggregateSQL, toRowSelection( 2, 5 ) ) ); } @@ -248,20 +248,20 @@ public void testGetLimitStringDistinctWithinAggregationWithAliasNoAs() { @TestForIssue(jiraKey = "HHH-7370") public void testGetLimitStringWithMaxOnly() { final String query = "select product2x0_.id as id0_, product2x0_.description as descript2_0_ " + - "from Product2 product2x0_ order by product2x0_.id"; + "from product2 product2x0_ order by product2x0_.id"; assertEquals( - "select TOP(?) product2x0_.id as id0_, product2x0_.description as descript2_0_ " + - "from Product2 product2x0_ order by product2x0_.id", + "select top(?) product2x0_.id as id0_, product2x0_.description as descript2_0_ " + + "from product2 product2x0_ order by product2x0_.id", dialect.getLimitHandler().processSql( query, toRowSelection( 0, 1 ) ) ); final String distinctQuery = "select distinct product2x0_.id as id0_, product2x0_.description as descript2_0_ " + - "from Product2 product2x0_ order by product2x0_.id"; + "from product2 product2x0_ order by product2x0_.id"; assertEquals( - "select distinct TOP(?) product2x0_.id as id0_, product2x0_.description as descript2_0_ " + - "from Product2 product2x0_ order by product2x0_.id", + "select distinct top(?) product2x0_.id as id0_, product2x0_.description as descript2_0_ " + + "from product2 product2x0_ order by product2x0_.id", dialect.getLimitHandler().processSql( distinctQuery, toRowSelection( 0, 5 ) ) ); } @@ -269,14 +269,14 @@ public void testGetLimitStringWithMaxOnly() { @Test @TestForIssue(jiraKey = "HHH-7781") public void testGetLimitStringWithCastOperator() { - final String query = "select cast(lc302_doku6_.redniBrojStavke as varchar(255)) as col_0_0_, lc302_doku6_.dokumentiID as col_1_0_ " + - "from LC302_Dokumenti lc302_doku6_ order by lc302_doku6_.dokumentiID DESC"; + final String query = "select cast(lc302_doku6_.rednibrojstavke as varchar(255)) as col_0_0_, lc302_doku6_.dokumentiid as col_1_0_ " + + "from lc302_dokumenti lc302_doku6_ order by lc302_doku6_.dokumentiid desc"; assertEquals( - "WITH query AS (SELECT inner_query.*, ROW_NUMBER() OVER (ORDER BY CURRENT_TIMESTAMP) as __hibernate_row_nr__ FROM ( " + - "select TOP(?) cast(lc302_doku6_.redniBrojStavke as varchar(255)) as col_0_0_, lc302_doku6_.dokumentiID as col_1_0_ " + - "from LC302_Dokumenti lc302_doku6_ order by lc302_doku6_.dokumentiID DESC ) inner_query ) " + - "SELECT col_0_0_, col_1_0_ FROM query WHERE __hibernate_row_nr__ >= ? AND __hibernate_row_nr__ < ?", + "with query as (select inner_query.*, row_number() over (order by current_timestamp) as __row__ from ( " + + "select top(?) cast(lc302_doku6_.rednibrojstavke as varchar(255)) as col_0_0_, lc302_doku6_.dokumentiid as col_1_0_ " + + "from lc302_dokumenti lc302_doku6_ order by lc302_doku6_.dokumentiid desc ) inner_query ) " + + "select col_0_0_, col_1_0_ from query where __row__ >= ? and __row__ < ?", dialect.getLimitHandler().processSql( query, toRowSelection( 1, 3 ) ) ); } @@ -284,14 +284,14 @@ public void testGetLimitStringWithCastOperator() { @Test @TestForIssue(jiraKey = "HHH-10994") public void testGetLimitStringWithCastOperatorWithAliasNoAs() { - final String query = "select cast(lc302_doku6_.redniBrojStavke as varchar(255)) f1, lc302_doku6_.dokumentiID f2 " + - "from LC302_Dokumenti lc302_doku6_ order by lc302_doku6_.dokumentiID DESC"; + final String query = "select cast(lc302_doku6_.rednibrojstavke as varchar(255)) f1, lc302_doku6_.dokumentiid f2 " + + "from lc302_dokumenti lc302_doku6_ order by lc302_doku6_.dokumentiid desc"; assertEquals( - "WITH query AS (SELECT inner_query.*, ROW_NUMBER() OVER (ORDER BY CURRENT_TIMESTAMP) as __hibernate_row_nr__ FROM ( " + - "select TOP(?) cast(lc302_doku6_.redniBrojStavke as varchar(255)) f1, lc302_doku6_.dokumentiID f2 " + - "from LC302_Dokumenti lc302_doku6_ order by lc302_doku6_.dokumentiID DESC ) inner_query ) " + - "SELECT f1, f2 FROM query WHERE __hibernate_row_nr__ >= ? AND __hibernate_row_nr__ < ?", + "with query as (select inner_query.*, row_number() over (order by current_timestamp) as __row__ from ( " + + "select top(?) cast(lc302_doku6_.rednibrojstavke as varchar(255)) f1, lc302_doku6_.dokumentiid f2 " + + "from lc302_dokumenti lc302_doku6_ order by lc302_doku6_.dokumentiid desc ) inner_query ) " + + "select f1, f2 from query where __row__ >= ? and __row__ < ?", dialect.getLimitHandler().processSql( query, toRowSelection( 1, 3 ) ) ); } @@ -299,14 +299,14 @@ public void testGetLimitStringWithCastOperatorWithAliasNoAs() { @Test @TestForIssue(jiraKey = "HHH-10994") public void testGetLimitStringWithCastOperatorWithoutAliases() { - final String query = "select cast(lc302_doku6_.redniBrojStavke as varchar(255)), lc302_doku6_.dokumentiID " + - "from LC302_Dokumenti lc302_doku6_ order by lc302_doku6_.dokumentiID DESC"; + final String query = "select cast(lc302_doku6_.rednibrojstavke as varchar(255)), lc302_doku6_.dokumentiid " + + "from lc302_dokumenti lc302_doku6_ order by lc302_doku6_.dokumentiid desc"; assertEquals( - "WITH query AS (SELECT inner_query.*, ROW_NUMBER() OVER (ORDER BY CURRENT_TIMESTAMP) as __hibernate_row_nr__ FROM ( " + - "select TOP(?) cast(lc302_doku6_.redniBrojStavke as varchar(255)) as page0_, lc302_doku6_.dokumentiID as page1_ " + - "from LC302_Dokumenti lc302_doku6_ order by lc302_doku6_.dokumentiID DESC ) inner_query ) " + - "SELECT page0_, page1_ FROM query WHERE __hibernate_row_nr__ >= ? AND __hibernate_row_nr__ < ?", + "with query as (select inner_query.*, row_number() over (order by current_timestamp) as __row__ from ( " + + "select top(?) cast(lc302_doku6_.rednibrojstavke as varchar(255)) as page0_, lc302_doku6_.dokumentiid as page1_ " + + "from lc302_dokumenti lc302_doku6_ order by lc302_doku6_.dokumentiid desc ) inner_query ) " + + "select page0_, page1_ from query where __row__ >= ? and __row__ < ?", dialect.getLimitHandler().processSql( query, toRowSelection( 1, 3 ) ) ); } @@ -317,9 +317,9 @@ public void testGetLimitStringSelectingMultipleColumnsFromSeveralTables() { final String query = "select t1.*, t2.* from tab1 t1, tab2 t2 where t1.ref = t2.ref order by t1.id desc"; assertEquals( - "WITH query AS (SELECT inner_query.*, ROW_NUMBER() OVER (ORDER BY CURRENT_TIMESTAMP) as __hibernate_row_nr__ FROM ( " + - "select TOP(?) t1.*, t2.* from tab1 t1, tab2 t2 where t1.ref = t2.ref order by t1.id desc ) inner_query ) " + - "SELECT * FROM query WHERE __hibernate_row_nr__ >= ? AND __hibernate_row_nr__ < ?", + "with query as (select inner_query.*, row_number() over (order by current_timestamp) as __row__ from ( " + + "select top(?) t1.*, t2.* from tab1 t1, tab2 t2 where t1.ref = t2.ref order by t1.id desc ) inner_query ) " + + "select * from query where __row__ >= ? and __row__ < ?", dialect.getLimitHandler().processSql( query, toRowSelection( 1, 3 ) ) ); } @@ -330,9 +330,9 @@ public void testGetLimitStringSelectingAllColumns() { final String query = "select * from tab1 t1, tab2 t2 where t1.ref = t2.ref order by t1.id desc"; assertEquals( - "WITH query AS (SELECT inner_query.*, ROW_NUMBER() OVER (ORDER BY CURRENT_TIMESTAMP) as __hibernate_row_nr__ FROM ( " + - "select TOP(?) * from tab1 t1, tab2 t2 where t1.ref = t2.ref order by t1.id desc ) inner_query ) " + - "SELECT * FROM query WHERE __hibernate_row_nr__ >= ? AND __hibernate_row_nr__ < ?", + "with query as (select inner_query.*, row_number() over (order by current_timestamp) as __row__ from ( " + + "select top(?) * from tab1 t1, tab2 t2 where t1.ref = t2.ref order by t1.id desc ) inner_query ) " + + "select * from query where __row__ >= ? and __row__ < ?", dialect.getLimitHandler().processSql( query, toRowSelection( 1, 3 ) ) ); } @@ -342,9 +342,9 @@ public void testGetLimitStringSelectingAllColumns() { public void testGetLimitStringWithFromInColumnName() { final String query = "select [Created From Nonstock Item], field2 from table1"; - assertEquals( "WITH query AS (SELECT inner_query.*, ROW_NUMBER() OVER (ORDER BY CURRENT_TIMESTAMP) as __hibernate_row_nr__ FROM ( " + + assertEquals( "with query as (select inner_query.*, row_number() over (order by current_timestamp) as __row__ from ( " + "select [Created From Nonstock Item] as page0_, field2 as page1_ from table1 ) inner_query ) " + - "SELECT page0_, page1_ FROM query WHERE __hibernate_row_nr__ >= ? AND __hibernate_row_nr__ < ?", + "select page0_, page1_ from query where __row__ >= ? and __row__ < ?", dialect.getLimitHandler().processSql( query, toRowSelection( 1, 5 ) ) ); } @@ -354,9 +354,9 @@ public void testGetLimitStringWithFromInColumnName() { public void testGetLimitStringWithQuotedColumnNamesAndAlias() { final String query = "select [Created From Item] c1, field2 from table1"; - assertEquals( "WITH query AS (SELECT inner_query.*, ROW_NUMBER() OVER (ORDER BY CURRENT_TIMESTAMP) as __hibernate_row_nr__ FROM ( " + + assertEquals( "with query as (select inner_query.*, row_number() over (order by current_timestamp) as __row__ from ( " + "select [Created From Item] c1, field2 as page0_ from table1 ) inner_query ) " + - "SELECT c1, page0_ FROM query WHERE __hibernate_row_nr__ >= ? AND __hibernate_row_nr__ < ?", + "select c1, page0_ from query where __row__ >= ? and __row__ < ?", dialect.getLimitHandler().processSql( query, toRowSelection( 1, 5 ) ) ); } @@ -366,9 +366,9 @@ public void testGetLimitStringWithQuotedColumnNamesAndAlias() { public void testGetLimitStringWithQuotedColumnNamesAndAliasWithAs() { final String query = "select [Created From Item] as c1, field2 from table1"; - assertEquals( "WITH query AS (SELECT inner_query.*, ROW_NUMBER() OVER (ORDER BY CURRENT_TIMESTAMP) as __hibernate_row_nr__ FROM ( " + + assertEquals( "with query as (select inner_query.*, row_number() over (order by current_timestamp) as __row__ from ( " + "select [Created From Item] as c1, field2 as page0_ from table1 ) inner_query ) " + - "SELECT c1, page0_ FROM query WHERE __hibernate_row_nr__ >= ? AND __hibernate_row_nr__ < ?", + "select c1, page0_ from query where __row__ >= ? and __row__ < ?", dialect.getLimitHandler().processSql( query, toRowSelection( 1, 5 ) ) ); } @@ -376,12 +376,12 @@ public void testGetLimitStringWithQuotedColumnNamesAndAliasWithAs() { @Test @TestForIssue(jiraKey = "HHH-11324") public void testGetLimitStringWithSelectClauseNestedQueryUsingParenthesis() { - final String query = "select t1.c1 as col_0_0, (select case when count(t2.c1)>0 then 'ADDED' else 'UNMODIFIED' end from table2 t2 WHERE (t2.c1 in (?))) as col_1_0 from table1 t1 WHERE 1=1 ORDER BY t1.c1 ASC"; + final String query = "select t1.c1 as col_0_0, (select case when count(t2.c1)>0 then 'added' else 'unmodified' end from table2 t2 where (t2.c1 in (?))) as col_1_0 from table1 t1 where 1=1 order by t1.c1 asc"; assertEquals( - "WITH query AS (SELECT inner_query.*, ROW_NUMBER() OVER (ORDER BY CURRENT_TIMESTAMP) as __hibernate_row_nr__ FROM ( " + - "select TOP(?) t1.c1 as col_0_0, (select case when count(t2.c1)>0 then 'ADDED' else 'UNMODIFIED' end from table2 t2 WHERE (t2.c1 in (?))) as col_1_0 from table1 t1 WHERE 1=1 ORDER BY t1.c1 ASC ) inner_query ) " + - "SELECT col_0_0, col_1_0 FROM query WHERE __hibernate_row_nr__ >= ? AND __hibernate_row_nr__ < ?", + "with query as (select inner_query.*, row_number() over (order by current_timestamp) as __row__ from ( " + + "select top(?) t1.c1 as col_0_0, (select case when count(t2.c1)>0 then 'added' else 'unmodified' end from table2 t2 where (t2.c1 in (?))) as col_1_0 from table1 t1 where 1=1 order by t1.c1 asc ) inner_query ) " + + "select col_0_0, col_1_0 from query where __row__ >= ? and __row__ < ?", dialect.getLimitHandler().processSql( query, toRowSelection( 1, 5 ) ) ); } @@ -389,11 +389,11 @@ public void testGetLimitStringWithSelectClauseNestedQueryUsingParenthesis() { @Test @TestForIssue(jiraKey = "HHH-11650") public void testGetLimitWithStringValueContainingParenthesis() { - final String query = "select t1.c1 as col_0_0 FROM table1 t1 where t1.c1 = '(123' ORDER BY t1.c1 ASC"; + final String query = "select t1.c1 as col_0_0 from table1 t1 where t1.c1 = '(123' order by t1.c1 asc"; assertEquals( - "WITH query AS (SELECT inner_query.*, ROW_NUMBER() OVER (ORDER BY CURRENT_TIMESTAMP) as __hibernate_row_nr__ FROM ( " + - "select TOP(?) t1.c1 as col_0_0 FROM table1 t1 where t1.c1 = '(123' ORDER BY t1.c1 ASC ) inner_query ) SELECT col_0_0 FROM query WHERE __hibernate_row_nr__ >= ? AND __hibernate_row_nr__ < ?", + "with query as (select inner_query.*, row_number() over (order by current_timestamp) as __row__ from ( " + + "select top(?) t1.c1 as col_0_0 from table1 t1 where t1.c1 = '(123' order by t1.c1 asc ) inner_query ) select col_0_0 from query where __row__ >= ? and __row__ < ?", dialect.getLimitHandler().processSql( query, toRowSelection( 1, 5 ) ) ); } @@ -401,10 +401,10 @@ public void testGetLimitWithStringValueContainingParenthesis() { @Test @TestForIssue(jiraKey = "HHH-11324") public void testGetLimitStringWithSelectClauseNestedQueryUsingParenthesisOnlyTop() { - final String query = "select t1.c1 as col_0_0, (select case when count(t2.c1)>0 then 'ADDED' else 'UNMODIFIED' end from table2 t2 WHERE (t2.c1 in (?))) as col_1_0 from table1 t1 WHERE 1=1 ORDER BY t1.c1 ASC"; + final String query = "select t1.c1 as col_0_0, (select case when count(t2.c1)>0 then 'ADDED' else 'UNMODIFIED' end from table2 t2 where (t2.c1 in (?))) as col_1_0 from table1 t1 where 1=1 order by t1.c1 asc"; assertEquals( - "select TOP(?) t1.c1 as col_0_0, (select case when count(t2.c1)>0 then 'ADDED' else 'UNMODIFIED' end from table2 t2 WHERE (t2.c1 in (?))) as col_1_0 from table1 t1 WHERE 1=1 ORDER BY t1.c1 ASC", + "select top(?) t1.c1 as col_0_0, (select case when count(t2.c1)>0 then 'ADDED' else 'UNMODIFIED' end from table2 t2 where (t2.c1 in (?))) as col_1_0 from table1 t1 where 1=1 order by t1.c1 asc", dialect.getLimitHandler().processSql( query, toRowSelection( 0, 5 ) ) ); } @@ -415,34 +415,34 @@ public void testGetLimitStringUsingCTEQueryNoOffset() { RowSelection selection = toRowSelection( 0, 5 ); // test top-based CTE with single CTE query definition with no odd formatting - final String query1 = "WITH a (c1, c2) AS (SELECT c1, c2 FROM t) SELECT c1, c2 FROM a"; + final String query1 = "with a (c1, c2) as (select c1, c2 from t) select c1, c2 from a"; assertEquals( - "WITH a (c1, c2) AS (SELECT c1, c2 FROM t) SELECT TOP(?) c1, c2 FROM a", + "with a (c1, c2) as (select c1, c2 from t) select top(?) c1, c2 from a", dialect.getLimitHandler().processSql( query1, selection ) ); // test top-based CTE with single CTE query definition and various tab, newline spaces - final String query2 = " \n\tWITH a (c1\n\t,c2)\t\nAS (SELECT\n\tc1,c2 FROM t)\t\nSELECT c1, c2 FROM a"; + final String query2 = " \n\twith a (c1\n\t,c2)\t\nas (select\n\tc1,c2 from t)\t\nselect c1, c2 from a"; assertEquals( - " \n\tWITH a (c1\n\t,c2)\t\nAS (SELECT\n\tc1,c2 FROM t)\t\nSELECT TOP(?) c1, c2 FROM a", + " \n\twith a (c1\n\t,c2)\t\nas (select\n\tc1,c2 from t)\t\nselect top(?) c1, c2 from a", dialect.getLimitHandler().processSql( query2, selection ) ); // test top-based CTE with multiple CTE query definitions with no odd formatting - final String query3 = "WITH a (c1, c2) AS (SELECT c1, c2 FROM t1), b (b1, b2) AS (SELECT b1, b2 FROM t2) " + - "SELECT c1, c2, b1, b2 FROM t1, t2 WHERE t1.c1 = t2.b1"; + final String query3 = "with a (c1, c2) as (select c1, c2 from t1), b (b1, b2) as (select b1, b2 from t2) " + + "select c1, c2, b1, b2 from t1, t2 where t1.c1 = t2.b1"; assertEquals( - "WITH a (c1, c2) AS (SELECT c1, c2 FROM t1), b (b1, b2) AS (SELECT b1, b2 FROM t2) " + - "SELECT TOP(?) c1, c2, b1, b2 FROM t1, t2 WHERE t1.c1 = t2.b1", + "with a (c1, c2) as (select c1, c2 from t1), b (b1, b2) as (select b1, b2 from t2) " + + "select top(?) c1, c2, b1, b2 from t1, t2 where t1.c1 = t2.b1", dialect.getLimitHandler().processSql( query3, selection ) ); // test top-based CTE with multiple CTE query definitions and various tab, newline spaces - final String query4 = " \n\r\tWITH a (c1, c2) AS\n\r (SELECT c1, c2 FROM t1)\n\r, b (b1, b2)\tAS\t" + - "(SELECT b1, b2 FROM t2) SELECT c1, c2, b1, b2 FROM t1, t2 WHERE t1.c1 = t2.b1"; + final String query4 = " \n\r\twith a (c1, c2) as\n\r (select c1, c2 from t1)\n\r, b (b1, b2)\tas\t" + + "(select b1, b2 from t2) select c1, c2, b1, b2 from t1, t2 where t1.c1 = t2.b1"; assertEquals( - " \n\r\tWITH a (c1, c2) AS\n\r (SELECT c1, c2 FROM t1)\n\r, b (b1, b2)\tAS\t(SELECT b1, b2 FROM t2)" + - " SELECT TOP(?) c1, c2, b1, b2 FROM t1, t2 WHERE t1.c1 = t2.b1", + " \n\r\twith a (c1, c2) as\n\r (select c1, c2 from t1)\n\r, b (b1, b2)\tas\t(select b1, b2 from t2)" + + " select top(?) c1, c2, b1, b2 from t1, t2 where t1.c1 = t2.b1", dialect.getLimitHandler().processSql( query4, selection ) ); } @@ -453,44 +453,44 @@ public void testGetLimitStringUsingCTEQueryWithOffset() { RowSelection selection = toRowSelection( 1, 5 ); // test non-top based CTE with single CTE query definition with no odd formatting - final String query1 = "WITH a (c1, c2) AS (SELECT c1, c2 FROM t) SELECT c1, c2 FROM a"; + final String query1 = "with a (c1, c2) as (select c1, c2 from t) select c1, c2 from a"; assertEquals( - "WITH a (c1, c2) AS (SELECT c1, c2 FROM t), query AS (SELECT inner_query.*, ROW_NUMBER() OVER " + - "(ORDER BY CURRENT_TIMESTAMP) as __hibernate_row_nr__ FROM ( SELECT c1 as page0_, c2 as page1_ " + - "FROM a ) inner_query ) SELECT page0_, page1_ FROM query WHERE __hibernate_row_nr__ >= ? " + - "AND __hibernate_row_nr__ < ?", + "with a (c1, c2) as (select c1, c2 from t), query as (select inner_query.*, row_number() over " + + "(order by current_timestamp) as __row__ from ( select c1 as page0_, c2 as page1_ " + + "from a ) inner_query ) select page0_, page1_ from query where __row__ >= ? " + + "and __row__ < ?", dialect.getLimitHandler().processSql( query1, selection ) ); // test non-top based CTE with single CTE query definition and various tab, newline spaces - final String query2 = " \n\tWITH a (c1\n\t,c2)\t\nAS (SELECT\n\tc1,c2 FROM t)\t\nSELECT c1, c2 FROM a"; + final String query2 = " \n\twith a (c1\n\t,c2)\t\nas (select\n\tc1,c2 from t)\t\nselect c1, c2 from a"; assertEquals( - " \n\tWITH a (c1\n\t,c2)\t\nAS (SELECT\n\tc1,c2 FROM t), query AS (SELECT inner_query.*, ROW_NUMBER()" + - " OVER (ORDER BY CURRENT_TIMESTAMP) as __hibernate_row_nr__ FROM ( \t\nSELECT c1 as page0_, c2 " + - "as page1_ FROM a ) inner_query ) SELECT page0_, page1_ FROM query WHERE __hibernate_row_nr__ >= " + - "? AND __hibernate_row_nr__ < ?", + " \n\twith a (c1\n\t,c2)\t\nas (select\n\tc1,c2 from t), query as (select inner_query.*, row_number()" + + " over (order by current_timestamp) as __row__ from ( \t\nselect c1 as page0_, c2 " + + "as page1_ from a ) inner_query ) select page0_, page1_ from query where __row__ >= " + + "? and __row__ < ?", dialect.getLimitHandler().processSql( query2, selection ) ); // test non-top based CTE with multiple CTE query definitions with no odd formatting - final String query3 = "WITH a (c1, c2) AS (SELECT c1, c2 FROM t1), b (b1, b2) AS (SELECT b1, b2 FROM t2) " + - " SELECT c1, c2, b1, b2 FROM t1, t2 WHERE t1.c1 = t2.b1"; + final String query3 = "with a (c1, c2) as (select c1, c2 from t1), b (b1, b2) as (select b1, b2 from t2) " + + " select c1, c2, b1, b2 from t1, t2 where t1.c1 = t2.b1"; assertEquals( - "WITH a (c1, c2) AS (SELECT c1, c2 FROM t1), b (b1, b2) AS (SELECT b1, b2 FROM t2), query AS (" + - "SELECT inner_query.*, ROW_NUMBER() OVER (ORDER BY CURRENT_TIMESTAMP) as __hibernate_row_nr__ FROM (" + - " SELECT c1 as page0_, c2 as page1_, b1 as page2_, b2 as page3_ FROM t1, t2 WHERE t1.c1 = t2.b1 ) inner_query )" + - " SELECT page0_, page1_, page2_, page3_ FROM query WHERE __hibernate_row_nr__ >= ? AND __hibernate_row_nr__ < ?", + "with a (c1, c2) as (select c1, c2 from t1), b (b1, b2) as (select b1, b2 from t2), query as (" + + "select inner_query.*, row_number() over (order by current_timestamp) as __row__ from (" + + " select c1 as page0_, c2 as page1_, b1 as page2_, b2 as page3_ from t1, t2 where t1.c1 = t2.b1 ) inner_query )" + + " select page0_, page1_, page2_, page3_ from query where __row__ >= ? and __row__ < ?", dialect.getLimitHandler().processSql( query3, selection ) ); // test top-based CTE with multiple CTE query definitions and various tab, newline spaces - final String query4 = " \n\r\tWITH a (c1, c2) AS\n\r (SELECT c1, c2 FROM t1)\n\r, b (b1, b2)\tAS\t(SELECT b1, " + - "b2 FROM t2) SELECT c1, c2, b1, b2 FROM t1, t2 WHERE t1.c1 = t2.b1"; + final String query4 = " \n\r\twith a (c1, c2) as\n\r (select c1, c2 from t1)\n\r, b (b1, b2)\tas\t(select b1, " + + "b2 from t2) select c1, c2, b1, b2 from t1, t2 where t1.c1 = t2.b1"; assertEquals( - " \n\r\tWITH a (c1, c2) AS\n\r (SELECT c1, c2 FROM t1)\n\r, b (b1, b2)\tAS\t(SELECT b1, b2 FROM t2), query AS (" + - "SELECT inner_query.*, ROW_NUMBER() OVER (ORDER BY CURRENT_TIMESTAMP) as __hibernate_row_nr__ FROM (" + - " SELECT c1 as page0_, c2 as page1_, b1 as page2_, b2 as page3_ FROM t1, t2 WHERE t1.c1 = t2.b1 ) inner_query )" + - " SELECT page0_, page1_, page2_, page3_ FROM query WHERE __hibernate_row_nr__ >= ? AND __hibernate_row_nr__ < ?", + " \n\r\twith a (c1, c2) as\n\r (select c1, c2 from t1)\n\r, b (b1, b2)\tas\t(select b1, b2 from t2), query as (" + + "select inner_query.*, row_number() over (order by current_timestamp) as __row__ from (" + + " select c1 as page0_, c2 as page1_, b1 as page2_, b2 as page3_ from t1, t2 where t1.c1 = t2.b1 ) inner_query )" + + " select page0_, page1_, page2_, page3_ from query where __row__ >= ? and __row__ < ?", dialect.getLimitHandler().processSql( query4, selection ) ); } diff --git a/hibernate-core/src/test/java/org/hibernate/dialect/SQLServer2012DialectTestCase.java b/hibernate-core/src/test/java/org/hibernate/dialect/SQLServer2012DialectTestCase.java index 468daf591f42..88ec294febfd 100644 --- a/hibernate-core/src/test/java/org/hibernate/dialect/SQLServer2012DialectTestCase.java +++ b/hibernate-core/src/test/java/org/hibernate/dialect/SQLServer2012DialectTestCase.java @@ -75,9 +75,9 @@ public void testGetLimitStringWithOffsetAndMaxRowsNoOrderBy() { // See SQLServer2012LimitHandler for why this falls back final String input = "select f1 from table"; assertEquals( - "with query as (select inner_query.*, row_number() over (order by current_timestamp) as __hibernate_row_nr__ " + + "with query as (select inner_query.*, row_number() over (order by current_timestamp) as __row__ " + "from ( select f1 as page0_ from table ) inner_query ) select page0_ from query where " + - "__hibernate_row_nr__ >= ? and __hibernate_row_nr__ < ?", + "__row__ >= ? and __row__ < ?", dialect.getLimitHandler().processSql( input, toRowSelection( 5, 10 ) ).toLowerCase( Locale.ROOT ) ); } diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/query/NamedQueryCommentTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/query/NamedQueryCommentTest.java index c0e07bcea0a6..163a78b22308 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/query/NamedQueryCommentTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/query/NamedQueryCommentTest.java @@ -207,7 +207,7 @@ public void testSelectNamedNativeQueryWithQueryHintUsingIndex() { sqlStatementInterceptor.assertExecutedCount(1); sqlStatementInterceptor.assertExecuted( - "/* COMMENT_SELECT_INDEX_game_title */ select namedquery0_.id as id1_0_, namedquery0_.title as title2_0_ from game namedquery0_ USE INDEX (idx_game_id) where namedquery0_.title=?" ) + "/* COMMENT_SELECT_INDEX_game_title */ select namedquery0_.id as id1_0_, namedquery0_.title as title2_0_ from game namedquery0_ use index (idx_game_id) where namedquery0_.title=?" ) ; } ); } From 2952b60cc33660c676efa7e55c7811e3431aa21b Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Thu, 20 May 2021 16:17:19 +0200 Subject: [PATCH 179/644] HHH-14624 add test --- .../test/pagination/OraclePaginationTest.java | 93 ++++--- .../OraclePaginationWithLocksTest.java | 253 ++++++++++++++++++ 2 files changed, 312 insertions(+), 34 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/pagination/OraclePaginationWithLocksTest.java diff --git a/hibernate-core/src/test/java/org/hibernate/test/pagination/OraclePaginationTest.java b/hibernate-core/src/test/java/org/hibernate/test/pagination/OraclePaginationTest.java index fda480877b0a..8e4caf63c834 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/pagination/OraclePaginationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/pagination/OraclePaginationTest.java @@ -16,6 +16,8 @@ import org.hibernate.testing.RequiresDialect; import org.hibernate.testing.TestForIssue; +import org.junit.After; +import org.junit.Before; import org.junit.Test; import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; @@ -34,39 +36,8 @@ protected Class[] getAnnotatedClasses() { }; } - @Entity(name = "RootEntity") - @Table(name = "V_MYTABLE_LAST") - public static class RootEntity implements Serializable { - - @Id - private Long id; - - @Id - private Long version; - - private String caption; - - private Long status; - - public RootEntity() { - } - - public RootEntity(Long id, Long version, String caption, Long status) { - this.id = id; - this.version = version; - this.caption = caption; - this.status = status; - } - - public Long getId() { - return id; - } - } - - @Test - @TestForIssue(jiraKey = "HHH-12087") - public void testPagination() throws Exception { - + @Before + public void setUp() { doInJPA( this::entityManagerFactory, entityManager -> { entityManager.persist( new RootEntity( 1L, 7L, "t40", 2L ) ); entityManager.persist( new RootEntity( 16L, 1L, "t47", 2L ) ); @@ -86,12 +57,26 @@ public void testPagination() throws Exception { entityManager.persist( new RootEntity( 5L, 6L, "t37", 1L ) ); entityManager.persist( new RootEntity( 13L, 1L, "t44", 1L ) ); } ); + } + + @After + public void tearDown() { + doInJPA( this::entityManagerFactory, entityManager -> { + entityManager.createQuery( "delete from RootEntity" ).executeUpdate(); + } ); + } + + @Test + @TestForIssue(jiraKey = "HHH-12087") + public void testPagination() { doInJPA( this::entityManagerFactory, entityManager -> { List rootEntitiesAllPages = getLimitedRows( entityManager, 0, 10 ); List rootEntitiesFirst = getLimitedRows( entityManager, 0, 5 ); + assertEquals( 5, rootEntitiesFirst.size() ); List rootEntitiesSecond = getLimitedRows( entityManager, 5, 10 ); + assertEquals( 10, rootEntitiesSecond.size() ); assertEquals( rootEntitiesAllPages.get( 0 ).getId(), rootEntitiesFirst.get( 0 ).getId() ); assertEquals( rootEntitiesAllPages.get( 1 ).getId(), rootEntitiesFirst.get( 1 ).getId() ); @@ -107,6 +92,20 @@ public void testPagination() throws Exception { } ); } + @Test + public void testPaginationWithSetMaxResultsOnly() { + doInJPA( this::entityManagerFactory, entityManager -> { + CriteriaBuilder cb = entityManager.getCriteriaBuilder(); + CriteriaQuery cq = cb.createQuery( RootEntity.class ); + Root c = cq.from( RootEntity.class ); + CriteriaQuery select = cq.select( c ).orderBy( cb.desc( c.get( "status" ) ) ); + TypedQuery typedQuery = entityManager.createQuery( select ); + typedQuery.setMaxResults( 10 ); + List resultList = typedQuery.getResultList(); + assertEquals( 10, resultList.size() ); + } ); + } + private List getAllRows(EntityManager em) { CriteriaBuilder cb = em.getCriteriaBuilder(); CriteriaQuery cq = cb.createQuery( RootEntity.class ); @@ -125,7 +124,33 @@ private List getLimitedRows(EntityManager em, int start, int end) { return typedQuery.getResultList(); } - private void createRootEntity(EntityManager entityManager, Long id, Long version, String caption, String status) { + @Entity(name = "RootEntity") + @Table(name = "V_MYTABLE_LAST") + public static class RootEntity implements Serializable { + + @Id + private Long id; + + @Id + private Long version; + + private String caption; + + private Long status; + + public RootEntity() { + } + + public RootEntity(Long id, Long version, String caption, Long status) { + this.id = id; + this.version = version; + this.caption = caption; + this.status = status; + } + public Long getId() { + return id; + } } + } diff --git a/hibernate-core/src/test/java/org/hibernate/test/pagination/OraclePaginationWithLocksTest.java b/hibernate-core/src/test/java/org/hibernate/test/pagination/OraclePaginationWithLocksTest.java new file mode 100644 index 000000000000..8aa64636ea6f --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/pagination/OraclePaginationWithLocksTest.java @@ -0,0 +1,253 @@ +package org.hibernate.test.pagination; + +import java.util.List; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; + +import org.hibernate.LockMode; +import org.hibernate.LockOptions; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.dialect.Oracle12cDialect; +import org.hibernate.resource.jdbc.spi.StatementInspector; + +import org.hibernate.testing.RequiresDialect; +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +@RequiresDialect(Oracle12cDialect.class) +@TestForIssue(jiraKey = "HHH-14624") +public class OraclePaginationWithLocksTest extends BaseCoreFunctionalTestCase { + private static final MostRecentStatementInspector mostRecentStatementInspector = new MostRecentStatementInspector(); + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { Person.class }; + } + + @Override + protected void configure(Configuration configuration) { + super.configure( configuration ); + configuration.getProperties().put( Environment.STATEMENT_INSPECTOR, mostRecentStatementInspector ); + } + + @Before + public void setUp() { + inTransaction( + session -> { + for ( int i = 0; i < 20; i++ ) { + session.persist( new Person( "name" + i ) ); + } + session.persist( new Person( "for update" ) ); + } + ); + } + + @After + public void tearDown() { + inTransaction( + session -> + session.createQuery( "delete from Person" ).executeUpdate() + + ); + } + + @Test + public void testNativeQuery() { + inTransaction( + session -> { + final List people = session.createNativeQuery( "select * from Person for update" ) + .setMaxResults( 10 ) + .list(); + assertEquals( 10, people.size() ); + assertFalse( mostRecentStatementInspector.sqlContains( "fetch" ) ); + } + ); + + inTransaction( + session -> { + final List people = session.createNativeQuery( "select * from Person" ) + .setMaxResults( 10 ) + .list(); + assertEquals( 10, people.size() ); + assertTrue( mostRecentStatementInspector.sqlContains( "fetch" ) ); + } + ); + + inTransaction( + session -> { + final List people = session.createNativeQuery( "select * from Person" ) + .setFirstResult( 3 ) + .setMaxResults( 10 ) + .list(); + assertEquals( 10, people.size() ); + assertTrue( mostRecentStatementInspector.sqlContains( "fetch" ) ); + } + ); + } + + @Test + public void testCriteriaQuery() { + inTransaction( + session -> { + final CriteriaQuery query = session.getCriteriaBuilder().createQuery( Person.class ); + final Root root = query.from( Person.class ); + query.select( root ); + final List people = session.createQuery( query ) + .setMaxResults( 10 ) + .setLockOptions( new LockOptions( LockMode.PESSIMISTIC_WRITE ).setFollowOnLocking( false ) ) + .getResultList(); + assertEquals( 10, people.size() ); + assertFalse( mostRecentStatementInspector.sqlContains( "fetch" ) ); + } + ); + + inTransaction( + session -> { + final CriteriaQuery query = session.getCriteriaBuilder().createQuery( Person.class ); + final Root root = query.from( Person.class ); + query.select( root ); + final List people = session.createQuery( query ) + .setMaxResults( 10 ) + .getResultList(); + assertEquals( 10, people.size() ); + assertTrue( mostRecentStatementInspector.sqlContains( "fetch" ) ); + } + ); + + inTransaction( + session -> { + final CriteriaQuery query = session.getCriteriaBuilder().createQuery( Person.class ); + final Root root = query.from( Person.class ); + query.select( root ); + final List people = session.createQuery( query ) + .setMaxResults( 10 ) + .setFirstResult( 2 ) + .getResultList(); + assertEquals( 10, people.size() ); + assertTrue( mostRecentStatementInspector.sqlContains( "fetch" ) ); + } + ); + + } + + @Test + public void testHqlQuery() { + inTransaction( + session -> { + List people = session.createQuery( + "select p from Person p", Person.class ) + .setMaxResults( 10 ) + .setLockOptions( new LockOptions( LockMode.PESSIMISTIC_WRITE ).setFollowOnLocking( false ) ) + .getResultList(); + assertEquals( 10, people.size() ); + assertFalse( mostRecentStatementInspector.sqlContains( "fetch" ) ); + } + ); + + inTransaction( + session -> { + List people = session.createQuery( + "select p from Person p", Person.class ) + .setMaxResults( 10 ) + .getResultList(); + assertEquals( 10, people.size() ); + assertTrue( mostRecentStatementInspector.sqlContains( "fetch" ) ); + } + ); + + inTransaction( + session -> { + List people = session.createQuery( + "select p from Person p", Person.class ) + .setFirstResult( 2 ) + .setMaxResults( 10 ) + .getResultList(); + assertEquals( 10, people.size() ); + assertEquals( 10, people.size() ); + assertTrue( mostRecentStatementInspector.sqlContains( "fetch" ) ); + } + ); + + inTransaction( + session -> { + List people = session.createQuery( + "select p from Person p where p.name = 'for update'", Person.class ) + .setMaxResults( 10 ) + .setLockOptions( new LockOptions( LockMode.PESSIMISTIC_WRITE ).setFollowOnLocking( false ) ) + .getResultList(); + assertEquals( 1, people.size() ); + assertFalse( mostRecentStatementInspector.sqlContains( "fetch" ) ); + } + ); + + inTransaction( + session -> { + List people = session.createQuery( + "select p from Person p where p.name = 'for update'", Person.class ) + .setMaxResults( 10 ) + .getResultList(); + assertEquals( 1, people.size() ); + assertTrue( mostRecentStatementInspector.sqlContains( "fetch" ) ); + } + ); + + + } + + private static class MostRecentStatementInspector implements StatementInspector { + private String mostRecentSql; + + public String inspect(String sql) { + mostRecentSql = sql; + return sql; + } + + public boolean sqlContains(String toCheck) { + return mostRecentSql.contains( toCheck ); + } + + } + + @Entity(name = "Person") + public static class Person { + @Id + @GeneratedValue + private Long id; + + private String name; + + public Person() { + } + + public Person(String name) { + this.name = name; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } +} From 422b80b80d5d87c1c70a00f5c83609a9c4eaca1a Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Thu, 20 May 2021 16:18:07 +0200 Subject: [PATCH 180/644] HHH-14624 Oracle from version 12 started supporting the syntax for pagination --- .../hibernate/dialect/Oracle12cDialect.java | 10 + .../dialect/pagination/LimitHandler.java | 15 +- .../pagination/Oracle12LimitHandler.java | 181 ++++++++++++++++++ .../java/org/hibernate/loader/Loader.java | 2 +- .../internal/AbstractLoadPlanBasedLoader.java | 2 +- 5 files changed, 207 insertions(+), 3 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/dialect/pagination/Oracle12LimitHandler.java diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/Oracle12cDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/Oracle12cDialect.java index 941159b4b458..e184c65e0c90 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/Oracle12cDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/Oracle12cDialect.java @@ -10,6 +10,9 @@ import org.hibernate.cfg.Environment; import org.hibernate.dialect.identity.IdentityColumnSupport; import org.hibernate.dialect.identity.Oracle12cIdentityColumnSupport; +import org.hibernate.dialect.pagination.AbstractLimitHandler; +import org.hibernate.dialect.pagination.LimitHandler; +import org.hibernate.dialect.pagination.Oracle12LimitHandler; import org.hibernate.engine.config.spi.ConfigurationService; import org.hibernate.engine.config.spi.StandardConverters; import org.hibernate.service.ServiceRegistry; @@ -24,6 +27,8 @@ public class Oracle12cDialect extends Oracle10gDialect { public static final String PREFER_LONG_RAW = "hibernate.dialect.oracle.prefer_long_raw"; + private static final AbstractLimitHandler LIMIT_HANDLER = Oracle12LimitHandler.INSTANCE; + public Oracle12cDialect() { super(); getDefaultProperties().setProperty( Environment.BATCH_VERSIONED_DATA, "true" ); @@ -62,4 +67,9 @@ public String getNativeIdentifierGeneratorStrategy() { public IdentityColumnSupport getIdentityColumnSupport() { return new Oracle12cIdentityColumnSupport(); } + + @Override + public LimitHandler getLimitHandler() { + return LIMIT_HANDLER; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/pagination/LimitHandler.java b/hibernate-core/src/main/java/org/hibernate/dialect/pagination/LimitHandler.java index 3013254bee5e..d0642b2277d1 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/pagination/LimitHandler.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/pagination/LimitHandler.java @@ -9,6 +9,7 @@ import java.sql.PreparedStatement; import java.sql.SQLException; +import org.hibernate.engine.spi.QueryParameters; import org.hibernate.engine.spi.RowSelection; /** @@ -37,13 +38,25 @@ public interface LimitHandler { /** * Return processed SQL query. * - * @param sql the SQL query to process. + * @param sql the SQL query to process. * @param selection the selection criteria for rows. * * @return Query statement with LIMIT clause applied. */ String processSql(String sql, RowSelection selection); + /** + * Return processed SQL query. + * + * @param sql the SQL query to process. + * @param queryParameters the queryParameters. + * + * @return Query statement with LIMIT clause applied. + */ + default String processSql(String sql, QueryParameters queryParameters ){ + return processSql( sql, queryParameters.getRowSelection() ); + } + /** * Bind parameter values needed by the LIMIT clause before original SELECT statement. * diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/pagination/Oracle12LimitHandler.java b/hibernate-core/src/main/java/org/hibernate/dialect/pagination/Oracle12LimitHandler.java new file mode 100644 index 000000000000..3067a01a818e --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/dialect/pagination/Oracle12LimitHandler.java @@ -0,0 +1,181 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.dialect.pagination; + +import java.util.Locale; + +import org.hibernate.LockMode; +import org.hibernate.LockOptions; +import org.hibernate.engine.spi.QueryParameters; +import org.hibernate.engine.spi.RowSelection; + +/** + * A {@link LimitHandler} for databases which support the + * ANSI SQL standard syntax {@code FETCH FIRST m ROWS ONLY} + * and {@code OFFSET n ROWS FETCH NEXT m ROWS ONLY}. + * + * @author Gavin King + */ +public class Oracle12LimitHandler extends AbstractLimitHandler { + + public boolean bindLimitParametersInReverseOrder; + public boolean useMaxForLimit; + + public static final Oracle12LimitHandler INSTANCE = new Oracle12LimitHandler(); + + Oracle12LimitHandler() { + } + + @Override + public String processSql(String sql, RowSelection selection) { + final boolean hasFirstRow = LimitHelper.hasFirstRow( selection ); + final boolean hasMaxRows = LimitHelper.hasMaxRows( selection ); + + if ( !hasMaxRows ) { + return sql; + } + + return processSql( sql, getForUpdateIndex( sql ), hasFirstRow ); + } + + @Override + public String processSql(String sql, QueryParameters queryParameters) { + final RowSelection selection = queryParameters.getRowSelection(); + + final boolean hasFirstRow = LimitHelper.hasFirstRow( selection ); + final boolean hasMaxRows = LimitHelper.hasMaxRows( selection ); + + if ( !hasMaxRows ) { + return sql; + } + + final LockOptions lockOptions = queryParameters.getLockOptions(); + if ( lockOptions != null ) { + final LockMode lockMode = lockOptions.getLockMode(); + switch ( lockMode ) { + case UPGRADE: + case PESSIMISTIC_READ: + case PESSIMISTIC_WRITE: + case UPGRADE_NOWAIT: + case FORCE: + case PESSIMISTIC_FORCE_INCREMENT: + case UPGRADE_SKIPLOCKED: + return processSql( sql, selection ); + default: + return processSqlOffsetFetch( sql, hasFirstRow ); + } + } + return processSqlOffsetFetch( sql, hasFirstRow ); + } + + private String processSqlOffsetFetch(String sql, boolean hasFirstRow) { + + final int forUpdateLastIndex = getForUpdateIndex( sql ); + + if ( forUpdateLastIndex > -1 ) { + return processSql( sql, forUpdateLastIndex, hasFirstRow ); + } + + bindLimitParametersInReverseOrder = false; + useMaxForLimit = false; + + sql = normalizeStatement( sql ); + final int offsetFetchLength; + final String offsetFetchString; + if ( hasFirstRow ) { + offsetFetchString = " offset ? rows fetch next ? rows only"; + } + else { + offsetFetchString = " fetch first ? rows only"; + } + offsetFetchLength = sql.length() + offsetFetchString.length(); + + return new StringBuilder( offsetFetchLength ).append( sql ).append( offsetFetchString ).toString(); + } + + private String processSql(String sql, int forUpdateIndex, boolean hasFirstRow) { + bindLimitParametersInReverseOrder = true; + useMaxForLimit = true; + sql = normalizeStatement( sql ); + + String forUpdateClause = null; + boolean isForUpdate = false; + if ( forUpdateIndex > -1 ) { + // save 'for update ...' and then remove it + forUpdateClause = sql.substring( forUpdateIndex ); + sql = sql.substring( 0, forUpdateIndex - 1 ); + isForUpdate = true; + } + + final StringBuilder pagingSelect; + + final int forUpdateClauseLength; + if ( forUpdateClause == null ) { + forUpdateClauseLength = 0; + } + else { + forUpdateClauseLength = forUpdateClause.length() + 1; + } + + if ( hasFirstRow ) { + pagingSelect = new StringBuilder( sql.length() + forUpdateClauseLength + 98 ); + pagingSelect.append( "select * from ( select row_.*, rownum rownum_ from ( " ); + pagingSelect.append( sql ); + pagingSelect.append( " ) row_ where rownum <= ?) where rownum_ > ?" ); + } + else { + pagingSelect = new StringBuilder( sql.length() + forUpdateClauseLength + 37 ); + pagingSelect.append( "select * from ( " ); + pagingSelect.append( sql ); + pagingSelect.append( " ) where rownum <= ?" ); + } + + if ( isForUpdate ) { + pagingSelect.append( " " ); + pagingSelect.append( forUpdateClause ); + } + + return pagingSelect.toString(); + } + + private String normalizeStatement(String sql) { + return sql.trim().replaceAll( "\\s+", " " ); + } + + private int getForUpdateIndex(String sql) { + final int forUpdateLastIndex = sql.toLowerCase( Locale.ROOT ).lastIndexOf( "for update" ); + // We need to recognize cases like : select a from t where b = 'for update'; + final int lastIndexOfQuote = sql.lastIndexOf( "'" ); + if ( forUpdateLastIndex > -1 ) { + if ( lastIndexOfQuote == -1 ) { + return forUpdateLastIndex; + } + if ( lastIndexOfQuote > forUpdateLastIndex ) { + return -1; + } + return forUpdateLastIndex; + } + return forUpdateLastIndex; + } + + @Override + public final boolean supportsLimit() { + return true; + } + + @Override + public boolean bindLimitParametersInReverseOrder() { + return bindLimitParametersInReverseOrder; + } + + @Override + public boolean useMaxForLimit() { + return useMaxForLimit; + } + + +} diff --git a/hibernate-core/src/main/java/org/hibernate/loader/Loader.java b/hibernate-core/src/main/java/org/hibernate/loader/Loader.java index db8e0e2fbeb4..5b8d2b87ed15 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/Loader.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/Loader.java @@ -2021,7 +2021,7 @@ protected SqlStatementWrapper executeQueryStatement( final LimitHandler limitHandler = getLimitHandler( queryParameters.getRowSelection() ); - String sql = limitHandler.processSql( queryParameters.getFilteredSQL(), queryParameters.getRowSelection() ); + String sql = limitHandler.processSql( queryParameters.getFilteredSQL(), queryParameters ); // Adding locks and comments. sql = preprocessSQL( sql, queryParameters, getFactory(), afterLoadActions ); diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/internal/AbstractLoadPlanBasedLoader.java b/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/internal/AbstractLoadPlanBasedLoader.java index eb320df4c7d2..ba906058aa19 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/internal/AbstractLoadPlanBasedLoader.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/internal/AbstractLoadPlanBasedLoader.java @@ -149,7 +149,7 @@ protected SqlStatementWrapper executeQueryStatement( final LimitHandler limitHandler = getLimitHandler( queryParameters.getRowSelection() ); - String sql = limitHandler.processSql( queryParameters.getFilteredSQL(), queryParameters.getRowSelection() ); + String sql = limitHandler.processSql( queryParameters.getFilteredSQL(), queryParameters ); // Adding locks and comments. sql = session.getJdbcServices().getJdbcEnvironment().getDialect() From fab2503981205a4bc9b381ab81fc11ddfb4dce11 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Tue, 1 Jun 2021 16:33:02 +0200 Subject: [PATCH 181/644] Update Jakarta XML Binding API to 3.0.1 --- gradle/libraries.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libraries.gradle b/gradle/libraries.gradle index bbc3df82aa78..1af583bc6c4e 100644 --- a/gradle/libraries.gradle +++ b/gradle/libraries.gradle @@ -87,7 +87,7 @@ ext { jakarta_interceptor: 'jakarta.interceptor:jakarta.interceptor-api:2.0.0', jakarta_activation: 'jakarta.activation:jakarta.activation-api:2.0.1', jakarta_resource: 'jakarta.resource:jakarta.resource-api:2.0.0', - jakarta_jaxb_api: 'jakarta.xml.bind:jakarta.xml.bind-api:3.0.0', + jakarta_jaxb_api: 'jakarta.xml.bind:jakarta.xml.bind-api:3.0.1', jakarta_jaxb_runtime: "org.glassfish.jaxb:jaxb-runtime:${jakartaJaxbRuntimeVersion}", jakarta_cdi: 'jakarta.enterprise:jakarta.enterprise.cdi-api:3.0.0', From 7a584223f81c61e872bafedebf3706f731fc2afe Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Tue, 1 Jun 2021 14:56:34 +0000 Subject: [PATCH 182/644] 5.5.0.Final --- changelog.txt | 17 +++++++++++++++++ gradle/version.properties | 2 +- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 45a2b4052b5d..7032ce85a2db 100644 --- a/changelog.txt +++ b/changelog.txt @@ -3,6 +3,23 @@ Hibernate 5 Changelog Note: Please refer to JIRA to learn more about each issue. +Changes in 5.5.0.Final (June 01, 2021) +------------------------------------------------------------------------------------------------------------------------ + +https://hibernate.atlassian.net/projects/HHH/versions/31946 + +** Bug + * [HHH-14139] - BasicBinder Trace Logging Causes Duplicated Message + +** Improvement + * [HHH-14632] - Call statistics.queryPlanCacheHit and statistics.queryPlanCacheMiss for FilterQueryPlan and NativeSQLQueryPlan + * [HHH-14624] - Oracle from version 12 started supporting the `offset ? rows fetch next ? rows only`syntax for pagination + * [HHH-14240] - Stop generating fragments of SQL as uppercase + +** Task + * [HHH-14635] - Upgrade to latest JUnit and to Log4j 2 + + Changes in 5.5.0.CR1 (May 24, 2021) ------------------------------------------------------------------------------------------------------------------------ diff --git a/gradle/version.properties b/gradle/version.properties index 27307e6e59d0..489815b34cca 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -hibernateVersion=5.5.0-SNAPSHOT \ No newline at end of file +hibernateVersion=5.5.0.Final \ No newline at end of file From bf48b81422b1913c9802517803b7348217135a1e Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Tue, 1 Jun 2021 15:02:43 +0000 Subject: [PATCH 183/644] 5.5.1-SNAPSHOT --- gradle/version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/version.properties b/gradle/version.properties index 489815b34cca..d5d6d7f95f05 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -hibernateVersion=5.5.0.Final \ No newline at end of file +hibernateVersion=5.5.1-SNAPSHOT \ No newline at end of file From 828afd348d2f3c2b9753bef686b19c98e4f37deb Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Wed, 2 Jun 2021 12:12:16 +0200 Subject: [PATCH 184/644] Parameterize Jenkins TCK pipelines and upload Jakarta JPA TCK results --- ci/jpa-2.2-tck.Jenkinsfile | 14 ++++++--- ci/jpa-3.0-tck.Jenkinsfile | 19 +++++++++---- tck/summary.md | 58 ++++++++++++++++++++++++++++++++++++++ 3 files changed, 82 insertions(+), 9 deletions(-) create mode 100644 tck/summary.md diff --git a/ci/jpa-2.2-tck.Jenkinsfile b/ci/jpa-2.2-tck.Jenkinsfile index 87e9aa7bab20..396536f53c0b 100644 --- a/ci/jpa-2.2-tck.Jenkinsfile +++ b/ci/jpa-2.2-tck.Jenkinsfile @@ -7,6 +7,9 @@ pipeline { tools { jdk 'OpenJDK 8 Latest' } + parameters { + booleanParam(name: 'NO_SLEEP', defaultValue: true, description: 'Whether the NO_SLEEP patch should be applied to speed up the TCK execution') + } stages { stage('Build') { steps { @@ -39,18 +42,21 @@ pipeline { steps { sh """ \ docker rm -f tck || true - docker run -v ~/.m2/repository/org/hibernate:/root/.m2/repository/org/hibernate:z -e NO_SLEEP=true -e HIBERNATE_VERSION=$HIBERNATE_VERSION --name tck jakarta-tck-runner - docker cp tck:/tck/persistence-tck/tmp/JTreport/ ./JTreport + docker rm -f tck-vol || true + docker volume create tck-vol + docker run -v ~/.m2/repository/org/hibernate:/root/.m2/repository/org/hibernate:z -v tck-vol:/tck/persistence-tck/tmp/:z -e NO_SLEEP=${params.NO_SLEEP} -e HIBERNATE_VERSION=$HIBERNATE_VERSION --name tck jakarta-tck-runner + docker cp tck:/tck/persistence-tck/tmp/ ./results """ - archiveArtifacts artifacts: 'JTreport/**' + archiveArtifacts artifacts: 'results/**' script { failures = sh ( script: """ \ + set +x while read line; do if [[ "\$line" != *"Passed." ]]; then echo "\$line" fi - done Date: Wed, 2 Jun 2021 15:44:15 +0100 Subject: [PATCH 185/644] HHH-14646 Updating the migration guide for 5.5 --- migration-guide.adoc | 40 ++++++++++++++-------------------------- 1 file changed, 14 insertions(+), 26 deletions(-) diff --git a/migration-guide.adoc b/migration-guide.adoc index 1614b2d28494..e2700b165ed2 100644 --- a/migration-guide.adoc +++ b/migration-guide.adoc @@ -1,7 +1,7 @@ -= 5.4 Migration Guide += 5.5 Migration Guide :toc: -This guide discusses migration from Hibernate ORM version 5.3 to version 5.4. For migration from +This guide discusses migration from Hibernate ORM version 5.4 to version 5.5. For migration from earlier versions, see any other pertinent migration guides as well. == Background @@ -9,33 +9,21 @@ earlier versions, see any other pertinent migration guides as well. == Known changes -=== Overriding Delayed Identity Insert Behavior +This version is very similar to Hibernate ORM 5.4; essentially it includes all bugfixes that have been +applied to the 5.4 maintenance releases, and on top of this it introduces support for the Jakarta Persistence +API (in addition the the JPA APIs we already support). -In Hibernate 5.3, we added support for `DelayedPostInsertIdentifier` behavior to be influenced based on the -`FlushMode` or `FlushModeType` values, in short enhancing Extended PersistenceContext support. Unfortunately, -there were a few side effects that were recently reported with this change. -In Hibernate 5.4, we wanted to preserve as much of the 5.3 behavior as possible and only restore very specific -`DelayedPostInsertIdentifier` behavior for selected use cases. +=== Dom4J based XML mapping -We understand mappings can be complex and there very well could be a corner case we didn't consider. In order -to make 5.4 as flexible with these changes as possible, we added a configuration option that you can use as a -_temporary_ solution to completely disable the 5.3 behavior, reverting it back to 5.2 and prior. +The implementation of Hibernate's parsing of XML mapping definitions has been entirely reimplemented based on +JAXB rather than DOM4J, making progress to remove this ancient dependency. +No specific issues are known at this time. -`hibernate.id.disable_delayed_identity_inserts=true` +=== Removed the ability to disable "enhanced proxies" -If you find you need to use this configuration setting, be sure to report the mapping to us in a JIRA issue so -that we can review it and determine if the mapping corner case should be included in our algorithm since the -configuration setting is meant to bridge behavior support for this across a few releases. +The "enhanced proxies" feature has been introduced as a performance improving feature in 5.3 initially, at +which time it was optional. -=== Hibernate Spatial depends on JTS 1.16 - -Hibernate Spatial depends on the https://github.com/locationtech/jts[Java Topology Suite (JTS)]. In 5.4 this - dependency has been upgraded to version 1.16. This implies a change in package naming: - all `com.vividsolutions.jts.\*` packages have been renamed to `org.locationtech.jts.*`. - -See https://github.com/locationtech/jts/blob/master/MIGRATION.md[the JTS Migration guide] for more information. - -=== SQL Server JDBC Driver version upgrade to at least 6.1.2 - -Due to fixing https://hibernate.atlassian.net/browse/HHH-12973[HHH-12973], you need to upgrade the JDBC Driver version to at least 6.1.2. Due to https://github.com/Microsoft/mssql-jdbc/issues/91[this bug], the older versions of the SQL Server JDBC Driver cannot introspect the `INFORMATION_SCHEMA.SEQUENCES` without closing the database connection. +Since then, many more corner cases have been fixed and this feature is now always enabled. Enjoy the improvements! +No changes are expected to be needed in user code to benefit from this. From c490e86fccdd357c5ddc4182ea5e4e8691fa5c95 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Wed, 2 Jun 2021 19:24:10 +0200 Subject: [PATCH 186/644] Fix issues with JPA 3.0 TCK run with alternative base image --- ci/jpa-3.0-tck.Jenkinsfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ci/jpa-3.0-tck.Jenkinsfile b/ci/jpa-3.0-tck.Jenkinsfile index 415e17f27cc6..03ea50515932 100644 --- a/ci/jpa-3.0-tck.Jenkinsfile +++ b/ci/jpa-3.0-tck.Jenkinsfile @@ -8,7 +8,7 @@ pipeline { jdk 'OpenJDK 8 Latest' } parameters { - string(name: 'BASE_IMAGE', defaultValue: 'openjdk:8-jdk', description: 'The JDK base image to use for the image i.e. `openjdk:11-jdk`') + choice(name: 'IMAGE_JDK', choices: ['jdk8', 'jdk11'], description: 'The JDK base image version to use for the TCK image.') string(name: 'TCK_VERSION', defaultValue: '3.0.0', description: 'The version of the Jakarta JPA TCK i.e. `2.2.0` or `3.0.1`') string(name: 'TCK_SHA', defaultValue: 'b08c8887f00306f8bb7ebe54c4c810f3452519f5395733637ccc639b5081aebf', description: 'The SHA256 of the Jakarta JPA TCK that is distributed under https://download.eclipse.org/jakartaee/persistence/3.0/jakarta-persistence-tck-${TCK_VERSION}.zip.sha256') booleanParam(name: 'NO_SLEEP', defaultValue: true, description: 'Whether the NO_SLEEP patch should be applied to speed up the TCK execution') @@ -36,7 +36,7 @@ pipeline { dir('tck') { checkout changelog: false, poll: false, scm: [$class: 'GitSCM', branches: [[name: '*/main']], extensions: [], userRemoteConfigs: [[url: 'https://github.com/hibernate/jakarta-tck-runner.git']]] sh """ \ - cd jpa-3.0; docker build -t jakarta-tck-runner --build-arg JDK_IMAGE=${params.BASE_IMAGE} --build-arg TCK_VERSION=${params.TCK_VERSION} --build-arg TCK_SHA=${params.TCK_SHA} . + cd jpa-3.0; docker build -f Dockerfile.${params.IMAGE_JDK} -t jakarta-tck-runner --build-arg JDK_IMAGE=${params.BASE_IMAGE} --build-arg TCK_VERSION=${params.TCK_VERSION} --build-arg TCK_SHA=${params.TCK_SHA} . """ } } From df48d19bbc370f89b5aa0915640b9bc6c3e77a43 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Wed, 2 Jun 2021 16:50:03 +0100 Subject: [PATCH 187/644] HHH-14647 Make ResourceRegistryStandardImpl#unassociatedResultSets lazily initialized --- .../jdbc/internal/ResourceRegistryStandardImpl.java | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/resource/jdbc/internal/ResourceRegistryStandardImpl.java b/hibernate-core/src/main/java/org/hibernate/resource/jdbc/internal/ResourceRegistryStandardImpl.java index 5c31b2f014ce..f8dbe76362a0 100644 --- a/hibernate-core/src/main/java/org/hibernate/resource/jdbc/internal/ResourceRegistryStandardImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/resource/jdbc/internal/ResourceRegistryStandardImpl.java @@ -52,7 +52,7 @@ public final class ResourceRegistryStandardImpl implements ResourceRegistry { private final JdbcObserver jdbcObserver; private final HashMap> xref = new HashMap<>(); - private final HashMap unassociatedResultSets = new HashMap(); + private HashMap unassociatedResultSets; private ArrayList blobs; private ArrayList clobs; @@ -138,7 +138,7 @@ public void release(ResultSet resultSet, Statement statement) { } } else { - final Object removed = unassociatedResultSets.remove( resultSet ); + final Object removed = unassociatedResultSets == null ? null : unassociatedResultSets.remove( resultSet ); if ( removed == null ) { log.unregisteredResultSetWithoutStatement(); } @@ -147,6 +147,9 @@ public void release(ResultSet resultSet, Statement statement) { } private static void closeAll(final HashMap resultSets) { + if ( resultSets == null ) { + return; + } resultSets.forEach( (resultSet, o) -> close( resultSet ) ); resultSets.clear(); } @@ -234,6 +237,9 @@ public void register(ResultSet resultSet, Statement statement) { resultSets.put( resultSet, PRESENT ); } else { + if ( unassociatedResultSets == null ) { + this.unassociatedResultSets = new HashMap(); + } unassociatedResultSets.put( resultSet, PRESENT ); } } From c22393d57b1368414b35265f881619bcdf81726f Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Wed, 2 Jun 2021 17:07:18 +0100 Subject: [PATCH 188/644] HHH-14650 Optimise AbstractRowReader for iterations on entity initializers --- .../exec/process/internal/AbstractRowReader.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/process/internal/AbstractRowReader.java b/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/process/internal/AbstractRowReader.java index 32f8b01870ea..dfd5be870e98 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/process/internal/AbstractRowReader.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/process/internal/AbstractRowReader.java @@ -46,7 +46,9 @@ public abstract class AbstractRowReader implements RowReader { private static final Logger log = CoreLogging.logger( AbstractRowReader.class ); - private final List entityReferenceInitializers; + private static final EntityReferenceInitializer[] EMPTY_REFERENCE_INITIALIZERS = new EntityReferenceInitializer[0]; + + private final EntityReferenceInitializer[] entityReferenceInitializers; private final List arrayReferenceInitializers; private final List collectionReferenceInitializers; @@ -56,11 +58,9 @@ public abstract class AbstractRowReader implements RowReader { public AbstractRowReader(ReaderCollector readerCollector) { if ( CollectionHelper.isNotEmpty( readerCollector.getEntityReferenceInitializers() ) ) { - entityReferenceInitializers = new ArrayList( - readerCollector.getEntityReferenceInitializers() - ); + entityReferenceInitializers = readerCollector.getEntityReferenceInitializers().toArray( EMPTY_REFERENCE_INITIALIZERS ); entityInitializerByEntityReference = - new HashMap( entityReferenceInitializers.size() ); + new HashMap( entityReferenceInitializers.length ); for ( EntityReferenceInitializer entityReferenceInitializer : entityReferenceInitializers ) { entityInitializerByEntityReference.put( entityReferenceInitializer.getEntityReference(), @@ -69,7 +69,7 @@ public AbstractRowReader(ReaderCollector readerCollector) { } } else { - entityReferenceInitializers = Collections.emptyList(); + entityReferenceInitializers = EMPTY_REFERENCE_INITIALIZERS; entityInitializerByEntityReference = Collections.emptyMap(); } this.arrayReferenceInitializers = readerCollector.getArrayReferenceInitializers(); @@ -82,7 +82,7 @@ protected abstract Object readLogicalRow(ResultSet resultSet, ResultSetProcessin @Override public Object readRow(ResultSet resultSet, ResultSetProcessingContextImpl context) throws SQLException { - final boolean hasEntityReferenceInitializers = CollectionHelper.isNotEmpty( entityReferenceInitializers ); + final boolean hasEntityReferenceInitializers = entityReferenceInitializers.length != 0; if ( hasEntityReferenceInitializers ) { // 1) allow entity references to resolve identifiers (in 2 steps) From fb69172a4b0f42741b3b48b73dc01c2f1bcbd95c Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Thu, 3 Jun 2021 10:07:19 +0100 Subject: [PATCH 189/644] HHH-14650 AbstractRowReader: no need to pre-compute the entityInitializerByEntityReference cache in advance --- .../process/internal/AbstractRowReader.java | 45 ++++++++----------- 1 file changed, 19 insertions(+), 26 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/process/internal/AbstractRowReader.java b/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/process/internal/AbstractRowReader.java index dfd5be870e98..c511fd61ad37 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/process/internal/AbstractRowReader.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/process/internal/AbstractRowReader.java @@ -8,7 +8,6 @@ import java.sql.ResultSet; import java.sql.SQLException; -import java.util.ArrayList; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -16,12 +15,9 @@ import org.hibernate.engine.internal.TwoPhaseLoad; import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.event.service.spi.EventListenerRegistry; import org.hibernate.event.spi.EventSource; -import org.hibernate.event.spi.EventType; import org.hibernate.event.spi.PostLoadEvent; import org.hibernate.event.spi.PreLoadEvent; -import org.hibernate.event.spi.PreLoadEventListener; import org.hibernate.internal.CoreLogging; import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.loader.plan.exec.process.spi.CollectionReferenceInitializer; @@ -54,24 +50,10 @@ public abstract class AbstractRowReader implements RowReader { // cache map for looking up EntityReferenceInitializer by EntityReference to help with resolving // bidirectional EntityReference and fetches. - private final Map entityInitializerByEntityReference; + private Map entityInitializerByEntityReference; public AbstractRowReader(ReaderCollector readerCollector) { - if ( CollectionHelper.isNotEmpty( readerCollector.getEntityReferenceInitializers() ) ) { - entityReferenceInitializers = readerCollector.getEntityReferenceInitializers().toArray( EMPTY_REFERENCE_INITIALIZERS ); - entityInitializerByEntityReference = - new HashMap( entityReferenceInitializers.length ); - for ( EntityReferenceInitializer entityReferenceInitializer : entityReferenceInitializers ) { - entityInitializerByEntityReference.put( - entityReferenceInitializer.getEntityReference(), - entityReferenceInitializer - ); - } - } - else { - entityReferenceInitializers = EMPTY_REFERENCE_INITIALIZERS; - entityInitializerByEntityReference = Collections.emptyMap(); - } + this.entityReferenceInitializers = readerCollector.getEntityReferenceInitializers().toArray( EMPTY_REFERENCE_INITIALIZERS ); this.arrayReferenceInitializers = readerCollector.getArrayReferenceInitializers(); this.collectionReferenceInitializers = readerCollector.getNonArrayCollectionReferenceInitializers(); } @@ -148,9 +130,7 @@ private void resolveEntityKey( FetchSource fetchSource) throws SQLException { // Resolve any bidirectional entity references first. for ( BidirectionalEntityReference bidirectionalEntityReference : fetchSource.getBidirectionalEntityReferences() ) { - final EntityReferenceInitializer targetEntityReferenceInitializer = entityInitializerByEntityReference.get( - bidirectionalEntityReference.getTargetEntityReference() - ); + final EntityReferenceInitializer targetEntityReferenceInitializer = getInitializerByEntityReference( bidirectionalEntityReference.getTargetEntityReference() ); resolveEntityKey( resultSet, context, @@ -161,9 +141,7 @@ private void resolveEntityKey( for ( Fetch fetch : fetchSource.getFetches() ) { if ( EntityFetch.class.isInstance( fetch ) ) { final EntityFetch entityFetch = (EntityFetch) fetch; - final EntityReferenceInitializer entityReferenceInitializer = entityInitializerByEntityReference.get( - entityFetch - ); + final EntityReferenceInitializer entityReferenceInitializer = getInitializerByEntityReference( entityFetch ); if ( entityReferenceInitializer != null ) { resolveEntityKey( resultSet, @@ -183,6 +161,21 @@ else if ( CompositeFetch.class.isInstance( fetch ) ) { } } + private EntityReferenceInitializer getInitializerByEntityReference(EntityReference targetEntityReference) { + if ( entityInitializerByEntityReference == null ) { + entityInitializerByEntityReference = new HashMap<>( entityReferenceInitializers.length ); + for ( EntityReferenceInitializer entityReferenceInitializer : entityReferenceInitializers ) { + entityInitializerByEntityReference.put( + entityReferenceInitializer.getEntityReference(), + entityReferenceInitializer + ); + } + } + return entityInitializerByEntityReference.get( + targetEntityReference + ); + } + @Override public void finishUp(ResultSetProcessingContextImpl context, List afterLoadActionList) { final List hydratedEntityRegistrations = context.getHydratedEntityRegistrationList(); From 84e7c5f63ba97823a95ddb8c0553e6ee1c3196be Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Thu, 3 Jun 2021 10:12:26 +0100 Subject: [PATCH 190/644] HHH-14650 AbstractRowReader: remove unnecessary nullchecks --- .../exec/process/internal/AbstractRowReader.java | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/process/internal/AbstractRowReader.java b/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/process/internal/AbstractRowReader.java index c511fd61ad37..56db17060e87 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/process/internal/AbstractRowReader.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/process/internal/AbstractRowReader.java @@ -97,15 +97,11 @@ public Object readRow(ResultSet resultSet, ResultSetProcessingContextImpl contex entityReferenceInitializer.finishUpRow( resultSet, context ); } } - if ( collectionReferenceInitializers != null ) { - for ( CollectionReferenceInitializer collectionReferenceInitializer : collectionReferenceInitializers ) { - collectionReferenceInitializer.finishUpRow( resultSet, context ); - } + for ( CollectionReferenceInitializer collectionReferenceInitializer : collectionReferenceInitializers ) { + collectionReferenceInitializer.finishUpRow( resultSet, context ); } - if ( arrayReferenceInitializers != null ) { - for ( CollectionReferenceInitializer arrayReferenceInitializer : arrayReferenceInitializers ) { - arrayReferenceInitializer.finishUpRow( resultSet, context ); - } + for ( CollectionReferenceInitializer arrayReferenceInitializer : arrayReferenceInitializers ) { + arrayReferenceInitializer.finishUpRow( resultSet, context ); } return logicalRow; From 5579a38d4d9de5e702a762bb7c7bb15d98936d23 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Thu, 3 Jun 2021 10:14:35 +0100 Subject: [PATCH 191/644] HHH-14650 AbstractRowReader: remove more redundant checks --- .../process/internal/AbstractRowReader.java | 42 +++++++------------ 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/process/internal/AbstractRowReader.java b/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/process/internal/AbstractRowReader.java index 56db17060e87..3f80975a2eb8 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/process/internal/AbstractRowReader.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/plan/exec/process/internal/AbstractRowReader.java @@ -63,39 +63,29 @@ protected abstract Object readLogicalRow(ResultSet resultSet, ResultSetProcessin @Override public Object readRow(ResultSet resultSet, ResultSetProcessingContextImpl context) throws SQLException { - - final boolean hasEntityReferenceInitializers = entityReferenceInitializers.length != 0; - - if ( hasEntityReferenceInitializers ) { - // 1) allow entity references to resolve identifiers (in 2 steps) - for ( EntityReferenceInitializer entityReferenceInitializer : entityReferenceInitializers ) { - entityReferenceInitializer.hydrateIdentifier( resultSet, context ); - } - for ( EntityReferenceInitializer entityReferenceInitializer : entityReferenceInitializers ) { - resolveEntityKey( - resultSet, - context, - entityReferenceInitializer - ); - } - - // 2) allow entity references to resolve their non-identifier hydrated state and entity instance - for ( EntityReferenceInitializer entityReferenceInitializer : entityReferenceInitializers ) { - entityReferenceInitializer.hydrateEntityState( resultSet, context ); - } + // 1) allow entity references to resolve identifiers (in 2 steps) + for ( EntityReferenceInitializer entityReferenceInitializer : entityReferenceInitializers ) { + entityReferenceInitializer.hydrateIdentifier( resultSet, context ); + } + for ( EntityReferenceInitializer entityReferenceInitializer : entityReferenceInitializers ) { + resolveEntityKey( + resultSet, + context, + entityReferenceInitializer + ); } + // 2) allow entity references to resolve their non-identifier hydrated state and entity instance + for ( EntityReferenceInitializer entityReferenceInitializer : entityReferenceInitializers ) { + entityReferenceInitializer.hydrateEntityState( resultSet, context ); + } // 3) read the logical row - Object logicalRow = readLogicalRow( resultSet, context ); - // 4) allow arrays, entities and collections after row callbacks - if ( hasEntityReferenceInitializers ) { - for ( EntityReferenceInitializer entityReferenceInitializer : entityReferenceInitializers ) { - entityReferenceInitializer.finishUpRow( resultSet, context ); - } + for ( EntityReferenceInitializer entityReferenceInitializer : entityReferenceInitializers ) { + entityReferenceInitializer.finishUpRow( resultSet, context ); } for ( CollectionReferenceInitializer collectionReferenceInitializer : collectionReferenceInitializers ) { collectionReferenceInitializer.finishUpRow( resultSet, context ); From d828bfb0867fc86057acde809b4730f6610db17a Mon Sep 17 00:00:00 2001 From: "nathan.xu" Date: Wed, 2 Jun 2021 17:14:23 -0400 Subject: [PATCH 192/644] HHH-14641 replace 'http://' reference with 'https://' --- CONTRIBUTING.md | 14 +++++----- README.md | 12 ++++---- documentation/documentation.gradle | 6 ++-- .../asciidoc/integrationguide/Preface.adoc | 2 +- .../asciidoc/quickstart/guides/obtaining.adoc | 16 +++++------ .../asciidoc/quickstart/guides/preface.adoc | 10 +++---- .../guides/tutorial_annotations.adoc | 4 +-- .../metamodelgen/MetamodelGenerator.adoc | 8 +++--- .../topical/registries/ServiceRegistries.adoc | 2 +- .../asciidoc/topical/wildfly/Wildfly.adoc | 2 +- .../src/main/asciidoc/userguide/Preface.adoc | 14 +++++----- .../userguide/appendices/Annotations.adoc | 2 +- .../userguide/appendices/BestPractices.adoc | 4 +-- .../userguide/appendices/Configurations.adoc | 12 ++++---- .../userguide/chapters/batch/Batching.adoc | 2 +- .../userguide/chapters/caching/Caching.adoc | 8 +++--- .../chapters/domain/basic_types.adoc | 2 +- .../userguide/chapters/domain/entity.adoc | 4 +-- .../userguide/chapters/envers/Envers.adoc | 4 +-- .../chapters/jdbc/Database_Access.adoc | 28 +++++++++---------- .../userguide/chapters/locking/Locking.adoc | 2 +- .../chapters/portability/Portability.adoc | 2 +- .../userguide/chapters/query/hql/HQL.adoc | 2 +- .../chapters/query/spatial/Spatial.adoc | 4 +-- .../chapters/transactions/Transactions.adoc | 2 +- gradle/published-java-module.gradle | 14 +++++----- gradle/publishing-pom.gradle | 14 +++++----- 27 files changed, 98 insertions(+), 98 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 81c00899efbc..47752c2935e8 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -21,10 +21,10 @@ While we try to keep requirements for contributing to a minimum, there are a few we ask that you mind. For code contributions, these guidelines include: -* respect the project code style - find templates for [IntelliJ IDEA](https://community.jboss.org/docs/DOC-15468) or [Eclipse](https://community.jboss.org/docs/DOC-16649) +* respect the project code style - find templates for [IntelliJ IDEA](https://hibernate.org/community/contribute/intellij-idea/) or [Eclipse](https://hibernate.org/community/contribute/eclipse-ide/) * have a corresponding JIRA issue and the key for this JIRA issue should be used in the commit message * have a set of appropriate tests. For bug reports, the tests reproduce the initial reported bug - and illustrates that the solution actually fixes the bug. For features/enhancements, the + and illustrate that the solution actually fixes the bug. For features/enhancements, the tests illustrate the feature working as intended. In both cases the tests are incorporated into the project to protect against regressions * if applicable, documentation is updated to reflect the introduced changes @@ -47,14 +47,14 @@ GitHub there are a few pre-requisite steps to follow: the linked page, this also includes: * [set up your local git install](https://help.github.com/articles/set-up-git) * clone your fork -* See the wiki pages for setting up your IDE, whether you use -[IntelliJ IDEA](https://community.jboss.org/wiki/ContributingToHibernateUsingIntelliJ) -or [Eclipse](https://community.jboss.org/wiki/ContributingToHibernateUsingEclipse)(1). +* see the wiki pages for setting up your IDE, whether you use +[IntelliJ IDEA](https://hibernate.org/community/contribute/intellij-idea/) +or [Eclipse](https://hibernate.org/community/contribute/eclipse-ide/)(1). ## Create the working (topic) branch -Create a [topic branch](http://git-scm.com/book/en/Git-Branching-Branching-Workflows#Topic-Branches) +Create a [topic branch](https://git-scm.com/book/en/Git-Branching-Branching-Workflows#Topic-Branches) on which you will work. The convention is to incorporate the JIRA issue key in the name of this branch, although this is more of a mnemonic strategy than a hard-and-fast rule - but doing so helps: * remember what each branch is for @@ -87,7 +87,7 @@ appreciated btw), please use rebasing rather than merging. Merging creates ## Submit * push your changes to the topic branch in your fork of the repository -* initiate a [pull request](http://help.github.com/articles/creating-a-pull-request) +* initiate a [pull request](https://help.github.com/articles/creating-a-pull-request) * update the JIRA issue by providing the PR link in the **Pull Request** column on the right diff --git a/README.md b/README.md index 8f5a40840b4d..dc84c8ec51c1 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ - + Hibernate ORM is a library providing Object/Relational Mapping (ORM) support @@ -6,9 +6,9 @@ to applications, libraries, and frameworks. It also provides an implementation of the JPA specification, which is the standard Java specification for ORM. -This is the repository of its source code: see [Hibernate.org](http://hibernate.org/orm/) for additional information. +This is the repository of its source code: see [Hibernate.org](https://hibernate.org/orm/) for additional information. -[![Build Status](http://ci.hibernate.org/job/hibernate-orm-main-h2-main/badge/icon)](http://ci.hibernate.org/job/hibernate-orm-main-h2-main/) +[![Build Status](https://ci.hibernate.org/job/hibernate-orm-main-h2-main/badge/icon)](https://ci.hibernate.org/job/hibernate-orm-main-h2-main/) [![Language grade: Java](https://img.shields.io/lgtm/grade/java/g/hibernate/hibernate-orm.svg?logo=lgtm&logoWidth=18)](https://lgtm.com/projects/g/hibernate/hibernate-orm/context:java) Building from sources @@ -23,7 +23,7 @@ Gradle. Contributors should read the [Contributing Guide](CONTRIBUTING.md). -See the guides for setting up [IntelliJ](http://hibernate.org/community/contribute/intellij-idea/) or +See the guides for setting up [IntelliJ](https://hibernate.org/community/contribute/intellij-idea/) or [Eclipse](https://hibernate.org/community/contribute/eclipse-ide/) as your development environment. Check out the _Getting Started_ section in CONTRIBUTING.md for getting started working on Hibernate source. @@ -32,9 +32,9 @@ Check out the _Getting Started_ section in CONTRIBUTING.md for getting started w Continuous Integration ========= -Hibernate makes use of [Jenkins](http://jenkins-ci.org) for its CI needs. The project is built continuous on each +Hibernate makes use of [Jenkins](https://jenkins-ci.org) for its CI needs. The project is built continuous on each push to the upstream repository. Overall there are a few different jobs, all of which can be seen at -[http://ci.hibernate.org/view/ORM/](http://ci.hibernate.org/view/ORM/) +[https://ci.hibernate.org/view/ORM/](https://ci.hibernate.org/view/ORM/) Gradle primer diff --git a/documentation/documentation.gradle b/documentation/documentation.gradle index 88ca53586634..275e27527a03 100644 --- a/documentation/documentation.gradle +++ b/documentation/documentation.gradle @@ -119,14 +119,14 @@ task aggregateJavadocs(type: Javadoc) { overview = project.file( 'src/main/javadoc/overview.html' ) windowTitle = 'Hibernate JavaDocs' docTitle = "Hibernate JavaDoc ($project.version)" - bottom = "Copyright © 2001-$currentYear Red Hat, Inc. All Rights Reserved." + bottom = "Copyright © 2001-$currentYear Red Hat, Inc. All Rights Reserved." use = true options.encoding = 'UTF-8' links = [ 'https://docs.oracle.com/javase/8/docs/api/', - 'http://docs.jboss.org/hibernate/beanvalidation/spec/2.0/api/', - 'http://docs.jboss.org/cdi/api/2.0/', + 'https://docs.jboss.org/hibernate/beanvalidation/spec/2.0/api/', + 'https://docs.jboss.org/cdi/api/2.0/', 'https://javaee.github.io/javaee-spec/javadocs/' ] diff --git a/documentation/src/main/asciidoc/integrationguide/Preface.adoc b/documentation/src/main/asciidoc/integrationguide/Preface.adoc index 0223536c22bc..d348dc231a36 100644 --- a/documentation/src/main/asciidoc/integrationguide/Preface.adoc +++ b/documentation/src/main/asciidoc/integrationguide/Preface.adoc @@ -1,7 +1,7 @@ [[preface]] == Preface -Hibernate is an http://en.wikipedia.org/wiki/Object-relational_mapping[Object/Relational Mapping] solution for Java environments. +Hibernate is an https://en.wikipedia.org/wiki/Object-relational_mapping[Object/Relational Mapping] solution for Java environments. Hibernate not only takes care of the mapping from Java classes to database tables (and from Java data types to SQL data types), but also provides data query and retrieval facilities. It can significantly reduce development time otherwise spent with manual data handling in SQL and JDBC. diff --git a/documentation/src/main/asciidoc/quickstart/guides/obtaining.adoc b/documentation/src/main/asciidoc/quickstart/guides/obtaining.adoc index 58cb23b7a38e..bfab8989a979 100644 --- a/documentation/src/main/asciidoc/quickstart/guides/obtaining.adoc +++ b/documentation/src/main/asciidoc/quickstart/guides/obtaining.adoc @@ -9,14 +9,14 @@ hibernate-core:: The main (core) Hibernate module. Defines its ORM features and hibernate-envers:: Hibernate's historical entity versioning feature hibernate-spatial:: Hibernate's Spatial/GIS data-type support hibernate-osgi:: Hibernate support for running in OSGi containers. -hibernate-agroal:: Integrates the http://agroal.github.io/[Agroal] connection pooling library into Hibernate -hibernate-c3p0:: Integrates the http://www.mchange.com/projects/c3p0/[C3P0] connection pooling library into Hibernate +hibernate-agroal:: Integrates the https://agroal.github.io/[Agroal] connection pooling library into Hibernate +hibernate-c3p0:: Integrates the https://www.mchange.com/projects/c3p0/[C3P0] connection pooling library into Hibernate hibernate-hikaricp:: Integrates the https://github.com/brettwooldridge/HikariCP/[HikariCP] connection pooling library into Hibernate -hibernate-vibur:: Integrates the http://www.vibur.org/[Vibur DBCP] connection pooling library into Hibernate -hibernate-proxool:: Integrates the http://proxool.sourceforge.net/[Proxool] connection pooling library into Hibernate +hibernate-vibur:: Integrates the https://www.vibur.org/[Vibur DBCP] connection pooling library into Hibernate +hibernate-proxool:: Integrates the https://proxool.sourceforge.net/[Proxool] connection pooling library into Hibernate hibernate-jcache:: Integrates the https://jcp.org/en/jsr/detail?id=107$$[JCache] caching specification into Hibernate, enabling any compliant implementation to become a second-level cache provider. -hibernate-ehcache:: Integrates the http://ehcache.org/[Ehcache] caching library into Hibernate as a second-level cache provider. +hibernate-ehcache:: Integrates the https://ehcache.org/[Ehcache] caching library into Hibernate as a second-level cache provider. === Release Bundle Downloads @@ -43,10 +43,10 @@ synced to Maven Central as part of an automated job (some small delay may occur) The team responsible for the JBoss Maven repository maintains a number of Wiki pages that contain important information: -* http://community.jboss.org/docs/DOC-14900 - General information about the repository. -* http://community.jboss.org/docs/DOC-15170 - Information about setting up the JBoss repositories in order to do +* https://community.jboss.org/docs/DOC-14900 - General information about the repository. +* https://community.jboss.org/docs/DOC-15170 - Information about setting up the JBoss repositories in order to do development work on JBoss projects themselves. -* http://community.jboss.org/docs/DOC-15169 - Information about setting up access to the repository to use JBoss +* https://community.jboss.org/docs/DOC-15169 - Information about setting up access to the repository to use JBoss projects as part of your own software. The Hibernate ORM artifacts are published under the `org.hibernate` groupId. \ No newline at end of file diff --git a/documentation/src/main/asciidoc/quickstart/guides/preface.adoc b/documentation/src/main/asciidoc/quickstart/guides/preface.adoc index 9cdc505b630a..03bc59fd1504 100644 --- a/documentation/src/main/asciidoc/quickstart/guides/preface.adoc +++ b/documentation/src/main/asciidoc/quickstart/guides/preface.adoc @@ -7,14 +7,14 @@ Working with both Object-Oriented software and Relational Databases can be cumbe Development costs are significantly higher due to a number of "paradigm mismatches" between how data is represented in objects versus relational databases. Hibernate is an Object/Relational Mapping (ORM) solution for Java environments. The term Object/Relational Mapping refers to the technique of mapping data between an object model representation to -a relational data model representation. See http://en.wikipedia.org/wiki/Object-relational_mapping for a good -high-level discussion. Also, Martin Fowler's link:$$http://martinfowler.com/bliki/OrmHate.html$$[OrmHate] article +a relational data model representation. See https://en.wikipedia.org/wiki/Object-relational_mapping for a good +high-level discussion. Also, Martin Fowler's link:$$https://martinfowler.com/bliki/OrmHate.html$$[OrmHate] article takes a look at many of the mismatch problems. Although having a strong background in SQL is not required to use Hibernate, having a basic understanding of the concepts can help you understand Hibernate more quickly and fully. An understanding of data modeling principles -is especially important. Both http://www.agiledata.org/essays/dataModeling101.html and -http://en.wikipedia.org/wiki/Data_modeling are good starting points for understanding these data modeling +is especially important. Both https://www.agiledata.org/essays/dataModeling101.html and +https://en.wikipedia.org/wiki/Data_modeling are good starting points for understanding these data modeling principles. If you are completely new to database access in Java, https://www.marcobehler.com/guides/a-guide-to-accessing-databases-in-java contains a good overview of the various parts, pieces and options. @@ -33,6 +33,6 @@ logic in the Java-based middle-tier. However, Hibernate can certainly help you t vendor-specific SQL code and streamlines the common task of translating result sets from a tabular representation to a graph of objects. -See http://hibernate.org/orm/contribute/ for information on getting involved. +See https://hibernate.org/orm/contribute/ for information on getting involved. IMPORTANT: The projects and code for the tutorials referenced in this guide are available as link:hibernate-tutorials.zip[] diff --git a/documentation/src/main/asciidoc/quickstart/guides/tutorial_annotations.adoc b/documentation/src/main/asciidoc/quickstart/guides/tutorial_annotations.adoc index 3bf9f8e97395..6c4a588e81b4 100644 --- a/documentation/src/main/asciidoc/quickstart/guides/tutorial_annotations.adoc +++ b/documentation/src/main/asciidoc/quickstart/guides/tutorial_annotations.adoc @@ -98,7 +98,7 @@ any mapping information associated with `title`. .Practice Exercises - [ ] Add an association to the `Event` entity to model a message thread. Use the -http://docs.jboss.org/hibernate/orm/current/userguide/html_single/Hibernate_User_Guide.html[_User Guide_] for more details. +https://docs.jboss.org/hibernate/orm/current/userguide/html_single/Hibernate_User_Guide.html[_User Guide_] for more details. - [ ] Add a callback to receive notifications when an `Event` is created, updated or deleted. Try the same with an event listener. Use the -http://docs.jboss.org/hibernate/orm/current/userguide/html_single/Hibernate_User_Guide.html[_User Guide_] for more details. +https://docs.jboss.org/hibernate/orm/current/userguide/html_single/Hibernate_User_Guide.html[_User Guide_] for more details. diff --git a/documentation/src/main/asciidoc/topical/metamodelgen/MetamodelGenerator.adoc b/documentation/src/main/asciidoc/topical/metamodelgen/MetamodelGenerator.adoc index 65dac38984e9..9aba27c3dcf3 100644 --- a/documentation/src/main/asciidoc/topical/metamodelgen/MetamodelGenerator.adoc +++ b/documentation/src/main/asciidoc/topical/metamodelgen/MetamodelGenerator.adoc @@ -12,7 +12,7 @@ static metamodel classes. For developers it is important that the task of the metamodel generation can be automated. Hibernate Static Metamodel Generator is an annotation processor based on -http://jcp.org/en/jsr/detail?id=269[JSR_269] with the task of creating JPA 2 +https://jcp.org/en/jsr/detail?id=269[JSR_269] with the task of creating JPA 2 static metamodel classes. The following example shows two JPA 2 entities `Order` and `Item`, together with the metamodel class `Order_` and a typesafe query. @@ -111,7 +111,7 @@ persistence unit metadata: == Canonical Metamodel The structure of the metamodel classes is described in the JPA 2 -(JSR 317) http://jcp.org/en/jsr/detail?id=317[specification], but for +(JSR 317) https://jcp.org/en/jsr/detail?id=317[specification], but for completeness the definition is repeated in the following paragraphs. Feel free to skip ahead to the <>, if you are not interested into the gory details. @@ -258,9 +258,9 @@ pass the processor option to the compiler plugin: ==== The maven-compiler-plugin approach has the disadvantage that the maven compiler plugin does currently not allow to specify multiple compiler arguments -(http://jira.codehaus.org/browse/MCOMPILER-62[MCOMPILER-62]) +(https://jira.codehaus.org/browse/MCOMPILER-62[MCOMPILER-62]) and that messages from the Messenger API are suppressed -(http://jira.codehaus.org/browse/MCOMPILER-66[MCOMPILER-66]). +(https://jira.codehaus.org/browse/MCOMPILER-66[MCOMPILER-66]). A better approach is to disable annotation processing for the compiler plugin as seen in below. diff --git a/documentation/src/main/asciidoc/topical/registries/ServiceRegistries.adoc b/documentation/src/main/asciidoc/topical/registries/ServiceRegistries.adoc index 856dba0fc0d9..0f8042ce80e1 100644 --- a/documentation/src/main/asciidoc/topical/registries/ServiceRegistries.adoc +++ b/documentation/src/main/asciidoc/topical/registries/ServiceRegistries.adoc @@ -343,7 +343,7 @@ service to be injected is optional, use `InjectService#required=false`. Once built, a ServiceRegistry is generally considered immutable. The Services themselves might accept re-configuration, but immutability here means adding/replacing services. So all the services hosted in a particular ServiceRegistry must be known up-front. To this end, building a ServiceRegistry usually employees a -http://en.wikipedia.org/wiki/Builder_pattern[builder^]. +https://en.wikipedia.org/wiki/Builder_pattern[builder^]. === Building BootstrapServiceRegistry diff --git a/documentation/src/main/asciidoc/topical/wildfly/Wildfly.adoc b/documentation/src/main/asciidoc/topical/wildfly/Wildfly.adoc index 146fbb5f1a35..0c7eb5987915 100644 --- a/documentation/src/main/asciidoc/topical/wildfly/Wildfly.adoc +++ b/documentation/src/main/asciidoc/topical/wildfly/Wildfly.adoc @@ -2,7 +2,7 @@ == Hibernate ORM within WildFly -The http://wildfly.org/[WildFly application server] includes Hibernate ORM as the default JPA provider out of the box. +The https://wildfly.org/[WildFly application server] includes Hibernate ORM as the default JPA provider out of the box. In previous versions of Hibernate ORM, we offered a "feature pack" to enable anyone to use the very latest version in WildFly as soon as a new release of Hibernate ORM was published. diff --git a/documentation/src/main/asciidoc/userguide/Preface.adoc b/documentation/src/main/asciidoc/userguide/Preface.adoc index 56ccbdfdfc3f..95c422c70ed5 100644 --- a/documentation/src/main/asciidoc/userguide/Preface.adoc +++ b/documentation/src/main/asciidoc/userguide/Preface.adoc @@ -4,7 +4,7 @@ Working with both Object-Oriented software and Relational Databases can be cumbersome and time-consuming. Development costs are significantly higher due to a paradigm mismatch between how data is represented in objects versus relational databases. Hibernate is an Object/Relational Mapping solution for Java environments. -The term http://en.wikipedia.org/wiki/Object-relational_mapping[Object/Relational Mapping] refers to the technique of mapping data from an object model representation to a relational data model representation (and vice versa). +The term https://en.wikipedia.org/wiki/Object-relational_mapping[Object/Relational Mapping] refers to the technique of mapping data from an object model representation to a relational data model representation (and vice versa). Hibernate not only takes care of the mapping from Java classes to database tables (and from Java data types to SQL data types), but also provides data query and retrieval facilities. It can significantly reduce development time otherwise spent with manual data handling in SQL and JDBC. @@ -16,9 +16,9 @@ However, Hibernate can certainly help you to remove or encapsulate vendor-specif === Get Involved -* Use Hibernate and report any bugs or issues you find. See http://hibernate.org/issuetracker[Issue Tracker] for details. -* Try your hand at fixing some bugs or implementing enhancements. Again, see http://hibernate.org/issuetracker[Issue Tracker]. -* Engage with the community using mailing lists, forums, IRC, or other ways listed in the http://hibernate.org/community[Community section]. +* Use Hibernate and report any bugs or issues you find. See https://hibernate.org/issuetracker[Issue Tracker] for details. +* Try your hand at fixing some bugs or implementing enhancements. Again, see https://hibernate.org/issuetracker[Issue Tracker]. +* Engage with the community using mailing lists, forums, IRC, or other ways listed in the https://hibernate.org/community[Community section]. * Help improve or translate this documentation. Contact us on the developer mailing list if you have interest. * Spread the word. Let the rest of your organization know about the benefits of Hibernate. @@ -36,7 +36,7 @@ When building Hibernate 5.1 or older from sources, you need Java 1.7 due to a bu === Getting Started Guide New users may want to first look through the https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/quickstart/html_single/[Hibernate Getting Started Guide] for basic information as well as tutorials. -There is also a series of http://docs.jboss.org/hibernate/orm/{majorMinorVersion}/topical/html_single/[topical guides] providing deep dives into various topics. +There is also a series of https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/topical/html_single/[topical guides] providing deep dives into various topics. [NOTE] ==== @@ -44,8 +44,8 @@ While having a strong background in SQL is not required to use Hibernate, it cer Probably even more important is an understanding of data modeling principles. You might want to consider these resources as a good starting point: -* http://en.wikipedia.org/wiki/Data_modeling[Data modeling Wikipedia definition] -* http://www.agiledata.org/essays/dataModeling101.html[Data Modeling 101] +* https://en.wikipedia.org/wiki/Data_modeling[Data modeling Wikipedia definition] +* https://www.agiledata.org/essays/dataModeling101.html[Data Modeling 101] Understanding the basics of transactions and design patterns such as _Unit of Work_ (<>) or _Application Transaction_ are important as well. These topics will be discussed in the documentation, but a prior understanding will certainly help. diff --git a/documentation/src/main/asciidoc/userguide/appendices/Annotations.adoc b/documentation/src/main/asciidoc/userguide/appendices/Annotations.adoc index 61af303f9281..d2170f6a99ae 100644 --- a/documentation/src/main/asciidoc/userguide/appendices/Annotations.adoc +++ b/documentation/src/main/asciidoc/userguide/appendices/Annotations.adoc @@ -674,7 +674,7 @@ See the <> chapter for more info. [[annotations-hibernate-cascade]] ==== `@Cascade` -The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/Cascade.html[`@Cascade`] annotation is used to apply the Hibernate specific http://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/CascadeType.html[`CascadeType`] strategies (e.g. `CascadeType.LOCK`, `CascadeType.SAVE_UPDATE`, `CascadeType.REPLICATE`) on a given association. +The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/Cascade.html[`@Cascade`] annotation is used to apply the Hibernate specific https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/CascadeType.html[`CascadeType`] strategies (e.g. `CascadeType.LOCK`, `CascadeType.SAVE_UPDATE`, `CascadeType.REPLICATE`) on a given association. For JPA cascading, prefer using the {jpaJavadocUrlPrefix}CascadeType.html[`javax.persistence.CascadeType`] instead. diff --git a/documentation/src/main/asciidoc/userguide/appendices/BestPractices.adoc b/documentation/src/main/asciidoc/userguide/appendices/BestPractices.adoc index e1160a01f58d..2fdae829ccb2 100644 --- a/documentation/src/main/asciidoc/userguide/appendices/BestPractices.adoc +++ b/documentation/src/main/asciidoc/userguide/appendices/BestPractices.adoc @@ -10,7 +10,7 @@ Hibernate comes with a great variety of features that can help you tune the data Although Hibernate provides the `update` option for the `hibernate.hbm2ddl.auto` configuration property, this feature is not suitable for a production environment. -An automated schema migration tool (e.g. https://flywaydb.org/[Flyway], http://www.liquibase.org/[Liquibase]) allows you to use any database-specific DDL feature (e.g. Rules, Triggers, Partitioned Tables). +An automated schema migration tool (e.g. https://flywaydb.org/[Flyway], https://www.liquibase.org/[Liquibase]) allows you to use any database-specific DDL feature (e.g. Rules, Triggers, Partitioned Tables). Every migration should have an associated script, which is stored on the Version Control System, along with the application source code. When the application is deployed on a production-like QA environment, and the deployment worked as expected, then pushing the deployment to a production environment should be straightforward since the latest schema migration was already tested. @@ -233,7 +233,7 @@ and you should consider these alternatives prior to jumping to a second-level ca After properly tuning the database, to further reduce the average response time and increase the system throughput, application-level caching becomes inevitable. -Typically, a key-value application-level cache like https://memcached.org/[Memcached] or http://redis.io/[Redis] is a common choice to store data aggregates. +Typically, a key-value application-level cache like https://memcached.org/[Memcached] or https://redis.io/[Redis] is a common choice to store data aggregates. If you can duplicate all data in the key-value store, you have the option of taking down the database system for maintenance without completely losing availability since read-only traffic can still be served from the cache. One of the main challenges of using an application-level cache is ensuring data consistency across entity aggregates. diff --git a/documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc b/documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc index 75ff5d99c96a..832b9d747157 100644 --- a/documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc +++ b/documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc @@ -207,22 +207,22 @@ The number of seconds between two consecutive pool validations. During validatio === c3p0 properties `*hibernate.c3p0.min_size*` (e.g. 1):: - Minimum size of C3P0 connection pool. Refers to http://www.mchange.com/projects/c3p0/#minPoolSize[c3p0 `minPoolSize` setting]. + Minimum size of C3P0 connection pool. Refers to https://www.mchange.com/projects/c3p0/#minPoolSize[c3p0 `minPoolSize` setting]. `*hibernate.c3p0.max_size*` (e.g. 5):: - Maximum size of C3P0 connection pool. Refers to http://www.mchange.com/projects/c3p0/#maxPoolSize[c3p0 `maxPoolSize` setting]. + Maximum size of C3P0 connection pool. Refers to https://www.mchange.com/projects/c3p0/#maxPoolSize[c3p0 `maxPoolSize` setting]. `*hibernate.c3p0.timeout*` (e.g. 30):: - Maximum idle time for C3P0 connection pool. Refers to http://www.mchange.com/projects/c3p0/#maxIdleTime[c3p0 `maxIdleTime` setting]. + Maximum idle time for C3P0 connection pool. Refers to https://www.mchange.com/projects/c3p0/#maxIdleTime[c3p0 `maxIdleTime` setting]. `*hibernate.c3p0.max_statements*` (e.g. 5):: - Maximum size of C3P0 statement cache. Refers to http://www.mchange.com/projects/c3p0/#maxStatements[c3p0 `maxStatements` setting]. + Maximum size of C3P0 statement cache. Refers to https://www.mchange.com/projects/c3p0/#maxStatements[c3p0 `maxStatements` setting]. `*hibernate.c3p0.acquire_increment*` (e.g. 2):: - The number of connections acquired at a time when there's no connection available in the pool. Refers to http://www.mchange.com/projects/c3p0/#acquireIncrement[c3p0 `acquireIncrement` setting]. + The number of connections acquired at a time when there's no connection available in the pool. Refers to https://www.mchange.com/projects/c3p0/#acquireIncrement[c3p0 `acquireIncrement` setting]. `*hibernate.c3p0.idle_test_period*` (e.g. 5):: - Idle time before a C3P0 pooled connection is validated. Refers to http://www.mchange.com/projects/c3p0/#idleConnectionTestPeriod[c3p0 `idleConnectionTestPeriod` setting]. + Idle time before a C3P0 pooled connection is validated. Refers to https://www.mchange.com/projects/c3p0/#idleConnectionTestPeriod[c3p0 `idleConnectionTestPeriod` setting]. `*hibernate.c3p0*`:: A setting prefix used to indicate additional c3p0 properties that need to be passed to the underlying c3p0 connection pool. diff --git a/documentation/src/main/asciidoc/userguide/chapters/batch/Batching.adoc b/documentation/src/main/asciidoc/userguide/chapters/batch/Batching.adoc index 0d0cf1072550..e53d55f1bfb1 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/batch/Batching.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/batch/Batching.adoc @@ -489,7 +489,7 @@ However, this strategy requires the IN-clause row value expression for composite If you can use temporary tables, that's probably the best choice. However, if you are not allowed to create temporary tables, you must pick one of these four strategies that works with your underlying database. Before making up your mind, you should benchmark which one works best for your current workload. -For instance, http://blog.2ndquadrant.com/postgresql-ctes-are-optimization-fences/[CTE are optimization fences in PostgreSQL], so make sure you measure before making a decision. +For instance, https://blog.2ndquadrant.com/postgresql-ctes-are-optimization-fences/[CTE are optimization fences in PostgreSQL], so make sure you measure before making a decision. If you're using Oracle or MySQL 5.7, you can choose either `InlineIdsOrClauseBulkIdStrategy` or `InlineIdsInClauseBulkIdStrategy`. For older version of MySQL, then you can only use `InlineIdsOrClauseBulkIdStrategy`. diff --git a/documentation/src/main/asciidoc/userguide/chapters/caching/Caching.adoc b/documentation/src/main/asciidoc/userguide/chapters/caching/Caching.adoc index caf5ca65c1e9..51846edc3cdb 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/caching/Caching.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/caching/Caching.adoc @@ -612,7 +612,7 @@ and also log a warning about the missing cache. ==== Note that caches created this way may not be suitable for production usage (unlimited size and no eviction in particular) unless the cache provider explicitly provides a specific configuration for default caches. -Ehcache, in particular, allows to set such default configuration using cache templates. See the http://www.ehcache.org/documentation/3.0/107.html#supplement-jsr-107-configurations[Ehcache documentation] for more details. +Ehcache, in particular, allows to set such default configuration using cache templates. See the https://www.ehcache.org/documentation/3.0/107.html#supplement-jsr-107-configurations[Ehcache documentation] for more details. ==== [[caching-provider-ehcache]] @@ -622,7 +622,7 @@ This integration covers Ehcache 2.x, in order to use Ehcache 3.x as second level [NOTE] ==== -Use of the built-in integration for http://www.ehcache.org/[Ehcache] requires that the `hibernate-ehcache` module jar (and all of its dependencies) are on the classpath. +Use of the built-in integration for https://www.ehcache.org/[Ehcache] requires that the `hibernate-ehcache` module jar (and all of its dependencies) are on the classpath. ==== [[caching-provider-ehcache-region-factory]] @@ -665,12 +665,12 @@ To use the `SingletonEhCacheRegionFactory`, you need to specify the following co ---- ==== -The `SingletonEhCacheRegionFactory` configures a singleton `net.sf.ehcache.CacheManager` (see http://www.ehcache.org/apidocs/2.8.4/net/sf/ehcache/CacheManager.html#create%28%29[CacheManager#create()]), +The `SingletonEhCacheRegionFactory` configures a singleton `net.sf.ehcache.CacheManager` (see https://www.ehcache.org/apidocs/2.8.4/net/sf/ehcache/CacheManager.html#create%28%29[CacheManager#create()]), shared among multiple `SessionFactory` instances in the same JVM. [NOTE] ==== -The http://www.ehcache.org/documentation/2.8/integrations/hibernate#optional[Ehcache documentation] recommends using multiple non-singleton ``CacheManager``s when there are multiple Hibernate `SessionFactory` instances running in the same JVM. +The https://www.ehcache.org/documentation/2.8/integrations/hibernate#optional[Ehcache documentation] recommends using multiple non-singleton ``CacheManager``s when there are multiple Hibernate `SessionFactory` instances running in the same JVM. ==== [[caching-provider-ehcache-missing-cache-strategy]] diff --git a/documentation/src/main/asciidoc/userguide/chapters/domain/basic_types.adoc b/documentation/src/main/asciidoc/userguide/chapters/domain/basic_types.adoc index fe4816863849..a5544a778ddd 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/domain/basic_types.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/domain/basic_types.adoc @@ -199,7 +199,7 @@ But first, let's explore how implicit resolution works and how applications can ==== A thorough discussion of `BasicTypeRegistry` and all the different ways to contribute types is beyond the scope of this documentation. -Please see the http://docs.jboss.org/hibernate/orm/{majorMinorVersion}/integrationguide/html_single/Hibernate_Integration_Guide.html[Integration Guide] for complete details. +Please see the https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/integrationguide/html_single/Hibernate_Integration_Guide.html[Integration Guide] for complete details. ==== As an example, take a String attribute such as we saw before with Product#sku. diff --git a/documentation/src/main/asciidoc/userguide/chapters/domain/entity.adoc b/documentation/src/main/asciidoc/userguide/chapters/domain/entity.adoc index 42d154f1dee4..4b7235f33e8f 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/domain/entity.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/domain/entity.adoc @@ -455,8 +455,8 @@ Hibernate will trigger a Persistence Context flush if there are pending `Account ==== Define a custom entity proxy By default, when it needs to use a proxy instead of the actual POJO, Hibernate is going to use a Bytecode manipulation library like -http://jboss-javassist.github.io/javassist/[Javassist] or -http://bytebuddy.net/[Byte Buddy]. +https://jboss-javassist.github.io/javassist/[Javassist] or +https://bytebuddy.net/[Byte Buddy]. However, if the entity class is final, Javassist will not create a proxy and you will get a POJO even when you only need a proxy reference. In this case, you could proxy an interface that this particular entity implements, as illustrated by the following example. diff --git a/documentation/src/main/asciidoc/userguide/chapters/envers/Envers.adoc b/documentation/src/main/asciidoc/userguide/chapters/envers/Envers.adoc index 17552968f020..af0e847abc26 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/envers/Envers.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/envers/Envers.adoc @@ -1580,8 +1580,8 @@ And sometime in 2011, the last partition (or 'extension bucket') is split into t [[envers-links]] === Envers links -. http://hibernate.org[Hibernate main page] -. http://hibernate.org/community/[Forum] +. https://hibernate.org[Hibernate main page] +. https://hibernate.org/community/[Forum] . https://hibernate.atlassian.net/[JIRA issue tracker] (when adding issues concerning Envers, be sure to select the "envers" component!) . https://hibernate.zulipchat.com/#narrow/stream/132096-hibernate-user[Zulip channel] . https://community.jboss.org/wiki/EnversFAQ[FAQ] diff --git a/documentation/src/main/asciidoc/userguide/chapters/jdbc/Database_Access.adoc b/documentation/src/main/asciidoc/userguide/chapters/jdbc/Database_Access.adoc index 4d2ef0ed3db5..adf7b217abc7 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/jdbc/Database_Access.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/jdbc/Database_Access.adoc @@ -55,20 +55,20 @@ NOTE: Not all properties apply to all situations. For example, if you are provid To use the c3p0 integration, the application must include the `hibernate-c3p0` module jar (as well as its dependencies) on the classpath. ==== -Hibernate also provides support for applications to use http://www.mchange.com/projects/c3p0/[c3p0] connection pooling. +Hibernate also provides support for applications to use https://www.mchange.com/projects/c3p0/[c3p0] connection pooling. When c3p0 support is enabled, a number of c3p0-specific configuration settings are recognized in addition to the general ones described in <>. Transaction isolation of the Connections is managed by the `ConnectionProvider` itself. See <>. -`hibernate.c3p0.min_size` or `c3p0.minPoolSize`:: The minimum size of the c3p0 pool. See http://www.mchange.com/projects/c3p0/#minPoolSize[c3p0 minPoolSize] -`hibernate.c3p0.max_size` or `c3p0.maxPoolSize`:: The maximum size of the c3p0 pool. See http://www.mchange.com/projects/c3p0/#maxPoolSize[c3p0 maxPoolSize] -`hibernate.c3p0.timeout` or `c3p0.maxIdleTime`:: The Connection idle time. See http://www.mchange.com/projects/c3p0/#maxIdleTime[c3p0 maxIdleTime] -`hibernate.c3p0.max_statements` or `c3p0.maxStatements`:: Controls the c3p0 PreparedStatement cache size (if using). See http://www.mchange.com/projects/c3p0/#maxStatements[c3p0 maxStatements] -`hibernate.c3p0.acquire_increment` or `c3p0.acquireIncrement`:: Number of connections c3p0 should acquire at a time when the pool is exhausted. See http://www.mchange.com/projects/c3p0/#acquireIncrement[c3p0 acquireIncrement] -`hibernate.c3p0.idle_test_period` or `c3p0.idleConnectionTestPeriod`:: Idle time before a c3p0 pooled connection is validated. See http://www.mchange.com/projects/c3p0/#idleConnectionTestPeriod[c3p0 idleConnectionTestPeriod] -`hibernate.c3p0.initialPoolSize`:: The initial c3p0 pool size. If not specified, default is to use the min pool size. See http://www.mchange.com/projects/c3p0/#initialPoolSize[c3p0 initialPoolSize] +`hibernate.c3p0.min_size` or `c3p0.minPoolSize`:: The minimum size of the c3p0 pool. See https://www.mchange.com/projects/c3p0/#minPoolSize[c3p0 minPoolSize] +`hibernate.c3p0.max_size` or `c3p0.maxPoolSize`:: The maximum size of the c3p0 pool. See https://www.mchange.com/projects/c3p0/#maxPoolSize[c3p0 maxPoolSize] +`hibernate.c3p0.timeout` or `c3p0.maxIdleTime`:: The Connection idle time. See https://www.mchange.com/projects/c3p0/#maxIdleTime[c3p0 maxIdleTime] +`hibernate.c3p0.max_statements` or `c3p0.maxStatements`:: Controls the c3p0 PreparedStatement cache size (if using). See https://www.mchange.com/projects/c3p0/#maxStatements[c3p0 maxStatements] +`hibernate.c3p0.acquire_increment` or `c3p0.acquireIncrement`:: Number of connections c3p0 should acquire at a time when the pool is exhausted. See https://www.mchange.com/projects/c3p0/#acquireIncrement[c3p0 acquireIncrement] +`hibernate.c3p0.idle_test_period` or `c3p0.idleConnectionTestPeriod`:: Idle time before a c3p0 pooled connection is validated. See https://www.mchange.com/projects/c3p0/#idleConnectionTestPeriod[c3p0 idleConnectionTestPeriod] +`hibernate.c3p0.initialPoolSize`:: The initial c3p0 pool size. If not specified, default is to use the min pool size. See https://www.mchange.com/projects/c3p0/#initialPoolSize[c3p0 initialPoolSize] Any other settings prefixed with `hibernate.c3p0.`:: Will have the `hibernate.` portion stripped and be passed to c3p0. -Any other settings prefixed with `c3p0.`:: Get passed to c3p0 as is. See http://www.mchange.com/projects/c3p0/#configuration[c3p0 configuration] +Any other settings prefixed with `c3p0.`:: Get passed to c3p0 as is. See https://www.mchange.com/projects/c3p0/#configuration[c3p0 configuration] [[database-connectionprovider-proxool]] === Using Proxool @@ -78,7 +78,7 @@ Any other settings prefixed with `c3p0.`:: Get passed to c3p0 as is. See http:// To use the Proxool integration, the application must include the `hibernate-proxool` module jar (as well as its dependencies) on the classpath. ==== -Hibernate also provides support for applications to use http://proxool.sourceforge.net/[Proxool] connection pooling. +Hibernate also provides support for applications to use https://proxool.sourceforge.net/[Proxool] connection pooling. Transaction isolation of the Connections is managed by the `ConnectionProvider` itself. See <>. @@ -92,14 +92,14 @@ If set to true, this ConnectionProvider will use an already existing Proxool poo ==== Configuring Proxool via XML The `hibernate.proxool.xml` setting names a Proxool configuration XML file to be loaded as a classpath resource and loaded by Proxool's JAXPConfigurator. -See http://proxool.sourceforge.net/configure.html[proxool configuration]. +See https://proxool.sourceforge.net/configure.html[proxool configuration]. `hibernate.proxool.pool_alias` must be set to indicate which pool to use. [[database-connectionprovider-proxool-properties]] ==== Configuring Proxool via Properties The `hibernate.proxool.properties` setting names a Proxool configuration properties file to be loaded as a classpath resource and loaded by Proxool's `PropertyConfigurator`. -See http://proxool.sourceforge.net/configure.html[proxool configuration]. +See https://proxool.sourceforge.net/configure.html[proxool configuration]. `hibernate.proxool.pool_alias` must be set to indicate which pool to use. [[database-connectionprovider-hikari]] @@ -131,7 +131,7 @@ Note that Hikari only supports JDBC standard isolation levels (apparently). To use the Vibur DBCP integration, the application must include the `hibernate-vibur` module jar (as well as its dependencies) on the classpath. ==== -Hibernate also provides support for applications to use http://www.vibur.org/[Vibur DBCP] connection pool. +Hibernate also provides support for applications to use https://www.vibur.org/[Vibur DBCP] connection pool. Set all of your Vibur settings in Hibernate prefixed by `hibernate.vibur.` and this `ConnectionProvider` will pick them up and pass them along to Vibur DBCP. Additionally, this `ConnectionProvider` will pick up the following Hibernate-specific properties and map them to the corresponding Vibur ones (any `hibernate.vibur.` prefixed ones have precedence): @@ -151,7 +151,7 @@ Additionally, this `ConnectionProvider` will pick up the following Hibernate-spe To use the Agroal integration, the application must include the `hibernate-agroal` module jar (as well as its dependencies) on the classpath. ==== -Hibernate also provides support for applications to use http://agroal.github.io/[Agroal] connection pool. +Hibernate also provides support for applications to use https://agroal.github.io/[Agroal] connection pool. Set all of your Agroal settings in Hibernate prefixed by `hibernate.agroal.` and this `ConnectionProvider` will pick them up and pass them along to Agroal connection pool. Additionally, this `ConnectionProvider` will pick up the following Hibernate-specific properties and map them to the corresponding Agroal ones (any `hibernate.agroal.` prefixed ones have precedence): diff --git a/documentation/src/main/asciidoc/userguide/chapters/locking/Locking.adoc b/documentation/src/main/asciidoc/userguide/chapters/locking/Locking.adoc index 7784ce31c653..c8877537591c 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/locking/Locking.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/locking/Locking.adoc @@ -8,7 +8,7 @@ In a relational database, locking refers to actions taken to prevent data from c Your locking strategy can be either optimistic or pessimistic. Optimistic:: -http://en.wikipedia.org/wiki/Optimistic_locking[Optimistic locking] assumes that multiple transactions can complete without affecting each other, +https://en.wikipedia.org/wiki/Optimistic_locking[Optimistic locking] assumes that multiple transactions can complete without affecting each other, and that therefore transactions can proceed without locking the data resources that they affect. Before committing, each transaction verifies that no other transaction has modified its data. If the check reveals conflicting modifications, the committing transaction rolls back. diff --git a/documentation/src/main/asciidoc/userguide/chapters/portability/Portability.adoc b/documentation/src/main/asciidoc/userguide/chapters/portability/Portability.adoc index 1e8cf2fed1e7..298d7d972623 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/portability/Portability.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/portability/Portability.adoc @@ -66,7 +66,7 @@ Hibernate was changed slightly, once the implications of this were better unders The underlying issue is that the actual semantics of the application itself changes in these cases. ==== -Starting with version 3.2.3, Hibernate comes with a set of http://in.relation.to/2082.lace[enhanced] identifier generators targeting portability in a much different way. +Starting with version 3.2.3, Hibernate comes with a set of https://in.relation.to/2082.lace[enhanced] identifier generators targeting portability in a much different way. [NOTE] ==== diff --git a/documentation/src/main/asciidoc/userguide/chapters/query/hql/HQL.adoc b/documentation/src/main/asciidoc/userguide/chapters/query/hql/HQL.adoc index 2e8fc345e43f..69706a7f32e8 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/query/hql/HQL.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/query/hql/HQL.adoc @@ -909,7 +909,7 @@ include::{extrasdir}/hql-distinct-entity-query-example.sql[] ---- ==== -In this case, the `DISTINCT` SQL keyword is undesirable since it does a redundant result set sorting, as explained http://in.relation.to/2016/08/04/introducing-distinct-pass-through-query-hint/[in this blog post]. +In this case, the `DISTINCT` SQL keyword is undesirable since it does a redundant result set sorting, as explained https://in.relation.to/2016/08/04/introducing-distinct-pass-through-query-hint/[in this blog post]. To fix this issue, Hibernate 5.2.2 added support for the `HINT_PASS_DISTINCT_THROUGH` entity query hint: [[hql-distinct-entity-query-hint-example]] diff --git a/documentation/src/main/asciidoc/userguide/chapters/query/spatial/Spatial.adoc b/documentation/src/main/asciidoc/userguide/chapters/query/spatial/Spatial.adoc index 578048ac4d01..2baffcb4341c 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/query/spatial/Spatial.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/query/spatial/Spatial.adoc @@ -15,13 +15,13 @@ It supports most of the functions described by the OGC Simple Feature Specificat PostgreSQL/PostGIS, MySQL, Microsoft SQL Server and H2/GeoDB. Spatial data types are not part of the Java standard library, and they are absent from the JDBC specification. -Over the years http://tsusiatsoftware.net/jts/main.html[JTS] has emerged the _de facto_ standard to fill this gap. JTS is +Over the years https://tsusiatsoftware.net/jts/main.html[JTS] has emerged the _de facto_ standard to fill this gap. JTS is an implementation of the https://portal.opengeospatial.org/files/?artifact_id=829[Simple Feature Specification (SFS)]. Many databases on the other hand implement the SQL/MM - Part 3: Spatial Data specification - a related, but broader specification. The biggest difference is that SFS is limited to 2D geometries in the projected plane (although JTS supports 3D coordinates), whereas SQL/MM supports 2-, 3- or 4-dimensional coordinate spaces. -Hibernate Spatial supports two different geometry models: http://tsusiatsoftware.net/jts/main.html[JTS] and +Hibernate Spatial supports two different geometry models: https://tsusiatsoftware.net/jts/main.html[JTS] and https://github.com/GeoLatte/geolatte-geom[geolatte-geom]. As already mentioned, JTS is the _de facto_ standard. Geolatte-geom (also written by the lead developer of Hibernate Spatial) is a more recent library that supports many features specified in SQL/MM but not available in JTS (such as support for 4D geometries, and support for extended WKT/WKB formats). diff --git a/documentation/src/main/asciidoc/userguide/chapters/transactions/Transactions.adoc b/documentation/src/main/asciidoc/userguide/chapters/transactions/Transactions.adoc index ef2aae6b7146..3f00ebd6574e 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/transactions/Transactions.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/transactions/Transactions.adoc @@ -40,7 +40,7 @@ or provide a custom `org.hibernate.resource.transaction.TransactionCoordinatorBu [NOTE] ==== For details on implementing a custom `TransactionCoordinatorBuilder`, or simply better understanding how it works, see the -http://docs.jboss.org/hibernate/orm/{majorMinorVersion}/integrationguide/html_single/Hibernate_Integration_Guide.html[Integration Guide] . +https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/integrationguide/html_single/Hibernate_Integration_Guide.html[Integration Guide] . ==== Hibernate uses JDBC connections and JTA resources directly, without adding any additional locking behavior. diff --git a/gradle/published-java-module.gradle b/gradle/published-java-module.gradle index cfee264828ef..df0fd448b2c5 100644 --- a/gradle/published-java-module.gradle +++ b/gradle/published-java-module.gradle @@ -24,7 +24,7 @@ jar { 'Implementation-Version': project.version, 'Implementation-Vendor': 'Hibernate.org', 'Implementation-Vendor-Id': 'org.hibernate', - 'Implementation-Url': 'http://hibernate.org/orm', + 'Implementation-Url': 'https://hibernate.org/orm', // Java 9 module name 'Automatic-Module-Name': project.java9ModuleName, @@ -37,7 +37,7 @@ jar { 'Bundle-Name': project.name, 'Bundle-SymbolicName': project.java9ModuleName, 'Bundle-Vendor': 'Hibernate.org', - 'Bundle-DocURL': "http://www.hibernate.org/orm/${project.ormVersion.family}", + 'Bundle-DocURL': "https://hibernate.org/orm/${project.ormVersion.family}", // This is overridden in some sub-projects 'Import-Package': [ // Temporarily support JTA 1.1 -- Karaf and other frameworks still @@ -65,7 +65,7 @@ task sourcesJar(type: Jar) { 'Implementation-Version': project.version, 'Implementation-Vendor': 'Hibernate.org', 'Implementation-Vendor-Id': 'org.hibernate', - 'Implementation-Url': 'http://hibernate.org/orm', + 'Implementation-Url': 'https://hibernate.org/orm', // Hibernate-specific JAR manifest attributes 'Hibernate-VersionFamily': project.ormVersion.family, @@ -87,7 +87,7 @@ task javadocJar(type: Jar) { 'Implementation-Version': project.version, 'Implementation-Vendor': 'Hibernate.org', 'Implementation-Vendor-Id': 'org.hibernate', - 'Implementation-Url': 'http://hibernate.org/orm', + 'Implementation-Url': 'https://hibernate.org/orm', // Hibernate-specific JAR manifest attributes 'Hibernate-VersionFamily': project.ormVersion.family, @@ -110,13 +110,13 @@ javadoc { configure( options ) { windowTitle = "$project.name JavaDocs" docTitle = "$project.name JavaDocs ($project.version)" - bottom = "Copyright © 2001-$currentYear Red Hat, Inc. All Rights Reserved." + bottom = "Copyright © 2001-$currentYear Red Hat, Inc. All Rights Reserved." use = true encoding = 'UTF-8' links += [ 'https://docs.oracle.com/javase/8/docs/api/', - 'http://docs.jboss.org/hibernate/beanvalidation/spec/2.0/api/', - 'http://docs.jboss.org/cdi/api/2.0/', + 'https://docs.jboss.org/hibernate/beanvalidation/spec/2.0/api/', + 'https://docs.jboss.org/cdi/api/2.0/', 'https://javaee.github.io/javaee-spec/javadocs/' ] tags = [ "apiNote", 'implSpec', 'implNote', 'todo' ] diff --git a/gradle/publishing-pom.gradle b/gradle/publishing-pom.gradle index eb3e94d4c62d..8179f3459164 100644 --- a/gradle/publishing-pom.gradle +++ b/gradle/publishing-pom.gradle @@ -20,25 +20,25 @@ publishing { pom { name = 'Hibernate ORM - ' + project.name description = project.description - url = 'http://hibernate.org/orm' + url = 'https://hibernate.org/orm' organization { name = 'Hibernate.org' - url = 'http://hibernate.org' + url = 'https://hibernate.org' } licenses { license { name = 'GNU Library General Public License v2.1 or later' - url = 'http://www.opensource.org/licenses/LGPL-2.1' - comments = 'See discussion at http://hibernate.org/community/license/ for more details.' + url = 'https://www.opensource.org/licenses/LGPL-2.1' + comments = 'See discussion at https://hibernate.org/community/license/ for more details.' distribution = 'repo' } } scm { - url = 'http://github.com/hibernate/hibernate-orm' - connection = 'scm:git:http://github.com/hibernate/hibernate-orm.git' + url = 'https://github.com/hibernate/hibernate-orm' + connection = 'scm:git:https://github.com/hibernate/hibernate-orm.git' developerConnection = 'scm:git:git@github.com:hibernate/hibernate-orm.git' } @@ -52,7 +52,7 @@ publishing { id = 'hibernate-team' name = 'The Hibernate Development Team' organization = 'Hibernate.org' - organizationUrl = 'http://hibernate.org' + organizationUrl = 'https://hibernate.org' } } From 5df5ddbe3ad0d68a14f34f89a54f79d6d2cf51d2 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Fri, 4 Jun 2021 13:32:23 +0200 Subject: [PATCH 193/644] Remove obsolete JPA 3.0 TCK build arg --- ci/jpa-3.0-tck.Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ci/jpa-3.0-tck.Jenkinsfile b/ci/jpa-3.0-tck.Jenkinsfile index 03ea50515932..3d1aab779c82 100644 --- a/ci/jpa-3.0-tck.Jenkinsfile +++ b/ci/jpa-3.0-tck.Jenkinsfile @@ -36,7 +36,7 @@ pipeline { dir('tck') { checkout changelog: false, poll: false, scm: [$class: 'GitSCM', branches: [[name: '*/main']], extensions: [], userRemoteConfigs: [[url: 'https://github.com/hibernate/jakarta-tck-runner.git']]] sh """ \ - cd jpa-3.0; docker build -f Dockerfile.${params.IMAGE_JDK} -t jakarta-tck-runner --build-arg JDK_IMAGE=${params.BASE_IMAGE} --build-arg TCK_VERSION=${params.TCK_VERSION} --build-arg TCK_SHA=${params.TCK_SHA} . + cd jpa-3.0; docker build -f Dockerfile.${params.IMAGE_JDK} -t jakarta-tck-runner --build-arg TCK_VERSION=${params.TCK_VERSION} --build-arg TCK_SHA=${params.TCK_SHA} . """ } } From 3443541f6c2d763a346a7d4850fcadac76cbcf70 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Mon, 7 Jun 2021 15:20:29 +0200 Subject: [PATCH 194/644] HHH-14655 Upper case the information schema sequence identifier again to fix issues with case sensitive databases --- .../main/java/org/hibernate/dialect/SQLServer2012Dialect.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServer2012Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServer2012Dialect.java index 5ecc7b3b8113..6cfb6bed5175 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServer2012Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServer2012Dialect.java @@ -48,8 +48,8 @@ public String getSequenceNextValString(String sequenceName) { @Override public String getQuerySequencesString() { - // The upper-case name should work on both case-sensitive and case-insensitive collations. - return "select * from information_schema.sequences"; + // The upper-case name is necessary here so that both case-sensitive and case-insensitive collations work + return "select * from INFORMATION_SCHEMA.SEQUENCES"; } @Override From 40ed10e9fa08191ca9b252ef8499fee1693fc227 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Sun, 6 Jun 2021 20:46:20 +0100 Subject: [PATCH 195/644] HHH-14662 Remove unnecessary statuful lambda instances from StatisticsImpl --- .../stat/internal/StatisticsImpl.java | 114 +++++++++++------- 1 file changed, 68 insertions(+), 46 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/stat/internal/StatisticsImpl.java b/hibernate-core/src/main/java/org/hibernate/stat/internal/StatisticsImpl.java index 62d4e95121d0..70a1fe847a61 100644 --- a/hibernate-core/src/main/java/org/hibernate/stat/internal/StatisticsImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/stat/internal/StatisticsImpl.java @@ -224,7 +224,7 @@ public String[] getEntityNames() { public EntityStatisticsImpl getEntityStatistics(String entityName) { return entityStatsMap.getOrCompute( entityName, - s -> new EntityStatisticsImpl( metamodel.entityPersister( s ) ) + this::instantiateEntityStatistics ); } @@ -328,7 +328,7 @@ public String[] getCollectionRoleNames() { public CollectionStatisticsImpl getCollectionStatistics(String role) { return collectionStatsMap.getOrCompute( role, - s -> new CollectionStatisticsImpl( metamodel.collectionPersister( s ) ) + this::instantiateCollectionStatistics ); } @@ -416,13 +416,7 @@ public void collectionCacheMiss(NavigableRole collectionRole, String regionName) public NaturalIdStatisticsImpl getNaturalIdStatistics(String rootEntityName) { return naturalIdQueryStatsMap.getOrCompute( rootEntityName, - s -> { - final EntityPersister entityDescriptor = metamodel.entityPersister( s ); - if ( !entityDescriptor.hasNaturalIdentifier() ) { - throw new IllegalArgumentException( "Given entity [" + s + "] does not define natural-id" ); - } - return new NaturalIdStatisticsImpl( entityDescriptor ); - } + this::instantiateNaturalStatistics ); } @@ -431,10 +425,7 @@ public DeprecatedNaturalIdCacheStatisticsImpl getNaturalIdCacheStatistics(String final String key = cache.unqualifyRegionName( regionName ); return deprecatedNaturalIdStatsMap.getOrCompute( key, - unqualifiedRegionName -> new DeprecatedNaturalIdCacheStatisticsImpl( - unqualifiedRegionName, - cache.getNaturalIdAccessesInRegion( unqualifiedRegionName ) - ) + this::instantiateDeprecatedNaturalIdCacheStatistics ); } @@ -563,21 +554,7 @@ public String[] getSecondLevelCacheRegionNames() { public CacheRegionStatisticsImpl getDomainDataRegionStatistics(String regionName) { return l2CacheStatsMap.getOrCompute( regionName, - s -> { - final Region region = cache.getRegion( s ); - - if ( region == null ) { - throw new IllegalArgumentException( "Unknown cache region : " + s ); - } - - if ( region instanceof QueryResultsRegion ) { - throw new IllegalArgumentException( - "Region name [" + s + "] referred to a query result region, not a domain data region" - ); - } - - return new CacheRegionStatisticsImpl( region ); - } + this::instantiateCacheRegionStatistics ); } @@ -608,22 +585,7 @@ public CacheRegionStatisticsImpl getCacheRegionStatistics(String regionName) { return l2CacheStatsMap.getOrCompute( regionName, - s -> { - Region region = cache.getRegion( s ); - - if ( region == null ) { - - if ( ! queryCacheEnabled ) { - return null; - } - - // this is the pre-5.3 behavior. and since this is a pre-5.3 method it should behave consistently - // NOTE that this method is deprecated - region = cache.getQueryResultsCache( s ).getRegion(); - } - - return new CacheRegionStatisticsImpl( region ); - } + this::createCacheRegionStatistics ); } @@ -690,7 +652,7 @@ public String[] getQueries() { public QueryStatisticsImpl getQueryStatistics(String queryString) { return queryStatsMap.getOrCompute( queryString, - s -> new QueryStatisticsImpl( s ) + QueryStatisticsImpl::new ); } @@ -825,7 +787,7 @@ public void queryPlanCacheMiss(String query) { private CacheRegionStatisticsImpl getQueryRegionStats(String regionName) { return l2CacheStatsMap.getOrCompute( regionName, - s -> new CacheRegionStatisticsImpl( cache.getQueryResultsCache( regionName ).getRegion() ) + this::instantiateCacheRegionStatsForQueryResults ); } @@ -998,4 +960,64 @@ public String toString() { .append( ']' ) .toString(); } + + private EntityStatisticsImpl instantiateEntityStatistics(final String entityName) { + return new EntityStatisticsImpl( metamodel.entityPersister( entityName ) ); + } + + private CollectionStatisticsImpl instantiateCollectionStatistics(final String role) { + return new CollectionStatisticsImpl( metamodel.collectionPersister( role ) ); + } + + private NaturalIdStatisticsImpl instantiateNaturalStatistics(final String entityName) { + final EntityPersister entityDescriptor = metamodel.entityPersister( entityName ); + if ( !entityDescriptor.hasNaturalIdentifier() ) { + throw new IllegalArgumentException( "Given entity [" + entityName + "] does not define natural-id" ); + } + return new NaturalIdStatisticsImpl( entityDescriptor ); + } + + private DeprecatedNaturalIdCacheStatisticsImpl instantiateDeprecatedNaturalIdCacheStatistics(final String unqualifiedRegionName) { + return new DeprecatedNaturalIdCacheStatisticsImpl( + unqualifiedRegionName, + cache.getNaturalIdAccessesInRegion( unqualifiedRegionName ) + ); + } + + private CacheRegionStatisticsImpl instantiateCacheRegionStatistics(final String regionName) { + final Region region = cache.getRegion( regionName ); + + if ( region == null ) { + throw new IllegalArgumentException( "Unknown cache region : " + regionName ); + } + + if ( region instanceof QueryResultsRegion ) { + throw new IllegalArgumentException( + "Region name [" + regionName + "] referred to a query result region, not a domain data region" + ); + } + + return new CacheRegionStatisticsImpl( region ); + } + + private CacheRegionStatisticsImpl instantiateCacheRegionStatsForQueryResults(final String regionName) { + return new CacheRegionStatisticsImpl( cache.getQueryResultsCache( regionName ).getRegion() ); + } + + private CacheRegionStatisticsImpl createCacheRegionStatistics(final String regionName) { + Region region = cache.getRegion( regionName ); + + if ( region == null ) { + + if ( !queryCacheEnabled ) { + return null; + } + + // this is the pre-5.3 behavior. and since this is a pre-5.3 method it should behave consistently + // NOTE that this method is deprecated + region = cache.getQueryResultsCache( regionName ).getRegion(); + } + + return new CacheRegionStatisticsImpl( region ); + } } From 6155f95cf78e35196e6d6c89f338a8bedee95d81 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Sun, 6 Jun 2021 20:49:21 +0100 Subject: [PATCH 196/644] HHH-14661 GraalVM support should not register ANTLR parser nodes when the Parser isn't reacheable --- .../graalvm/internal/QueryParsingSupport.java | 152 ++++++++++++++++++ .../graalvm/internal/StaticClassLists.java | 61 ------- 2 files changed, 152 insertions(+), 61 deletions(-) create mode 100644 hibernate-graalvm/src/main/java/org/hibernate/graalvm/internal/QueryParsingSupport.java diff --git a/hibernate-graalvm/src/main/java/org/hibernate/graalvm/internal/QueryParsingSupport.java b/hibernate-graalvm/src/main/java/org/hibernate/graalvm/internal/QueryParsingSupport.java new file mode 100644 index 000000000000..cc1c2d77b6e8 --- /dev/null +++ b/hibernate-graalvm/src/main/java/org/hibernate/graalvm/internal/QueryParsingSupport.java @@ -0,0 +1,152 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.graalvm.internal; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Executable; +import java.util.ArrayList; +import java.util.concurrent.atomic.AtomicBoolean; + +import org.hibernate.internal.util.ReflectHelper; + +import com.oracle.svm.core.annotate.AutomaticFeature; +import org.graalvm.nativeimage.hosted.Feature; +import org.graalvm.nativeimage.hosted.RuntimeReflection; + +/** + * This registers all ANTLR parser nodes for reflection, something that is necessary + * as the HQL parser's inner workings are based on reflection. + * This is different than the "static" registrations of {@link GraalVMStaticAutofeature} + * as we only register these if the HQL parser is actually reachable: some particularly + * simple applications might not need dynamic queries being expressed in string form, + * and for such cases the reflective registrations can be skipped. + * + * At time of writing, this is particularly unlikely to be effective as Hibernate ORM + * requires the parsers during bootstrap, but there is reasonable hope that this might + * be improved on, and can already be used by framework integrations which are able + * to bypass the traditional boot sequence. + * + * @author Sanne Grinovero + */ +@AutomaticFeature +public final class QueryParsingSupport implements Feature { + + private final AtomicBoolean triggered = new AtomicBoolean( false); + + /** + * To set this, add `-J-Dorg.hibernate.graalvm.diagnostics=true` to the native-image parameters + */ + private static final boolean log = Boolean.getBoolean( "org.hibernate.graalvm.diagnostics" ); + + @Override + public void beforeAnalysis(BeforeAnalysisAccess access) { + Class lexerClazz = access.findClassByName("org.hibernate.hql.internal.ast.HqlLexer"); + Class parserClazz = access.findClassByName("org.hibernate.hql.internal.ast.HqlParser"); + access.registerReachabilityHandler(this::enableHQLSupport, lexerClazz); + access.registerReachabilityHandler(this::enableHQLSupport, parserClazz); + } + + private void enableHQLSupport(DuringAnalysisAccess duringAnalysisAccess) { + final boolean needsEnablingYet = triggered.compareAndSet( false, true ); + if ( needsEnablingYet ) { + if ( log ) { + System.out.println( "Hibernate ORM 's automatic feature for GraalVM native images: enabling support for HQL query parsing" ); + } + enableAntlrParsersSupport(); + } + } + + private void enableAntlrParsersSupport() { + final Class[] needsHavingSimpleConstructors = typesNeedingDefaultConstructorAccessible(); + final Class[] neddingAllConstructorsAccessible = typesNeedingAllConstructorsAccessible(); + //Size formula is just a reasonable guess: + ArrayList executables = new ArrayList<>( needsHavingSimpleConstructors.length + neddingAllConstructorsAccessible.length * 3 ); + for ( Class c : needsHavingSimpleConstructors ) { + executables.add( ReflectHelper.getDefaultConstructor( c ) ); + } + for ( Class c : neddingAllConstructorsAccessible ) { + for ( Constructor declaredConstructor : c.getDeclaredConstructors() ) { + executables.add( declaredConstructor ); + } + } + RuntimeReflection.register( needsHavingSimpleConstructors ); + RuntimeReflection.register( neddingAllConstructorsAccessible ); + RuntimeReflection.register( executables.toArray(new Executable[0]) ); + } + + public static Class[] typesNeedingAllConstructorsAccessible() { + return new Class[] { + //ANTLR special ones: + org.hibernate.hql.internal.ast.tree.EntityJoinFromElement.class, + org.hibernate.hql.internal.ast.tree.MapKeyEntityFromElement.class, + org.hibernate.hql.internal.ast.tree.ComponentJoin.class, + }; + } + + public static Class[] typesNeedingDefaultConstructorAccessible() { + return new Class[] { + //Support for @OrderBy + org.hibernate.sql.ordering.antlr.NodeSupport.class, + org.hibernate.sql.ordering.antlr.OrderByFragment.class, + org.hibernate.sql.ordering.antlr.SortSpecification.class, + org.hibernate.sql.ordering.antlr.OrderingSpecification.class, + org.hibernate.sql.ordering.antlr.CollationSpecification.class, + org.hibernate.sql.ordering.antlr.SortKey.class, + + //ANTLR tokens: + antlr.CommonToken.class, + org.hibernate.hql.internal.ast.tree.SelectClause.class, + org.hibernate.hql.internal.ast.tree.HqlSqlWalkerNode.class, + org.hibernate.hql.internal.ast.tree.MethodNode.class, + org.hibernate.hql.internal.ast.tree.UnaryLogicOperatorNode.class, + org.hibernate.hql.internal.ast.tree.NullNode.class, + org.hibernate.hql.internal.ast.tree.IntoClause.class, + org.hibernate.hql.internal.ast.tree.UpdateStatement.class, + org.hibernate.hql.internal.ast.tree.SelectExpressionImpl.class, + org.hibernate.hql.internal.ast.tree.CastFunctionNode.class, + org.hibernate.hql.internal.ast.tree.DeleteStatement.class, + org.hibernate.hql.internal.ast.tree.SqlNode.class, + org.hibernate.hql.internal.ast.tree.SearchedCaseNode.class, + org.hibernate.hql.internal.ast.tree.FromElement.class, + org.hibernate.hql.internal.ast.tree.JavaConstantNode.class, + org.hibernate.hql.internal.ast.tree.SqlFragment.class, + org.hibernate.hql.internal.ast.tree.MapKeyNode.class, + org.hibernate.hql.internal.ast.tree.ImpliedFromElement.class, + org.hibernate.hql.internal.ast.tree.IsNotNullLogicOperatorNode.class, + org.hibernate.hql.internal.ast.tree.InsertStatement.class, + org.hibernate.hql.internal.ast.tree.UnaryArithmeticNode.class, + org.hibernate.hql.internal.ast.tree.CollectionFunction.class, + org.hibernate.hql.internal.ast.tree.BinaryLogicOperatorNode.class, + org.hibernate.hql.internal.ast.tree.CountNode.class, + org.hibernate.hql.internal.ast.tree.IsNullLogicOperatorNode.class, + org.hibernate.hql.internal.ast.tree.IdentNode.class, + org.hibernate.hql.internal.ast.tree.ParameterNode.class, + org.hibernate.hql.internal.ast.tree.MapEntryNode.class, + org.hibernate.hql.internal.ast.tree.MapValueNode.class, + org.hibernate.hql.internal.ast.tree.InLogicOperatorNode.class, + org.hibernate.hql.internal.ast.tree.IndexNode.class, + org.hibernate.hql.internal.ast.tree.DotNode.class, + org.hibernate.hql.internal.ast.tree.ResultVariableRefNode.class, + org.hibernate.hql.internal.ast.tree.BetweenOperatorNode.class, + org.hibernate.hql.internal.ast.tree.AggregateNode.class, + org.hibernate.hql.internal.ast.tree.QueryNode.class, + org.hibernate.hql.internal.ast.tree.BooleanLiteralNode.class, + org.hibernate.hql.internal.ast.tree.SimpleCaseNode.class, + org.hibernate.hql.internal.ast.tree.OrderByClause.class, + org.hibernate.hql.internal.ast.tree.FromClause.class, + org.hibernate.hql.internal.ast.tree.ConstructorNode.class, + org.hibernate.hql.internal.ast.tree.LiteralNode.class, + org.hibernate.hql.internal.ast.tree.BinaryArithmeticOperatorNode.class, + + //Special tokens: + org.hibernate.hql.internal.ast.HqlToken.class, + org.hibernate.hql.internal.ast.tree.Node.class, + + }; + } + +} diff --git a/hibernate-graalvm/src/main/java/org/hibernate/graalvm/internal/StaticClassLists.java b/hibernate-graalvm/src/main/java/org/hibernate/graalvm/internal/StaticClassLists.java index 15480200f0e9..e386e70bd05e 100644 --- a/hibernate-graalvm/src/main/java/org/hibernate/graalvm/internal/StaticClassLists.java +++ b/hibernate-graalvm/src/main/java/org/hibernate/graalvm/internal/StaticClassLists.java @@ -31,79 +31,18 @@ public static Class[] typesNeedingAllConstructorsAccessible() { org.hibernate.persister.entity.UnionSubclassEntityPersister.class, org.hibernate.persister.entity.SingleTableEntityPersister.class, org.hibernate.tuple.entity.PojoEntityTuplizer.class, - //ANTLR special ones: - org.hibernate.hql.internal.ast.tree.EntityJoinFromElement.class, - org.hibernate.hql.internal.ast.tree.MapKeyEntityFromElement.class, - org.hibernate.hql.internal.ast.tree.ComponentJoin.class, }; } public static Class[] typesNeedingDefaultConstructorAccessible() { return new Class[] { - //Support for @OrderBy - org.hibernate.sql.ordering.antlr.NodeSupport.class, - org.hibernate.sql.ordering.antlr.OrderByFragment.class, - org.hibernate.sql.ordering.antlr.SortSpecification.class, - org.hibernate.sql.ordering.antlr.OrderingSpecification.class, - org.hibernate.sql.ordering.antlr.CollationSpecification.class, - org.hibernate.sql.ordering.antlr.SortKey.class, - - //ANTLR tokens: - antlr.CommonToken.class, - org.hibernate.hql.internal.ast.tree.SelectClause.class, - org.hibernate.hql.internal.ast.tree.HqlSqlWalkerNode.class, - org.hibernate.hql.internal.ast.tree.MethodNode.class, - org.hibernate.hql.internal.ast.tree.UnaryLogicOperatorNode.class, - org.hibernate.hql.internal.ast.tree.NullNode.class, - org.hibernate.hql.internal.ast.tree.IntoClause.class, - org.hibernate.hql.internal.ast.tree.UpdateStatement.class, - org.hibernate.hql.internal.ast.tree.SelectExpressionImpl.class, - org.hibernate.hql.internal.ast.tree.CastFunctionNode.class, - org.hibernate.hql.internal.ast.tree.DeleteStatement.class, - org.hibernate.hql.internal.ast.tree.SqlNode.class, - org.hibernate.hql.internal.ast.tree.SearchedCaseNode.class, - org.hibernate.hql.internal.ast.tree.FromElement.class, - org.hibernate.hql.internal.ast.tree.JavaConstantNode.class, - org.hibernate.hql.internal.ast.tree.SqlFragment.class, - org.hibernate.hql.internal.ast.tree.MapKeyNode.class, - org.hibernate.hql.internal.ast.tree.ImpliedFromElement.class, - org.hibernate.hql.internal.ast.tree.IsNotNullLogicOperatorNode.class, - org.hibernate.hql.internal.ast.tree.InsertStatement.class, - org.hibernate.hql.internal.ast.tree.UnaryArithmeticNode.class, - org.hibernate.hql.internal.ast.tree.CollectionFunction.class, - org.hibernate.hql.internal.ast.tree.BinaryLogicOperatorNode.class, - org.hibernate.hql.internal.ast.tree.CountNode.class, - org.hibernate.hql.internal.ast.tree.IsNullLogicOperatorNode.class, - org.hibernate.hql.internal.ast.tree.IdentNode.class, - org.hibernate.hql.internal.ast.tree.ParameterNode.class, - org.hibernate.hql.internal.ast.tree.MapEntryNode.class, - org.hibernate.hql.internal.ast.tree.MapValueNode.class, - org.hibernate.hql.internal.ast.tree.InLogicOperatorNode.class, - org.hibernate.hql.internal.ast.tree.IndexNode.class, - org.hibernate.hql.internal.ast.tree.DotNode.class, - org.hibernate.hql.internal.ast.tree.ResultVariableRefNode.class, - org.hibernate.hql.internal.ast.tree.BetweenOperatorNode.class, - org.hibernate.hql.internal.ast.tree.AggregateNode.class, - org.hibernate.hql.internal.ast.tree.QueryNode.class, - org.hibernate.hql.internal.ast.tree.BooleanLiteralNode.class, - org.hibernate.hql.internal.ast.tree.SimpleCaseNode.class, - org.hibernate.hql.internal.ast.tree.OrderByClause.class, - org.hibernate.hql.internal.ast.tree.FromClause.class, - org.hibernate.hql.internal.ast.tree.ConstructorNode.class, - org.hibernate.hql.internal.ast.tree.LiteralNode.class, - org.hibernate.hql.internal.ast.tree.BinaryArithmeticOperatorNode.class, - //Various well known needs: - org.hibernate.resource.transaction.backend.jdbc.internal.JdbcResourceLocalTransactionCoordinatorBuilderImpl.class, org.hibernate.id.enhanced.SequenceStyleGenerator.class, org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl.class, org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorBuilderImpl.class, EnumType.class, MultipleLinesSqlCommandExtractor.class, - org.hibernate.hql.internal.ast.HqlToken.class, - org.hibernate.hql.internal.ast.tree.Node.class, - }; } From 10cba26bda99c6e0cdc988b57ef63470f2393096 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Tue, 8 Jun 2021 17:08:59 +0200 Subject: [PATCH 197/644] HHH-14665 Use semi-colon as the default statement delimiter for scripts --- .../main/asciidoc/userguide/appendices/Configurations.adoc | 1 + .../src/main/java/org/hibernate/cfg/AvailableSettings.java | 3 ++- .../tool/schema/internal/HibernateSchemaManagementTool.java | 4 ++-- .../schemaupdate/PostgreSQLMultipleSchemaSequenceTest.java | 4 ++-- .../schemaupdate/idgenerator/SequenceGenerationTest.java | 4 ++-- .../schemaupdate/idgenerator/SequenceGeneratorsTest.java | 4 ++-- .../test/schemaupdate/idgenerator/TableGeneratorTest.java | 6 +++--- .../test/schemaupdate/idgenerator/TableGeneratorsTest.java | 6 +++--- .../uniqueconstraint/UniqueConstraintGenerationTest.java | 4 ++-- .../org/hibernate/graalvm/internal/QueryParsingSupport.java | 2 ++ 10 files changed, 21 insertions(+), 17 deletions(-) diff --git a/documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc b/documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc index 832b9d747157..333409606e61 100644 --- a/documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc +++ b/documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc @@ -929,6 +929,7 @@ Valid options are defined by the `strategy` value of the https://docs.jboss.org/ `*hibernate.hbm2ddl.delimiter*` (e.g. `;`):: Identifies the delimiter to use to separate schema management statements in script outputs. +The default value is `;`. `*hibernate.schema_management_tool*` (e.g. A schema name):: Used to specify the `SchemaManagementTool` to use for performing schema management. The default is to use `HibernateSchemaManagementTool`. diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java index 88338b5d0f42..b7efa75376fe 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java @@ -1859,7 +1859,8 @@ public interface AvailableSettings extends org.hibernate.jpa.AvailableSettings { String HBM2DDL_JDBC_METADATA_EXTRACTOR_STRATEGY = "hibernate.hbm2ddl.jdbc_metadata_extraction_strategy"; /** - * Identifies the delimiter to use to separate schema management statements in script outputs + * Identifies the delimiter to use to separate schema management statements in script outputs. + * The default value is ;. */ String HBM2DDL_DELIMITER = "hibernate.hbm2ddl.delimiter"; diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/HibernateSchemaManagementTool.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/HibernateSchemaManagementTool.java index 60cc75ed9a85..7765e9248f77 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/HibernateSchemaManagementTool.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/HibernateSchemaManagementTool.java @@ -123,7 +123,7 @@ GenerationTarget[] buildGenerationTargets( JdbcContext jdbcContext, Map options, boolean needsAutoCommit) { - final String scriptDelimiter = ConfigurationHelper.getString( HBM2DDL_DELIMITER, options ); + final String scriptDelimiter = ConfigurationHelper.getString( HBM2DDL_DELIMITER, options, ";" ); final GenerationTarget[] targets = new GenerationTarget[ targetDescriptor.getTargetTypes().size() ]; @@ -156,7 +156,7 @@ GenerationTarget[] buildGenerationTargets( TargetDescriptor targetDescriptor, DdlTransactionIsolator ddlTransactionIsolator, Map options) { - final String scriptDelimiter = ConfigurationHelper.getString( HBM2DDL_DELIMITER, options ); + final String scriptDelimiter = ConfigurationHelper.getString( HBM2DDL_DELIMITER, options, ";" ); final GenerationTarget[] targets = new GenerationTarget[ targetDescriptor.getTargetTypes().size() ]; diff --git a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/PostgreSQLMultipleSchemaSequenceTest.java b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/PostgreSQLMultipleSchemaSequenceTest.java index caa10efa4871..ad5fc1afebc7 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/PostgreSQLMultipleSchemaSequenceTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/PostgreSQLMultipleSchemaSequenceTest.java @@ -85,7 +85,7 @@ public void test() { ); try(Statement statement = ddlTransactionIsolator1.getIsolatedConnection().createStatement()) { statement.execute( String.format( "DROP SCHEMA IF EXISTS %s CASCADE", extraSchemaName ) ); - statement.execute( String.format( "CREATE SCHEMA %s", extraSchemaName ) ); + statement.execute( String.format( "CREATE SCHEMA %s;", extraSchemaName ) ); try(ResultSet resultSet = statement.executeQuery( "SELECT NEXTVAL('SEQ_TEST')" )) { while ( resultSet.next() ) { @@ -156,7 +156,7 @@ public void test() { assertEquals( 2 , sqlLines .stream() - .filter( s -> s.equalsIgnoreCase( "create sequence SEQ_TEST start 1 increment 1" ) ) + .filter( s -> s.equalsIgnoreCase( "create sequence SEQ_TEST start 1 increment 1;" ) ) .count() ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/idgenerator/SequenceGenerationTest.java b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/idgenerator/SequenceGenerationTest.java index 0cc4b946417e..9f604f7b9945 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/idgenerator/SequenceGenerationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/idgenerator/SequenceGenerationTest.java @@ -68,12 +68,12 @@ public void testSequenceIsGenerated() throws Exception { List commands = Files.readAllLines( output.toPath() ); assertThat( - isCommandGenerated( commands, "create table test_entity \\(id .*, primary key \\(id\\)\\)" ), + isCommandGenerated( commands, "create table test_entity \\(id .*, primary key \\(id\\)\\);" ), is( true ) ); assertThat( - isCommandGenerated( commands, "create sequence sequence_generator start with 5 increment by 3" ), + isCommandGenerated( commands, "create sequence sequence_generator start with 5 increment by 3;" ), is( true ) ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/idgenerator/SequenceGeneratorsTest.java b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/idgenerator/SequenceGeneratorsTest.java index 236e7ff984d2..45941b2b7281 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/idgenerator/SequenceGeneratorsTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/idgenerator/SequenceGeneratorsTest.java @@ -70,12 +70,12 @@ public void testSequenceIsGenerated() throws Exception { List commands = Files.readAllLines( output.toPath() ); assertThat( - isCommandGenerated( commands, "CREATE TABLE TEST_ENTITY \\(ID .*, PRIMARY KEY \\(ID\\)\\)" ), + isCommandGenerated( commands, "CREATE TABLE TEST_ENTITY \\(ID .*, PRIMARY KEY \\(ID\\)\\);" ), is( true ) ); assertThat( - isCommandGenerated( commands, "CREATE SEQUENCE SEQUENCE_GENERATOR START WITH 5 INCREMENT BY 3" ), + isCommandGenerated( commands, "CREATE SEQUENCE SEQUENCE_GENERATOR START WITH 5 INCREMENT BY 3;" ), is( true ) ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/idgenerator/TableGeneratorTest.java b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/idgenerator/TableGeneratorTest.java index 1cd2ca335eea..249bb17cf98d 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/idgenerator/TableGeneratorTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/idgenerator/TableGeneratorTest.java @@ -71,13 +71,13 @@ public void testTableGeneratorIsGenerated() throws Exception { final List commands = Files.readAllLines( output.toPath() ); - final String expectedTestEntityTableCreationCommand = "CREATE TABLE TEST_ENTITY \\(ID .*, PRIMARY KEY \\(ID\\)\\)"; + final String expectedTestEntityTableCreationCommand = "CREATE TABLE TEST_ENTITY \\(ID .*, PRIMARY KEY \\(ID\\)\\);"; assertTrue( "The command '" + expectedTestEntityTableCreationCommand + "' has not been correctly generated", isCommandGenerated( commands, expectedTestEntityTableCreationCommand ) ); - final String expectedIdTableGeneratorCreationCommand = "CREATE TABLE ID_TABLE_GENERATOR \\(PK .*, VALUE .*, PRIMARY KEY \\(PK\\)\\)"; + final String expectedIdTableGeneratorCreationCommand = "CREATE TABLE ID_TABLE_GENERATOR \\(PK .*, VALUE .*, PRIMARY KEY \\(PK\\)\\);"; assertTrue( "The command '" + expectedIdTableGeneratorCreationCommand + "' has not been correctly generated", @@ -88,7 +88,7 @@ public void testTableGeneratorIsGenerated() throws Exception { ) ); - final String expectedInsertIntoTableGeneratorCommand = "INSERT INTO ID_TABLE_GENERATOR\\(PK, VALUE\\) VALUES \\('TEST_ENTITY_ID'," + EXPECTED_DB_INSERTED_VALUE + "\\)"; + final String expectedInsertIntoTableGeneratorCommand = "INSERT INTO ID_TABLE_GENERATOR\\(PK, VALUE\\) VALUES \\('TEST_ENTITY_ID'," + EXPECTED_DB_INSERTED_VALUE + "\\);"; assertTrue( "The command '" + expectedInsertIntoTableGeneratorCommand + "' has not been correctly generated", diff --git a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/idgenerator/TableGeneratorsTest.java b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/idgenerator/TableGeneratorsTest.java index 8195b899e680..1ce8aa1b2ee4 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/idgenerator/TableGeneratorsTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/idgenerator/TableGeneratorsTest.java @@ -72,13 +72,13 @@ public void testTableGeneratorIsGenerated() throws Exception { final List commands = Files.readAllLines( output.toPath() ); - final String expectedTestEntityTableCreationCommand = "CREATE TABLE TEST_ENTITY \\(ID .*, PRIMARY KEY \\(ID\\)\\)"; + final String expectedTestEntityTableCreationCommand = "CREATE TABLE TEST_ENTITY \\(ID .*, PRIMARY KEY \\(ID\\)\\);"; assertTrue( "The command '" + expectedTestEntityTableCreationCommand + "' has not been correctly generated", isCommandGenerated( commands, expectedTestEntityTableCreationCommand ) ); - final String expectedIdTableGeneratorCreationCommand = "CREATE TABLE ID_TABLE_GENERATOR \\(PK .*, VALUE .*, PRIMARY KEY \\(PK\\)\\)"; + final String expectedIdTableGeneratorCreationCommand = "CREATE TABLE ID_TABLE_GENERATOR \\(PK .*, VALUE .*, PRIMARY KEY \\(PK\\)\\);"; assertTrue( "The command '" + expectedIdTableGeneratorCreationCommand + "' has not been correctly generated", @@ -89,7 +89,7 @@ public void testTableGeneratorIsGenerated() throws Exception { ) ); - final String expectedInsertIntoTableGeneratorCommand = "INSERT INTO ID_TABLE_GENERATOR\\(PK, VALUE\\) VALUES \\('TEST_ENTITY_ID'," + EXPECTED_DB_INSERTED_VALUE + "\\)"; + final String expectedInsertIntoTableGeneratorCommand = "INSERT INTO ID_TABLE_GENERATOR\\(PK, VALUE\\) VALUES \\('TEST_ENTITY_ID'," + EXPECTED_DB_INSERTED_VALUE + "\\);"; assertTrue( "The command '" + expectedInsertIntoTableGeneratorCommand + "' has not been correctly generated", diff --git a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/uniqueconstraint/UniqueConstraintGenerationTest.java b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/uniqueconstraint/UniqueConstraintGenerationTest.java index bfecfad11e9c..ef13a300b127 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/uniqueconstraint/UniqueConstraintGenerationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/uniqueconstraint/UniqueConstraintGenerationTest.java @@ -93,7 +93,7 @@ private Dialect getDialect() { private boolean isUniqueConstraintGenerated(String tableName, String columnName) throws IOException { boolean matches = false; - final String regex = getDialect().getAlterTableString( tableName ) + " add constraint uk_(.)* unique \\(" + columnName + "\\)"; + final String regex = getDialect().getAlterTableString( tableName ) + " add constraint uk_(.)* unique \\(" + columnName + "\\);"; final String fileContent = new String( Files.readAllBytes( output.toPath() ) ).toLowerCase(); final String[] split = fileContent.split( System.lineSeparator() ); @@ -109,7 +109,7 @@ private boolean isUniqueConstraintGenerated(String tableName, String columnName) private boolean isCreateUniqueIndexGenerated(String tableName, String columnName) throws IOException { boolean matches = false; - String regex = "create unique index uk_(.)* on " + tableName + " \\(" + columnName + "\\)"; + String regex = "create unique index uk_(.)* on " + tableName + " \\(" + columnName + "\\);"; final String fileContent = new String( Files.readAllBytes( output.toPath() ) ).toLowerCase(); final String[] split = fileContent.split( System.lineSeparator() ); diff --git a/hibernate-graalvm/src/main/java/org/hibernate/graalvm/internal/QueryParsingSupport.java b/hibernate-graalvm/src/main/java/org/hibernate/graalvm/internal/QueryParsingSupport.java index cc1c2d77b6e8..28b1833e77d0 100644 --- a/hibernate-graalvm/src/main/java/org/hibernate/graalvm/internal/QueryParsingSupport.java +++ b/hibernate-graalvm/src/main/java/org/hibernate/graalvm/internal/QueryParsingSupport.java @@ -11,6 +11,7 @@ import java.util.ArrayList; import java.util.concurrent.atomic.AtomicBoolean; +import org.hibernate.internal.build.AllowSysOut; import org.hibernate.internal.util.ReflectHelper; import com.oracle.svm.core.annotate.AutomaticFeature; @@ -50,6 +51,7 @@ public void beforeAnalysis(BeforeAnalysisAccess access) { access.registerReachabilityHandler(this::enableHQLSupport, parserClazz); } + @AllowSysOut private void enableHQLSupport(DuringAnalysisAccess duringAnalysisAccess) { final boolean needsEnablingYet = triggered.compareAndSet( false, true ); if ( needsEnablingYet ) { From 66ae1c9557f6feb5cdb5e77edf936dec2cb980bf Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Tue, 8 Jun 2021 23:05:51 +0200 Subject: [PATCH 198/644] HHH-14665 Fix schema generation test missing the default semi-colon in comments --- .../java/org/hibernate/test/schemaupdate/TableCommentTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/TableCommentTest.java b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/TableCommentTest.java index 5726267e09e5..afa69db71dd1 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/TableCommentTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/TableCommentTest.java @@ -61,7 +61,7 @@ public void testCommentOnTableStatementIsGenerated() throws IOException { final String tableName = getTableName(); for ( String sqlStatement : sqlLines ) { if ( sqlStatement.toLowerCase() - .equals( "comment on table " + tableName.toLowerCase() + " is 'comment snippet'" ) ) { + .equals( "comment on table " + tableName.toLowerCase() + " is 'comment snippet';" ) ) { if ( getDialect().supportsCommentOn() ) { found = true; } From 0eb187fae49f3e24a1d6ebafa3913f8112b0a083 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Mon, 7 Jun 2021 10:40:38 +0200 Subject: [PATCH 199/644] HHH-14659 Test join fetch correctly in HHH3949Test --- .../test/bytecode/enhancement/join/HHH3949Test.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/join/HHH3949Test.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/join/HHH3949Test.java index e39604755e52..6ab4bc36a22c 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/join/HHH3949Test.java +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/join/HHH3949Test.java @@ -23,6 +23,7 @@ import java.util.List; import static org.hibernate.Hibernate.isInitialized; +import static org.hibernate.Hibernate.isPropertyInitialized; import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -131,6 +132,11 @@ private void performQueryAndVerifyPersonResults(String query) { for ( Person person : persons ) { assertTrue( isInitialized( person ) ); if ( shouldHaveVehicle( person ) ) { + // We used a "join fetch", so the vehicle must be initialized + // before we even call the getter + // (which could trigger lazy initialization if the join fetch didn't work). + assertTrue( isPropertyInitialized( person, "vehicle" ) ); + assertNotNull( person.getVehicle() ); assertTrue( isInitialized( person.getVehicle() ) ); assertNotNull( person.getVehicle().getDriver() ); @@ -146,6 +152,11 @@ private void performQueryAndVerifyVehicleResults(String query) { } for ( Vehicle vehicle : vehicles ) { if ( shouldHaveDriver( vehicle ) ) { + // We used a "join fetch", so the drover must be initialized + // before we even call the getter + // (which could trigger lazy initialization if the join fetch didn't work). + assertTrue( isPropertyInitialized( vehicle, "driver" ) ); + assertNotNull( vehicle.getDriver() ); assertNotNull( vehicle.getDriver().getVehicle() ); } From 50b8ad1f2b62b0bfe4c249ad28288271af2ff8e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Mon, 7 Jun 2021 11:10:59 +0200 Subject: [PATCH 200/644] HHH-14659 Test query "join fetch" on lazy to-one associations with bytecode enhancement --- .../JoinFetchedManyToOneAllowProxyTests.java | 61 +++++++++++++++---- .../manytoone/ManyToOneAllowProxyTests.java | 28 ++++++++- .../ManyToOneExplicitOptionTests.java | 49 +++++++++++---- .../mappedby/InverseToOneAllowProxyTests.java | 27 +++++++- .../InverseToOneExplicitOptionTests.java | 49 +++++++++++---- ...oinFetchedInverseToOneAllowProxyTests.java | 27 +++++++- .../JoinFetchedOneToOneAllowProxyTests.java | 27 +++++++- .../onetoone/OneToOneAllowProxyTests.java | 27 +++++++- .../onetoone/OneToOneExplicitOptionTests.java | 27 +++++++- .../JoinFetchedPolymorphicToOneTests.java | 16 +++++ .../PolymorphicToOneExplicitOptionTests.java | 17 ++++++ .../PolymorphicToOneImplicitOptionTests.java | 17 ++++++ 12 files changed, 327 insertions(+), 45 deletions(-) diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/manytoone/JoinFetchedManyToOneAllowProxyTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/manytoone/JoinFetchedManyToOneAllowProxyTests.java index 70354ce1c15d..5274ebf6dc86 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/manytoone/JoinFetchedManyToOneAllowProxyTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/manytoone/JoinFetchedManyToOneAllowProxyTests.java @@ -20,12 +20,17 @@ import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor; import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata; import org.hibernate.cfg.AvailableSettings; +import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.testing.BeforeClassOnce; +import org.hibernate.testing.TestForIssue; import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; import org.hibernate.testing.bytecode.enhancement.EnhancementOptions; import org.hibernate.testing.jdbc.SQLStatementInterceptor; import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; +import org.junit.After; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -36,6 +41,7 @@ import static org.hamcrest.CoreMatchers.sameInstance; import static org.hamcrest.MatcherAssert.assertThat; import static org.hibernate.annotations.FetchMode.JOIN; +import static org.junit.Assert.assertTrue; /** * Test for lazy uni-directional to-one (with JOIN fetching) when enhanced proxies are allowed @@ -61,17 +67,6 @@ protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBu @Test public void testOwnerIsProxy() { - inTransaction( - (session) -> { - final Customer customer = new Customer( 1, "Acme Brick" ); - session.persist( customer ); - final Order order = new Order( 1, customer, BigDecimal.ONE ); - session.persist( order ); - } - ); - - sqlStatementInterceptor.clear(); - final EntityPersister orderDescriptor = sessionFactory().getMetamodel().entityPersister( Order.class ); final BytecodeEnhancementMetadata orderEnhancementMetadata = orderDescriptor.getBytecodeEnhancementMetadata(); assertThat( orderEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) ); @@ -116,6 +111,50 @@ public void testOwnerIsProxy() { ); } + @Test + @TestForIssue(jiraKey = "HHH-14659") + public void testQueryJoinFetch() { + Order order = fromTransaction( (session) -> { + final Order result = session.createQuery( + "select o from Order o join fetch o.customer", + Order.class ) + .uniqueResult(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) ); + return result; + } ); + + // The "join fetch" should have already initialized the property, + // so that the getter can safely be called outside of a session. + assertTrue( Hibernate.isPropertyInitialized( order, "customer" ) ); + // The "join fetch" should have already initialized the associated entity. + Customer customer = order.getCustomer(); + assertTrue( Hibernate.isInitialized( customer ) ); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) ); + } + + @Before + public void createTestData() { + inTransaction( + (session) -> { + final Customer customer = new Customer( 1, "Acme Brick" ); + session.persist( customer ); + final Order order = new Order( 1, customer, BigDecimal.ONE ); + session.persist( order ); + } + ); + sqlStatementInterceptor.clear(); + } + + @After + public void dropTestData() { + inTransaction( + (session) -> { + session.createQuery( "delete Order" ).executeUpdate(); + session.createQuery( "delete Customer" ).executeUpdate(); + } + ); + } + @Entity( name = "Customer" ) @Table( name = "customer" ) public static class Customer { diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/manytoone/ManyToOneAllowProxyTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/manytoone/ManyToOneAllowProxyTests.java index 085ae6388833..81ba37a20678 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/manytoone/ManyToOneAllowProxyTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/manytoone/ManyToOneAllowProxyTests.java @@ -12,6 +12,7 @@ import javax.persistence.ManyToOne; import javax.persistence.Table; +import org.hibernate.Hibernate; import org.hibernate.boot.MetadataSources; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.bytecode.enhance.spi.interceptor.BytecodeLazyAttributeInterceptor; @@ -19,8 +20,10 @@ import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor; import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata; import org.hibernate.cfg.AvailableSettings; +import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.testing.TestForIssue; import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; import org.hibernate.testing.bytecode.enhancement.EnhancementOptions; import org.hibernate.testing.jdbc.SQLStatementInterceptor; @@ -36,6 +39,7 @@ import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.CoreMatchers.sameInstance; import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertTrue; /** * Test for lazy uni-directional to-one (with SELECT fetching) when enhanced proxies are allowed @@ -61,8 +65,6 @@ protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBu @Test public void testOwnerIsProxy() { - sqlStatementInterceptor.clear(); - final EntityPersister orderDescriptor = sessionFactory().getMetamodel().entityPersister( Order.class ); final BytecodeEnhancementMetadata orderEnhancementMetadata = orderDescriptor.getBytecodeEnhancementMetadata(); assertThat( orderEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) ); @@ -115,6 +117,27 @@ public void testOwnerIsProxy() { ); } + @Test + @TestForIssue(jiraKey = "HHH-14659") + public void testQueryJoinFetch() { + Order order = fromTransaction( (session) -> { + final Order result = session.createQuery( + "select o from Order o join fetch o.customer", + Order.class ) + .uniqueResult(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) ); + return result; + } ); + + // The "join fetch" should have already initialized the property, + // so that the getter can safely be called outside of a session. + assertTrue( Hibernate.isPropertyInitialized( order, "customer" ) ); + // The "join fetch" should have already initialized the associated entity. + Customer customer = order.getCustomer(); + assertTrue( Hibernate.isInitialized( customer ) ); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) ); + } + @Before public void createTestData() { inTransaction( @@ -125,6 +148,7 @@ public void createTestData() { session.persist( order ); } ); + sqlStatementInterceptor.clear(); } @After diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/manytoone/ManyToOneExplicitOptionTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/manytoone/ManyToOneExplicitOptionTests.java index b88991d0763f..5eecf3134ca3 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/manytoone/ManyToOneExplicitOptionTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/manytoone/ManyToOneExplicitOptionTests.java @@ -12,6 +12,7 @@ import javax.persistence.ManyToOne; import javax.persistence.Table; +import org.hibernate.Hibernate; import org.hibernate.annotations.LazyToOne; import org.hibernate.boot.MetadataSources; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; @@ -22,11 +23,13 @@ import org.hibernate.cfg.AvailableSettings; import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.testing.TestForIssue; import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; import org.hibernate.testing.bytecode.enhancement.EnhancementOptions; import org.hibernate.testing.jdbc.SQLStatementInterceptor; import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; import org.junit.After; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -37,6 +40,7 @@ import static org.hamcrest.CoreMatchers.sameInstance; import static org.hamcrest.MatcherAssert.assertThat; import static org.hibernate.annotations.LazyToOneOption.NO_PROXY; +import static org.junit.Assert.assertTrue; /** * Baseline test for uni-directional to-one, using an explicit @LazyToOne(NO_PROXY) @@ -64,17 +68,6 @@ protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBu @Test public void testOwnerIsProxy() { - inTransaction( - (session) -> { - final Customer customer = new Customer( 1, "Acme Brick" ); - session.persist( customer ); - final Order order = new Order( 1, customer, BigDecimal.ONE ); - session.persist( order ); - } - ); - - sqlStatementInterceptor.clear(); - final EntityPersister orderDescriptor = sessionFactory().getMetamodel().entityPersister( Order.class ); final BytecodeEnhancementMetadata orderEnhancementMetadata = orderDescriptor.getBytecodeEnhancementMetadata(); assertThat( orderEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) ); @@ -127,6 +120,40 @@ public void testOwnerIsProxy() { ); } + @Test + @TestForIssue(jiraKey = "HHH-14659") + public void testQueryJoinFetch() { + Order order = fromTransaction( (session) -> { + final Order result = session.createQuery( + "select o from Order o join fetch o.customer", + Order.class ) + .uniqueResult(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) ); + return result; + } ); + + // The "join fetch" should have already initialized the property, + // so that the getter can safely be called outside of a session. + assertTrue( Hibernate.isPropertyInitialized( order, "customer" ) ); + // The "join fetch" should have already initialized the associated entity. + Customer customer = order.getCustomer(); + assertTrue( Hibernate.isInitialized( customer ) ); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) ); + } + + @Before + public void createTestData() { + inTransaction( + (session) -> { + final Customer customer = new Customer( 1, "Acme Brick" ); + session.persist( customer ); + final Order order = new Order( 1, customer, BigDecimal.ONE ); + session.persist( order ); + } + ); + sqlStatementInterceptor.clear(); + } + @After public void dropTestData() { inTransaction( diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/mappedby/InverseToOneAllowProxyTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/mappedby/InverseToOneAllowProxyTests.java index 9f27598f1452..4637c0c1a746 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/mappedby/InverseToOneAllowProxyTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/mappedby/InverseToOneAllowProxyTests.java @@ -11,6 +11,7 @@ import javax.persistence.OneToOne; import javax.persistence.Table; +import org.hibernate.Hibernate; import org.hibernate.boot.MetadataSources; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.bytecode.enhance.spi.interceptor.BytecodeLazyAttributeInterceptor; @@ -20,6 +21,7 @@ import org.hibernate.cfg.AvailableSettings; import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.testing.TestForIssue; import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; import org.hibernate.testing.bytecode.enhancement.EnhancementOptions; import org.hibernate.testing.jdbc.SQLStatementInterceptor; @@ -35,6 +37,7 @@ import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.CoreMatchers.sameInstance; import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertTrue; /** * @author Steve Ebersole @@ -60,8 +63,6 @@ protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBu @Test public void testOwnerIsProxy() { - sqlStatementInterceptor.clear(); - final EntityPersister supplementalInfoDescriptor = sessionFactory().getMetamodel().entityPersister( SupplementalInfo.class ); final BytecodeEnhancementMetadata supplementalInfoEnhancementMetadata = supplementalInfoDescriptor.getBytecodeEnhancementMetadata(); assertThat( supplementalInfoEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) ); @@ -113,6 +114,27 @@ public void testOwnerIsProxy() { ); } + @Test + @TestForIssue(jiraKey = "HHH-14659") + public void testQueryJoinFetch() { + SupplementalInfo info = fromTransaction( (session) -> { + final SupplementalInfo result = session.createQuery( + "select s from SupplementalInfo s join fetch s.customer", + SupplementalInfo.class ) + .uniqueResult(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) ); + return result; + } ); + + // The "join fetch" should have already initialized the property, + // so that the getter can safely be called outside of a session. + assertTrue( Hibernate.isPropertyInitialized( info, "customer" ) ); + // The "join fetch" should have already initialized the associated entity. + Customer customer = info.getCustomer(); + assertTrue( Hibernate.isInitialized( customer ) ); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) ); + } + @Before public void createTestData() { inTransaction( @@ -123,6 +145,7 @@ public void createTestData() { session.persist( supplementalInfo ); } ); + sqlStatementInterceptor.clear(); } @After diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/mappedby/InverseToOneExplicitOptionTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/mappedby/InverseToOneExplicitOptionTests.java index 6c19c1139a1e..f4c413e791d4 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/mappedby/InverseToOneExplicitOptionTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/mappedby/InverseToOneExplicitOptionTests.java @@ -11,6 +11,7 @@ import javax.persistence.OneToOne; import javax.persistence.Table; +import org.hibernate.Hibernate; import org.hibernate.annotations.LazyToOne; import org.hibernate.boot.MetadataSources; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; @@ -20,11 +21,13 @@ import org.hibernate.cfg.AvailableSettings; import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.testing.TestForIssue; import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; import org.hibernate.testing.bytecode.enhancement.EnhancementOptions; import org.hibernate.testing.jdbc.SQLStatementInterceptor; import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; import org.junit.After; +import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -33,6 +36,7 @@ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static org.hibernate.annotations.LazyToOneOption.NO_PROXY; +import static org.junit.Assert.assertTrue; /** * Baseline test for inverse (mappedBy) to-one, using an explicit @LazyToOne(NO_PROXY) @@ -58,17 +62,6 @@ protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBu @Test public void testOwnerIsProxy() { - inTransaction( - (session) -> { - final Customer customer = new Customer( 1, "Acme Brick" ); - session.persist( customer ); - final SupplementalInfo supplementalInfo = new SupplementalInfo( 1, customer, "extra details" ); - session.persist( supplementalInfo ); - } - ); - - sqlStatementInterceptor.clear(); - final EntityPersister supplementalInfoDescriptor = sessionFactory().getMetamodel().entityPersister( SupplementalInfo.class ); final BytecodeEnhancementMetadata supplementalInfoEnhancementMetadata = supplementalInfoDescriptor.getBytecodeEnhancementMetadata(); assertThat( supplementalInfoEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) ); @@ -140,6 +133,40 @@ public void testOwnerIsProxy() { ); } + @Test + @TestForIssue(jiraKey = "HHH-14659") + public void testQueryJoinFetch() { + SupplementalInfo info = fromTransaction( (session) -> { + final SupplementalInfo result = session.createQuery( + "select s from SupplementalInfo s join fetch s.customer", + SupplementalInfo.class ) + .uniqueResult(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) ); + return result; + } ); + + // The "join fetch" should have already initialized the property, + // so that the getter can safely be called outside of a session. + assertTrue( Hibernate.isPropertyInitialized( info, "customer" ) ); + // The "join fetch" should have already initialized the associated entity. + Customer customer = info.getCustomer(); + assertTrue( Hibernate.isInitialized( customer ) ); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) ); + } + + @Before + public void createTestData() { + inTransaction( + (session) -> { + final Customer customer = new Customer( 1, "Acme Brick" ); + session.persist( customer ); + final SupplementalInfo supplementalInfo = new SupplementalInfo( 1, customer, "extra details" ); + session.persist( supplementalInfo ); + } + ); + sqlStatementInterceptor.clear(); + } + @After public void dropTestData() { inTransaction( diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/mappedby/JoinFetchedInverseToOneAllowProxyTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/mappedby/JoinFetchedInverseToOneAllowProxyTests.java index 036a1f247dec..86eec07153c0 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/mappedby/JoinFetchedInverseToOneAllowProxyTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/mappedby/JoinFetchedInverseToOneAllowProxyTests.java @@ -11,6 +11,7 @@ import javax.persistence.OneToOne; import javax.persistence.Table; +import org.hibernate.Hibernate; import org.hibernate.annotations.Fetch; import org.hibernate.boot.MetadataSources; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; @@ -21,6 +22,7 @@ import org.hibernate.cfg.AvailableSettings; import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.testing.TestForIssue; import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; import org.hibernate.testing.bytecode.enhancement.EnhancementOptions; import org.hibernate.testing.jdbc.SQLStatementInterceptor; @@ -37,6 +39,7 @@ import static org.hamcrest.CoreMatchers.sameInstance; import static org.hamcrest.MatcherAssert.assertThat; import static org.hibernate.annotations.FetchMode.JOIN; +import static org.junit.Assert.assertTrue; /** * @author Steve Ebersole @@ -62,8 +65,6 @@ protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBu @Test public void testOwnerIsProxy() { - sqlStatementInterceptor.clear(); - final EntityPersister supplementalInfoDescriptor = sessionFactory().getMetamodel().entityPersister( SupplementalInfo.class ); final BytecodeEnhancementMetadata supplementalInfoEnhancementMetadata = supplementalInfoDescriptor.getBytecodeEnhancementMetadata(); assertThat( supplementalInfoEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) ); @@ -110,6 +111,27 @@ public void testOwnerIsProxy() { ); } + @Test + @TestForIssue(jiraKey = "HHH-14659") + public void testQueryJoinFetch() { + SupplementalInfo info = fromTransaction( (session) -> { + final SupplementalInfo result = session.createQuery( + "select s from SupplementalInfo s join fetch s.customer", + SupplementalInfo.class ) + .uniqueResult(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) ); + return result; + } ); + + // The "join fetch" should have already initialized the property, + // so that the getter can safely be called outside of a session. + assertTrue( Hibernate.isPropertyInitialized( info, "customer" ) ); + // The "join fetch" should have already initialized the associated entity. + Customer customer = info.getCustomer(); + assertTrue( Hibernate.isInitialized( customer ) ); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) ); + } + @Before public void createTestData() { inTransaction( @@ -120,6 +142,7 @@ public void createTestData() { session.persist( supplementalInfo ); } ); + sqlStatementInterceptor.clear(); } @After diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/onetoone/JoinFetchedOneToOneAllowProxyTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/onetoone/JoinFetchedOneToOneAllowProxyTests.java index 6b5c0cfada64..97c4c1c4088f 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/onetoone/JoinFetchedOneToOneAllowProxyTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/onetoone/JoinFetchedOneToOneAllowProxyTests.java @@ -11,6 +11,7 @@ import javax.persistence.OneToOne; import javax.persistence.Table; +import org.hibernate.Hibernate; import org.hibernate.annotations.Fetch; import org.hibernate.boot.MetadataSources; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; @@ -18,6 +19,7 @@ import org.hibernate.cfg.AvailableSettings; import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.testing.TestForIssue; import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; import org.hibernate.testing.bytecode.enhancement.EnhancementOptions; import org.hibernate.testing.jdbc.SQLStatementInterceptor; @@ -31,6 +33,7 @@ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static org.hibernate.annotations.FetchMode.JOIN; +import static org.junit.Assert.assertTrue; /** * @author Steve Ebersole @@ -56,8 +59,6 @@ protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBu @Test public void testOwnerIsProxy() { - sqlStatementInterceptor.clear(); - final EntityPersister supplementalInfoDescriptor = sessionFactory().getMetamodel().entityPersister( SupplementalInfo.class ); final BytecodeEnhancementMetadata supplementalInfoEnhancementMetadata = supplementalInfoDescriptor.getBytecodeEnhancementMetadata(); assertThat( supplementalInfoEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) ); @@ -94,6 +95,27 @@ public void testOwnerIsProxy() { ); } + @Test + @TestForIssue(jiraKey = "HHH-14659") + public void testQueryJoinFetch() { + SupplementalInfo info = fromTransaction( (session) -> { + final SupplementalInfo result = session.createQuery( + "select s from SupplementalInfo s join fetch s.customer", + SupplementalInfo.class ) + .uniqueResult(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) ); + return result; + } ); + + // The "join fetch" should have already initialized the property, + // so that the getter can safely be called outside of a session. + assertTrue( Hibernate.isPropertyInitialized( info, "customer" ) ); + // The "join fetch" should have already initialized the associated entity. + Customer customer = info.getCustomer(); + assertTrue( Hibernate.isInitialized( customer ) ); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) ); + } + @Before public void createTestData() { inTransaction( @@ -104,6 +126,7 @@ public void createTestData() { session.persist( supplementalInfo ); } ); + sqlStatementInterceptor.clear(); } @After diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/onetoone/OneToOneAllowProxyTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/onetoone/OneToOneAllowProxyTests.java index a0c577d6339d..521944eea726 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/onetoone/OneToOneAllowProxyTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/onetoone/OneToOneAllowProxyTests.java @@ -11,6 +11,7 @@ import javax.persistence.OneToOne; import javax.persistence.Table; +import org.hibernate.Hibernate; import org.hibernate.boot.MetadataSources; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.bytecode.enhance.spi.interceptor.BytecodeLazyAttributeInterceptor; @@ -20,6 +21,7 @@ import org.hibernate.cfg.AvailableSettings; import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.testing.TestForIssue; import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; import org.hibernate.testing.bytecode.enhancement.EnhancementOptions; import org.hibernate.testing.jdbc.SQLStatementInterceptor; @@ -35,6 +37,7 @@ import static org.hamcrest.CoreMatchers.not; import static org.hamcrest.CoreMatchers.sameInstance; import static org.hamcrest.MatcherAssert.assertThat; +import static org.junit.Assert.assertTrue; /** * @author Steve Ebersole @@ -60,8 +63,6 @@ protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBu @Test public void testOwnerIsProxy() { - sqlStatementInterceptor.clear(); - final EntityPersister supplementalInfoDescriptor = sessionFactory().getMetamodel().entityPersister( SupplementalInfo.class ); final BytecodeEnhancementMetadata supplementalInfoEnhancementMetadata = supplementalInfoDescriptor.getBytecodeEnhancementMetadata(); assertThat( supplementalInfoEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) ); @@ -114,6 +115,27 @@ public void testOwnerIsProxy() { ); } + @Test + @TestForIssue(jiraKey = "HHH-14659") + public void testQueryJoinFetch() { + SupplementalInfo info = fromTransaction( (session) -> { + final SupplementalInfo result = session.createQuery( + "select s from SupplementalInfo s join fetch s.customer", + SupplementalInfo.class ) + .uniqueResult(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) ); + return result; + } ); + + // The "join fetch" should have already initialized the property, + // so that the getter can safely be called outside of a session. + assertTrue( Hibernate.isPropertyInitialized( info, "customer" ) ); + // The "join fetch" should have already initialized the associated entity. + Customer customer = info.getCustomer(); + assertTrue( Hibernate.isInitialized( customer ) ); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) ); + } + @Before public void createTestData() { inTransaction( @@ -124,6 +146,7 @@ public void createTestData() { session.persist( supplementalInfo ); } ); + sqlStatementInterceptor.clear(); } @After diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/onetoone/OneToOneExplicitOptionTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/onetoone/OneToOneExplicitOptionTests.java index 47bd908f8881..ce8198c50e53 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/onetoone/OneToOneExplicitOptionTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/onetoone/OneToOneExplicitOptionTests.java @@ -11,6 +11,7 @@ import javax.persistence.OneToOne; import javax.persistence.Table; +import org.hibernate.Hibernate; import org.hibernate.annotations.LazyToOne; import org.hibernate.boot.MetadataSources; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; @@ -21,6 +22,7 @@ import org.hibernate.cfg.AvailableSettings; import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.testing.TestForIssue; import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; import org.hibernate.testing.bytecode.enhancement.EnhancementOptions; import org.hibernate.testing.jdbc.SQLStatementInterceptor; @@ -37,6 +39,7 @@ import static org.hamcrest.CoreMatchers.sameInstance; import static org.hamcrest.MatcherAssert.assertThat; import static org.hibernate.annotations.LazyToOneOption.NO_PROXY; +import static org.junit.Assert.assertTrue; /** * Baseline test for uni-directional one-to-one, using an explicit @LazyToOne(NO_PROXY) and allowing enhanced proxies @@ -62,8 +65,6 @@ protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBu @Test public void testOwnerIsProxy() { - sqlStatementInterceptor.clear(); - final EntityPersister supplementalInfoDescriptor = sessionFactory().getMetamodel().entityPersister( SupplementalInfo.class ); final BytecodeEnhancementMetadata supplementalInfoEnhancementMetadata = supplementalInfoDescriptor.getBytecodeEnhancementMetadata(); assertThat( supplementalInfoEnhancementMetadata.isEnhancedForLazyLoading(), is( true ) ); @@ -116,6 +117,27 @@ public void testOwnerIsProxy() { ); } + @Test + @TestForIssue(jiraKey = "HHH-14659") + public void testQueryJoinFetch() { + SupplementalInfo info = fromTransaction( (session) -> { + final SupplementalInfo result = session.createQuery( + "select s from SupplementalInfo s join fetch s.customer", + SupplementalInfo.class ) + .uniqueResult(); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) ); + return result; + } ); + + // The "join fetch" should have already initialized the property, + // so that the getter can safely be called outside of a session. + assertTrue( Hibernate.isPropertyInitialized( info, "customer" ) ); + // The "join fetch" should have already initialized the associated entity. + Customer customer = info.getCustomer(); + assertTrue( Hibernate.isInitialized( customer ) ); + assertThat( sqlStatementInterceptor.getSqlQueries().size(), is( 1 ) ); + } + @Before public void createTestData() { inTransaction( @@ -126,6 +148,7 @@ public void createTestData() { session.persist( supplementalInfo ); } ); + sqlStatementInterceptor.clear(); } @After diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/polymorphic/JoinFetchedPolymorphicToOneTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/polymorphic/JoinFetchedPolymorphicToOneTests.java index 13b57b5ea2a9..477b0031a4a9 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/polymorphic/JoinFetchedPolymorphicToOneTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/polymorphic/JoinFetchedPolymorphicToOneTests.java @@ -20,6 +20,7 @@ import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cfg.AvailableSettings; +import org.hibernate.testing.TestForIssue; import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; import org.hibernate.testing.bytecode.enhancement.EnhancementOptions; import org.hibernate.testing.jdbc.SQLStatementInterceptor; @@ -72,6 +73,21 @@ public void testInheritedToOneLaziness() { ); } + @Test + @TestForIssue(jiraKey = "HHH-14659") + public void testQueryJoinFetch() { + inTransaction( + (session) -> { + final Order order = session.createQuery( "select o from Order o join fetch o.customer", Order.class ) + .uniqueResult(); + + assertTrue( Hibernate.isPropertyInitialized( order, "customer" ) ); + Customer customer = order.getCustomer(); + assertTrue( Hibernate.isInitialized( customer ) ); + } + ); + } + @Before public void createTestData() { inTransaction( diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/polymorphic/PolymorphicToOneExplicitOptionTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/polymorphic/PolymorphicToOneExplicitOptionTests.java index 60c0837bba65..60de4f42156e 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/polymorphic/PolymorphicToOneExplicitOptionTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/polymorphic/PolymorphicToOneExplicitOptionTests.java @@ -22,6 +22,7 @@ import org.hibernate.cfg.AvailableSettings; import org.hibernate.proxy.HibernateProxy; +import org.hibernate.testing.TestForIssue; import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; import org.hibernate.testing.bytecode.enhancement.EnhancementOptions; import org.hibernate.testing.jdbc.SQLStatementInterceptor; @@ -36,6 +37,7 @@ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; /** * @author Steve Ebersole @@ -100,6 +102,21 @@ public void testInheritedToOneLaziness() { ); } + @Test + @TestForIssue(jiraKey = "HHH-14659") + public void testQueryJoinFetch() { + inTransaction( + (session) -> { + final Order order = session.createQuery( "select o from Order o join fetch o.customer", Order.class ) + .uniqueResult(); + + assertTrue( Hibernate.isPropertyInitialized( order, "customer" ) ); + Customer customer = order.getCustomer(); + assertTrue( Hibernate.isInitialized( customer ) ); + } + ); + } + @Before public void createTestData() { inTransaction( diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/polymorphic/PolymorphicToOneImplicitOptionTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/polymorphic/PolymorphicToOneImplicitOptionTests.java index 038fcdd8df88..0f30bd29b768 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/polymorphic/PolymorphicToOneImplicitOptionTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/polymorphic/PolymorphicToOneImplicitOptionTests.java @@ -20,6 +20,7 @@ import org.hibernate.cfg.AvailableSettings; import org.hibernate.proxy.HibernateProxy; +import org.hibernate.testing.TestForIssue; import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; import org.hibernate.testing.bytecode.enhancement.EnhancementOptions; import org.hibernate.testing.jdbc.SQLStatementInterceptor; @@ -34,6 +35,7 @@ import static org.hamcrest.CoreMatchers.is; import static org.hamcrest.MatcherAssert.assertThat; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; /** * @author Steve Ebersole @@ -72,6 +74,21 @@ public void testInheritedToOneLaziness() { ); } + @Test + @TestForIssue(jiraKey = "HHH-14659") + public void testQueryJoinFetch() { + inTransaction( + (session) -> { + final Order order = session.createQuery( "select o from Order o join fetch o.customer", Order.class ) + .uniqueResult(); + + assertTrue( Hibernate.isPropertyInitialized( order, "customer" ) ); + Customer customer = order.getCustomer(); + assertTrue( Hibernate.isInitialized( customer ) ); + } + ); + } + @Before public void createTestData() { inTransaction( From 916bcbdef01550f6d033d7e77ebd8cffba5d2c58 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Mon, 7 Jun 2021 14:47:22 +0200 Subject: [PATCH 201/644] HHH-14659 Fix "join fetch" on mapped-by association being ignored when using bytecode enhancement --- .../java/org/hibernate/loader/Loader.java | 25 ++++++++++-- .../org/hibernate/loader/hql/QueryLoader.java | 38 ++++++++++++++++++- .../entity/AbstractEntityPersister.java | 6 ++- .../hibernate/persister/entity/Loadable.java | 17 ++++++++- 4 files changed, 77 insertions(+), 9 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/loader/Loader.java b/hibernate-core/src/main/java/org/hibernate/loader/Loader.java index 5b8d2b87ed15..2adef4848117 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/Loader.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/Loader.java @@ -65,7 +65,6 @@ import org.hibernate.event.spi.EventSource; import org.hibernate.event.spi.PostLoadEvent; import org.hibernate.event.spi.PreLoadEvent; -import org.hibernate.event.spi.PreLoadEventListener; import org.hibernate.hql.internal.HolderInstantiator; import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreMessageLogger; @@ -136,7 +135,9 @@ public Loader(SessionFactoryImplementor factory) { /** * An array indicating whether the entities have eager property fetching - * enabled. + * enabled for all of their properties. + *

    + * Supersedes {@link #getEntityEagerPerPropertyFetches()}. * * @return Eager property fetching indicators. */ @@ -144,6 +145,17 @@ protected boolean[] getEntityEagerPropertyFetches() { return null; } + /** + * An array indicating for each entity which specific properties must have eager fetching enabled. + *

    + * Superseded by {@link #getEntityEagerPropertyFetches()}. + * + * @return Eager property fetching indicators. + */ + protected boolean[][] getEntityEagerPerPropertyFetches() { + return null; + } + /** * An array of indexes of the entity that owns a one-to-one association * to the entity at the given index (-1 if there is no "owner"). The @@ -1799,11 +1811,15 @@ private void hydrateEntityState( hydratedObjects.add( object ); } - private boolean isEagerPropertyFetchEnabled(int i) { + private boolean isAllPropertyEagerFetchEnabled(int i) { boolean[] array = getEntityEagerPropertyFetches(); return array != null && array[i]; } + private boolean[] getPerPropertyEagerFetchEnabled(int i) { + boolean[][] array = getEntityEagerPerPropertyFetches(); + return array != null ? array[i] : null; + } /** * Hydrate the state an object from the SQL ResultSet, into @@ -1837,7 +1853,7 @@ private void loadFromResultSet( ); } - boolean fetchAllPropertiesRequested = isEagerPropertyFetchEnabled( i ); + boolean fetchAllPropertiesRequested = isAllPropertyEagerFetchEnabled( i ); // add temp entry so that the next step is circular-reference // safe - only needed because some types don't take proper @@ -1862,6 +1878,7 @@ private void loadFromResultSet( rootPersister, cols, fetchAllPropertiesRequested, + getPerPropertyEagerFetchEnabled( i ), session ); diff --git a/hibernate-core/src/main/java/org/hibernate/loader/hql/QueryLoader.java b/hibernate-core/src/main/java/org/hibernate/loader/hql/QueryLoader.java index b9a8222a687e..d15a13036085 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/hql/QueryLoader.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/hql/QueryLoader.java @@ -32,7 +32,6 @@ import org.hibernate.hql.internal.ast.tree.FromElement; import org.hibernate.hql.internal.ast.tree.QueryNode; import org.hibernate.hql.internal.ast.tree.SelectClause; -import org.hibernate.hql.spi.NamedParameterInformation; import org.hibernate.hql.spi.ParameterInformation; import org.hibernate.internal.IteratorImpl; import org.hibernate.internal.util.collections.ArrayHelper; @@ -81,6 +80,7 @@ public class QueryLoader extends BasicLoader { private EntityType[] ownerAssociationTypes; private int[] owners; private boolean[] entityEagerPropertyFetches; + private boolean[][] entityEagerPerPropertyFetches; private int[] collectionOwners; private QueryableCollection[] collectionPersisters; @@ -141,6 +141,7 @@ private void initialize(SelectClause selectClause) { int size = fromElementList.size(); entityPersisters = new Queryable[size]; entityEagerPropertyFetches = new boolean[size]; + entityEagerPerPropertyFetches = new boolean[size][]; entityAliases = new String[size]; sqlAliases = new String[size]; sqlAliasSuffixes = new String[size]; @@ -157,6 +158,7 @@ private void initialize(SelectClause selectClause) { } entityEagerPropertyFetches[i] = element.isAllPropertyFetch(); + entityEagerPerPropertyFetches[i] = null; sqlAliases[i] = element.getTableAlias(); entityAliases[i] = element.getClassAlias(); sqlAliasByEntityAlias.put( entityAliases[i], sqlAliases[i] ); @@ -177,7 +179,19 @@ private void initialize(SelectClause selectClause) { else if ( element.getDataType().isEntityType() ) { EntityType entityType = (EntityType) element.getDataType(); if ( entityType.isOneToOne() ) { - owners[i] = fromElementList.indexOf( element.getOrigin() ); + int originIndex = fromElementList.indexOf( element.getOrigin() ); + owners[i] = originIndex; + + // HHH-14659: remember that this association is loaded eagerly in this query (even if it's usually lazy) + Integer propertyIndex = propertyIndexInOrigin( element, entityPersisters[originIndex] ); + // This should always be true, but let's be extra cautious to avoid introducing regressions... + if ( propertyIndex != null ) { + if ( entityEagerPerPropertyFetches[originIndex] == null ) { + entityEagerPerPropertyFetches[originIndex] = + new boolean[entityPersisters[originIndex].getPropertyNames().length]; + } + entityEagerPerPropertyFetches[originIndex][propertyIndex] = true; + } } ownerAssociationTypes[i] = entityType; } @@ -188,6 +202,21 @@ else if ( element.getDataType().isEntityType() ) { defaultLockModes = ArrayHelper.fillArray( LockMode.NONE, size ); } + private static Integer propertyIndexInOrigin(FromElement element, Queryable originPersister) { + // This is the only way I found to retrieve a reference to the property corresponding to this join... + // A better solution would require changes in FromElement, and I'd rather avoid that code, + // which is being rewritten in ORM 6 anyway. + int attributeStartIndex = element.getOrigin().getClassName().length() + 1; + String role = element.getRole(); + if ( attributeStartIndex >= role.length() ) { + // Should not happen, but let's be safe... + return null; + } + String propertyName = role.substring( attributeStartIndex ); + + return originPersister.getEntityMetamodel().getPropertyIndexOrNull( propertyName ); + } + public AggregatedSelectExpression getAggregatedSelectExpression() { return aggregatedSelectExpression; } @@ -260,6 +289,11 @@ protected boolean[] getEntityEagerPropertyFetches() { return entityEagerPropertyFetches; } + @Override + public boolean[][] getEntityEagerPerPropertyFetches() { + return entityEagerPerPropertyFetches; + } + /** * An array of indexes of the entity that owns a one-to-one association * to the entity at the given index (-1 if there is no "owner") diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index 53924d8dc9ed..61a2b609ce63 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -3127,13 +3127,15 @@ else if ( id != null ) { * without resolving associations or collections. Question: should * this really be here, or should it be sent back to Loader? */ + @Override public Object[] hydrate( final ResultSet rs, final Serializable id, final Object object, final Loadable rootLoadable, final String[][] suffixedPropertyColumns, - final boolean allProperties, + final boolean forceEager, + final boolean[] propertiesForceEager, final SharedSessionContractImplementor session) throws SQLException, HibernateException { if ( LOG.isTraceEnabled() ) { @@ -3195,7 +3197,7 @@ public Object[] hydrate( if ( !propertySelectable[i] ) { values[i] = PropertyAccessStrategyBackRefImpl.UNKNOWN; } - else if ( allProperties || !laziness[i] ) { + else if ( forceEager || !laziness[i] || propertiesForceEager != null && propertiesForceEager[i] ) { //decide which ResultSet to get the property value from: final boolean propertyIsDeferred = hasDeferred && rootPersister.isSubclassPropertyDeferred( propNames[i], propSubclassNames[i] ); diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/Loadable.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/Loadable.java index 27b7dda17367..5a0e1054c872 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/Loadable.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/Loadable.java @@ -80,6 +80,20 @@ public interface Loadable extends EntityPersister { */ boolean hasRowId(); + /** + * Retrieve property values from one row of a result set + */ + default Object[] hydrate( + ResultSet rs, + Serializable id, + Object object, + Loadable rootLoadable, + String[][] suffixedPropertyColumns, + boolean forceEager, + SharedSessionContractImplementor session) throws SQLException, HibernateException { + return hydrate( rs, id, object, rootLoadable, suffixedPropertyColumns, forceEager, null, session ); + } + /** * Retrieve property values from one row of a result set */ @@ -89,7 +103,8 @@ Object[] hydrate( Object object, Loadable rootLoadable, String[][] suffixedPropertyColumns, - boolean allProperties, + boolean forceEager, + boolean[] propertiesForceEager, SharedSessionContractImplementor session) throws SQLException, HibernateException; boolean isAbstract(); From d60dc9255d7abf4736bacddd6c8ac64f9641daea Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Wed, 9 Jun 2021 18:15:05 +0200 Subject: [PATCH 202/644] HHH-14660 Deprecate component mappings with different attributes for the same class --- .../internal/log/DeprecationLogger.java | 8 +++ .../metamodel/internal/AttributeFactory.java | 68 +++++++++++-------- .../metamodel/internal/MetadataContext.java | 38 +++++++++-- 3 files changed, 79 insertions(+), 35 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java b/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java index 2866a1a3097b..a3084bc76b1b 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java @@ -250,4 +250,12 @@ void connectionProviderClassDeprecated( "5.3 in upgrading. It will be removed in a later version." ) void logUseOfDeprecatedZeroBasedJdbcStyleParams(); + + @LogMessage(level = WARN) + @Message( + id = 90000025, + value = "Encountered multiple component mappings for the same java class [%s] with different property mappings. " + + "This is deprecated and will be removed in a future version. Every property mapping combination should have its own java class" + ) + void deprecatedComponentMapping(String name); } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/AttributeFactory.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/AttributeFactory.java index 4fe8d46283bf..f7b5629f337d 100755 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/AttributeFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/AttributeFactory.java @@ -102,34 +102,40 @@ public PersistentAttributeDescriptor buildAttribute(ManagedTypeDesc if ( attributeContext.getPropertyMapping().getType().isComponentType() && jpaAttributeNature.equals( Attribute.PersistentAttributeType.BASIC ) ) { CompositeType compositeType = (CompositeType) attributeContext.getPropertyMapping().getType(); - EmbeddableTypeImpl embeddableType = new EmbeddableTypeImpl<>( - attributeMetadata.getJavaType(), - ownerType, - compositeType, - context.getSessionFactory() - ); - context.registerEmbeddedableType(embeddableType); - - String[] propertyNames = compositeType.getPropertyNames(); - org.hibernate.type.Type[] subtypes = compositeType.getSubtypes(); - InFlightAccess inFlightAccess = embeddableType.getInFlightAccess(); - - for ( int i = 0; i < propertyNames.length; i++ ) { - SingularAttributeImpl nestedAttribute = new SingularAttributeImpl( - embeddableType, - propertyNames[i], - Attribute.PersistentAttributeType.BASIC, - new BasicTypeImpl(subtypes[i].getReturnedClass(), Type.PersistenceType.BASIC), - null, - false, - false, - property.isOptional() - ); - inFlightAccess.addAttribute(nestedAttribute); - } - - metaModelType = embeddableType; + metaModelType = context.locateEmbeddable( attributeMetadata.getJavaType(), compositeType ); jpaAttributeNature = Attribute.PersistentAttributeType.EMBEDDED; + if ( metaModelType == null ) { + metaModelType = context.locateEmbeddable( attributeMetadata.getJavaType(), compositeType ); + if ( metaModelType == null ) { + EmbeddableTypeImpl embeddableType = new EmbeddableTypeImpl<>( + attributeMetadata.getJavaType(), + ownerType, + compositeType, + context.getSessionFactory() + ); + context.registerEmbeddableType( embeddableType, compositeType ); + + String[] propertyNames = compositeType.getPropertyNames(); + org.hibernate.type.Type[] subtypes = compositeType.getSubtypes(); + InFlightAccess inFlightAccess = embeddableType.getInFlightAccess(); + + for (int i = 0; i < propertyNames.length; i++) { + SingularAttributeImpl nestedAttribute = new SingularAttributeImpl( + embeddableType, + propertyNames[i], + Attribute.PersistentAttributeType.BASIC, + new BasicTypeImpl( subtypes[i].getReturnedClass(), Type.PersistenceType.BASIC ), + null, + false, + false, + property.isOptional() + ); + inFlightAccess.addAttribute( nestedAttribute ); + } + + metaModelType = embeddableType; + } + } } return new SingularAttributeImpl( @@ -249,13 +255,17 @@ private SimpleTypeDescriptor determineSimpleType(ValueContext typeContext } case EMBEDDABLE: { final Component component = (Component) typeContext.getHibernateValue(); - + final CompositeType compositeType = (CompositeType) component.getType(); Class javaType; if ( component.getComponentClassName() == null ) { javaType = typeContext.getJpaBindableType(); } else { javaType = component.getComponentClass(); + final EmbeddedTypeDescriptor cached = context.locateEmbeddable( javaType, compositeType ); + if ( cached != null ) { + return cached; + } } final EmbeddedTypeDescriptor embeddableType = new EmbeddableTypeImpl( @@ -264,7 +274,7 @@ private SimpleTypeDescriptor determineSimpleType(ValueContext typeContext (ComponentType) typeContext.getHibernateValue().getType(), context.getSessionFactory() ); - context.registerEmbeddedableType( embeddableType ); + context.registerEmbeddableType( embeddableType, compositeType ); final InFlightAccess inFlightAccess = embeddableType.getInFlightAccess(); final Iterator subProperties = component.getPropertyIterator(); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetadataContext.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetadataContext.java index 644cbff1e98b..55e5025016a7 100755 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetadataContext.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetadataContext.java @@ -8,6 +8,7 @@ import java.lang.reflect.Field; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; @@ -25,6 +26,7 @@ import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.internal.EntityManagerMessageLogger; import org.hibernate.internal.HEMLogging; +import org.hibernate.internal.log.DeprecationLogger; import org.hibernate.internal.util.ReflectHelper; import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.mapping.Component; @@ -42,6 +44,7 @@ import org.hibernate.metamodel.model.domain.spi.ManagedTypeDescriptor; import org.hibernate.metamodel.model.domain.spi.MappedSuperclassTypeDescriptor; import org.hibernate.metamodel.model.domain.spi.SingularPersistentAttribute; +import org.hibernate.type.CompositeType; /** * Defines a context for storing information during the building of the {@link MetamodelImpl}. @@ -51,7 +54,7 @@ *

    * At the end of the day, clients are interested in the {@link #getEntityTypeMap} and {@link #getEmbeddableTypeSet} * results, which represent all the registered {@linkplain #registerEntityType entities} and - * {@linkplain #registerEmbeddedableType embeddables} respectively. + * {@linkplain #registerEmbeddableType embeddables} respectively. * * @author Steve Ebersole * @author Emmanuel Bernard @@ -68,7 +71,8 @@ class MetadataContext { private Map> entityTypesByEntityName = new HashMap<>(); private Map> entityTypesByPersistentClass = new HashMap<>(); - private Set> embeddables = new HashSet<>(); + private Map>> embeddablesToProcess = new HashMap<>(); + private Map, CompositeType> componentByEmbeddable = new HashMap<>(); private Map> mappedSuperclassByMappedSuperclassMapping = new HashMap<>(); private Map, PersistentClass> mappedSuperClassTypeToPersistentClass = new HashMap<>(); @@ -108,7 +112,7 @@ public Map, EntityTypeDescriptor> getEntityTypeMap() { } public Set> getEmbeddableTypeSet() { - return Collections.unmodifiableSet( embeddables ); + return Collections.unmodifiableSet( componentByEmbeddable.keySet() ); } public Map, MappedSuperclassType> getMappedSuperclassTypeMap() { @@ -141,9 +145,13 @@ public Map, MappedSuperclassType> getMappedSuperclassTypeMap() { orderedMappings.add( persistentClass ); } - /*package*/ void registerEmbeddedableType(EmbeddedTypeDescriptor embeddableType) { + /*package*/ void registerEmbeddableType(EmbeddedTypeDescriptor embeddableType, CompositeType component) { + final List> existingEmbeddables = embeddablesToProcess.computeIfAbsent( + embeddableType.getJavaType(), k -> new ArrayList<>( 1 ) + ); + existingEmbeddables.add( embeddableType ); if ( !( ignoreUnsupported && embeddableType.getParent().getJavaType() == null ) ) { - embeddables.add( embeddableType ); + componentByEmbeddable.put( embeddableType, component ); } } @@ -198,6 +206,24 @@ public Map> getEntityTypesByEntityName() { return Collections.unmodifiableMap( entityTypesByEntityName ); } + public EmbeddedTypeDescriptor locateEmbeddable(Class embeddableClass, CompositeType component) { + final List> embeddableDomainTypes = embeddablesToProcess.get( embeddableClass ); + if ( embeddableDomainTypes != null ) { + for ( EmbeddedTypeDescriptor embeddableDomainType : embeddableDomainTypes ) { + final CompositeType cachedComponent = componentByEmbeddable.get( embeddableDomainType ); + if ( Arrays.equals( cachedComponent.getPropertyNames(), component.getPropertyNames() ) ) { + //noinspection unchecked + return (EmbeddedTypeDescriptor) embeddableDomainType; + } + else { + // See HHH-14660 + DeprecationLogger.DEPRECATION_LOGGER.deprecatedComponentMapping(embeddableClass.getName() ); + } + } + } + return null; + } + @SuppressWarnings({"unchecked"}) public void wrapUp() { if ( LOG.isTraceEnabled() ) { @@ -294,7 +320,7 @@ else if ( MappedSuperclass.class.isAssignableFrom( mapping.getClass() ) ) { } if ( staticMetamodelScanEnabled ) { - for ( EmbeddedTypeDescriptor embeddable : embeddables ) { + for ( EmbeddedTypeDescriptor embeddable : componentByEmbeddable.keySet() ) { populateStaticMetamodel( embeddable ); } } From bbc2ecb4840fcdcb6e2003ab2be5faf7d33b73db Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Thu, 3 Jun 2021 11:51:50 +0200 Subject: [PATCH 203/644] HHH-14649 Add test for issue --- .../dialect/Oracle12LimitHandlerTest.java | 67 +++++++++++++++++++ .../OraclePaginationWithLocksTest.java | 24 +++++++ 2 files changed, 91 insertions(+) create mode 100644 hibernate-core/src/test/java/org/hibernate/dialect/Oracle12LimitHandlerTest.java diff --git a/hibernate-core/src/test/java/org/hibernate/dialect/Oracle12LimitHandlerTest.java b/hibernate-core/src/test/java/org/hibernate/dialect/Oracle12LimitHandlerTest.java new file mode 100644 index 000000000000..96e35caebd74 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/dialect/Oracle12LimitHandlerTest.java @@ -0,0 +1,67 @@ +package org.hibernate.dialect; + +import org.hibernate.dialect.pagination.Oracle12LimitHandler; +import org.hibernate.engine.spi.QueryParameters; +import org.hibernate.engine.spi.RowSelection; + +import org.hibernate.testing.TestForIssue; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +@TestForIssue( jiraKey = "HHH-14649") +public class Oracle12LimitHandlerTest { + + @Test + public void testSqlWithSpace() { + final String sql = "select p.name from Person p where p.id = 1 for update"; + final String expected = "select * from ( select p.name from Person p where p.id = 1 ) where rownum <= ? for update"; + + final QueryParameters queryParameters = getQueryParameters( 0, 5 ); + final String processedSql = Oracle12LimitHandler.INSTANCE.processSql( sql, queryParameters ); + + assertEquals( expected, processedSql ); + } + + @Test + public void testSqlWithSpaceInsideQuotedString() { + final String sql = "select p.name from Person p where p.name = ' this is a string with spaces ' for update"; + final String expected = "select * from ( select p.name from Person p where p.name = ' this is a string with spaces ' ) where rownum <= ? for update"; + + final QueryParameters queryParameters = getQueryParameters( 0, 5 ); + final String processedSql = Oracle12LimitHandler.INSTANCE.processSql( sql, queryParameters ); + + assertEquals( expected, processedSql ); + } + + @Test + public void testSqlWithForUpdateInsideQuotedString() { + final String sql = "select a.prop from A a where a.name = 'this is for update '"; + final String expected = "select a.prop from A a where a.name = 'this is for update ' fetch first ? rows only"; + + final QueryParameters queryParameters = getQueryParameters( 0, 5 ); + final String processedSql = Oracle12LimitHandler.INSTANCE.processSql( sql, queryParameters ); + + assertEquals( expected, processedSql ); + } + + @Test + public void testSqlWithForUpdateInsideAndOutsideQuotedStringA() { + final String sql = "select a.prop from A a where a.name = 'this is for update ' for update"; + final String expected = "select * from ( select a.prop from A a where a.name = 'this is for update ' ) where rownum <= ? for update"; + + final QueryParameters queryParameters = getQueryParameters( 0, 5 ); + final String processedSql = Oracle12LimitHandler.INSTANCE.processSql( sql, queryParameters ); + + assertEquals( expected, processedSql ); + } + + private QueryParameters getQueryParameters(int firstRow, int maxRow) { + final QueryParameters queryParameters = new QueryParameters(); + RowSelection rowSelection = new RowSelection(); + rowSelection.setFirstRow( firstRow ); + rowSelection.setMaxRows( maxRow ); + queryParameters.setRowSelection( rowSelection ); + return queryParameters; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/pagination/OraclePaginationWithLocksTest.java b/hibernate-core/src/test/java/org/hibernate/test/pagination/OraclePaginationWithLocksTest.java index 8aa64636ea6f..2280fcebd4d6 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/pagination/OraclePaginationWithLocksTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/pagination/OraclePaginationWithLocksTest.java @@ -96,6 +96,30 @@ public void testNativeQuery() { ); } + @Test + public void testNativeQueryWithSpaces() { + inTransaction( session -> { + final List people = session.createNativeQuery( + "select p.name from Person p where p.id = 1 for update" ) + .setMaxResults( 10 ) + .list(); + } ); + + inTransaction( session -> { + Person p = new Person(); + p.setName( " this is a string with spaces " ); + session.persist( p ); + } ); + + inTransaction( session -> { + final List people = session.createNativeQuery( + "select p.name from Person p where p.name = ' this is a string with spaces ' for update" ) + .setMaxResults( 10 ) + .list(); + assertEquals( 1, people.size() ); + } ); + } + @Test public void testCriteriaQuery() { inTransaction( From 8002b188bbb7f4c799ba1172db833827bb39c259 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Thu, 3 Jun 2021 11:52:18 +0200 Subject: [PATCH 204/644] HHH-14649 Oracle limit handler create wrong sql query when multiple spaces are present in the query --- .../hibernate/dialect/pagination/Oracle12LimitHandler.java | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/pagination/Oracle12LimitHandler.java b/hibernate-core/src/main/java/org/hibernate/dialect/pagination/Oracle12LimitHandler.java index 3067a01a818e..c4d7f23f15db 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/pagination/Oracle12LimitHandler.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/pagination/Oracle12LimitHandler.java @@ -52,6 +52,7 @@ public String processSql(String sql, QueryParameters queryParameters) { if ( !hasMaxRows ) { return sql; } + sql = sql.trim(); final LockOptions lockOptions = queryParameters.getLockOptions(); if ( lockOptions != null ) { @@ -83,7 +84,6 @@ private String processSqlOffsetFetch(String sql, boolean hasFirstRow) { bindLimitParametersInReverseOrder = false; useMaxForLimit = false; - sql = normalizeStatement( sql ); final int offsetFetchLength; final String offsetFetchString; if ( hasFirstRow ) { @@ -100,7 +100,6 @@ private String processSqlOffsetFetch(String sql, boolean hasFirstRow) { private String processSql(String sql, int forUpdateIndex, boolean hasFirstRow) { bindLimitParametersInReverseOrder = true; useMaxForLimit = true; - sql = normalizeStatement( sql ); String forUpdateClause = null; boolean isForUpdate = false; @@ -142,10 +141,6 @@ private String processSql(String sql, int forUpdateIndex, boolean hasFirstRow) { return pagingSelect.toString(); } - private String normalizeStatement(String sql) { - return sql.trim().replaceAll( "\\s+", " " ); - } - private int getForUpdateIndex(String sql) { final int forUpdateLastIndex = sql.toLowerCase( Locale.ROOT ).lastIndexOf( "for update" ); // We need to recognize cases like : select a from t where b = 'for update'; From f8da005f3a465799f60acb238be41d209f7e81bf Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Wed, 9 Jun 2021 14:40:02 +0100 Subject: [PATCH 205/644] HHH-14667 Remove extraction of TypeInfo from the Database JDBC metadata as it's unused --- .../ExtractedDatabaseMetaDataImpl.java | 36 ------------------- .../env/internal/JdbcEnvironmentImpl.java | 12 ++----- .../env/spi/ExtractedDatabaseMetaData.java | 9 ----- .../engine/jdbc/env/spi/JdbcEnvironment.java | 9 ----- 4 files changed, 2 insertions(+), 64 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/ExtractedDatabaseMetaDataImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/ExtractedDatabaseMetaDataImpl.java index 36a74edeb485..80d4f187176e 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/ExtractedDatabaseMetaDataImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/ExtractedDatabaseMetaDataImpl.java @@ -9,10 +9,8 @@ import java.sql.DatabaseMetaData; import java.sql.ResultSet; import java.sql.SQLException; -import java.util.Arrays; import java.util.Collections; import java.util.HashSet; -import java.util.LinkedHashSet; import java.util.List; import java.util.Set; @@ -21,8 +19,6 @@ import org.hibernate.engine.jdbc.env.spi.ExtractedDatabaseMetaData; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.engine.jdbc.env.spi.SQLStateType; -import org.hibernate.engine.jdbc.spi.TypeInfo; -import org.hibernate.internal.util.StringHelper; import org.hibernate.tool.schema.extract.spi.SequenceInformation; /** @@ -47,7 +43,6 @@ public class ExtractedDatabaseMetaDataImpl implements ExtractedDatabaseMetaData private final boolean lobLocatorUpdateCopy; private final Set extraKeywords; - private final LinkedHashSet typeInfoSet; private final List sequenceInformationList; private ExtractedDatabaseMetaDataImpl( @@ -55,7 +50,6 @@ private ExtractedDatabaseMetaDataImpl( String connectionCatalogName, String connectionSchemaName, Set extraKeywords, - LinkedHashSet typeInfoSet, boolean supportsRefCursors, boolean supportsNamedParameters, boolean supportsScrollableResults, @@ -74,9 +68,6 @@ private ExtractedDatabaseMetaDataImpl( this.extraKeywords = extraKeywords != null ? extraKeywords : Collections.emptySet(); - this.typeInfoSet = typeInfoSet != null - ? typeInfoSet - : new LinkedHashSet(); this.supportsRefCursors = supportsRefCursors; this.supportsNamedParameters = supportsNamedParameters; @@ -155,11 +146,6 @@ public String getConnectionSchemaName() { return connectionSchemaName; } - @Override - public LinkedHashSet getTypeInfoSet() { - return typeInfoSet; - } - @Override public List getSequenceInformationList() { return sequenceInformationList; @@ -172,7 +158,6 @@ public static class Builder { private String connectionCatalogName; private Set extraKeywords; - private LinkedHashSet typeInfoSet; private boolean supportsRefCursors; private boolean supportsNamedParameters; @@ -202,8 +187,6 @@ public Builder apply(DatabaseMetaData databaseMetaData) throws SQLException { extraKeywords = parseKeywords( databaseMetaData.getSQLKeywords() ); sqlStateType = SQLStateType.interpretReportedSQLStateType( databaseMetaData.getSQLStateType() ); lobLocatorUpdateCopy = databaseMetaData.locatorsUpdateCopy(); - typeInfoSet = new LinkedHashSet(); - typeInfoSet.addAll( TypeInfo.extractTypeInfo( databaseMetaData ) ); return this; } @@ -239,24 +222,6 @@ public Builder addExtraKeyword(String keyword) { return this; } - public Builder setTypeInfoSet(LinkedHashSet typeInfoSet) { - if ( this.typeInfoSet == null ) { - this.typeInfoSet = typeInfoSet; - } - else { - this.typeInfoSet.addAll( typeInfoSet ); - } - return this; - } - - public Builder addTypeInfo(TypeInfo typeInfo) { - if ( this.typeInfoSet == null ) { - this.typeInfoSet = new LinkedHashSet(); - } - typeInfoSet.add( typeInfo ); - return this; - } - public Builder setSupportsRefCursors(boolean supportsRefCursors) { this.supportsRefCursors = supportsRefCursors; return this; @@ -313,7 +278,6 @@ public ExtractedDatabaseMetaDataImpl build() { connectionCatalogName, connectionSchemaName, extraKeywords, - typeInfoSet, supportsRefCursors, supportsNamedParameters, supportsScrollableResults, diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentImpl.java index b236dd6da16a..420e8c0a49ad 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentImpl.java @@ -60,7 +60,6 @@ public class JdbcEnvironmentImpl implements JdbcEnvironment { private final QualifiedObjectNameFormatter qualifiedObjectNameFormatter; private final LobCreatorBuilderImpl lobCreatorBuilder; - private final LinkedHashSet typeInfoSet = new LinkedHashSet(); private final NameQualifierSupport nameQualifierSupport; /** @@ -277,8 +276,6 @@ public JdbcEnvironmentImpl( databaseMetaData ); - this.typeInfoSet.addAll( TypeInfo.extractTypeInfo( databaseMetaData ) ); - this.lobCreatorBuilder = LobCreatorBuilderImpl.makeLobCreatorBuilder( dialect, cfgService.getSettings(), @@ -379,14 +376,9 @@ public LobCreatorBuilder getLobCreatorBuilder() { return lobCreatorBuilder; } - @Override public TypeInfo getTypeInfoForJdbcCode(int jdbcTypeCode) { - for ( TypeInfo typeInfo : typeInfoSet ) { - if ( typeInfo.getJdbcTypeCode() == jdbcTypeCode ) { - return typeInfo; - } - } - return null; + throw new UnsupportedOperationException( "Support for getting TypeInfo from jdbcTypeCode has been disabled as it wasn't used." + + " Use org.hibernate.engine.jdbc.spi.TypeInfo.extractTypeInfo as alternative, or report an issue and explain." ); } /** diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/ExtractedDatabaseMetaData.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/ExtractedDatabaseMetaData.java index 7410cdbf32fc..cf98795e52af 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/ExtractedDatabaseMetaData.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/ExtractedDatabaseMetaData.java @@ -45,15 +45,6 @@ public interface ExtractedDatabaseMetaData { */ String getConnectionSchemaName(); - /** - * Set of type info reported by the driver. - * - * @return The type information obtained from the driver. - * - * @see java.sql.DatabaseMetaData#getTypeInfo() - */ - LinkedHashSet getTypeInfoSet(); - /** * Get the list of extra keywords (beyond standard SQL92 keywords) reported by the driver. * diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/JdbcEnvironment.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/JdbcEnvironment.java index ec94471af123..3d4f79a1c8b1 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/JdbcEnvironment.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/JdbcEnvironment.java @@ -9,7 +9,6 @@ import org.hibernate.boot.model.naming.Identifier; import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.spi.SqlExceptionHelper; -import org.hibernate.engine.jdbc.spi.TypeInfo; import org.hibernate.service.Service; /** @@ -89,12 +88,4 @@ public interface JdbcEnvironment extends Service { */ LobCreatorBuilder getLobCreatorBuilder(); - /** - * Find type information for the type identified by the given "JDBC type code". - * - * @param jdbcTypeCode The JDBC type code. - * - * @return The corresponding type info. - */ - TypeInfo getTypeInfoForJdbcCode(int jdbcTypeCode); } From fd3585728456e17e5482802bee1ad9a053519f8c Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Wed, 9 Jun 2021 14:48:21 +0100 Subject: [PATCH 206/644] HHH-14667 Remove some dead code --- .../jdbc/env/internal/JdbcEnvironmentImpl.java | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentImpl.java index 420e8c0a49ad..e6fdf2d4a021 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentImpl.java @@ -9,12 +9,8 @@ import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.SQLException; -import java.util.Arrays; import java.util.Collections; -import java.util.HashSet; -import java.util.LinkedHashSet; import java.util.List; -import java.util.Set; import java.util.stream.Collectors; import java.util.stream.StreamSupport; @@ -288,7 +284,7 @@ public JdbcEnvironmentImpl( private String determineCurrentSchemaName( DatabaseMetaData databaseMetaData, ServiceRegistry serviceRegistry, - Dialect dialect) throws SQLException { + Dialect dialect) { final SchemaNameResolver schemaNameResolver; final Object setting = serviceRegistry.getService( ConfigurationService.class ).getSettings().get( @@ -323,14 +319,6 @@ private SqlExceptionHelper buildSqlExceptionHelper(Dialect dialect, boolean logW return new SqlExceptionHelper( sqlExceptionConverter, logWarnings ); } - private Set buildMergedReservedWords(Dialect dialect, DatabaseMetaData dbmd) throws SQLException { - Set reservedWords = new HashSet(); - reservedWords.addAll( dialect.getKeywords() ); - // todo : do we need to explicitly handle SQL:2003 keywords? - reservedWords.addAll( Arrays.asList( dbmd.getSQLKeywords().split( "," ) ) ); - return reservedWords; - } - @Override public Dialect getDialect() { return dialect; From c10493435ef924d867d679a96607ce2bb3864767 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Wed, 9 Jun 2021 15:05:19 +0100 Subject: [PATCH 207/644] HHH-14667 Skip loading all keywords from the DB when keyword auto-quoting is disabled --- .../engine/jdbc/env/spi/IdentifierHelperBuilder.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/IdentifierHelperBuilder.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/IdentifierHelperBuilder.java index 0f74afd8f373..74de34f77298 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/IdentifierHelperBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/IdentifierHelperBuilder.java @@ -61,6 +61,10 @@ public void applyReservedWords(DatabaseMetaData metaData) throws SQLException { return; } + //Important optimisation: skip loading all keywords from the DB when autoQuoteKeywords is disabled + if ( autoQuoteKeywords == false ) { + return; + } this.reservedWords.addAll( parseKeywords( metaData.getSQLKeywords() ) ); } @@ -176,6 +180,10 @@ public void clearReservedWords() { } public void applyReservedWords(Set words) { + //No use when autoQuoteKeywords is disabled + if ( autoQuoteKeywords == false ) { + return; + } this.reservedWords.addAll( words ); } From 8f765eeff82f60de42a2acad7b14e1306626a166 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Wed, 9 Jun 2021 15:53:01 +0100 Subject: [PATCH 208/644] HHH-14667 Remove also unused: ExtractedDatabaseMetaData#getTypeInfoSet() and doesLobLocatorUpdateCopy() --- .../internal/ExtractedDatabaseMetaDataImpl.java | 16 ---------------- .../jdbc/env/spi/ExtractedDatabaseMetaData.java | 9 --------- .../test/jdbc/env/NoDatabaseMetaDataTest.java | 4 ---- 3 files changed, 29 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/ExtractedDatabaseMetaDataImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/ExtractedDatabaseMetaDataImpl.java index 80d4f187176e..d16643cebff2 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/ExtractedDatabaseMetaDataImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/ExtractedDatabaseMetaDataImpl.java @@ -40,7 +40,6 @@ public class ExtractedDatabaseMetaDataImpl implements ExtractedDatabaseMetaData private final boolean supportsDataDefinitionInTransaction; private final boolean doesDataDefinitionCauseTransactionCommit; private final SQLStateType sqlStateType; - private final boolean lobLocatorUpdateCopy; private final Set extraKeywords; private final List sequenceInformationList; @@ -58,7 +57,6 @@ private ExtractedDatabaseMetaDataImpl( boolean supportsDataDefinitionInTransaction, boolean doesDataDefinitionCauseTransactionCommit, SQLStateType sqlStateType, - boolean lobLocatorUpdateCopy, List sequenceInformationList) { this.jdbcEnvironment = jdbcEnvironment; @@ -77,7 +75,6 @@ private ExtractedDatabaseMetaDataImpl( this.supportsDataDefinitionInTransaction = supportsDataDefinitionInTransaction; this.doesDataDefinitionCauseTransactionCommit = doesDataDefinitionCauseTransactionCommit; this.sqlStateType = sqlStateType; - this.lobLocatorUpdateCopy = lobLocatorUpdateCopy; this.sequenceInformationList = sequenceInformationList; } @@ -131,11 +128,6 @@ public SQLStateType getSqlStateType() { return sqlStateType; } - @Override - public boolean doesLobLocatorUpdateCopy() { - return lobLocatorUpdateCopy; - } - @Override public String getConnectionCatalogName() { return connectionCatalogName; @@ -167,7 +159,6 @@ public static class Builder { private boolean supportsDataDefinitionInTransaction; private boolean doesDataDefinitionCauseTransactionCommit; private SQLStateType sqlStateType; - private boolean lobLocatorUpdateCopy; private List sequenceInformationList = Collections.emptyList(); public Builder(JdbcEnvironment jdbcEnvironment) { @@ -186,7 +177,6 @@ public Builder apply(DatabaseMetaData databaseMetaData) throws SQLException { doesDataDefinitionCauseTransactionCommit = databaseMetaData.dataDefinitionCausesTransactionCommit(); extraKeywords = parseKeywords( databaseMetaData.getSQLKeywords() ); sqlStateType = SQLStateType.interpretReportedSQLStateType( databaseMetaData.getSQLStateType() ); - lobLocatorUpdateCopy = databaseMetaData.locatorsUpdateCopy(); return this; } @@ -262,11 +252,6 @@ public Builder setSqlStateType(SQLStateType sqlStateType) { return this; } - public Builder setLobLocatorUpdateCopy(boolean lobLocatorUpdateCopy) { - this.lobLocatorUpdateCopy = lobLocatorUpdateCopy; - return this; - } - public Builder setSequenceInformationList(List sequenceInformationList) { this.sequenceInformationList = sequenceInformationList; return this; @@ -286,7 +271,6 @@ public ExtractedDatabaseMetaDataImpl build() { supportsDataDefinitionInTransaction, doesDataDefinitionCauseTransactionCommit, sqlStateType, - lobLocatorUpdateCopy, sequenceInformationList ); } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/ExtractedDatabaseMetaData.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/ExtractedDatabaseMetaData.java index cf98795e52af..a87ac934202c 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/ExtractedDatabaseMetaData.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/ExtractedDatabaseMetaData.java @@ -127,15 +127,6 @@ public interface ExtractedDatabaseMetaData { */ SQLStateType getSqlStateType(); - /** - * Did the driver report that updates to a LOB locator affect a copy of the LOB? - * - * @return True if updates to the state of a LOB locator update only a copy. - * - * @see java.sql.DatabaseMetaData#locatorsUpdateCopy() - */ - boolean doesLobLocatorUpdateCopy(); - /** * Retrieve the list of {@code SequenceInformation} objects which describe the underlying database sequences. * diff --git a/hibernate-core/src/test/java/org/hibernate/test/jdbc/env/NoDatabaseMetaDataTest.java b/hibernate-core/src/test/java/org/hibernate/test/jdbc/env/NoDatabaseMetaDataTest.java index 017bc525705a..ef92e999a498 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/jdbc/env/NoDatabaseMetaDataTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/jdbc/env/NoDatabaseMetaDataTest.java @@ -38,7 +38,6 @@ public void testNoJdbcMetadataDefaultDialect() { assertNull( extractedDatabaseMetaData.getConnectionCatalogName() ); assertNull( extractedDatabaseMetaData.getConnectionSchemaName() ); - assertTrue( extractedDatabaseMetaData.getTypeInfoSet().isEmpty() ); assertTrue( extractedDatabaseMetaData.getExtraKeywords().isEmpty() ); assertFalse( extractedDatabaseMetaData.supportsNamedParameters() ); assertFalse( extractedDatabaseMetaData.supportsRefCursors() ); @@ -48,7 +47,6 @@ public void testNoJdbcMetadataDefaultDialect() { assertFalse( extractedDatabaseMetaData.supportsDataDefinitionInTransaction() ); assertFalse( extractedDatabaseMetaData.doesDataDefinitionCauseTransactionCommit() ); assertNull( extractedDatabaseMetaData.getSqlStateType() ); - assertFalse( extractedDatabaseMetaData.doesLobLocatorUpdateCopy() ); StandardServiceRegistryBuilder.destroy( serviceRegistry ); } @@ -65,7 +63,6 @@ public void testNoJdbcMetadataDialectOverride() { assertNull( extractedDatabaseMetaData.getConnectionCatalogName() ); assertNull( extractedDatabaseMetaData.getConnectionSchemaName() ); - assertTrue( extractedDatabaseMetaData.getTypeInfoSet().isEmpty() ); assertTrue( extractedDatabaseMetaData.getExtraKeywords().isEmpty() ); assertTrue( extractedDatabaseMetaData.supportsNamedParameters() ); assertFalse( extractedDatabaseMetaData.supportsRefCursors() ); @@ -75,7 +72,6 @@ public void testNoJdbcMetadataDialectOverride() { assertFalse( extractedDatabaseMetaData.supportsDataDefinitionInTransaction() ); assertFalse( extractedDatabaseMetaData.doesDataDefinitionCauseTransactionCommit() ); assertNull( extractedDatabaseMetaData.getSqlStateType() ); - assertFalse( extractedDatabaseMetaData.doesLobLocatorUpdateCopy() ); StandardServiceRegistryBuilder.destroy( serviceRegistry ); } From ab8c81482c7d7d0f65a8f7e9a584dacef965bbf5 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Wed, 9 Jun 2021 22:56:29 +0100 Subject: [PATCH 209/644] HHH-14667 Remove also ExtractedDatabaseMetaData#getExtraKeywords() as it's unused as well --- .../ExtractedDatabaseMetaDataImpl.java | 36 ------------------- .../env/spi/ExtractedDatabaseMetaData.java | 9 ----- .../test/jdbc/env/NoDatabaseMetaDataTest.java | 2 -- 3 files changed, 47 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/ExtractedDatabaseMetaDataImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/ExtractedDatabaseMetaDataImpl.java index d16643cebff2..18a40d684cc0 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/ExtractedDatabaseMetaDataImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/ExtractedDatabaseMetaDataImpl.java @@ -10,7 +10,6 @@ import java.sql.ResultSet; import java.sql.SQLException; import java.util.Collections; -import java.util.HashSet; import java.util.List; import java.util.Set; @@ -41,14 +40,12 @@ public class ExtractedDatabaseMetaDataImpl implements ExtractedDatabaseMetaData private final boolean doesDataDefinitionCauseTransactionCommit; private final SQLStateType sqlStateType; - private final Set extraKeywords; private final List sequenceInformationList; private ExtractedDatabaseMetaDataImpl( JdbcEnvironment jdbcEnvironment, String connectionCatalogName, String connectionSchemaName, - Set extraKeywords, boolean supportsRefCursors, boolean supportsNamedParameters, boolean supportsScrollableResults, @@ -59,14 +56,8 @@ private ExtractedDatabaseMetaDataImpl( SQLStateType sqlStateType, List sequenceInformationList) { this.jdbcEnvironment = jdbcEnvironment; - this.connectionCatalogName = connectionCatalogName; this.connectionSchemaName = connectionSchemaName; - - this.extraKeywords = extraKeywords != null - ? extraKeywords - : Collections.emptySet(); - this.supportsRefCursors = supportsRefCursors; this.supportsNamedParameters = supportsNamedParameters; this.supportsScrollableResults = supportsScrollableResults; @@ -118,11 +109,6 @@ public boolean doesDataDefinitionCauseTransactionCommit() { return doesDataDefinitionCauseTransactionCommit; } - @Override - public Set getExtraKeywords() { - return extraKeywords; - } - @Override public SQLStateType getSqlStateType() { return sqlStateType; @@ -149,8 +135,6 @@ public static class Builder { private String connectionSchemaName; private String connectionCatalogName; - private Set extraKeywords; - private boolean supportsRefCursors; private boolean supportsNamedParameters; private boolean supportsScrollableResults; @@ -175,7 +159,6 @@ public Builder apply(DatabaseMetaData databaseMetaData) throws SQLException { supportsBatchUpdates = databaseMetaData.supportsBatchUpdates(); supportsDataDefinitionInTransaction = !databaseMetaData.dataDefinitionIgnoredInTransactions(); doesDataDefinitionCauseTransactionCommit = databaseMetaData.dataDefinitionCausesTransactionCommit(); - extraKeywords = parseKeywords( databaseMetaData.getSQLKeywords() ); sqlStateType = SQLStateType.interpretReportedSQLStateType( databaseMetaData.getSQLStateType() ); return this; } @@ -194,24 +177,6 @@ public Builder setConnectionCatalogName(String connectionCatalogName) { return this; } - public Builder setExtraKeywords(Set extraKeywords) { - if ( this.extraKeywords == null ) { - this.extraKeywords = extraKeywords; - } - else { - this.extraKeywords.addAll( extraKeywords ); - } - return this; - } - - public Builder addExtraKeyword(String keyword) { - if ( this.extraKeywords == null ) { - this.extraKeywords = new HashSet(); - } - this.extraKeywords.add( keyword ); - return this; - } - public Builder setSupportsRefCursors(boolean supportsRefCursors) { this.supportsRefCursors = supportsRefCursors; return this; @@ -262,7 +227,6 @@ public ExtractedDatabaseMetaDataImpl build() { jdbcEnvironment, connectionCatalogName, connectionSchemaName, - extraKeywords, supportsRefCursors, supportsNamedParameters, supportsScrollableResults, diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/ExtractedDatabaseMetaData.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/ExtractedDatabaseMetaData.java index a87ac934202c..33f5a4c57db2 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/ExtractedDatabaseMetaData.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/ExtractedDatabaseMetaData.java @@ -45,15 +45,6 @@ public interface ExtractedDatabaseMetaData { */ String getConnectionSchemaName(); - /** - * Get the list of extra keywords (beyond standard SQL92 keywords) reported by the driver. - * - * @return The extra keywords used by this database. - * - * @see java.sql.DatabaseMetaData#getSQLKeywords() - */ - Set getExtraKeywords(); - /** * Does the driver report supporting named parameters? * diff --git a/hibernate-core/src/test/java/org/hibernate/test/jdbc/env/NoDatabaseMetaDataTest.java b/hibernate-core/src/test/java/org/hibernate/test/jdbc/env/NoDatabaseMetaDataTest.java index ef92e999a498..dbe88a7c4eaa 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/jdbc/env/NoDatabaseMetaDataTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/jdbc/env/NoDatabaseMetaDataTest.java @@ -38,7 +38,6 @@ public void testNoJdbcMetadataDefaultDialect() { assertNull( extractedDatabaseMetaData.getConnectionCatalogName() ); assertNull( extractedDatabaseMetaData.getConnectionSchemaName() ); - assertTrue( extractedDatabaseMetaData.getExtraKeywords().isEmpty() ); assertFalse( extractedDatabaseMetaData.supportsNamedParameters() ); assertFalse( extractedDatabaseMetaData.supportsRefCursors() ); assertFalse( extractedDatabaseMetaData.supportsScrollableResults() ); @@ -63,7 +62,6 @@ public void testNoJdbcMetadataDialectOverride() { assertNull( extractedDatabaseMetaData.getConnectionCatalogName() ); assertNull( extractedDatabaseMetaData.getConnectionSchemaName() ); - assertTrue( extractedDatabaseMetaData.getExtraKeywords().isEmpty() ); assertTrue( extractedDatabaseMetaData.supportsNamedParameters() ); assertFalse( extractedDatabaseMetaData.supportsRefCursors() ); assertFalse( extractedDatabaseMetaData.supportsScrollableResults() ); From 5b2289e883fb022beaf1c0dcb6097cd69463e399 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Thu, 10 Jun 2021 12:05:32 +0100 Subject: [PATCH 210/644] HHH-14667 Avoid triggering the load of sequence metadata when not required Also introduce SequenceMismatchStrategy#NONE, which allows to fully disable the checks performed by SequenceMismatchStrategy on initialization; combining these two changes, users have the option to fully skip loading the details about existing sequences from the DB. --- .../userguide/appendices/Configurations.adoc | 2 +- .../org/hibernate/cfg/AvailableSettings.java | 5 +- .../ExtractedDatabaseMetaDataImpl.java | 98 ++++++++++++++++--- .../env/internal/JdbcEnvironmentImpl.java | 60 +++--------- .../internal/JdbcEnvironmentInitiator.java | 3 +- .../id/SequenceMismatchStrategy.java | 8 +- .../id/enhanced/SequenceStyleGenerator.java | 16 +-- .../SkipLoadingSequenceInformationTest.java | 71 ++++++++++++++ ...LServerDialectSequenceInformationTest.java | 10 +- .../test/schemafilter/SequenceFilterTest.java | 1 + .../boot/BasicTestingJdbcServiceImpl.java | 4 +- 11 files changed, 199 insertions(+), 79 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/engine/jdbc/env/internal/SkipLoadingSequenceInformationTest.java diff --git a/documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc b/documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc index 333409606e61..3f608e0b55bf 100644 --- a/documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc +++ b/documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc @@ -275,7 +275,7 @@ Please report your mapping that causes the problem to us so we can examine the d + The default value is `false` which means Hibernate will use an algorithm to determine if the insert can be delayed or if the insert should be performed immediately. -`*hibernate.id.sequence.increment_size_mismatch_strategy*` (e.g. `LOG`, `FIX` or `EXCEPTION` (default value)):: +`*hibernate.id.sequence.increment_size_mismatch_strategy*` (e.g. `LOG`, `FIX`, `NONE` or `EXCEPTION` (default value)):: This setting defines the `org.hibernate.id.SequenceMismatchStrategy` used when Hibernate detects a mismatch between a sequence configuration in an entity mapping and its database sequence object counterpart. diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java index b7efa75376fe..51e765ebd0fc 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java @@ -2423,8 +2423,9 @@ public interface AvailableSettings extends org.hibernate.jpa.AvailableSettings { * and its database sequence object counterpart. *

    * Possible values are {@link org.hibernate.id.SequenceMismatchStrategy#EXCEPTION}, - * {@link org.hibernate.id.SequenceMismatchStrategy#LOG}, and - * {@link org.hibernate.id.SequenceMismatchStrategy#FIX}. + * {@link org.hibernate.id.SequenceMismatchStrategy#LOG}, + * {@link org.hibernate.id.SequenceMismatchStrategy#FIX} + * and {@link org.hibernate.id.SequenceMismatchStrategy#NONE}. *

    * The default value is given by the {@link org.hibernate.id.SequenceMismatchStrategy#EXCEPTION}, * meaning that an Exception is thrown when detecting such a conflict. diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/ExtractedDatabaseMetaDataImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/ExtractedDatabaseMetaDataImpl.java index 18a40d684cc0..1ac0389086f7 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/ExtractedDatabaseMetaDataImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/ExtractedDatabaseMetaDataImpl.java @@ -6,18 +6,25 @@ */ package org.hibernate.engine.jdbc.env.internal; +import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.ResultSet; import java.sql.SQLException; import java.util.Collections; import java.util.List; import java.util.Set; +import java.util.stream.Collectors; +import java.util.stream.StreamSupport; +import org.hibernate.HibernateException; import org.hibernate.boot.model.source.internal.hbm.CommaSeparatedStringHelper; +import org.hibernate.dialect.Dialect; +import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess; import org.hibernate.engine.jdbc.cursor.internal.StandardRefCursorSupport; import org.hibernate.engine.jdbc.env.spi.ExtractedDatabaseMetaData; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.engine.jdbc.env.spi.SQLStateType; +import org.hibernate.tool.schema.extract.spi.ExtractionContext; import org.hibernate.tool.schema.extract.spi.SequenceInformation; /** @@ -26,7 +33,9 @@ * @author Steve Ebersole */ public class ExtractedDatabaseMetaDataImpl implements ExtractedDatabaseMetaData { + private final JdbcEnvironment jdbcEnvironment; + private final JdbcConnectionAccess connectionAccess; private final String connectionCatalogName; private final String connectionSchemaName; @@ -39,11 +48,16 @@ public class ExtractedDatabaseMetaDataImpl implements ExtractedDatabaseMetaData private final boolean supportsDataDefinitionInTransaction; private final boolean doesDataDefinitionCauseTransactionCommit; private final SQLStateType sqlStateType; + private final boolean jdbcMetadataAccessible; - private final List sequenceInformationList; + //Lazily initialized: loading all sequence information upfront has been + //shown to be too slow in some cases. In this way we only load it + //when there is actual need for these details. + private List sequenceInformationList; private ExtractedDatabaseMetaDataImpl( JdbcEnvironment jdbcEnvironment, + JdbcConnectionAccess connectionAccess, String connectionCatalogName, String connectionSchemaName, boolean supportsRefCursors, @@ -54,8 +68,9 @@ private ExtractedDatabaseMetaDataImpl( boolean supportsDataDefinitionInTransaction, boolean doesDataDefinitionCauseTransactionCommit, SQLStateType sqlStateType, - List sequenceInformationList) { + boolean jdbcMetadataIsAccessible) { this.jdbcEnvironment = jdbcEnvironment; + this.connectionAccess = connectionAccess; this.connectionCatalogName = connectionCatalogName; this.connectionSchemaName = connectionSchemaName; this.supportsRefCursors = supportsRefCursors; @@ -66,7 +81,7 @@ private ExtractedDatabaseMetaDataImpl( this.supportsDataDefinitionInTransaction = supportsDataDefinitionInTransaction; this.doesDataDefinitionCauseTransactionCommit = doesDataDefinitionCauseTransactionCommit; this.sqlStateType = sqlStateType; - this.sequenceInformationList = sequenceInformationList; + this.jdbcMetadataAccessible = jdbcMetadataIsAccessible; } @Override @@ -125,12 +140,26 @@ public String getConnectionSchemaName() { } @Override - public List getSequenceInformationList() { - return sequenceInformationList; + public synchronized List getSequenceInformationList() { + if ( jdbcMetadataAccessible ) { + //Loading the sequence information can take a while on large databases, + //even minutes in some cases. + //We trigger this lazily as only certain combinations of configurations, + //mappings and used features actually trigger any use of such details. + if ( sequenceInformationList == null ) { + sequenceInformationList = sequenceInformationList(); + } + return sequenceInformationList; + } + else { + return Collections.emptyList(); + } } public static class Builder { private final JdbcEnvironment jdbcEnvironment; + private final boolean jdbcMetadataIsAccessible; + private final JdbcConnectionAccess connectionAccess; private String connectionSchemaName; private String connectionCatalogName; @@ -143,10 +172,11 @@ public static class Builder { private boolean supportsDataDefinitionInTransaction; private boolean doesDataDefinitionCauseTransactionCommit; private SQLStateType sqlStateType; - private List sequenceInformationList = Collections.emptyList(); - public Builder(JdbcEnvironment jdbcEnvironment) { + public Builder(JdbcEnvironment jdbcEnvironment, boolean jdbcMetadataIsAccessible, JdbcConnectionAccess connectionAccess) { this.jdbcEnvironment = jdbcEnvironment; + this.jdbcMetadataIsAccessible = jdbcMetadataIsAccessible; + this.connectionAccess = connectionAccess; } public Builder apply(DatabaseMetaData databaseMetaData) throws SQLException { @@ -217,14 +247,10 @@ public Builder setSqlStateType(SQLStateType sqlStateType) { return this; } - public Builder setSequenceInformationList(List sequenceInformationList) { - this.sequenceInformationList = sequenceInformationList; - return this; - } - public ExtractedDatabaseMetaDataImpl build() { return new ExtractedDatabaseMetaDataImpl( jdbcEnvironment, + connectionAccess, connectionCatalogName, connectionSchemaName, supportsRefCursors, @@ -235,8 +261,54 @@ public ExtractedDatabaseMetaDataImpl build() { supportsDataDefinitionInTransaction, doesDataDefinitionCauseTransactionCommit, sqlStateType, - sequenceInformationList + jdbcMetadataIsAccessible ); } } + + /** + * Get the sequence information List from the database. + * + * @return sequence information List + */ + private List sequenceInformationList() { + final JdbcEnvironment jdbcEnvironment = this.jdbcEnvironment; + final Dialect dialect = this.jdbcEnvironment.getDialect(); + + Connection connection = null; + try { + connection = connectionAccess.obtainConnection(); + final Connection c = connection; + Iterable sequenceInformationIterable = dialect + .getSequenceInformationExtractor() + .extractMetadata( new ExtractionContext.EmptyExtractionContext() { + @Override + public Connection getJdbcConnection() { + return c; + } + + @Override + public JdbcEnvironment getJdbcEnvironment() { + return jdbcEnvironment; + } + } + ); + return StreamSupport.stream( sequenceInformationIterable.spliterator(), false ) + .collect( Collectors.toList() ); + } + catch (SQLException e) { + throw new HibernateException( "Could not fetch the SequenceInformation from the database", e ); + } + finally { + if ( connection != null ) { + try { + connectionAccess.releaseConnection( connection ); + } + catch (SQLException throwables) { + //ignored + } + } + } + } + } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentImpl.java index e6fdf2d4a021..ab55ef3d4661 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentImpl.java @@ -6,13 +6,8 @@ */ package org.hibernate.engine.jdbc.env.internal; -import java.sql.Connection; import java.sql.DatabaseMetaData; import java.sql.SQLException; -import java.util.Collections; -import java.util.List; -import java.util.stream.Collectors; -import java.util.stream.StreamSupport; import org.hibernate.boot.model.naming.Identifier; import org.hibernate.boot.registry.selector.spi.StrategySelector; @@ -20,6 +15,7 @@ import org.hibernate.dialect.Dialect; import org.hibernate.engine.config.spi.ConfigurationService; import org.hibernate.engine.config.spi.StandardConverters; +import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess; import org.hibernate.engine.jdbc.env.spi.ExtractedDatabaseMetaData; import org.hibernate.engine.jdbc.env.spi.IdentifierHelper; import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder; @@ -35,8 +31,6 @@ import org.hibernate.exception.internal.StandardSQLExceptionConverter; import org.hibernate.service.ServiceRegistry; import org.hibernate.service.spi.ServiceRegistryImplementor; -import org.hibernate.tool.schema.extract.spi.ExtractionContext; -import org.hibernate.tool.schema.extract.spi.SequenceInformation; import org.jboss.logging.Logger; @@ -64,7 +58,7 @@ public class JdbcEnvironmentImpl implements JdbcEnvironment { * @param serviceRegistry The service registry * @param dialect The resolved dialect. */ - public JdbcEnvironmentImpl(final ServiceRegistryImplementor serviceRegistry, Dialect dialect) { + public JdbcEnvironmentImpl(final ServiceRegistryImplementor serviceRegistry, final Dialect dialect) { this.dialect = dialect; final ConfigurationService cfgService = serviceRegistry.getService( ConfigurationService.class ); @@ -86,7 +80,7 @@ public JdbcEnvironmentImpl(final ServiceRegistryImplementor serviceRegistry, Dia identifierHelperBuilder.setNameQualifierSupport( nameQualifierSupport ); IdentifierHelper identifierHelper = null; - ExtractedDatabaseMetaDataImpl.Builder dbMetaDataBuilder = new ExtractedDatabaseMetaDataImpl.Builder( this ); + ExtractedDatabaseMetaDataImpl.Builder dbMetaDataBuilder = new ExtractedDatabaseMetaDataImpl.Builder( this, false, null ); try { identifierHelper = dialect.buildIdentifierHelper( identifierHelperBuilder, null ); dbMetaDataBuilder.setSupportsNamedParameters( dialect.supportsNamedParameters( null ) ); @@ -150,8 +144,12 @@ private static boolean autoKeywordQuoting(ConfigurationService cfgService) { * Constructor form used from testing * * @param dialect The dialect + * @param jdbcConnectionAccess */ - public JdbcEnvironmentImpl(DatabaseMetaData databaseMetaData, Dialect dialect) throws SQLException { + public JdbcEnvironmentImpl( + DatabaseMetaData databaseMetaData, + Dialect dialect, + JdbcConnectionAccess jdbcConnectionAccess) throws SQLException { this.dialect = dialect; this.sqlExceptionHelper = buildSqlExceptionHelper( dialect, false ); @@ -177,10 +175,9 @@ public JdbcEnvironmentImpl(DatabaseMetaData databaseMetaData, Dialect dialect) t } this.identifierHelper = identifierHelper; - this.extractedMetaDataSupport = new ExtractedDatabaseMetaDataImpl.Builder( this ) + this.extractedMetaDataSupport = new ExtractedDatabaseMetaDataImpl.Builder( this, true, jdbcConnectionAccess ) .apply( databaseMetaData ) .setSupportsNamedParameters( databaseMetaData.supportsNamedParameters() ) - .setSequenceInformationList( sequenceInformationList( databaseMetaData.getConnection() ) ) .build(); this.currentCatalog = null; @@ -224,7 +221,8 @@ else if ( supportsSchemas ) { public JdbcEnvironmentImpl( ServiceRegistryImplementor serviceRegistry, Dialect dialect, - DatabaseMetaData databaseMetaData) throws SQLException { + DatabaseMetaData databaseMetaData, + JdbcConnectionAccess jdbcConnectionAccess) throws SQLException { this.dialect = dialect; final ConfigurationService cfgService = serviceRegistry.getService( ConfigurationService.class ); @@ -256,11 +254,10 @@ public JdbcEnvironmentImpl( } this.identifierHelper = identifierHelper; - this.extractedMetaDataSupport = new ExtractedDatabaseMetaDataImpl.Builder( this ) + this.extractedMetaDataSupport = new ExtractedDatabaseMetaDataImpl.Builder( this, true, jdbcConnectionAccess ) .apply( databaseMetaData ) .setConnectionSchemaName( determineCurrentSchemaName( databaseMetaData, serviceRegistry, dialect ) ) .setSupportsNamedParameters( dialect.supportsNamedParameters( databaseMetaData ) ) - .setSequenceInformationList( sequenceInformationList( databaseMetaData.getConnection() ) ) .build(); // and that current-catalog and current-schema happen after it @@ -369,37 +366,4 @@ public TypeInfo getTypeInfoForJdbcCode(int jdbcTypeCode) { " Use org.hibernate.engine.jdbc.spi.TypeInfo.extractTypeInfo as alternative, or report an issue and explain." ); } - /** - * Get the sequence information List from the database. - * - * @param connection database connection - * @return sequence information List - */ - private List sequenceInformationList(final Connection connection) { - try { - - Iterable sequenceInformationIterable = dialect - .getSequenceInformationExtractor() - .extractMetadata( new ExtractionContext.EmptyExtractionContext() { - @Override - public Connection getJdbcConnection() { - return connection; - } - - @Override - public JdbcEnvironment getJdbcEnvironment() { - return JdbcEnvironmentImpl.this; - } - } - ); - - return StreamSupport.stream( sequenceInformationIterable.spliterator(), false ) - .collect( Collectors.toList() ); - } - catch (SQLException e) { - log.error( "Could not fetch the SequenceInformation from the database", e ); - } - - return Collections.emptyList(); - } } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentInitiator.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentInitiator.java index d2563e4251fd..edf0f769d976 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentInitiator.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentInitiator.java @@ -114,7 +114,8 @@ public DialectResolutionInfo getDialectResolutionInfo() { return new JdbcEnvironmentImpl( registry, dialect, - dbmd + dbmd, + jdbcConnectionAccess ); } catch (SQLException e) { diff --git a/hibernate-core/src/main/java/org/hibernate/id/SequenceMismatchStrategy.java b/hibernate-core/src/main/java/org/hibernate/id/SequenceMismatchStrategy.java index cd90cdf0b962..b9ece879fe69 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/SequenceMismatchStrategy.java +++ b/hibernate-core/src/main/java/org/hibernate/id/SequenceMismatchStrategy.java @@ -32,7 +32,13 @@ public enum SequenceMismatchStrategy { * When detecting a mismatch, Hibernate tries to fix it by overriding the entity sequence mapping using the one * found in the database. */ - FIX; + FIX, + + /** + * Don't perform any check. This is useful to speedup bootstrap as it won't query the sequences on the DB, + * at cost of not validating the sequences. + */ + NONE; /** * Interpret the configured SequenceMismatchStrategy value. diff --git a/hibernate-core/src/main/java/org/hibernate/id/enhanced/SequenceStyleGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/enhanced/SequenceStyleGenerator.java index 2996ad104e60..d3d7de7e5c1e 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/enhanced/SequenceStyleGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/enhanced/SequenceStyleGenerator.java @@ -12,6 +12,7 @@ import org.hibernate.HibernateException; import org.hibernate.MappingException; +import org.hibernate.boot.SchemaAutoTooling; import org.hibernate.boot.model.naming.Identifier; import org.hibernate.boot.model.relational.Database; import org.hibernate.boot.model.relational.QualifiedName; @@ -242,19 +243,20 @@ public void configure(Type type, Properties params, ServiceRegistry serviceRegis final boolean isPooledOptimizer = OptimizerFactory.isPooledOptimizer( optimizationStrategy ); - if ( isPooledOptimizer && isPhysicalSequence( jdbcEnvironment, forceTableUse ) ) { + + SequenceMismatchStrategy sequenceMismatchStrategy = configurationService.getSetting( + AvailableSettings.SEQUENCE_INCREMENT_SIZE_MISMATCH_STRATEGY, + SequenceMismatchStrategy::interpret, + SequenceMismatchStrategy.EXCEPTION + ); + + if ( sequenceMismatchStrategy != SequenceMismatchStrategy.NONE && isPooledOptimizer && isPhysicalSequence( jdbcEnvironment, forceTableUse ) ) { String databaseSequenceName = sequenceName.getObjectName().getText(); Long databaseIncrementValue = getSequenceIncrementValue( jdbcEnvironment, databaseSequenceName ); if ( databaseIncrementValue != null && !databaseIncrementValue.equals( (long) incrementSize ) ) { int dbIncrementValue = databaseIncrementValue.intValue(); - SequenceMismatchStrategy sequenceMismatchStrategy = configurationService.getSetting( - AvailableSettings.SEQUENCE_INCREMENT_SIZE_MISMATCH_STRATEGY, - SequenceMismatchStrategy::interpret, - SequenceMismatchStrategy.EXCEPTION - ); - switch ( sequenceMismatchStrategy ) { case EXCEPTION: throw new MappingException( diff --git a/hibernate-core/src/test/java/org/hibernate/engine/jdbc/env/internal/SkipLoadingSequenceInformationTest.java b/hibernate-core/src/test/java/org/hibernate/engine/jdbc/env/internal/SkipLoadingSequenceInformationTest.java new file mode 100644 index 000000000000..8d49430855ca --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/engine/jdbc/env/internal/SkipLoadingSequenceInformationTest.java @@ -0,0 +1,71 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.engine.jdbc.env.internal; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; + +import org.hibernate.annotations.GenericGenerator; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; +import org.hibernate.dialect.H2Dialect; +import org.hibernate.id.SequenceMismatchStrategy; +import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.Test; + +/** + * Verifies that setting {@code AvailableSettings.SEQUENCE_INCREMENT_SIZE_MISMATCH_STRATEGY} to {@code none} + * is going to skip loading the sequence information from the database. + */ +@TestForIssue( jiraKey = "HHH-14667") +public class SkipLoadingSequenceInformationTest extends BaseCoreFunctionalTestCase { + + @Override + protected void configure(Configuration configuration) { + configuration.setProperty( AvailableSettings.SEQUENCE_INCREMENT_SIZE_MISMATCH_STRATEGY, SequenceMismatchStrategy.NONE.name() ); + configuration.setProperty( Environment.DIALECT, VetoingDialect.class.getName() ); + } + + @Entity(name="seqentity") + static class SequencingEntity { + @Id + @GenericGenerator(name = "pooledoptimizer", strategy = "enhanced-sequence", + parameters = { + @org.hibernate.annotations.Parameter(name = "optimizer", value = "pooled"), + @org.hibernate.annotations.Parameter(name = "initial_value", value = "1"), + @org.hibernate.annotations.Parameter(name = "increment_size", value = "2") + } + ) + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "pooledoptimizer") + Integer id; + String name; + } + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[]{SequencingEntity.class}; + } + + @Test + public void test() { + // If it's able to boot, we're good. + } + + public static class VetoingDialect extends H2Dialect { + @Override + public SequenceInformationExtractor getSequenceInformationExtractor() { + throw new IllegalStateException("Should really not invoke this method in this setup"); + } + } + +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/dialect/functional/SQLServerDialectSequenceInformationTest.java b/hibernate-core/src/test/java/org/hibernate/test/dialect/functional/SQLServerDialectSequenceInformationTest.java index 5352df7fb90a..1193cf8d6852 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/dialect/functional/SQLServerDialectSequenceInformationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/dialect/functional/SQLServerDialectSequenceInformationTest.java @@ -22,6 +22,7 @@ import org.hibernate.cfg.Environment; import org.hibernate.dialect.Dialect; import org.hibernate.dialect.SQLServer2012Dialect; +import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess; import org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentImpl; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.engine.jdbc.spi.JdbcServices; @@ -82,15 +83,16 @@ public void testExtractSequenceInformationForSqlServerWithCaseSensitiveCollation ssrb.applySettings( Collections.singletonMap( AvailableSettings.URL, newUrl ) ); StandardServiceRegistry ssr = ssrb.build(); - try ( Connection connection = ssr.getService( JdbcServices.class ) - .getBootstrapJdbcConnectionAccess() - .obtainConnection() ) { + final JdbcConnectionAccess bootstrapJdbcConnectionAccess = ssr.getService( JdbcServices.class ) + .getBootstrapJdbcConnectionAccess(); + + try ( Connection connection = bootstrapJdbcConnectionAccess.obtainConnection() ) { try (Statement statement = connection.createStatement()) { statement.execute( "CREATE SEQUENCE ITEM_SEQ START WITH 100 INCREMENT BY 10" ); } - JdbcEnvironment jdbcEnvironment = new JdbcEnvironmentImpl( connection.getMetaData(), dialect ); + JdbcEnvironment jdbcEnvironment = new JdbcEnvironmentImpl( connection.getMetaData(), dialect, bootstrapJdbcConnectionAccess ); Iterable sequenceInformations = SequenceInformationExtractorLegacyImpl.INSTANCE.extractMetadata( new ExtractionContext.EmptyExtractionContext() { @Override diff --git a/hibernate-core/src/test/java/org/hibernate/test/schemafilter/SequenceFilterTest.java b/hibernate-core/src/test/java/org/hibernate/test/schemafilter/SequenceFilterTest.java index e794cd28b313..fd80567369ed 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/schemafilter/SequenceFilterTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/schemafilter/SequenceFilterTest.java @@ -62,6 +62,7 @@ public void setUp() { Map settings = new HashMap(); settings.putAll( Environment.getProperties() ); settings.put( AvailableSettings.DIALECT, H2Dialect.class.getName() ); + settings.put( "hibernate.temp.use_jdbc_metadata_defaults", "false" ); settings.put( AvailableSettings.FORMAT_SQL, false ); this.serviceRegistry = ServiceRegistryBuilder.buildServiceRegistry( settings ); diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/boot/BasicTestingJdbcServiceImpl.java b/hibernate-testing/src/main/java/org/hibernate/testing/boot/BasicTestingJdbcServiceImpl.java index 836c3f50c8f1..c3ade8b0a1cb 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/boot/BasicTestingJdbcServiceImpl.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/boot/BasicTestingJdbcServiceImpl.java @@ -58,10 +58,11 @@ public void prepare(boolean allowAggressiveRelease) throws SQLException { dialect = ConnectionProviderBuilder.getCorrespondingDialect(); connectionProvider = ConnectionProviderBuilder.buildConnectionProvider( allowAggressiveRelease ); sqlStatementLogger = new SqlStatementLogger( true, false, false ); + this.jdbcConnectionAccess = new JdbcConnectionAccessImpl( connectionProvider ); Connection jdbcConnection = connectionProvider.getConnection(); try { - jdbcEnvironment = new JdbcEnvironmentImpl( jdbcConnection.getMetaData(), dialect ); + jdbcEnvironment = new JdbcEnvironmentImpl( jdbcConnection.getMetaData(), dialect, jdbcConnectionAccess ); } finally { try { @@ -71,7 +72,6 @@ public void prepare(boolean allowAggressiveRelease) throws SQLException { } } - this.jdbcConnectionAccess = new JdbcConnectionAccessImpl( connectionProvider ); } public void release() { From ee55768587abc2893d26fca1915ac32e86242fa2 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Fri, 11 Jun 2021 10:05:28 +0100 Subject: [PATCH 211/644] HHH-14667 SequenceFilterTest only needs to be run on H2 --- .../test/schemafilter/SequenceFilterTest.java | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/hibernate-core/src/test/java/org/hibernate/test/schemafilter/SequenceFilterTest.java b/hibernate-core/src/test/java/org/hibernate/test/schemafilter/SequenceFilterTest.java index fd80567369ed..f64b90feb1e6 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/schemafilter/SequenceFilterTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/schemafilter/SequenceFilterTest.java @@ -6,19 +6,16 @@ */ package org.hibernate.test.schemafilter; -import javax.persistence.Entity; -import javax.persistence.GeneratedValue; -import javax.persistence.GenerationType; -import javax.persistence.Id; -import javax.persistence.SequenceGenerator; import java.util.Arrays; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; - -import org.hamcrest.BaseMatcher; -import org.hamcrest.Description; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.SequenceGenerator; import org.hibernate.boot.Metadata; import org.hibernate.boot.MetadataSources; @@ -34,16 +31,17 @@ import org.hibernate.tool.schema.internal.SchemaDropperImpl; import org.hibernate.tool.schema.spi.SchemaFilter; +import org.hibernate.testing.RequiresDialect; +import org.hibernate.testing.ServiceRegistryBuilder; +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseUnitTestCase; import org.junit.After; import org.junit.Assert; import org.junit.Before; import org.junit.Test; -import org.hibernate.testing.DialectChecks; -import org.hibernate.testing.RequiresDialectFeature; -import org.hibernate.testing.ServiceRegistryBuilder; -import org.hibernate.testing.TestForIssue; -import org.hibernate.testing.junit4.BaseUnitTestCase; +import org.hamcrest.BaseMatcher; +import org.hamcrest.Description; import static org.hibernate.test.schemafilter.RecordingTarget.Category.SEQUENCE_CREATE; import static org.hibernate.test.schemafilter.RecordingTarget.Category.SEQUENCE_DROP; @@ -52,7 +50,7 @@ * @author Andrea Boriero */ @TestForIssue(jiraKey = "HHH-10937") -@RequiresDialectFeature(value = {DialectChecks.SupportSchemaCreation.class}) +@RequiresDialect(H2Dialect.class) public class SequenceFilterTest extends BaseUnitTestCase { private StandardServiceRegistryImpl serviceRegistry; private Metadata metadata; From e2f24c5436316fc09792fe9801151e189269af48 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Mon, 14 Jun 2021 15:31:48 +0100 Subject: [PATCH 212/644] HHH-14667 Maintain backwards compatibility for Hibernate Reactive --- .../env/internal/JdbcEnvironmentImpl.java | 19 ++++++++++++++----- .../engine/jdbc/env/spi/JdbcEnvironment.java | 10 ++++++++++ 2 files changed, 24 insertions(+), 5 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentImpl.java index ab55ef3d4661..e19585abbc8c 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/internal/JdbcEnvironmentImpl.java @@ -209,6 +209,20 @@ else if ( supportsSchemas ) { } } + /** + * @deprecated currently used by Hibernate Reactive + * This version of the constructor should handle the case in which we do actually have the option to access the DatabaseMetaData, + * but since Hibernate Reactive is currently not making use of it we take a shortcut. + */ + @Deprecated + public JdbcEnvironmentImpl( + ServiceRegistryImplementor serviceRegistry, + Dialect dialect, + DatabaseMetaData databaseMetaData + /*JdbcConnectionAccess jdbcConnectionAccess*/) throws SQLException { + this(serviceRegistry, dialect); + } + /** * The main constructor form. Builds a JdbcEnvironment using the available DatabaseMetaData * @@ -361,9 +375,4 @@ public LobCreatorBuilder getLobCreatorBuilder() { return lobCreatorBuilder; } - public TypeInfo getTypeInfoForJdbcCode(int jdbcTypeCode) { - throw new UnsupportedOperationException( "Support for getting TypeInfo from jdbcTypeCode has been disabled as it wasn't used." + - " Use org.hibernate.engine.jdbc.spi.TypeInfo.extractTypeInfo as alternative, or report an issue and explain." ); - } - } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/JdbcEnvironment.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/JdbcEnvironment.java index 3d4f79a1c8b1..2a9fa57f0b6a 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/JdbcEnvironment.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/JdbcEnvironment.java @@ -9,6 +9,7 @@ import org.hibernate.boot.model.naming.Identifier; import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.spi.SqlExceptionHelper; +import org.hibernate.engine.jdbc.spi.TypeInfo; import org.hibernate.service.Service; /** @@ -88,4 +89,13 @@ public interface JdbcEnvironment extends Service { */ LobCreatorBuilder getLobCreatorBuilder(); + /** + * @deprecated This is currently not implemented an will likely be removed + * (A default method is provided to facilitate removal from implementors) + */ + @Deprecated + default TypeInfo getTypeInfoForJdbcCode(int jdbcTypeCode) { + throw new UnsupportedOperationException( "Support for getting TypeInfo from jdbcTypeCode has been disabled as it wasn't used. Use org.hibernate.engine.jdbc.spi.TypeInfo.extractTypeInfo as alternative, or report an issue and explain." ); + } + } From f91fe0335276896cafcdf841f1ec9d8cbbfb1417 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Fri, 11 Jun 2021 11:52:01 -0500 Subject: [PATCH 213/644] HHH-14679 - Deprecate ResultSetWrapper and friends --- .../hibernate/boot/internal/SessionFactoryOptionsBuilder.java | 1 + .../java/org/hibernate/boot/spi/SessionFactoryOptions.java | 4 ++++ .../src/main/java/org/hibernate/cfg/AvailableSettings.java | 3 +++ .../main/java/org/hibernate/engine/jdbc/ColumnNameCache.java | 3 +++ .../java/org/hibernate/engine/jdbc/ResultSetWrapperProxy.java | 3 +++ .../hibernate/engine/jdbc/internal/ResultSetWrapperImpl.java | 4 +++- .../java/org/hibernate/engine/jdbc/spi/ResultSetWrapper.java | 3 +++ 7 files changed, 20 insertions(+), 1 deletion(-) diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java index 7ddff3bf790e..2f8bf765a9bc 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java @@ -1273,6 +1273,7 @@ public void enableScrollableResultSupport(boolean enabled) { this.scrollableResultSetsEnabled = enabled; } + @Deprecated public void enableResultSetWrappingSupport(boolean enabled) { this.wrapResultSetsEnabled = enabled; } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java index df6e62f99c09..632abf1cb970 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java @@ -219,6 +219,10 @@ default boolean isStrictJpaQueryLanguageCompliance() { boolean isScrollableResultSetsEnabled(); + /** + * @deprecated (since 5.5) Scheduled for removal in 6.0 as ResultSet wrapping is no longer needed + */ + @Deprecated boolean isWrapResultSetsEnabled(); boolean isGetGeneratedKeysEnabled(); diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java index 51e765ebd0fc..a40320d3b704 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java @@ -1114,7 +1114,10 @@ public interface AvailableSettings extends org.hibernate.jpa.AvailableSettings { /** * Enable wrapping of JDBC result sets in order to speed up column name lookups for * broken JDBC drivers + * + * @deprecated (since 5.5) Scheduled for removal in 6.0 as ResultSet wrapping is no longer needed */ + @Deprecated String WRAP_RESULT_SETS = "hibernate.jdbc.wrap_result_sets"; /** diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/ColumnNameCache.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/ColumnNameCache.java index b231a00e0a3c..52897f8b18a0 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/ColumnNameCache.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/ColumnNameCache.java @@ -13,8 +13,11 @@ /** * Cache of column-name -> column-index resolutions * + * @deprecated (since 5.5) Scheduled for removal in 6.0 as ResultSet wrapping is no longer needed + * * @author Steve Ebersole */ +@Deprecated public final class ColumnNameCache { private static final float LOAD_FACTOR = .75f; diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/ResultSetWrapperProxy.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/ResultSetWrapperProxy.java index d179c0af9c85..6db6cc63a3db 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/ResultSetWrapperProxy.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/ResultSetWrapperProxy.java @@ -27,9 +27,12 @@ * A proxy for a ResultSet delegate, responsible for locally caching the columnName-to-columnIndex resolution that * has been found to be inefficient in a few vendor's drivers (i.e., Oracle and Postgres). * + * @deprecated (since 5.5) Scheduled for removal in 6.0 as ResultSet wrapping is no longer needed + * * @author Steve Ebersole * @author Gail Badner */ +@Deprecated public class ResultSetWrapperProxy implements InvocationHandler { private static final CoreMessageLogger LOG = messageLogger( ResultSetWrapperProxy.class ); diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/ResultSetWrapperImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/ResultSetWrapperImpl.java index 46eacc8810d2..4f267c9a0037 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/ResultSetWrapperImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/ResultSetWrapperImpl.java @@ -8,7 +8,6 @@ import java.sql.ResultSet; -import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.engine.jdbc.ColumnNameCache; import org.hibernate.engine.jdbc.ResultSetWrapperProxy; import org.hibernate.engine.jdbc.spi.ResultSetWrapper; @@ -18,9 +17,12 @@ * Standard Hibernate implementation for wrapping a {@link ResultSet} in a " column name cache" wrapper. * + * @deprecated (since 5.5) Scheduled for removal in 6.0 as ResultSet wrapping is no longer needed + * * @author Steve Ebersole * @author Gail Badner */ +@Deprecated public class ResultSetWrapperImpl implements ResultSetWrapper { private final ServiceRegistry serviceRegistry; diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/spi/ResultSetWrapper.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/spi/ResultSetWrapper.java index 355bbc78578c..59e99686a99d 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/spi/ResultSetWrapper.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/spi/ResultSetWrapper.java @@ -13,8 +13,11 @@ /** * Contract for wrapping a {@link ResultSet} in a "column name cache" wrapper. * + * @deprecated (since 5.5) Scheduled for removal in 6.0 as ResultSet wrapping is no longer needed + * * @author Gail Badner */ +@Deprecated public interface ResultSetWrapper { /** * Wrap a result set in a "column name cache" wrapper. From 423b13b50ae7940c11807a4b8c545d16a12e8059 Mon Sep 17 00:00:00 2001 From: Markus Heiden Date: Tue, 8 Jun 2021 01:01:06 +0200 Subject: [PATCH 214/644] HHH-14657 Use the compile instead of runtime classpath The runtime classpath contains the dependencies as jars that are not yet built when the plugin needs them. So use the compile classpath plus the compiled classes of the current project. --- .../orm/tooling/gradle/EnhancementHelper.java | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/tooling/hibernate-gradle-plugin/src/main/groovy/org/hibernate/orm/tooling/gradle/EnhancementHelper.java b/tooling/hibernate-gradle-plugin/src/main/groovy/org/hibernate/orm/tooling/gradle/EnhancementHelper.java index 927fa254e5d2..85982c8c5b87 100644 --- a/tooling/hibernate-gradle-plugin/src/main/groovy/org/hibernate/orm/tooling/gradle/EnhancementHelper.java +++ b/tooling/hibernate-gradle-plugin/src/main/groovy/org/hibernate/orm/tooling/gradle/EnhancementHelper.java @@ -37,7 +37,7 @@ */ public class EnhancementHelper { static void enhance(SourceSet sourceSet, EnhanceExtension options, Project project) { - final ClassLoader classLoader = toClassLoader( sourceSet.getRuntimeClasspath() ); + final ClassLoader classLoader = toClassLoader( sourceSet.getCompileClasspath(), sourceSet.getOutput().getClassesDirs() ); final EnhancementContext enhancementContext = new DefaultEnhancementContext() { @Override @@ -96,14 +96,16 @@ public boolean doExtendedEnhancement(UnloadedClass classDescriptor) { } } - public static ClassLoader toClassLoader(FileCollection runtimeClasspath) { + public static ClassLoader toClassLoader(FileCollection... classpaths) { List urls = new ArrayList<>(); - for ( File file : runtimeClasspath ) { - try { - urls.add( file.toURI().toURL() ); - } - catch (MalformedURLException e) { - throw new GradleException( "Unable to resolve classpath entry to URL : " + file.getAbsolutePath(), e ); + for ( FileCollection classpath : classpaths ) { + for ( File file : classpath ) { + try { + urls.add( file.toURI().toURL() ); + } + catch (MalformedURLException e) { + throw new GradleException( "Unable to resolve classpath entry to URL : " + file.getAbsolutePath(), e ); + } } } return new URLClassLoader( urls.toArray( new URL[0] ), Enhancer.class.getClassLoader() ); From 26038d1b002ed02692a37a6c6156fea243f870eb Mon Sep 17 00:00:00 2001 From: Markus Heiden Date: Tue, 8 Jun 2021 01:01:06 +0200 Subject: [PATCH 215/644] HHH-14657 Use the compile instead of runtime classpath The runtime classpath contains the dependencies as jars that are not yet built when the plugin needs them. So use the compile classpath plus the compiled classes of the current project. --- .../org/hibernate/orm/tooling/gradle/EnhancementHelper.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/tooling/hibernate-gradle-plugin/src/main/groovy/org/hibernate/orm/tooling/gradle/EnhancementHelper.java b/tooling/hibernate-gradle-plugin/src/main/groovy/org/hibernate/orm/tooling/gradle/EnhancementHelper.java index 85982c8c5b87..2afc97d04ff6 100644 --- a/tooling/hibernate-gradle-plugin/src/main/groovy/org/hibernate/orm/tooling/gradle/EnhancementHelper.java +++ b/tooling/hibernate-gradle-plugin/src/main/groovy/org/hibernate/orm/tooling/gradle/EnhancementHelper.java @@ -37,6 +37,11 @@ */ public class EnhancementHelper { static void enhance(SourceSet sourceSet, EnhanceExtension options, Project project) { + // The compile classpath contains the jar dependencies and + // the output directories with the compiled classes of project dependencies in a multi-project build. + // The classes directories contain the compiled classes of this project. + // The runtime classpath cannot be used for this purpose + // because it contains the jars of project dependencies which are not yet built. final ClassLoader classLoader = toClassLoader( sourceSet.getCompileClasspath(), sourceSet.getOutput().getClassesDirs() ); final EnhancementContext enhancementContext = new DefaultEnhancementContext() { From 1b1a6e7c1c782ef521278f89f62639c314ee9d6a Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Mon, 14 Jun 2021 15:40:24 +0000 Subject: [PATCH 216/644] 5.5.2.Final --- changelog.txt | 13 +++++++++++++ gradle/version.properties | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 7032ce85a2db..c1070194e09e 100644 --- a/changelog.txt +++ b/changelog.txt @@ -3,6 +3,19 @@ Hibernate 5 Changelog Note: Please refer to JIRA to learn more about each issue. +Changes in 5.5.2.Final (June 14, 2021) +------------------------------------------------------------------------------------------------------------------------ + +https://hibernate.atlassian.net/projects/HHH/versions/31957 + +** Bug + * [HHH-14609] - Fetch join association within fetched element collection fails + * [HHH-14608] - Merge causes StackOverflow when JPA proxy compliance is enabled + +** Task + * [HHH-14599] - Upgrade to Gradle 7 in support of Java 17 + + Changes in 5.5.0.Final (June 01, 2021) ------------------------------------------------------------------------------------------------------------------------ diff --git a/gradle/version.properties b/gradle/version.properties index d5d6d7f95f05..cf08f61f7dbf 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -hibernateVersion=5.5.1-SNAPSHOT \ No newline at end of file +hibernateVersion=5.5.2.Final \ No newline at end of file From d345516ab8cc11d6d43b80586efadba0caa766fa Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Mon, 14 Jun 2021 15:45:29 +0000 Subject: [PATCH 217/644] 5.5.2-SNAPSHOT --- gradle/version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/version.properties b/gradle/version.properties index cf08f61f7dbf..cf7403230f98 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -hibernateVersion=5.5.2.Final \ No newline at end of file +hibernateVersion=5.5.2-SNAPSHOT \ No newline at end of file From 9630ca9a7f7272f923745d282c816d7eddb89df3 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Mon, 14 Jun 2021 20:26:08 +0100 Subject: [PATCH 218/644] Actually next will be 5.5.3-SNAPSHOT --- gradle/version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/version.properties b/gradle/version.properties index cf7403230f98..df600108580d 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -hibernateVersion=5.5.2-SNAPSHOT \ No newline at end of file +hibernateVersion=5.5.3-SNAPSHOT From 107849c3c81c8a1fd7242a1cc51104062890c0b2 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Wed, 16 Jun 2021 08:37:14 +0200 Subject: [PATCH 219/644] Fix jakarta sources transformation issues --- hibernate-core/hibernate-core.gradle | 4 ++++ hibernate-envers/hibernate-envers.gradle | 4 ++++ 2 files changed, 8 insertions(+) diff --git a/hibernate-core/hibernate-core.gradle b/hibernate-core/hibernate-core.gradle index 069335b2b74b..c04f082d21c1 100644 --- a/hibernate-core/hibernate-core.gradle +++ b/hibernate-core/hibernate-core.gradle @@ -229,6 +229,10 @@ task copyBundleResources (type: Copy) { } processTestResources.dependsOn copyBundleResources +sourcesJar { + duplicatesStrategy = DuplicatesStrategy.EXCLUDE +} + task testJar(type: Jar, dependsOn: testClasses) { duplicatesStrategy = DuplicatesStrategy.EXCLUDE archiveClassifier.set( 'test' ) diff --git a/hibernate-envers/hibernate-envers.gradle b/hibernate-envers/hibernate-envers.gradle index 5bcc7d4e9fce..005453e9183a 100644 --- a/hibernate-envers/hibernate-envers.gradle +++ b/hibernate-envers/hibernate-envers.gradle @@ -71,6 +71,10 @@ jar { } } +sourcesJar { + duplicatesStrategy = DuplicatesStrategy.EXCLUDE +} + task testJar(type: Jar, dependsOn: testClasses) { duplicatesStrategy = DuplicatesStrategy.EXCLUDE archiveClassifier.set( 'test' ) From 8fc45a90044f4e6e54e1a03f1d3b074253554918 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Wed, 16 Jun 2021 16:03:50 +0200 Subject: [PATCH 220/644] HHH-11817 Allow schema-export commands written to file to truncate in addition to current appending --- .../userguide/appendices/Configurations.adoc | 4 +++ .../org/hibernate/cfg/AvailableSettings.java | 10 ++++++ .../hibernate/tool/hbm2ddl/SchemaExport.java | 31 +++++++++++++++++-- .../hibernate/tool/hbm2ddl/SchemaUpdate.java | 15 ++++++++- .../tool/schema/internal/Helper.java | 5 +-- .../exec/ScriptTargetOutputToFile.java | 29 ++++++++++++----- .../exec/ScriptTargetOutputToUrl.java | 24 +++++++++++--- .../spi/SchemaManagementToolCoordinator.java | 28 +++++++++++------ 8 files changed, 120 insertions(+), 26 deletions(-) diff --git a/documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc b/documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc index 3f608e0b55bf..d896314c5c70 100644 --- a/documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc +++ b/documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc @@ -887,6 +887,10 @@ For cases where the `javax.persistence.schema-generation.scripts.action` value i `*javax.persistence.schema-generation.scripts.drop-target*`:: For cases where the `javax.persistence.schema-generation.scripts.action` value indicates that schema dropping commands should be written to DDL script file, `javax.persistence.schema-generation.scripts.drop-target` specifies either a `java.io.Writer` configured for output of the DDL script or a string specifying the file URL for the DDL script. +`*hibernate.hbm2ddl.schema-generation.script.append*` (e.g. `true` (default value) or `false`):: +For cases where the `javax.persistence.schema-generation.scripts.action` value indicates that schema commands should be written to DDL script file, `hibernate.hbm2ddl.schema-generation.script.append` specifies if schema commands should be appended to the end of the file rather than written at the beginning of the file. +Values are `true` for appending schema commands to the end of the file, `false` for writing achema commands at the beginning of the file. + `*javax.persistence.hibernate.hbm2ddl.import_files*` (e.g. `import.sql` (default value)):: Comma-separated names of the optional files containing SQL DML statements executed during the `SessionFactory` creation. File order matters, the statements of a given file are executed before the statements of the following one. diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java index a40320d3b704..13cb5b8a6f2a 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java @@ -1588,6 +1588,16 @@ public interface AvailableSettings extends org.hibernate.jpa.AvailableSettings { @SuppressWarnings("JavaDoc") String HBM2DDL_SCRIPTS_CREATE_TARGET = "javax.persistence.schema-generation.scripts.create-target"; + /** + * For cases where the {@value #HBM2DDL_SCRIPTS_ACTION} value indicates that schema commands should + * be written to DDL script file, specifies if schema commands should be appended to the end of the file rather than written at the beginning of the file. + * + * Values are: {@code true} for appending schema commands to the end of the file, {@code false} for writing schema commands at the beginning. + * + * The default value is {@code true} + */ + String HBM2DDL_SCRIPTS_CREATE_APPEND = "hibernate.hbm2ddl.schema-generation.script.append"; + /** * For cases where the {@value #HBM2DDL_SCRIPTS_ACTION} value indicates that schema drop commands should * be written to DDL script file, {@value #HBM2DDL_SCRIPTS_DROP_TARGET} specifies either a diff --git a/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaExport.java b/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaExport.java index f80bb8c3f583..33d3e680949e 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaExport.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaExport.java @@ -135,6 +135,7 @@ else if ( actionText.equalsIgnoreCase( "drop-and-create" ) ) { } } + boolean append = true; boolean haltOnError = false; boolean format = false; boolean manageNamespaces = false; @@ -159,6 +160,18 @@ public SchemaExport setOutputFile(String filename) { return this; } + /** + * For generating a export script file, by default the content will be appended at the begin or end of the file. + * + * The sql will be written at the beginning of the file rather append to the end. + * + * @return this + */ + public SchemaExport setOverrideOutputFileContent() { + append = false; + return this; + } + /** * Comma-separated list of resource names to use for database init commands on create. * @@ -244,7 +257,12 @@ public void execute(EnumSet targetTypes, Action action, Metadata met LOG.runningHbm2ddlSchemaExport(); - final TargetDescriptor targetDescriptor = buildTargetDescriptor( targetTypes, outputFile, serviceRegistry ); + final TargetDescriptor targetDescriptor = buildTargetDescriptor( + targetTypes, + outputFile, + append, + serviceRegistry + ); doExecution( action, needsJdbcConnection( targetTypes ), metadata, serviceRegistry, targetDescriptor ); } @@ -316,6 +334,14 @@ public static TargetDescriptor buildTargetDescriptor( EnumSet targetTypes, String outputFile, ServiceRegistry serviceRegistry) { + return buildTargetDescriptor( targetTypes, outputFile, true, serviceRegistry ); + } + + public static TargetDescriptor buildTargetDescriptor( + EnumSet targetTypes, + String outputFile, + boolean append, + ServiceRegistry serviceRegistry) { final ScriptTargetOutput scriptTarget; if ( targetTypes.contains( TargetType.SCRIPT ) ) { if ( outputFile == null ) { @@ -324,7 +350,8 @@ public static TargetDescriptor buildTargetDescriptor( scriptTarget = Helper.interpretScriptTargetSetting( outputFile, serviceRegistry.getService( ClassLoaderService.class ), - (String) serviceRegistry.getService( ConfigurationService.class ).getSettings().get( AvailableSettings.HBM2DDL_CHARSET_NAME ) + (String) serviceRegistry.getService( ConfigurationService.class ).getSettings().get( AvailableSettings.HBM2DDL_CHARSET_NAME ), + append ); } else { diff --git a/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaUpdate.java b/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaUpdate.java index 1b4a8768ae3e..4fe27c453ea2 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaUpdate.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaUpdate.java @@ -55,6 +55,7 @@ public class SchemaUpdate { boolean haltOnError = false; private String outputFile; + private boolean append = true; private String delimiter; private boolean format; @@ -87,7 +88,7 @@ public void execute(EnumSet targetTypes, Metadata metadata, ServiceR exceptionHandler ); - final TargetDescriptor targetDescriptor = SchemaExport.buildTargetDescriptor( targetTypes, outputFile, serviceRegistry ); + final TargetDescriptor targetDescriptor = SchemaExport.buildTargetDescriptor( targetTypes, outputFile, append, serviceRegistry ); try { tool.getSchemaMigrator( config ).doMigration( metadata, executionOptions, targetDescriptor ); @@ -123,6 +124,18 @@ public SchemaUpdate setOutputFile(String outputFile) { return this; } + /** + * For generating a export script file, by default the content will be appended at the begin or end of the file. + * + * The sql will be written at the beginning of the file rather append to the end. + * + * @return this + */ + public SchemaUpdate setOverrideOutputFileContent() { + append = false; + return this; + } + /** * Set the end of statement delimiter * diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/Helper.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/Helper.java index 49c66cff1756..f4513baccdee 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/Helper.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/Helper.java @@ -93,7 +93,8 @@ private static ScriptSourceInput interpretScriptSourceSetting( public static ScriptTargetOutput interpretScriptTargetSetting( Object scriptTargetSetting, ClassLoaderService classLoaderService, - String charsetName ) { + String charsetName, + boolean append) { if ( scriptTargetSetting == null ) { return null; } @@ -118,7 +119,7 @@ else if ( Writer.class.isInstance( scriptTargetSetting ) ) { // assume it is a File path final File file = new File( scriptTargetSettingString ); - return new ScriptTargetOutputToFile( file, charsetName ); + return new ScriptTargetOutputToFile( file, charsetName, append ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/exec/ScriptTargetOutputToFile.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/exec/ScriptTargetOutputToFile.java index 3338377500bd..abdc3309efc8 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/exec/ScriptTargetOutputToFile.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/exec/ScriptTargetOutputToFile.java @@ -28,6 +28,7 @@ public class ScriptTargetOutputToFile extends AbstractScriptTargetOutput impleme private final File file; private final String charsetName; + private final boolean append; private Writer writer; @@ -36,10 +37,24 @@ public class ScriptTargetOutputToFile extends AbstractScriptTargetOutput impleme * * @param file The file to read from * @param charsetName The charset name + * @param append If true, then bytes will be written to the end of the file rather than the beginning */ - public ScriptTargetOutputToFile(File file, String charsetName) { + public ScriptTargetOutputToFile(File file, String charsetName, boolean append) { this.file = file; this.charsetName = charsetName; + this.append = append; + } + + /** + * Constructs a ScriptTargetOutputToFile instance, + * the bytes will be written to the end of the file rather than the beginning + * + * @param file The file to read from + * @param charsetName The charset name + * + */ + public ScriptTargetOutputToFile(File file, String charsetName ) { + this(file, charsetName, true); } @Override @@ -53,7 +68,7 @@ protected Writer writer() { @Override public void prepare() { super.prepare(); - this.writer = toFileWriter( this.file, this.charsetName ); + this.writer = toFileWriter( this.file, this.charsetName, append ); } @Override @@ -63,7 +78,7 @@ public void release() { writer.close(); } catch (IOException e) { - throw new SchemaManagementException( "Unable to close file writer : " + e.toString() ); + throw new SchemaManagementException( "Unable to close file writer : " + e ); } finally { writer = null; @@ -72,7 +87,7 @@ public void release() { } @SuppressWarnings("ResultOfMethodCallIgnored") - static Writer toFileWriter( File file, String charsetName ) { + static Writer toFileWriter(File file, String charsetName, boolean append) { try { if ( ! file.exists() ) { // best effort, since this is very likely not allowed in EE environments @@ -84,17 +99,17 @@ static Writer toFileWriter( File file, String charsetName ) { } } catch (Exception e) { - log.debug( "Exception calling File#createNewFile : " + e.toString() ); + log.debug( "Exception calling File#createNewFile : " + e ); } try { return charsetName != null ? new OutputStreamWriter( - new FileOutputStream( file, true ), + new FileOutputStream( file, append ), charsetName ) : new OutputStreamWriter( new FileOutputStream( file, - true + append ) ); } catch (IOException e) { diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/exec/ScriptTargetOutputToUrl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/exec/ScriptTargetOutputToUrl.java index 02fca127429f..f342efb61344 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/exec/ScriptTargetOutputToUrl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/exec/ScriptTargetOutputToUrl.java @@ -28,6 +28,7 @@ public class ScriptTargetOutputToUrl extends AbstractScriptTargetOutput implemen private final URL url; private final String charsetName; + private final boolean append; private Writer writer; @@ -36,10 +37,23 @@ public class ScriptTargetOutputToUrl extends AbstractScriptTargetOutput implemen * * @param url The url to read from * @param charsetName The charset name + * @param append If true, then bytes will be written to the end of the file rather than the beginning */ - public ScriptTargetOutputToUrl(URL url, String charsetName) { + public ScriptTargetOutputToUrl(URL url, String charsetName, boolean append) { this.url = url; this.charsetName = charsetName; + this.append = append; + } + + /** + * Constructs a ScriptTargetOutputToUrl instance + * the bytes will be written to the end of the file rather than the beginning + * + * @param url The url to read from + * @param charsetName The charset name + */ + public ScriptTargetOutputToUrl(URL url, String charsetName) { + this( url, charsetName, true ); } @Override @@ -53,7 +67,7 @@ protected Writer writer() { @Override public void prepare() { super.prepare(); - this.writer = toWriter( url, charsetName ); + this.writer = toWriter( url, charsetName, append ); } @Override @@ -62,17 +76,17 @@ public void release() { writer().close(); } catch (IOException e) { - throw new SchemaManagementException( "Unable to close file writer : " + e.toString() ); + throw new SchemaManagementException( "Unable to close file writer : " + e ); } } - private static Writer toWriter( URL url, String charsetName ) { + private static Writer toWriter( URL url, String charsetName, boolean append ) { log.debug( "Attempting to resolve writer for URL : " + url ); // technically only "strings corresponding to file URLs" are supported, which I take to mean URLs whose // protocol is "file" try { - return ScriptTargetOutputToFile.toFileWriter( new File( url.toURI() ), charsetName ); + return ScriptTargetOutputToFile.toFileWriter( new File( url.toURI() ), charsetName, append ); } catch (URISyntaxException e) { throw new SchemaManagementException( diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/SchemaManagementToolCoordinator.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/SchemaManagementToolCoordinator.java index d0d27aaccf59..4c0c33807cb9 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/SchemaManagementToolCoordinator.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/SchemaManagementToolCoordinator.java @@ -77,7 +77,7 @@ public static void process( ExceptionHandlerLoggedImpl.INSTANCE ); - performScriptAction( actions.getScriptAction(), metadata, tool, serviceRegistry, executionOptions ); + performScriptAction( actions.getScriptAction(), metadata, tool, serviceRegistry, executionOptions, configService ); performDatabaseAction( actions.getDatabaseAction(), metadata, tool, serviceRegistry, executionOptions ); if ( actions.getDatabaseAction() == Action.CREATE_DROP ) { @@ -260,13 +260,15 @@ private static void performScriptAction( Metadata metadata, SchemaManagementTool tool, ServiceRegistry serviceRegistry, - ExecutionOptions executionOptions) { + ExecutionOptions executionOptions, + ConfigurationService configurationService) { switch ( scriptAction ) { case CREATE_ONLY: { final JpaTargetAndSourceDescriptor createDescriptor = buildScriptTargetDescriptor( executionOptions.getConfigurationValues(), CreateSettingSelector.INSTANCE, - serviceRegistry + serviceRegistry, + configurationService ); tool.getSchemaCreator( executionOptions.getConfigurationValues() ).doCreation( metadata, @@ -281,7 +283,8 @@ private static void performScriptAction( final JpaTargetAndSourceDescriptor dropDescriptor = buildScriptTargetDescriptor( executionOptions.getConfigurationValues(), DropSettingSelector.INSTANCE, - serviceRegistry + serviceRegistry, + configurationService ); tool.getSchemaDropper( executionOptions.getConfigurationValues() ).doDrop( metadata, @@ -292,7 +295,8 @@ private static void performScriptAction( final JpaTargetAndSourceDescriptor createDescriptor = buildScriptTargetDescriptor( executionOptions.getConfigurationValues(), CreateSettingSelector.INSTANCE, - serviceRegistry + serviceRegistry, + configurationService ); tool.getSchemaCreator( executionOptions.getConfigurationValues() ).doCreation( metadata, @@ -306,7 +310,8 @@ private static void performScriptAction( final JpaTargetAndSourceDescriptor dropDescriptor = buildScriptTargetDescriptor( executionOptions.getConfigurationValues(), DropSettingSelector.INSTANCE, - serviceRegistry + serviceRegistry, + configurationService ); tool.getSchemaDropper( executionOptions.getConfigurationValues() ).doDrop( metadata, @@ -320,7 +325,8 @@ private static void performScriptAction( final JpaTargetAndSourceDescriptor migrateDescriptor = buildScriptTargetDescriptor( executionOptions.getConfigurationValues(), MigrateSettingSelector.INSTANCE, - serviceRegistry + serviceRegistry, + configurationService ); tool.getSchemaMigrator( executionOptions.getConfigurationValues() ).doMigration( metadata, @@ -338,7 +344,8 @@ private static void performScriptAction( private static JpaTargetAndSourceDescriptor buildScriptTargetDescriptor( Map configurationValues, SettingSelector settingSelector, - ServiceRegistry serviceRegistry) { + ServiceRegistry serviceRegistry, + ConfigurationService configurationService) { final Object scriptSourceSetting = settingSelector.getScriptSourceSetting( configurationValues ); final SourceType sourceType = SourceType.interpret( settingSelector.getSourceTypeSetting( configurationValues ), @@ -358,10 +365,13 @@ private static JpaTargetAndSourceDescriptor buildScriptTargetDescriptor( ? Helper.interpretScriptSourceSetting( scriptSourceSetting, serviceRegistry.getService( ClassLoaderService.class ), charsetName ) : null; + + boolean append = configurationService.getSetting( AvailableSettings.HBM2DDL_SCRIPTS_CREATE_APPEND, StandardConverters.BOOLEAN, true ); final ScriptTargetOutput scriptTargetOutput = Helper.interpretScriptTargetSetting( settingSelector.getScriptTargetSetting( configurationValues ), serviceRegistry.getService( ClassLoaderService.class ), - charsetName + charsetName, + append ); return new JpaTargetAndSourceDescriptor() { From bdc08af163df6bcc0dfaf6483d961ee650123ee0 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Wed, 16 Jun 2021 16:04:10 +0200 Subject: [PATCH 221/644] HHH-11817 Add test for issue --- .../SchemaCreationToOutputScriptTest.java | 170 ++++++++++++++++ .../SchemaDropToOutputScriptTest.java | 170 ++++++++++++++++ .../SchemaMigrationToOutputScriptTest.java | 188 ++++++++++++++++++ 3 files changed, 528 insertions(+) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaCreationToOutputScriptTest.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaDropToOutputScriptTest.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaMigrationToOutputScriptTest.java diff --git a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaCreationToOutputScriptTest.java b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaCreationToOutputScriptTest.java new file mode 100644 index 000000000000..584dde20f4c1 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaCreationToOutputScriptTest.java @@ -0,0 +1,170 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.schemaupdate; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.nio.file.Files; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import javax.persistence.Entity; +import javax.persistence.Id; + +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.boot.spi.MetadataImplementor; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.cfg.Environment; +import org.hibernate.dialect.H2Dialect; +import org.hibernate.engine.config.spi.ConfigurationService; +import org.hibernate.service.ServiceRegistry; +import org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator; + +import org.hibernate.testing.RequiresDialect; +import org.hibernate.testing.ServiceRegistryBuilder; +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseUnitTestCase; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.core.StringContains.containsString; + +@TestForIssue(jiraKey = "HHH-11817") +@RequiresDialect(H2Dialect.class) +public class SchemaCreationToOutputScriptTest extends BaseUnitTestCase { + + private final String createTableMyEntity = "create table MyEntity"; + private final String createTableMySecondEntity = "create table MySecondEntity"; + + private File output; + private ServiceRegistry serviceRegistry; + private MetadataImplementor metadata; + + @Before + public void setUp() throws Exception { + output = File.createTempFile( "creation_script", ".sql" ); + output.deleteOnExit(); + + List content = Arrays.asList( + "This is the database creation script generated by Hibernate" + , "This is the second line" + , "This is the third line" + , "This is the fourth line" + , "This is the fifth line" + , "This is the sixth line" + , "This is the seventh line" + , "This is the eighth line" + , "This is the ninth line" + ); + + try (BufferedWriter bw = new BufferedWriter( new FileWriter( output ) )) { + for ( String s : content ) { + bw.write( s ); + bw.write( System.lineSeparator() ); + } + } + } + + private void createServiceRegistryAndMetadata(String append) { + final StandardServiceRegistryBuilder standardServiceRegistryBuilder = new StandardServiceRegistryBuilder() + .applySetting( Environment.FORMAT_SQL, "false" ) + .applySetting( Environment.HBM2DDL_SCRIPTS_ACTION, "create" ) + .applySetting( AvailableSettings.HBM2DDL_SCRIPTS_CREATE_TARGET, output.getAbsolutePath() ); + if ( append != null ) { + standardServiceRegistryBuilder.applySetting( AvailableSettings.HBM2DDL_SCRIPTS_CREATE_APPEND, append ); + } + + serviceRegistry = standardServiceRegistryBuilder.build(); + + metadata = (MetadataImplementor) new MetadataSources( serviceRegistry ) + .addAnnotatedClass( MyEntity.class ) + .addAnnotatedClass( MySecondEntity.class ) + .buildMetadata(); + metadata.validate(); + } + + @After + public void tearDown() { + ServiceRegistryBuilder.destroy( serviceRegistry ); + } + + @Test + public void testAppendModeFalse() throws Exception { + createServiceRegistryAndMetadata( "false" ); + HashMap properties = new HashMap<>(); + properties.putAll( serviceRegistry.getService( ConfigurationService.class ).getSettings() ); + + SchemaManagementToolCoordinator.process( + metadata, + serviceRegistry, + properties, + null + ); + List commands = Files.readAllLines( output.toPath() ); + assertThat( commands.size(), is( 2 ) ); + assertThat( commands.get( 0 ), containsString( createTableMyEntity ) ); + assertThat( commands.get( 1 ), containsString( createTableMySecondEntity ) ); + } + + @Test + public void testAppendModeTrue() throws Exception { + createServiceRegistryAndMetadata( "true" ); + HashMap properties = new HashMap<>(); + properties.putAll( serviceRegistry.getService( ConfigurationService.class ).getSettings() ); + + SchemaManagementToolCoordinator.process( + metadata, + serviceRegistry, + properties, + null + ); + List commands = Files.readAllLines( output.toPath() ); + assertThat( commands.size(), is( 11 ) ); + assertThat( commands.get( 9 ), containsString( createTableMyEntity ) ); + assertThat( commands.get( 10 ), containsString( createTableMySecondEntity ) ); + } + + @Test + public void testDefaultAppendMode() throws Exception { + createServiceRegistryAndMetadata( null ); + HashMap properties = new HashMap<>(); + properties.putAll( serviceRegistry.getService( ConfigurationService.class ).getSettings() ); + + SchemaManagementToolCoordinator.process( + metadata, + serviceRegistry, + properties, + null + ); + List commands = Files.readAllLines( output.toPath() ); + assertThat( commands.size(), is( 11 ) ); + assertThat( commands.get( 9 ), containsString( createTableMyEntity ) ); + assertThat( commands.get( 10 ), containsString( createTableMySecondEntity ) ); + } + + @Entity(name = "MyEntity") + public static class MyEntity { + @Id + private Long id; + + private String name; + } + + @Entity(name = "MySecondEntity") + public static class MySecondEntity { + @Id + private Long id; + + private String name; + } + +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaDropToOutputScriptTest.java b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaDropToOutputScriptTest.java new file mode 100644 index 000000000000..d5de59440ae2 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaDropToOutputScriptTest.java @@ -0,0 +1,170 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.schemaupdate; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.nio.file.Files; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import javax.persistence.Entity; +import javax.persistence.Id; + +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.boot.spi.MetadataImplementor; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.cfg.Environment; +import org.hibernate.dialect.H2Dialect; +import org.hibernate.engine.config.spi.ConfigurationService; +import org.hibernate.service.ServiceRegistry; +import org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator; + +import org.hibernate.testing.RequiresDialect; +import org.hibernate.testing.ServiceRegistryBuilder; +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseUnitTestCase; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +@TestForIssue(jiraKey = "HHH-11817") +@RequiresDialect(H2Dialect.class) +public class SchemaDropToOutputScriptTest extends BaseUnitTestCase { + + private File output; + private ServiceRegistry serviceRegistry; + private MetadataImplementor metadata; + private final String dropMyEntityTable = "drop table if exists MyEntity"; + private final String dropMySecondEntityTable = "drop table if exists MySecondEntity"; + + + @Before + public void setUp() throws Exception { + output = File.createTempFile( "creation_script", ".sql" ); + output.deleteOnExit(); + List content = Arrays.asList( + "This is the database creation script generated by Hibernate" + , "This is the second line" + , "This is the third line" + , "This is the fourth line" + , "This is the fifth line" + , "This is the sixth line" + , "This is the seventh line" + , "This is the eighth line" + , "This is the ninth line" + ); + + try (BufferedWriter bw = new BufferedWriter( new FileWriter( output ) )) { + for ( String s : content ) { + bw.write( s ); + bw.write( System.lineSeparator() ); + } + } + } + + private void createServiceRegistryAndMetadata(String append) { + final StandardServiceRegistryBuilder standardServiceRegistryBuilder = new StandardServiceRegistryBuilder() + .applySetting( Environment.FORMAT_SQL, "false" ) + .applySetting( Environment.HBM2DDL_SCRIPTS_ACTION, "drop" ) + .applySetting( AvailableSettings.HBM2DDL_SCRIPTS_DROP_TARGET, output.getAbsolutePath() ); + + if ( append != null ) { + standardServiceRegistryBuilder.applySetting( AvailableSettings.HBM2DDL_SCRIPTS_CREATE_APPEND, append ); + } + + serviceRegistry = standardServiceRegistryBuilder.build(); + + metadata = (MetadataImplementor) new MetadataSources( serviceRegistry ) + .addAnnotatedClass( MyEntity.class ) + .addAnnotatedClass( MySecondEntity.class ) + .buildMetadata(); + metadata.validate(); + } + + @After + public void tearDown() { + ServiceRegistryBuilder.destroy( serviceRegistry ); + } + + @Test + public void testAppendModeFalse() throws Exception { + createServiceRegistryAndMetadata( "false" ); + HashMap properties = new HashMap<>(); + properties.putAll( serviceRegistry.getService( ConfigurationService.class ).getSettings() ); + + SchemaManagementToolCoordinator.process( + metadata, + serviceRegistry, + properties, + null + ); + List commands = Files.readAllLines( output.toPath() ); + assertThat( commands.size(), is( 2 ) ); + assertThat( commands.get( 0 ), containsString( dropMyEntityTable ) ); + assertThat( commands.get( 1 ), containsString( dropMySecondEntityTable ) ); + } + + @Test + public void testAppendModeTrue() throws Exception { + createServiceRegistryAndMetadata( "true" ); + HashMap properties = new HashMap<>(); + properties.putAll( serviceRegistry.getService( ConfigurationService.class ).getSettings() ); + + SchemaManagementToolCoordinator.process( + metadata, + serviceRegistry, + properties, + null + ); + List commands = Files.readAllLines( output.toPath() ); + assertThat( commands.size(), is( 11 ) ); + assertThat( commands.get( 9 ), containsString( dropMyEntityTable ) ); + assertThat( commands.get( 10 ), containsString( dropMySecondEntityTable ) ); + } + + @Test + public void testDefaultAppendMode() throws Exception { + createServiceRegistryAndMetadata( null ); + HashMap properties = new HashMap<>(); + properties.putAll( serviceRegistry.getService( ConfigurationService.class ).getSettings() ); + + SchemaManagementToolCoordinator.process( + metadata, + serviceRegistry, + properties, + null + ); + List commands = Files.readAllLines( output.toPath() ); + assertThat( commands.size(), is( 11 ) ); + assertThat( commands.get( 9 ), containsString( dropMyEntityTable ) ); + assertThat( commands.get( 10 ), containsString( dropMySecondEntityTable ) ); + } + + @Entity(name = "MyEntity") + public static class MyEntity { + @Id + private Long id; + + private String name; + } + + @Entity(name = "MySecondEntity") + public static class MySecondEntity { + @Id + private Long id; + + private String name; + } + +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaMigrationToOutputScriptTest.java b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaMigrationToOutputScriptTest.java new file mode 100644 index 000000000000..88d85f12ca76 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaMigrationToOutputScriptTest.java @@ -0,0 +1,188 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.schemaupdate; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.nio.file.Files; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import javax.persistence.Entity; +import javax.persistence.Id; + +import org.hibernate.SessionFactory; +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.boot.spi.MetadataImplementor; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.cfg.Environment; +import org.hibernate.dialect.H2Dialect; +import org.hibernate.engine.config.spi.ConfigurationService; +import org.hibernate.service.ServiceRegistry; +import org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator; + +import org.hibernate.testing.RequiresDialect; +import org.hibernate.testing.ServiceRegistryBuilder; +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseUnitTestCase; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.containsString; +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +@TestForIssue(jiraKey = "HHH-11817") +@RequiresDialect(H2Dialect.class) +public class SchemaMigrationToOutputScriptTest extends BaseUnitTestCase { + + private final String createTableMySecondEntity = "create table MySecondEntity"; + + private File output; + private ServiceRegistry serviceRegistry; + private MetadataImplementor metadata; + + @Before + public void setUp() throws Exception { + output = File.createTempFile( "creation_script", ".sql" ); + output.deleteOnExit(); + + List content = Arrays.asList( + "This is the database creation script generated by Hibernate" + , "This is the second line" + , "This is the third line" + , "This is the fourth line" + , "This is the fifth line" + , "This is the sixth line" + , "This is the seventh line" + , "This is the eighth line" + , "This is the ninth line" + ); + + try (BufferedWriter bw = new BufferedWriter( new FileWriter( output ) )) { + for ( String s : content ) { + bw.write( s ); + bw.write( System.lineSeparator() ); + } + } + + serviceRegistry = new StandardServiceRegistryBuilder().applySetting( + AvailableSettings.HBM2DDL_AUTO, + "create-only" + ) + .build(); + + metadata = (MetadataImplementor) new MetadataSources( serviceRegistry ) + .addAnnotatedClass( MyEntity.class ) + .buildMetadata(); + final SessionFactory sessionFactory = metadata.buildSessionFactory(); + sessionFactory.close(); + } + + private void createServiceRegistryAndMetadata(String append) { + final StandardServiceRegistryBuilder standardServiceRegistryBuilder = new StandardServiceRegistryBuilder() + .applySetting( Environment.FORMAT_SQL, "false" ) + .applySetting( Environment.HBM2DDL_SCRIPTS_ACTION, "update" ) + .applySetting( AvailableSettings.HBM2DDL_SCRIPTS_CREATE_TARGET, output.getAbsolutePath() ); + + if ( append != null ) { + standardServiceRegistryBuilder.applySetting( AvailableSettings.HBM2DDL_SCRIPTS_CREATE_APPEND, append ); + } + + serviceRegistry = standardServiceRegistryBuilder.build(); + + metadata = (MetadataImplementor) new MetadataSources( serviceRegistry ) + .addAnnotatedClass( MyEntity.class ) + .addAnnotatedClass( MySecondEntity.class ) + .buildMetadata(); + metadata.validate(); + } + + @After + public void tearDown() { + ServiceRegistryBuilder.destroy( serviceRegistry ); + serviceRegistry = new StandardServiceRegistryBuilder().applySetting( AvailableSettings.HBM2DDL_AUTO, "drop" ) + .build(); + + metadata = (MetadataImplementor) new MetadataSources( serviceRegistry ) + .addAnnotatedClass( MyEntity.class ) + .buildMetadata(); + final SessionFactory sessionFactory = metadata.buildSessionFactory(); + sessionFactory.close(); + } + + @Test + public void testAppendModeFalse() throws Exception { + createServiceRegistryAndMetadata( "false" ); + HashMap properties = new HashMap<>(); + properties.putAll( serviceRegistry.getService( ConfigurationService.class ).getSettings() ); + + SchemaManagementToolCoordinator.process( + metadata, + serviceRegistry, + properties, + null + ); + List commands = Files.readAllLines( output.toPath() ); + assertThat( commands.size(), is( 1 ) ); + assertThat( commands.get( 0 ), containsString( createTableMySecondEntity ) ); + } + + @Test + public void testAppendModeTrue() throws Exception { + createServiceRegistryAndMetadata( "true" ); + HashMap properties = new HashMap<>(); + properties.putAll( serviceRegistry.getService( ConfigurationService.class ).getSettings() ); + + SchemaManagementToolCoordinator.process( + metadata, + serviceRegistry, + properties, + null + ); + List commands = Files.readAllLines( output.toPath() ); + assertThat( commands.size(), is( 10 ) ); + assertThat( commands.get( 9 ), containsString( createTableMySecondEntity ) ); + } + + @Test + public void testDefaultAppendMode() throws Exception { + createServiceRegistryAndMetadata( null ); + HashMap properties = new HashMap<>(); + properties.putAll( serviceRegistry.getService( ConfigurationService.class ).getSettings() ); + + SchemaManagementToolCoordinator.process( + metadata, + serviceRegistry, + properties, + null + ); + List commands = Files.readAllLines( output.toPath() ); + assertThat( commands.size(), is( 10 ) ); + assertThat( commands.get( 9 ), containsString( createTableMySecondEntity ) ); + } + + @Entity(name = "MyEntity") + public static class MyEntity { + @Id + private Long id; + + private String name; + } + + @Entity(name = "MySecondEntity") + public static class MySecondEntity { + @Id + private Long id; + + private String name; + } + +} From 7329f444b5fd248ee671bb99f260d666c64e2d7e Mon Sep 17 00:00:00 2001 From: Karel Maesen Date: Fri, 18 Jun 2021 13:23:32 +0200 Subject: [PATCH 222/644] HHH-14654 Fix for schema validation bug --- .../cockroachdb/CockroachDB202SpatialDialect.java | 5 +++++ .../cockroachdb/CockroachSpatialDialectTrait.java | 5 +++++ .../dialect/postgis/PGSpatialDialectTrait.java | 11 +++++++++++ .../spatial/dialect/postgis/PostgisPG10Dialect.java | 8 ++++++++ .../spatial/dialect/postgis/PostgisPG82Dialect.java | 5 +++++ .../spatial/dialect/postgis/PostgisPG91Dialect.java | 6 ++++++ .../spatial/dialect/postgis/PostgisPG92Dialect.java | 6 ++++++ .../spatial/dialect/postgis/PostgisPG93Dialect.java | 6 ++++++ .../spatial/dialect/postgis/PostgisPG94Dialect.java | 6 ++++++ .../spatial/dialect/postgis/PostgisPG95Dialect.java | 5 +++++ .../spatial/dialect/postgis/PostgisPG9Dialect.java | 6 ++++++ .../spatial/dialect/postgis/PostgisSupport.java | 5 +++++ 12 files changed, 74 insertions(+) diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/cockroachdb/CockroachDB202SpatialDialect.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/cockroachdb/CockroachDB202SpatialDialect.java index d5ba27617a3b..31f9927e095a 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/cockroachdb/CockroachDB202SpatialDialect.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/cockroachdb/CockroachDB202SpatialDialect.java @@ -42,4 +42,9 @@ public void contributeTypes(TypeContributions typeContributions, ServiceRegistry delegateContributeTypes( typeContributions, serviceRegistry ); } + @Override + public boolean equivalentTypes(int typeCode1, int typeCode2) { + return super.equivalentTypes( typeCode1, typeCode2 ) || + ( isSpatial( typeCode1 ) && isSpatial( typeCode2 ) ); + } } diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/cockroachdb/CockroachSpatialDialectTrait.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/cockroachdb/CockroachSpatialDialectTrait.java index 17ffb69b7e8e..2df63848ff69 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/cockroachdb/CockroachSpatialDialectTrait.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/cockroachdb/CockroachSpatialDialectTrait.java @@ -74,4 +74,9 @@ default boolean supports(SpatialFunction function) { return DELEGATE.supports( function ); } + + default boolean isSpatial(int typeCode) { + return DELEGATE.isSpatial( typeCode ); + } + } diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PGSpatialDialectTrait.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PGSpatialDialectTrait.java index 2c6dd2edf10c..5b7abcd1e1a1 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PGSpatialDialectTrait.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PGSpatialDialectTrait.java @@ -7,6 +7,8 @@ package org.hibernate.spatial.dialect.postgis; +import java.sql.Types; + import org.hibernate.spatial.SpatialDialect; import org.hibernate.spatial.SpatialFunction; import org.hibernate.spatial.dialect.SpatialFunctionsRegistry; @@ -125,4 +127,13 @@ default boolean supportsFiltering() { default boolean supports(SpatialFunction function) { return support.supports( function ); } + + /** + * Checks whether the typeCode is (potentially) the code for a spatial type + * @param typeCode the JDBC type code + * @return if the typecode corresponds with a spatialt type + */ + default boolean isSpatial(int typeCode){ + return support.isSpatial( typeCode ); + } } diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG10Dialect.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG10Dialect.java index e7c9412b635a..1d238bde316c 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG10Dialect.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG10Dialect.java @@ -7,6 +7,7 @@ package org.hibernate.spatial.dialect.postgis; +import java.sql.Types; import java.util.Map; import org.hibernate.boot.model.TypeContributions; @@ -36,4 +37,11 @@ public void contributeTypes(TypeContributions typeContributions, ServiceRegistry support.contributeTypes( typeContributions, serviceRegistry ); } + @Override + public boolean equivalentTypes(int typeCode1, int typeCode2) { + return super.equivalentTypes( typeCode1, typeCode2 ) || + ( isSpatial( typeCode1 ) && isSpatial( typeCode2 ) ); + } + + } diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG82Dialect.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG82Dialect.java index f1fa67c919c3..9351bceabb82 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG82Dialect.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG82Dialect.java @@ -48,6 +48,11 @@ public void contributeTypes(TypeContributions typeContributions, ServiceRegistry support.contributeTypes( typeContributions, serviceRegistry ); } + @Override + public boolean equivalentTypes(int typeCode1, int typeCode2) { + return super.equivalentTypes( typeCode1, typeCode2 ) || + ( support.isSpatial( typeCode1 ) && support.isSpatial( typeCode2 ) ); + } @Override public String getSpatialRelateSQL(String columnName, int spatialRelation) { diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG91Dialect.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG91Dialect.java index ca871af1df12..f2577625f0b6 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG91Dialect.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG91Dialect.java @@ -48,6 +48,12 @@ public void contributeTypes(TypeContributions typeContributions, ServiceRegistry support.contributeTypes( typeContributions, serviceRegistry ); } + @Override + public boolean equivalentTypes(int typeCode1, int typeCode2) { + return super.equivalentTypes( typeCode1, typeCode2 ) || + ( support.isSpatial( typeCode1 ) && support.isSpatial( typeCode2 ) ); + } + /** * Returns the SQL fragment for the SQL WHERE-clause when parsing * org.hibernatespatial.criterion.SpatialRelateExpressions diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG92Dialect.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG92Dialect.java index c94d2e902109..e71f982f863b 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG92Dialect.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG92Dialect.java @@ -48,6 +48,12 @@ public void contributeTypes(TypeContributions typeContributions, ServiceRegistry support.contributeTypes( typeContributions, serviceRegistry ); } + @Override + public boolean equivalentTypes(int typeCode1, int typeCode2) { + return super.equivalentTypes( typeCode1, typeCode2 ) || + ( support.isSpatial( typeCode1 ) && support.isSpatial( typeCode2 ) ); + } + /** * Returns the SQL fragment for the SQL WHERE-clause when parsing * org.hibernatespatial.criterion.SpatialRelateExpressions diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG93Dialect.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG93Dialect.java index f8ac29a1a00e..ee4ddd988590 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG93Dialect.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG93Dialect.java @@ -48,6 +48,12 @@ public void contributeTypes(TypeContributions typeContributions, ServiceRegistry support.contributeTypes( typeContributions, serviceRegistry ); } + @Override + public boolean equivalentTypes(int typeCode1, int typeCode2) { + return super.equivalentTypes( typeCode1, typeCode2 ) || + ( support.isSpatial( typeCode1 ) && support.isSpatial( typeCode2 ) ); + } + /** * Returns the SQL fragment for the SQL WHERE-clause when parsing * org.hibernatespatial.criterion.SpatialRelateExpressions diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG94Dialect.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG94Dialect.java index c267cf6d8c46..6c14a2afc2e1 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG94Dialect.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG94Dialect.java @@ -48,6 +48,12 @@ public void contributeTypes(TypeContributions typeContributions, ServiceRegistry support.contributeTypes( typeContributions, serviceRegistry ); } + @Override + public boolean equivalentTypes(int typeCode1, int typeCode2) { + return super.equivalentTypes( typeCode1, typeCode2 ) || + ( support.isSpatial( typeCode1 ) && support.isSpatial( typeCode2 ) ); + } + /** * Returns the SQL fragment for the SQL WHERE-clause when parsing * org.hibernatespatial.criterion.SpatialRelateExpressions diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG95Dialect.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG95Dialect.java index 118584fac265..1c31d221ad74 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG95Dialect.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG95Dialect.java @@ -42,4 +42,9 @@ public void contributeTypes(TypeContributions typeContributions, ServiceRegistry support.contributeTypes( typeContributions, serviceRegistry ); } + @Override + public boolean equivalentTypes(int typeCode1, int typeCode2) { + return super.equivalentTypes( typeCode1, typeCode2 ) || + ( isSpatial( typeCode1 ) && isSpatial( typeCode2 ) ); + } } diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG9Dialect.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG9Dialect.java index 9182f947f0b5..88fefa520530 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG9Dialect.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisPG9Dialect.java @@ -48,6 +48,12 @@ public void contributeTypes(TypeContributions typeContributions, ServiceRegistry support.contributeTypes( typeContributions, serviceRegistry ); } + @Override + public boolean equivalentTypes(int typeCode1, int typeCode2) { + return super.equivalentTypes( typeCode1, typeCode2 ) || + ( support.isSpatial( typeCode1 ) && support.isSpatial( typeCode2 ) ); + } + /** * Returns the SQL fragment for the SQL WHERE-clause when parsing * org.hibernatespatial.criterion.SpatialRelateExpressions diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisSupport.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisSupport.java index 126a86e0728e..ef361f47f5f0 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisSupport.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisSupport.java @@ -7,6 +7,7 @@ package org.hibernate.spatial.dialect.postgis; import java.io.Serializable; +import java.sql.Types; import org.hibernate.boot.model.TypeContributions; import org.hibernate.service.ServiceRegistry; @@ -47,6 +48,10 @@ public SpatialFunctionsRegistry functionsToRegister() { return postgisFunctions; } + public boolean isSpatial(int typeCode){ + return typeCode == Types.OTHER || typeCode == PGGeometryTypeDescriptor.INSTANCE_WKB_1.getSqlType(); + } + /** * Returns the SQL fragment for the SQL WHERE-clause when parsing * org.hibernatespatial.criterion.SpatialRelateExpressions From 8f4450c43349eb8f96d613fab6ec6cdac57352b5 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Tue, 22 Jun 2021 10:55:43 +0200 Subject: [PATCH 223/644] HHH-14597 Test and fix for NPE while trying to delete cascade to-one association within element collection --- .../hibernate/engine/internal/Cascade.java | 37 ++++++++----- .../ElementCollectionOrphanTest.java | 53 +++++++++++++++++++ .../elementcollection/EnrollableClass.java | 34 ++++++++++++ .../elementcollection/EnrolledClassSeat.java | 31 +++++++++++ .../orphan/elementcollection/Student.java | 43 +++++++++++++++ .../StudentEnrolledClass.java | 31 +++++++++++ .../orphan/elementcollection/student.hbm.xml | 45 ++++++++++++++++ 7 files changed, 261 insertions(+), 13 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/orphan/elementcollection/ElementCollectionOrphanTest.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/orphan/elementcollection/EnrollableClass.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/orphan/elementcollection/EnrolledClassSeat.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/orphan/elementcollection/Student.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/orphan/elementcollection/StudentEnrolledClass.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/orphan/elementcollection/student.hbm.xml diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/Cascade.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/Cascade.java index 107a3eff8f87..762ab776f5a4 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/internal/Cascade.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/Cascade.java @@ -232,10 +232,12 @@ private static void cascadeProperty( } } else if ( type.isComponentType() ) { - if ( componentPath == null ) { + if ( componentPath == null && propertyName != null ) { componentPath = new ArrayList<>(); } - componentPath.add( propertyName ); + if ( componentPath != null ) { + componentPath.add( propertyName ); + } cascadeComponent( action, cascadePoint, @@ -246,7 +248,9 @@ else if ( type.isComponentType() ) { (CompositeType) type, anything ); - componentPath.remove( componentPath.size() - 1 ); + if ( componentPath != null ) { + componentPath.remove( componentPath.size() - 1 ); + } } } @@ -293,17 +297,24 @@ private static void cascadeLogicalOneToOneOrphanRemoval( // Since the loadedState in the EntityEntry is a flat domain type array // We first have to extract the component object and then ask the component type // recursively to give us the value of the sub-property of that object - loadedValue = entry.getLoadedValue( componentPath.get( 0 ) ); - ComponentType componentType = (ComponentType) entry.getPersister().getPropertyType( componentPath.get( 0 ) ); - if ( componentPath.size() != 1 ) { - for ( int i = 1; i < componentPath.size(); i++ ) { - final int subPropertyIndex = componentType.getPropertyIndex( componentPath.get( i ) ); - loadedValue = componentType.getPropertyValue( loadedValue, subPropertyIndex ); - componentType = (ComponentType) componentType.getSubtypes()[subPropertyIndex]; + final Type propertyType = entry.getPersister().getPropertyType( componentPath.get(0) ); + if ( propertyType instanceof ComponentType ) { + loadedValue = entry.getLoadedValue( componentPath.get( 0 ) ); + ComponentType componentType = (ComponentType) propertyType; + if ( componentPath.size() != 1 ) { + for ( int i = 1; i < componentPath.size(); i++ ) { + final int subPropertyIndex = componentType.getPropertyIndex( componentPath.get( i ) ); + loadedValue = componentType.getPropertyValue( loadedValue, subPropertyIndex ); + componentType = (ComponentType) componentType.getSubtypes()[subPropertyIndex]; + } } - } - loadedValue = componentType.getPropertyValue( loadedValue, componentType.getPropertyIndex( propertyName ) ); + loadedValue = componentType.getPropertyValue( loadedValue, componentType.getPropertyIndex( propertyName ) ); + } + else { + // Association is probably defined in an element collection, so we can't do orphan removals + loadedValue = null; + } } // orphaned if the association was nulled (child == null) or receives a new value while the @@ -538,7 +549,7 @@ private static void cascadeCollectionElements( itr.next(), elemType, style, - null, + collectionType.getRole().substring( collectionType.getRole().lastIndexOf('.') + 1 ), anything, isCascadeDeleteEnabled ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/orphan/elementcollection/ElementCollectionOrphanTest.java b/hibernate-core/src/test/java/org/hibernate/test/orphan/elementcollection/ElementCollectionOrphanTest.java new file mode 100644 index 000000000000..83de4af02098 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/orphan/elementcollection/ElementCollectionOrphanTest.java @@ -0,0 +1,53 @@ +package org.hibernate.test.orphan.elementcollection; + +import java.util.Collections; + +import org.hibernate.Session; +import org.hibernate.SessionFactory; +import org.hibernate.boot.Metadata; +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.hibernate.testing.transaction.TransactionUtil; +import org.junit.Before; +import org.junit.Test; + +@TestForIssue(jiraKey = "HHH-14597") +public class ElementCollectionOrphanTest extends BaseCoreFunctionalTestCase { + + @Override + protected String[] getMappings() { + return new String[] { "orphan/elementcollection/student.hbm.xml" }; + } + + @Test + public void setCompositeElementTest() { + TransactionUtil.doInHibernate( + this::sessionFactory, + session -> { + EnrollableClass aClass = new EnrollableClass(); + aClass.setId("123"); + aClass.setName("Math"); + session.save(aClass); + + Student aStudent = new Student(); + aStudent.setId("s1"); + aStudent.setFirstName("John"); + aStudent.setLastName("Smith"); + + EnrolledClassSeat seat = new EnrolledClassSeat(); + seat.setId("seat1"); + seat.setRow(10); + seat.setColumn(5); + + StudentEnrolledClass enrClass = new StudentEnrolledClass(); + enrClass.setEnrolledClass(aClass); + enrClass.setClassStartTime(130); + enrClass.setSeat(seat); + aStudent.setEnrolledClasses(Collections.singleton(enrClass)); + session.save(aStudent); + } + ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/orphan/elementcollection/EnrollableClass.java b/hibernate-core/src/test/java/org/hibernate/test/orphan/elementcollection/EnrollableClass.java new file mode 100644 index 000000000000..5ae6e94d60e6 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/orphan/elementcollection/EnrollableClass.java @@ -0,0 +1,34 @@ +package org.hibernate.test.orphan.elementcollection; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; + +@Entity +@Table(name = "ENROLLABLECLASS") +public class EnrollableClass { + + @Id + @Column(name = "id") + private String id; + + @Column(name = "name") + private String name; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/orphan/elementcollection/EnrolledClassSeat.java b/hibernate-core/src/test/java/org/hibernate/test/orphan/elementcollection/EnrolledClassSeat.java new file mode 100644 index 000000000000..3a1d2654d084 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/orphan/elementcollection/EnrolledClassSeat.java @@ -0,0 +1,31 @@ +package org.hibernate.test.orphan.elementcollection; + +public class EnrolledClassSeat { + private String id; + private int row; + private int column; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public int getRow() { + return row; + } + + public void setRow(int row) { + this.row = row; + } + + public int getColumn() { + return column; + } + + public void setColumn(int column) { + this.column = column; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/orphan/elementcollection/Student.java b/hibernate-core/src/test/java/org/hibernate/test/orphan/elementcollection/Student.java new file mode 100644 index 000000000000..541184233f01 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/orphan/elementcollection/Student.java @@ -0,0 +1,43 @@ +package org.hibernate.test.orphan.elementcollection; + +import java.util.Set; + +public class Student { + + private String id; + private String firstName; + private String lastName; + private Set< StudentEnrolledClass > enrolledClasses; + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public Set getEnrolledClasses() { + return enrolledClasses; + } + + public void setEnrolledClasses(Set enrolledClasses) { + this.enrolledClasses = enrolledClasses; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/orphan/elementcollection/StudentEnrolledClass.java b/hibernate-core/src/test/java/org/hibernate/test/orphan/elementcollection/StudentEnrolledClass.java new file mode 100644 index 000000000000..199c86500042 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/orphan/elementcollection/StudentEnrolledClass.java @@ -0,0 +1,31 @@ +package org.hibernate.test.orphan.elementcollection; + +public class StudentEnrolledClass { + private EnrollableClass enrolledClass; + private int classStartTime; + private EnrolledClassSeat seat; + + public EnrollableClass getEnrolledClass() { + return enrolledClass; + } + + public void setEnrolledClass(EnrollableClass enrolledClass) { + this.enrolledClass = enrolledClass; + } + + public int getClassStartTime() { + return classStartTime; + } + + public void setClassStartTime(int classStartTime) { + this.classStartTime = classStartTime; + } + + public EnrolledClassSeat getSeat() { + return seat; + } + + public void setSeat(EnrolledClassSeat seat) { + this.seat = seat; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/orphan/elementcollection/student.hbm.xml b/hibernate-core/src/test/java/org/hibernate/test/orphan/elementcollection/student.hbm.xml new file mode 100644 index 000000000000..60af2488131d --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/orphan/elementcollection/student.hbm.xml @@ -0,0 +1,45 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From 179c1d1da0f18ae86a84e0731974e3016f924265 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Thu, 5 Jul 2018 12:54:02 +0100 Subject: [PATCH 224/644] HHH-4808 Add test for issue --- .../LazyLoadingConnectionCloseTest.java | 365 ++++++++++++++++++ 1 file changed, 365 insertions(+) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/connections/LazyLoadingConnectionCloseTest.java diff --git a/hibernate-core/src/test/java/org/hibernate/test/connections/LazyLoadingConnectionCloseTest.java b/hibernate-core/src/test/java/org/hibernate/test/connections/LazyLoadingConnectionCloseTest.java new file mode 100644 index 000000000000..b3e322f6202d --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/connections/LazyLoadingConnectionCloseTest.java @@ -0,0 +1,365 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.connections; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import javax.persistence.Entity; +import javax.persistence.EntityManager; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; +import javax.persistence.Query; +import javax.sql.DataSource; + +import org.hibernate.annotations.Fetch; +import org.hibernate.annotations.FetchMode; +import org.hibernate.annotations.LazyCollection; +import org.hibernate.annotations.LazyCollectionOption; +import org.hibernate.annotations.LazyToOne; +import org.hibernate.annotations.LazyToOneOption; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.cfg.Environment; +import org.hibernate.engine.jdbc.connections.internal.UserSuppliedConnectionProviderImpl; +import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; +import org.hibernate.jpa.test.connection.BaseDataSource; +import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode; + +import org.hibernate.testing.TestForIssue; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import static junit.framework.TestCase.assertTrue; +import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; +import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.spy; + +/** + * @author Selaron + */ +@TestForIssue(jiraKey = "HHH-4808") +public class LazyLoadingConnectionCloseTest extends BaseEntityManagerFunctionalTestCase { + + private ConnectionProviderDecorator connectionProvider; + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { SimpleEntity.class, ChildEntity.class }; + } + + @Override + protected Map getConfig() { + Map config = super.getConfig(); + config.put( AvailableSettings.ENABLE_LAZY_LOAD_NO_TRANS, "true" ); + + config.put( AvailableSettings.CONNECTION_HANDLING, PhysicalConnectionHandlingMode.DELAYED_ACQUISITION_AND_RELEASE_AFTER_STATEMENT ); + + config.put( AvailableSettings.AUTOCOMMIT, "false" ); + + connectionProvider = new ConnectionProviderDecorator( getDataSource() ); + config.put( AvailableSettings.CONNECTION_PROVIDER, connectionProvider ); + return config; + } + + @Before + public void setUp() { + doInJPA( this::entityManagerFactory, entityManager -> { + final SimpleEntity entity = new SimpleEntity(); + entity.setId( 1L ); + entity.setName( "TheParent" ); + + final ChildEntity c1 = new ChildEntity(); + c1.setId( 1L ); + c1.setParent( entity ); + c1.setName( "child1" ); + + final ChildEntity c2 = new ChildEntity(); + c2.setId( 2L ); + c2.setParent( entity ); + c2.setName( "child2" ); + + entityManager.persist( entity ); + entityManager.persist( c1 ); + entityManager.persist( c2 ); + } ); + } + + /** + * Tests connections get closed after transaction commit. + */ + @Test + public void testConnectionCloseAfterTx() { + connectionProvider.clear(); + EntityManager entityManager = getOrCreateEntityManager(); + + try { + entityManager.getTransaction().begin(); + try { + + final Query qry = entityManager.createQuery( "FROM SimpleEntity" ); + final List entities = qry.getResultList(); + final SimpleEntity entity = entities.get( 0 ); + assertEquals( 1, connectionProvider.getCurrentOpenConnections() ); + } + catch (Exception e) { + if ( entityManager.getTransaction().isActive() ) { + entityManager.getTransaction().rollback(); + } + throw e; + } + finally { + if ( entityManager.getTransaction().isActive() ) { + entityManager.getTransaction().commit(); + } + } + assertTrue( connectionProvider.areAllConnectionClosed() ); + } + finally { + entityManager.close(); + } + + } + + /** + * Tests connections get closed after lazy collection initialization. + */ + @Test + public void testConnectionCloseAfterLazyCollectionInit() { + connectionProvider.clear(); + EntityManager entityManager = getOrCreateEntityManager(); + + try { + final Query qry = entityManager.createQuery( "FROM SimpleEntity" ); + final List entities = qry.getResultList(); + final SimpleEntity entity = entities.get( 0 ); + + // assert no connection is open + assertTrue( connectionProvider.areAllConnectionClosed() ); + + final int oldOpenedConnections = connectionProvider.getTotalOpenedConnectionCount(); + final Set lazyChildren = entity.getChildren(); + + // this will initialize the collection and such trigger a query + lazyChildren.stream().findAny(); + + // assert a connection had been opened + Assert.assertTrue( oldOpenedConnections < connectionProvider.getTotalOpenedConnectionCount() ); + + // assert there's no remaining connection left. + assertTrue( connectionProvider.areAllConnectionClosed() ); + + } + finally { + entityManager.close(); + } + } + + /** + * Tests connections get closed after transaction commit. + */ + @Test + public void testConnectionCloseAfterLazyPojoPropertyInit() { + connectionProvider.clear(); + EntityManager entityManager = getOrCreateEntityManager(); + + try { + final Query qry = entityManager.createQuery( "FROM ChildEntity" ); + final List entities = qry.getResultList(); + final ChildEntity entity = entities.get( 0 ); + + // assert no connection is open + assertTrue( connectionProvider.areAllConnectionClosed() ); + + final int oldOpenedConnections = connectionProvider.getTotalOpenedConnectionCount(); + + final SimpleEntity parent = entity.getParent(); + // this will initialize the collection and such trigger a query + parent.getName(); + // assert a connection had been opened + Assert.assertTrue( oldOpenedConnections < connectionProvider.getTotalOpenedConnectionCount() ); + + + // assert there's no remaining connection left. + assertTrue( connectionProvider.areAllConnectionClosed() ); + } + finally { + entityManager.close(); + } + } + + /** + * Tests connections get closed after transaction commit. + */ + @Test + public void testConnectionCloseAfterQueryWithoutTx() { + connectionProvider.clear(); + EntityManager entityManager = getOrCreateEntityManager(); + + try { + + final int oldOpenedConnections = connectionProvider.getTotalOpenedConnectionCount(); + final List childrenByQuery = entityManager.createQuery( "FROM ChildEntity" ).getResultList(); + assertTrue( childrenByQuery.size() > 0 ); + + // assert a connection had been opened + assertTrue( oldOpenedConnections < connectionProvider.getTotalOpenedConnectionCount() ); + // assert there's no remaining connection left. + assertTrue( connectionProvider.areAllConnectionClosed() ); + } + finally { + entityManager.close(); + } + } + + @Entity(name = "SimpleEntity") + public static class SimpleEntity { + private Long id; + + private String name; + + Set children = new HashSet<>(); + + @Id + public Long getId() { + return id; + } + + public void setId(final Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(final String name) { + this.name = name; + } + + @OneToMany(targetEntity = ChildEntity.class, mappedBy = "parent") + @LazyCollection(LazyCollectionOption.EXTRA) + @Fetch(FetchMode.SELECT) + public Set getChildren() { + return children; + } + + public void setChildren(final Set children) { + this.children = children; + } + } + + @Entity(name = "ChildEntity") + public static class ChildEntity { + private Long id; + + private String name; + + private SimpleEntity parent; + + @Id + public Long getId() { + return id; + } + + public void setId(final Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(final String name) { + this.name = name; + } + + @ManyToOne(fetch = FetchType.LAZY) + @JoinColumn + @LazyToOne(LazyToOneOption.PROXY) + public SimpleEntity getParent() { + return parent; + } + + public void setParent(final SimpleEntity parent) { + this.parent = parent; + } + } + + private BaseDataSource getDataSource() { + final Properties connectionProps = new Properties(); + connectionProps.put( "user", Environment.getProperties().getProperty( Environment.USER ) ); + connectionProps.put( "password", Environment.getProperties().getProperty( Environment.PASS ) ); + + final String url = Environment.getProperties().getProperty( Environment.URL ); + return new BaseDataSource() { + @Override + public Connection getConnection() throws SQLException { + return DriverManager.getConnection( url, connectionProps ); + } + + @Override + public Connection getConnection(String username, String password) throws SQLException { + return DriverManager.getConnection( url, connectionProps ); + } + }; + } + + public static class ConnectionProviderDecorator extends UserSuppliedConnectionProviderImpl { + + private final DataSource dataSource; + + private int connectionCount; + private int openConnections; + + private Connection connection; + + public ConnectionProviderDecorator(DataSource dataSource) { + this.dataSource = dataSource; + } + + @Override + public Connection getConnection() throws SQLException { + connectionCount++; + openConnections++; + connection = spy( dataSource.getConnection() ); + return connection; + } + + @Override + public void closeConnection(Connection connection) throws SQLException { + connection.close(); + openConnections--; + } + + public int getTotalOpenedConnectionCount() { + return this.connectionCount; + } + + public int getCurrentOpenConnections() { + return openConnections; + } + + public boolean areAllConnectionClosed() { + return openConnections == 0; + } + + public void clear() { + connectionCount = 0; + openConnections = 0; + } + } + +} From 3ea0484122aaef172a4728a1179a1c2192204117 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Thu, 5 Jul 2018 11:07:38 +0100 Subject: [PATCH 225/644] HHH-4808 SessionImpl.initializeCollection() does not release JDBC connection (if outside of a transaction) --- .../AbstractPersistentCollection.java | 12 ++++-- .../org/hibernate/internal/SessionImpl.java | 2 +- .../proxy/AbstractLazyInitializer.java | 37 +++++++++++-------- 3 files changed, 32 insertions(+), 19 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/collection/internal/AbstractPersistentCollection.java b/hibernate-core/src/main/java/org/hibernate/collection/internal/AbstractPersistentCollection.java index eee4af75d1fb..d8587afa48fb 100644 --- a/hibernate-core/src/main/java/org/hibernate/collection/internal/AbstractPersistentCollection.java +++ b/hibernate-core/src/main/java/org/hibernate/collection/internal/AbstractPersistentCollection.java @@ -251,7 +251,7 @@ else if ( !session.isConnected() ) { // be created even if a current session and transaction are // open (ex: session.clear() was used). We must prevent // multiple transactions. - ( (Session) session ).beginTransaction(); + session.beginTransaction(); } session.getPersistenceContextInternal().addUninitializedDetachedCollection( @@ -265,20 +265,26 @@ else if ( !session.isConnected() ) { } finally { if ( tempSession != null ) { + // make sure the just opened temp session gets closed! isTempSession = false; session = originalSession; try { if ( !isJTA ) { - ( (Session) tempSession ).getTransaction().commit(); + tempSession.getTransaction().commit(); } - ( (Session) tempSession ).close(); + tempSession.close(); } catch (Exception e) { LOG.warn( "Unable to close temporary session used to load lazy collection associated to no session" ); } } + else { + if ( !session.isTransactionInProgress() ) { + session.getJdbcCoordinator().afterTransaction(); + } + } } } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java index e54aabe09251..6dbb43f3e6c3 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java @@ -3380,7 +3380,7 @@ public T find(Class entityClass, Object primaryKey, LockModeType lockMode if ( getLoadQueryInfluencers().getEffectiveEntityGraph().getSemantic() == GraphSemantic.FETCH ) { setEnforcingFetchGraph( true ); } - + return loadAccess.load( (Serializable) primaryKey ); } catch ( EntityNotFoundException ignored ) { diff --git a/hibernate-core/src/main/java/org/hibernate/proxy/AbstractLazyInitializer.java b/hibernate-core/src/main/java/org/hibernate/proxy/AbstractLazyInitializer.java index 2e7de16b14df..9d481a2d71f9 100644 --- a/hibernate-core/src/main/java/org/hibernate/proxy/AbstractLazyInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/proxy/AbstractLazyInitializer.java @@ -163,22 +163,29 @@ public final void unsetSession() { @Override public final void initialize() throws HibernateException { if ( !initialized ) { - if ( allowLoadOutsideTransaction ) { - permissiveInitialization(); - } - else if ( session == null ) { - throw new LazyInitializationException( "could not initialize proxy [" + entityName + "#" + id + "] - no Session" ); - } - else if ( !session.isOpenOrWaitingForAutoClose() ) { - throw new LazyInitializationException( "could not initialize proxy [" + entityName + "#" + id + "] - the owning Session was closed" ); - } - else if ( !session.isConnected() ) { - throw new LazyInitializationException( "could not initialize proxy [" + entityName + "#" + id + "] - the owning Session is disconnected" ); + try { + if ( allowLoadOutsideTransaction ) { + permissiveInitialization(); + } + else if ( session == null ) { + throw new LazyInitializationException( "could not initialize proxy [" + entityName + "#" + id + "] - no Session" ); + } + else if ( !session.isOpenOrWaitingForAutoClose() ) { + throw new LazyInitializationException( "could not initialize proxy [" + entityName + "#" + id + "] - the owning Session was closed" ); + } + else if ( !session.isConnected() ) { + throw new LazyInitializationException( "could not initialize proxy [" + entityName + "#" + id + "] - the owning Session is disconnected" ); + } + else { + target = session.immediateLoad( entityName, id ); + initialized = true; + checkTargetState( session ); + } } - else { - target = session.immediateLoad( entityName, id ); - initialized = true; - checkTargetState(session); + finally { + if ( session != null && !session.isTransactionInProgress() ) { + session.getJdbcCoordinator().afterTransaction(); + } } } else { From e91901946a9388368e962a0418b797271a8ba436 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Mon, 21 Jun 2021 11:37:19 +0100 Subject: [PATCH 226/644] HHH-14690 Avoid fully resetting StatisticsImpl just after its constructor --- .../java/org/hibernate/stat/internal/StatisticsImpl.java | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/hibernate-core/src/main/java/org/hibernate/stat/internal/StatisticsImpl.java b/hibernate-core/src/main/java/org/hibernate/stat/internal/StatisticsImpl.java index 70a1fe847a61..8663465fcee3 100644 --- a/hibernate-core/src/main/java/org/hibernate/stat/internal/StatisticsImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/stat/internal/StatisticsImpl.java @@ -122,7 +122,7 @@ public StatisticsImpl(SessionFactoryImplementor sessionFactory) { Statistics.DEFAULT_QUERY_STATISTICS_MAX_SIZE, 20 ); - clear(); + resetStartTime(); metamodel = sessionFactory.getMetamodel(); cache = sessionFactory.getCache(); cacheRegionPrefix = sessionFactoryOptions.getCacheRegionPrefix(); @@ -192,6 +192,10 @@ public void clear() { queryPlanCacheHitCount.reset(); queryPlanCacheMissCount.reset(); + resetStartTime(); + } + + private void resetStartTime() { startTime = System.currentTimeMillis(); } From 916849a8af149b8239c423182b756dcf8ea74cec Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Tue, 22 Jun 2021 11:16:22 +0100 Subject: [PATCH 227/644] HHH-14691 Small optimisation for updating Query Cache Statistics --- .../stat/internal/StatisticsImpl.java | 23 ++++---- .../stat/internal/StatsNamedContainer.java | 27 ++++++---- ...tsNamedContainerNullComputedValueTest.java | 53 ++++++++++++++++++- 3 files changed, 79 insertions(+), 24 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/stat/internal/StatisticsImpl.java b/hibernate-core/src/main/java/org/hibernate/stat/internal/StatisticsImpl.java index 8663465fcee3..e02f7ecde9f2 100644 --- a/hibernate-core/src/main/java/org/hibernate/stat/internal/StatisticsImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/stat/internal/StatisticsImpl.java @@ -563,24 +563,21 @@ public CacheRegionStatisticsImpl getDomainDataRegionStatistics(String regionName } @Override - public CacheRegionStatisticsImpl getQueryRegionStatistics(String regionName) { - final CacheRegionStatisticsImpl existing = l2CacheStatsMap.get( regionName ); - if ( existing != null ) { - return existing; - } + public CacheRegionStatisticsImpl getQueryRegionStatistics(final String regionName) { + return l2CacheStatsMap.getOrCompute( regionName, this::computeQueryRegionStatistics ); + } - final QueryResultsCache regionAccess = cache - .getQueryResultsCacheStrictly( regionName ); + private CacheRegionStatisticsImpl computeQueryRegionStatistics(final String regionName) { + final QueryResultsCache regionAccess = cache.getQueryResultsCacheStrictly( regionName ); if ( regionAccess == null ) { - return null; + return null; //this null value will be cached + } + else { + return new CacheRegionStatisticsImpl( regionAccess.getRegion() ); } - - return l2CacheStatsMap.getOrCompute( - regionName, - s -> new CacheRegionStatisticsImpl( regionAccess.getRegion() ) - ); } + @Override public CacheRegionStatisticsImpl getCacheRegionStatistics(String regionName) { if ( ! secondLevelCacheEnabled ) { diff --git a/hibernate-core/src/main/java/org/hibernate/stat/internal/StatsNamedContainer.java b/hibernate-core/src/main/java/org/hibernate/stat/internal/StatsNamedContainer.java index dcf195a0561f..8e85c4aecb84 100644 --- a/hibernate-core/src/main/java/org/hibernate/stat/internal/StatsNamedContainer.java +++ b/hibernate-core/src/main/java/org/hibernate/stat/internal/StatsNamedContainer.java @@ -25,7 +25,8 @@ */ final class StatsNamedContainer { - private final ConcurrentMap map; + private final ConcurrentMap map; + private final static Object NULL_TOKEN = new Object(); /** * Creates a bounded container - based on BoundedConcurrentHashMap @@ -63,33 +64,39 @@ public String[] keysAsArray() { * sure the function is invoked at most once: we don't need this guarantee, and prefer to reduce risk of blocking. */ public V getOrCompute(final String key, final Function function) { - final V v1 = map.get( key ); + final Object v1 = map.get( key ); if ( v1 != null ) { - return v1; + if ( v1 == NULL_TOKEN ) { + return null; + } + return (V) v1; } else { final V v2 = function.apply( key ); - //Occasionally a function might return null. We can't store a null in the CHM, - // so a placeholder would be required to implement that, but we prefer to just keep this - // situation as slightly sub-optimal so to not make the code more complex just to handle the exceptional case: - // null values are assumed to be rare enough for this not being worth it. if ( v2 == null ) { + map.put( key, NULL_TOKEN ); return null; } else { - final V v3 = map.putIfAbsent( key, v2 ); + final Object v3 = map.putIfAbsent( key, v2 ); if ( v3 == null ) { return v2; } else { - return v3; + return (V) v3; } } } } public V get(final String key) { - return map.get( key ); + final Object o = map.get( key ); + if ( o == NULL_TOKEN) { + return null; + } + else { + return (V) o; + } } } diff --git a/hibernate-core/src/test/java/org/hibernate/stat/internal/StatsNamedContainerNullComputedValueTest.java b/hibernate-core/src/test/java/org/hibernate/stat/internal/StatsNamedContainerNullComputedValueTest.java index afd5b1088d07..307ba75034bb 100644 --- a/hibernate-core/src/test/java/org/hibernate/stat/internal/StatsNamedContainerNullComputedValueTest.java +++ b/hibernate-core/src/test/java/org/hibernate/stat/internal/StatsNamedContainerNullComputedValueTest.java @@ -6,14 +6,21 @@ */ package org.hibernate.stat.internal; +import java.util.concurrent.atomic.AtomicInteger; + import org.hibernate.testing.TestForIssue; +import org.junit.Assert; import org.junit.Test; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertNull; @TestForIssue(jiraKey = "HHH-13645") public class StatsNamedContainerNullComputedValueTest { + private final static AtomicInteger invocationCounterNullProducer = new AtomicInteger(); + private final static AtomicInteger invocationCounterValueProducer = new AtomicInteger(); + @Test public void testNullComputedValue() { final StatsNamedContainer statsNamedContainer = new StatsNamedContainer(); @@ -27,4 +34,48 @@ public void testNullComputedValue() { ); } -} \ No newline at end of file + @Test + public void abletoStoreNullValues() { + final StatsNamedContainer statsNamedContainer = new StatsNamedContainer(); + Assert.assertEquals( 0, invocationCounterNullProducer.get() ); + assertNull( getCacheWithNullValue( statsNamedContainer ) ); + Assert.assertEquals( 1, invocationCounterNullProducer.get() ); + assertNull( getCacheWithNullValue( statsNamedContainer ) ); + Assert.assertEquals( 1, invocationCounterNullProducer.get() ); + } + + @Test + public void abletoStoreActualValues() { + final StatsNamedContainer statsNamedContainer = new StatsNamedContainer(); + Assert.assertEquals( 0, invocationCounterValueProducer.get() ); + Assert.assertEquals( 5, getCacheWithActualValue( statsNamedContainer ) ); + Assert.assertEquals( 1, invocationCounterValueProducer.get() ); + Assert.assertEquals( 5, getCacheWithActualValue( statsNamedContainer ) ); + Assert.assertEquals( 1, invocationCounterValueProducer.get() ); + } + + private Object getCacheWithActualValue(StatsNamedContainer statsNamedContainer) { + return statsNamedContainer.getOrCompute( + "key", + StatsNamedContainerNullComputedValueTest::produceValue + ); + } + + private Object getCacheWithNullValue(StatsNamedContainer statsNamedContainer) { + return statsNamedContainer.getOrCompute( + "key", + StatsNamedContainerNullComputedValueTest::produceNull + ); + } + + private static Integer produceValue(Object o) { + invocationCounterValueProducer.getAndIncrement(); + return Integer.valueOf( 5 ); + } + + private static Integer produceNull(Object v) { + invocationCounterNullProducer.getAndIncrement(); + return null; + } + +} From dfdc439f662d656117bc0018ec0d2627f62935bc Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Tue, 17 Dec 2019 13:49:40 +0000 Subject: [PATCH 228/644] HHH-13788 Add test for issue --- ...faultsSettingToFalseAndQuotedNameTest.java | 147 ++++++++++++++++++ ...dbcMetadataDefaultsSettingToFalseTest.java | 141 +++++++++++++++++ 2 files changed, 288 insertions(+) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaUpdateWithUseJdbcMetadataDefaultsSettingToFalseAndQuotedNameTest.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaUpdateWithUseJdbcMetadataDefaultsSettingToFalseTest.java diff --git a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaUpdateWithUseJdbcMetadataDefaultsSettingToFalseAndQuotedNameTest.java b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaUpdateWithUseJdbcMetadataDefaultsSettingToFalseAndQuotedNameTest.java new file mode 100644 index 000000000000..a41cf2003609 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaUpdateWithUseJdbcMetadataDefaultsSettingToFalseAndQuotedNameTest.java @@ -0,0 +1,147 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.test.schemaupdate; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.EnumSet; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; + +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistry; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.boot.spi.MetadataImplementor; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.dialect.Dialect; +import org.hibernate.tool.hbm2ddl.SchemaExport; +import org.hibernate.tool.hbm2ddl.SchemaUpdate; +import org.hibernate.tool.hbm2ddl.SchemaValidator; +import org.hibernate.tool.schema.JdbcMetadaAccessStrategy; +import org.hibernate.tool.schema.TargetType; + +import org.hibernate.testing.TestForIssue; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertThat; + +@TestForIssue(jiraKey = "HHH-13788") +@RunWith(Parameterized.class) +public class SchemaUpdateWithUseJdbcMetadataDefaultsSettingToFalseAndQuotedNameTest { + @Parameterized.Parameters + public static String[] parameters() { + return new String[] { + JdbcMetadaAccessStrategy.GROUPED.toString(), + JdbcMetadaAccessStrategy.INDIVIDUALLY.toString() + }; + } + + @Parameterized.Parameter + public String jdbcMetadataExtractorStrategy; + + private File updateOutputFile; + private File createOutputFile; + private StandardServiceRegistry ssr; + private MetadataImplementor metadata; + + @Before + public void setUp() throws IOException { + createOutputFile = File.createTempFile( "create_script", ".sql" ); + createOutputFile.deleteOnExit(); + updateOutputFile = File.createTempFile( "update_script", ".sql" ); + updateOutputFile.deleteOnExit(); + ssr = new StandardServiceRegistryBuilder() + .applySetting( "hibernate.temp.use_jdbc_metadata_defaults", "false" ) + .applySetting( AvailableSettings.SHOW_SQL, "true" ) + .applySetting( + AvailableSettings.HBM2DDL_JDBC_METADATA_EXTRACTOR_STRATEGY, + jdbcMetadataExtractorStrategy + ) + .build(); + + final MetadataSources metadataSources = new MetadataSources( ssr ); + metadataSources.addAnnotatedClass( AnotherTestEntity.class ); + + metadata = (MetadataImplementor) metadataSources.buildMetadata(); + metadata.validate(); + } + + @After + public void tearDown() { + new SchemaExport().setHaltOnError( true ) + .setFormat( false ) + .drop( EnumSet.of( TargetType.DATABASE ), metadata ); + StandardServiceRegistryBuilder.destroy( ssr ); + } + + @Test + public void testSchemaUpdateDoesNotTryToRecreateExistingTables() + throws Exception { + createSchema(); + + new SchemaUpdate().setHaltOnError( true ) + .setOutputFile( updateOutputFile.getAbsolutePath() ) + .setFormat( false ) + .execute( EnumSet.of( TargetType.DATABASE, TargetType.SCRIPT ), metadata ); + + checkNoUpdateStatementHasBeenGenerated(); + } + + private void checkNoUpdateStatementHasBeenGenerated() throws IOException { + final String fileContent = new String( Files.readAllBytes( updateOutputFile.toPath() ) ); + assertThat( + "The update output file should be empty because the db schema had already been generated and the domain model was not modified", + fileContent, + is( "" ) + ); + } + + private void createSchema() throws Exception { + new SchemaUpdate().setHaltOnError( true ) + .setOutputFile( createOutputFile.getAbsolutePath() ) + .execute( EnumSet.of( TargetType.DATABASE, TargetType.SCRIPT ), metadata ); + new SchemaValidator().validate( metadata ); + checkSchemaHasBeenGenerated(); + } + + private void checkSchemaHasBeenGenerated() throws Exception { + String fileContent = new String( Files.readAllBytes( createOutputFile.toPath() ) ); + final Dialect dialect = metadata.getDatabase().getDialect(); + Pattern fileContentPattern; + if ( dialect.openQuote() == '[' ) { + fileContentPattern = Pattern.compile( "create( (column|row))? table " + "\\[" + "another_test_entity" + "\\]" ); + } + else { + fileContentPattern = Pattern.compile( "create( (column|row))? table " + dialect.openQuote() + "another_test_entity" + dialect + .closeQuote() ); + } + Matcher fileContentMatcher = fileContentPattern.matcher( fileContent.toLowerCase() ); + assertThat( + "The schema has not been correctly generated, Script file : " + fileContent.toLowerCase(), + fileContentMatcher.find(), + is( true ) + ); + } + + @Entity(name = "`Another_Test_Entity`") + public static class AnotherTestEntity { + @Id + private Long id; + + @Column(name = "`another_NAME`") + private String name; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaUpdateWithUseJdbcMetadataDefaultsSettingToFalseTest.java b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaUpdateWithUseJdbcMetadataDefaultsSettingToFalseTest.java new file mode 100644 index 000000000000..3d3eedf77710 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaUpdateWithUseJdbcMetadataDefaultsSettingToFalseTest.java @@ -0,0 +1,141 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.test.schemaupdate; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.util.EnumSet; +import java.util.regex.Matcher; +import java.util.regex.Pattern; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; + +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistry; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.boot.spi.MetadataImplementor; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.tool.hbm2ddl.SchemaExport; +import org.hibernate.tool.hbm2ddl.SchemaUpdate; +import org.hibernate.tool.hbm2ddl.SchemaValidator; +import org.hibernate.tool.schema.JdbcMetadaAccessStrategy; +import org.hibernate.tool.schema.TargetType; + +import org.hibernate.testing.TestForIssue; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertThat; + +/** + * @author Andrea Boriero + */ +@TestForIssue(jiraKey = "HHH-13788") +@RunWith(Parameterized.class) +public class SchemaUpdateWithUseJdbcMetadataDefaultsSettingToFalseTest { + + @Parameterized.Parameters + public static String[] parameters() { + return new String[] { + JdbcMetadaAccessStrategy.GROUPED.toString(), + JdbcMetadaAccessStrategy.INDIVIDUALLY.toString() + }; + } + + @Parameterized.Parameter + public String jdbcMetadataExtractorStrategy; + + private File updateOutputFile; + private File createOutputFile; + private StandardServiceRegistry ssr; + private MetadataImplementor metadata; + + @Before + public void setUp() throws IOException { + createOutputFile = File.createTempFile( "create_script", ".sql" ); + createOutputFile.deleteOnExit(); + updateOutputFile = File.createTempFile( "update_script", ".sql" ); + updateOutputFile.deleteOnExit(); + ssr = new StandardServiceRegistryBuilder() + .applySetting( "hibernate.temp.use_jdbc_metadata_defaults", "false" ) + .applySetting( AvailableSettings.SHOW_SQL, "true" ) + .applySetting( + AvailableSettings.HBM2DDL_JDBC_METADATA_EXTRACTOR_STRATEGY, + jdbcMetadataExtractorStrategy + ) + .build(); + + final MetadataSources metadataSources = new MetadataSources( ssr ); + metadataSources.addAnnotatedClass( TestEntity.class ); + + metadata = (MetadataImplementor) metadataSources.buildMetadata(); + metadata.validate(); + } + + @After + public void tearDown() { + new SchemaExport().setHaltOnError( true ) + .setFormat( false ) + .drop( EnumSet.of( TargetType.DATABASE ), metadata ); + StandardServiceRegistryBuilder.destroy( ssr ); + } + + @Test + public void testSchemaUpdateDoesNotTryToRecreateExistingTables() + throws Exception { + createSchema(); + + new SchemaUpdate().setHaltOnError( true ) + .setOutputFile( updateOutputFile.getAbsolutePath() ) + .setFormat( false ) + .execute( EnumSet.of( TargetType.DATABASE, TargetType.SCRIPT ), metadata ); + + checkNoUpdateStatementHasBeenGenerated(); + } + + private void checkNoUpdateStatementHasBeenGenerated() throws IOException { + final String fileContent = new String( Files.readAllBytes( updateOutputFile.toPath() ) ); + assertThat( + "The update output file should be empty because the db schema had already been generated and the domain model was not modified", + fileContent, + is( "" ) + ); + } + + private void createSchema() throws Exception { + new SchemaUpdate().setHaltOnError( true ) + .setOutputFile( createOutputFile.getAbsolutePath() ) + .execute( EnumSet.of( TargetType.DATABASE, TargetType.SCRIPT ), metadata ); + new SchemaValidator().validate( metadata ); + checkSchemaHasBeenGenerated(); + } + + private void checkSchemaHasBeenGenerated() throws Exception { + String fileContent = new String( Files.readAllBytes( createOutputFile.toPath() ) ); + Pattern fileContentPattern = Pattern.compile( "create( (column|row))? table my_test_entity" ); + Matcher fileContentMatcher = fileContentPattern.matcher( fileContent.toLowerCase() ); + assertThat( + "The schema has not been correctly generated, Script file : " + fileContent.toLowerCase(), + fileContentMatcher.find(), + is( true ) + ); + } + + @Entity(name = "My_Test_Entity") + public static class TestEntity { + @Id + private Long id; + + private String name; + } +} From b17e17cdb63cfec3bb8360b80fccec9b4bbba579 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Tue, 17 Dec 2019 13:51:02 +0000 Subject: [PATCH 229/644] HHH-13788 Schema update try to recreate existing tables --- ...tionExtractorJdbcDatabaseMetaDataImpl.java | 154 +++++++++++++++--- 1 file changed, 128 insertions(+), 26 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/InformationExtractorJdbcDatabaseMetaDataImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/InformationExtractorJdbcDatabaseMetaDataImpl.java index 8ff9abb13b6b..4a67ba2d3ca2 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/InformationExtractorJdbcDatabaseMetaDataImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/InformationExtractorJdbcDatabaseMetaDataImpl.java @@ -29,6 +29,8 @@ import org.hibernate.engine.config.spi.ConfigurationService; import org.hibernate.engine.config.spi.StandardConverters; import org.hibernate.engine.jdbc.env.spi.IdentifierHelper; +import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; +import org.hibernate.engine.jdbc.env.spi.NameQualifierSupport; import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.StringHelper; @@ -59,12 +61,26 @@ public class InformationExtractorJdbcDatabaseMetaDataImpl implements Information private final ExtractionContext extractionContext; + private final boolean useJdbcMetadataDefaultsSetting; + + private Identifier currentCatalog; + private Identifier currentSchema; + + private String currentCatalogFilter; + private String currentSchemaFilter; + public InformationExtractorJdbcDatabaseMetaDataImpl(ExtractionContext extractionContext) { this.extractionContext = extractionContext; ConfigurationService configService = extractionContext.getServiceRegistry() .getService( ConfigurationService.class ); + useJdbcMetadataDefaultsSetting = configService.getSetting( + "hibernate.temp.use_jdbc_metadata_defaults", + StandardConverters.BOOLEAN, + Boolean.TRUE + ); + final String extraPhysycalTableTypesConfig = configService.getSetting( AvailableSettings.EXTRA_PHYSICAL_TABLE_TYPES, StandardConverters.STRING, @@ -229,11 +245,14 @@ public TableInformation getTable(Identifier catalog, Identifier schema, Identifi TableInformation tableInfo = null; // 1) look in current namespace - if ( extractionContext.getJdbcEnvironment().getCurrentCatalog() != null - || extractionContext.getJdbcEnvironment().getCurrentSchema() != null ) { + final JdbcEnvironment jdbcEnvironment = extractionContext.getJdbcEnvironment(); + final Identifier currentSchema = getCurrentSchema( jdbcEnvironment ); + final Identifier currentCatalog = getCurrentCatalog( jdbcEnvironment ); + if ( currentCatalog != null + || currentSchema != null ) { tableInfo = locateTableInNamespace( - extractionContext.getJdbcEnvironment().getCurrentCatalog(), - extractionContext.getJdbcEnvironment().getCurrentSchema(), + currentCatalog, + currentSchema, tableName ); @@ -288,23 +307,106 @@ public TableInformation getTable(Identifier catalog, Identifier schema, Identifi } } + private Identifier getCurrentSchema(JdbcEnvironment jdbcEnvironment) { + if ( currentSchema != null ) { + return currentSchema; + } + final Identifier schema = jdbcEnvironment.getCurrentSchema(); + if ( schema != null ) { + currentSchema = schema; + } + if ( !useJdbcMetadataDefaultsSetting ) { + try { + currentSchema = extractionContext.getJdbcEnvironment() + .getIdentifierHelper() + .toIdentifier( extractionContext.getJdbcConnection().getSchema() ); + } + catch (SQLException ignore) { + log.sqlWarning( ignore.getErrorCode(), ignore.getSQLState() ); + } + } + return currentCatalog; + } + + private Identifier getCurrentCatalog(JdbcEnvironment jdbcEnvironment) { + if ( currentCatalog != null ) { + return currentCatalog; + } + final Identifier catalog = jdbcEnvironment.getCurrentCatalog(); + if ( catalog != null ) { + currentCatalog = catalog; + } + if ( !useJdbcMetadataDefaultsSetting ) { + try { + currentCatalog = extractionContext.getJdbcEnvironment() + .getIdentifierHelper() + .toIdentifier( extractionContext.getJdbcConnection().getCatalog() ); + } + catch (SQLException ignore) { + log.sqlWarning( ignore.getErrorCode(), ignore.getSQLState() ); + } + } + return currentCatalog; + } + + private String getCurrentCatalogFilter(JdbcEnvironment jdbcEnvironment) { + if ( currentCatalogFilter != null ) { + return currentCatalogFilter; + } + final Identifier currentCatalog = jdbcEnvironment.getCurrentCatalog(); + if ( currentCatalog != null ) { + currentCatalogFilter = toMetaDataObjectName( currentCatalog ); + } + if ( !useJdbcMetadataDefaultsSetting ) { + try { + currentCatalogFilter = extractionContext.getJdbcConnection().getCatalog(); + } + catch (SQLException ignore) { + log.sqlWarning( ignore.getErrorCode(), ignore.getSQLState() ); + } + } + return currentCatalogFilter; + } + + private String getCurrentSchemaFilter(JdbcEnvironment jdbcEnvironment) { + if ( currentSchemaFilter != null ) { + return currentSchemaFilter; + } + final Identifier currentSchema = jdbcEnvironment.getCurrentSchema(); + if ( currentSchema != null ) { + currentSchemaFilter = toMetaDataObjectName( currentSchema ); + } + + if ( !useJdbcMetadataDefaultsSetting ) { + try { + currentSchemaFilter = extractionContext.getJdbcConnection().getSchema(); + } + catch (SQLException ignore) { + log.sqlWarning( ignore.getErrorCode(), ignore.getSQLState() ); + } + } + return currentSchemaFilter; + } + public NameSpaceTablesInformation getTables(Identifier catalog, Identifier schema) { String catalogFilter = null; String schemaFilter = null; - if ( extractionContext.getJdbcEnvironment().getNameQualifierSupport().supportsCatalogs() ) { + final JdbcEnvironment jdbcEnvironment = extractionContext.getJdbcEnvironment(); + final NameQualifierSupport nameQualifierSupport = jdbcEnvironment.getNameQualifierSupport(); + if ( nameQualifierSupport.supportsCatalogs() ) { if ( catalog == null ) { - if ( extractionContext.getJdbcEnvironment().getCurrentCatalog() != null ) { - // 1) look in current namespace - catalogFilter = toMetaDataObjectName( extractionContext.getJdbcEnvironment().getCurrentCatalog() ); - } - else if ( extractionContext.getDefaultCatalog() != null ) { - // 2) look in default namespace - catalogFilter = toMetaDataObjectName( extractionContext.getDefaultCatalog() ); - } - else { - catalogFilter = ""; + // look in the current namespace + catalogFilter = getCurrentCatalogFilter(jdbcEnvironment); + if ( catalogFilter == null ) { + if ( extractionContext.getDefaultCatalog() != null ) { + // 2) look in default namespace + catalogFilter = toMetaDataObjectName( extractionContext.getDefaultCatalog() ); + } + else { + catalogFilter = ""; + } } } else { @@ -312,18 +414,18 @@ else if ( extractionContext.getDefaultCatalog() != null ) { } } - if ( extractionContext.getJdbcEnvironment().getNameQualifierSupport().supportsSchemas() ) { + if ( nameQualifierSupport.supportsSchemas() ) { if ( schema == null ) { - if ( extractionContext.getJdbcEnvironment().getCurrentSchema() != null ) { - // 1) look in current namespace - schemaFilter = toMetaDataObjectName( extractionContext.getJdbcEnvironment().getCurrentSchema() ); - } - else if ( extractionContext.getDefaultSchema() != null ) { - // 2) look in default namespace - schemaFilter = toMetaDataObjectName( extractionContext.getDefaultSchema() ); - } - else { - schemaFilter = ""; + // 1) look in current namespace + schemaFilter = getCurrentSchemaFilter( jdbcEnvironment ); + if ( schemaFilter == null ) { + if ( extractionContext.getDefaultSchema() != null ) { + // 2) look in default namespace + schemaFilter = toMetaDataObjectName( extractionContext.getDefaultSchema() ); + } + else { + schemaFilter = ""; + } } } else { From f1a5b2cbca159747cca517d61430241915251dbd Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Tue, 22 Jun 2021 16:29:09 +0200 Subject: [PATCH 230/644] HHH-13788 Fix default IdentifierHelper case strategy --- .../org/hibernate/dialect/MariaDBDialect.java | 19 +++++++++++++++++++ .../org/hibernate/dialect/MySQLDialect.java | 16 ++++++++++++++++ .../dialect/PostgreSQL81Dialect.java | 15 +++++++++++++++ .../hibernate/dialect/SQLServerDialect.java | 17 +++++++++++++++++ .../jdbc/env/spi/IdentifierHelperBuilder.java | 2 +- 5 files changed, 68 insertions(+), 1 deletion(-) diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/MariaDBDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/MariaDBDialect.java index db6b85813419..158cadebc5fb 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/MariaDBDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/MariaDBDialect.java @@ -6,6 +6,14 @@ */ package org.hibernate.dialect; +import java.sql.DatabaseMetaData; +import java.sql.SQLException; + +import org.hibernate.engine.jdbc.env.spi.AnsiSqlKeywords; +import org.hibernate.engine.jdbc.env.spi.IdentifierCaseStrategy; +import org.hibernate.engine.jdbc.env.spi.IdentifierHelper; +import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder; + /** * @author Vlad Mihalcea */ @@ -22,4 +30,15 @@ public boolean supportsRowValueConstructorSyntaxInInList() { protected MySQLStorageEngine getDefaultMySQLStorageEngine() { return InnoDBStorageEngine.INSTANCE; } + + @Override + public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData dbMetaData) + throws SQLException { + + // some MariaDB drivers does not return case strategy info + builder.setUnquotedCaseStrategy( IdentifierCaseStrategy.MIXED ); + builder.setQuotedCaseStrategy( IdentifierCaseStrategy.MIXED ); + + return super.buildIdentifierHelper( builder, dbMetaData ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java index 75b7d66f62db..945b44320686 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java @@ -7,6 +7,7 @@ package org.hibernate.dialect; import java.sql.CallableStatement; +import java.sql.DatabaseMetaData; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Types; @@ -27,6 +28,9 @@ import org.hibernate.dialect.pagination.LimitHelper; import org.hibernate.dialect.unique.MySQLUniqueDelegate; import org.hibernate.dialect.unique.UniqueDelegate; +import org.hibernate.engine.jdbc.env.spi.IdentifierCaseStrategy; +import org.hibernate.engine.jdbc.env.spi.IdentifierHelper; +import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder; import org.hibernate.engine.spi.RowSelection; import org.hibernate.exception.LockAcquisitionException; import org.hibernate.exception.LockTimeoutException; @@ -562,6 +566,18 @@ public JDBCException convert(SQLException sqlException, String message, String s }; } + @Override + public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData dbMetaData) + throws SQLException { + + if ( dbMetaData == null ) { + builder.setUnquotedCaseStrategy( IdentifierCaseStrategy.MIXED ); + builder.setQuotedCaseStrategy( IdentifierCaseStrategy.MIXED ); + } + + return super.buildIdentifierHelper( builder, dbMetaData ); + } + @Override public String getNotExpression(String expression) { return "not (" + expression + ")"; diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL81Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL81Dialect.java index 220cfb976a1f..95ea786bf336 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL81Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL81Dialect.java @@ -29,6 +29,9 @@ import org.hibernate.dialect.pagination.AbstractLimitHandler; import org.hibernate.dialect.pagination.LimitHandler; import org.hibernate.dialect.pagination.LimitHelper; +import org.hibernate.engine.jdbc.env.spi.IdentifierCaseStrategy; +import org.hibernate.engine.jdbc.env.spi.IdentifierHelper; +import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder; import org.hibernate.engine.spi.RowSelection; import org.hibernate.exception.LockAcquisitionException; import org.hibernate.exception.spi.SQLExceptionConversionDelegate; @@ -76,6 +79,18 @@ public boolean bindLimitParametersInReverseOrder() { } }; + @Override + public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData dbMetaData) + throws SQLException { + + if ( dbMetaData == null ) { + builder.setUnquotedCaseStrategy( IdentifierCaseStrategy.LOWER ); + builder.setQuotedCaseStrategy( IdentifierCaseStrategy.MIXED ); + } + + return super.buildIdentifierHelper( builder, dbMetaData ); + } + /** * Constructs a PostgreSQL81Dialect */ diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java index 2c9542a003c7..96bf1aa0a0a3 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java @@ -6,6 +6,8 @@ */ package org.hibernate.dialect; +import java.sql.DatabaseMetaData; +import java.sql.SQLException; import java.sql.Types; import java.util.Locale; @@ -19,6 +21,9 @@ import org.hibernate.dialect.pagination.LegacyLimitHandler; import org.hibernate.dialect.pagination.LimitHandler; import org.hibernate.dialect.pagination.TopLimitHandler; +import org.hibernate.engine.jdbc.env.spi.IdentifierCaseStrategy; +import org.hibernate.engine.jdbc.env.spi.IdentifierHelper; +import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder; import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.StringType; import org.hibernate.type.Type; @@ -107,6 +112,18 @@ public boolean useMaxForLimit() { return true; } + @Override + public IdentifierHelper buildIdentifierHelper( + IdentifierHelperBuilder builder, DatabaseMetaData dbMetaData) throws SQLException { + + if ( dbMetaData == null ) { + builder.setUnquotedCaseStrategy( IdentifierCaseStrategy.MIXED ); + builder.setQuotedCaseStrategy( IdentifierCaseStrategy.MIXED ); + } + + return super.buildIdentifierHelper( builder, dbMetaData ); + } + @Override public boolean supportsLimitOffset() { return false; diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/IdentifierHelperBuilder.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/IdentifierHelperBuilder.java index 74de34f77298..97fe15a2c678 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/IdentifierHelperBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/IdentifierHelperBuilder.java @@ -38,7 +38,7 @@ public class IdentifierHelperBuilder { private boolean globallyQuoteIdentifiers = false; private boolean skipGlobalQuotingForColumnDefinitions = false; private boolean autoQuoteKeywords = true; - private IdentifierCaseStrategy unquotedCaseStrategy = IdentifierCaseStrategy.MIXED; + private IdentifierCaseStrategy unquotedCaseStrategy = IdentifierCaseStrategy.UPPER; private IdentifierCaseStrategy quotedCaseStrategy = IdentifierCaseStrategy.MIXED; public static IdentifierHelperBuilder from(JdbcEnvironment jdbcEnvironment) { From ce514fe69ec2c22020f300fac6a463d804eb99a5 Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Tue, 22 Jun 2021 15:38:32 +0000 Subject: [PATCH 231/644] 5.5.3.Final --- changelog.txt | 19 +++++++++++++++++++ gradle/version.properties | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index c1070194e09e..12ad9644f32d 100644 --- a/changelog.txt +++ b/changelog.txt @@ -3,6 +3,25 @@ Hibernate 5 Changelog Note: Please refer to JIRA to learn more about each issue. +Changes in 5.5.3.Final (June 22, 2021) +------------------------------------------------------------------------------------------------------------------------ + +https://hibernate.atlassian.net/projects/HHH/versions/31957 + +** Bug + * [HHH-14654] - geolatte-geom Geometry types no longer works with geography column types + * [HHH-14597] - Regression bug: could not resolve property: null of: + * [HHH-13788] - Schema update try to recreate existing tables + * [HHH-4808] - SessionImpl.initializeCollection() does not release JDBC connection (if outside of a transaction) + +** Improvement + * [HHH-14691] - Small optimisation for updating Query Cache Statistics + * [HHH-14690] - Avoid fully resetting StatisticsImpl just after its constructor + +** New Feature + * [HHH-11817] - Allow schema-export commands written to file to truncate in addition to current appending + + Changes in 5.5.2.Final (June 14, 2021) ------------------------------------------------------------------------------------------------------------------------ diff --git a/gradle/version.properties b/gradle/version.properties index df600108580d..7f621f110512 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -hibernateVersion=5.5.3-SNAPSHOT +hibernateVersion=5.5.3.Final \ No newline at end of file From c3f8e56f28886918c2f41e9eea80f0f311ca9173 Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Tue, 22 Jun 2021 15:43:31 +0000 Subject: [PATCH 232/644] 5.5.4-SNAPSHOT --- gradle/version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/version.properties b/gradle/version.properties index 7f621f110512..73d49076c20d 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -hibernateVersion=5.5.3.Final \ No newline at end of file +hibernateVersion=5.5.4-SNAPSHOT \ No newline at end of file From 2226fda3315fee2a25426539687cdc6821fe1672 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Wed, 30 Jun 2021 18:57:20 +0200 Subject: [PATCH 233/644] Update SQL Server docker image URL as the old one does not work anymore --- docker_db.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker_db.sh b/docker_db.sh index 4f0cd16494df..e88589cada38 100755 --- a/docker_db.sh +++ b/docker_db.sh @@ -99,7 +99,7 @@ EOF mssql() { docker rm -f mssql || true - docker run --name mssql -d -p 1433:1433 -e "SA_PASSWORD=Hibernate_orm_test" -e ACCEPT_EULA=Y microsoft/mssql-server-linux:2017-CU13 + docker run --name mssql -d -p 1433:1433 -e "SA_PASSWORD=Hibernate_orm_test" -e ACCEPT_EULA=Y mcr.microsoft.com/mssql/server:2017-CU13 sleep 5 n=0 until [ "$n" -ge 5 ] From f168b8cff2c7fb41fc2d570ae2867f9e4b21fda0 Mon Sep 17 00:00:00 2001 From: Yanming Zhou Date: Tue, 22 Jun 2021 16:33:43 +0800 Subject: [PATCH 234/644] HHH-14688 Get IdentifierGenerator from BeanContainer if not registered --- .../DefaultIdentifierGeneratorFactory.java | 31 ++++- .../UserDefinedGeneratorsTests.java | 131 ++++++++++++++++++ 2 files changed, 160 insertions(+), 2 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/idgen/userdefined/UserDefinedGeneratorsTests.java diff --git a/hibernate-core/src/main/java/org/hibernate/id/factory/internal/DefaultIdentifierGeneratorFactory.java b/hibernate-core/src/main/java/org/hibernate/id/factory/internal/DefaultIdentifierGeneratorFactory.java index 71c153ae4b12..c2b80042ab9d 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/factory/internal/DefaultIdentifierGeneratorFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/id/factory/internal/DefaultIdentifierGeneratorFactory.java @@ -36,6 +36,9 @@ import org.hibernate.id.factory.spi.MutableIdentifierGeneratorFactory; import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreMessageLogger; +import org.hibernate.resource.beans.container.spi.BeanContainer; +import org.hibernate.resource.beans.internal.FallbackBeanInstanceProducer; +import org.hibernate.resource.beans.spi.ManagedBeanRegistry; import org.hibernate.service.ServiceRegistry; import org.hibernate.service.spi.ServiceRegistryAwareService; import org.hibernate.service.spi.ServiceRegistryImplementor; @@ -46,6 +49,7 @@ * * @author Steve Ebersole */ +@SuppressWarnings( { "deprecation" ,"rawtypes" ,"serial" } ) public class DefaultIdentifierGeneratorFactory implements MutableIdentifierGeneratorFactory, Serializable, ServiceRegistryAwareService { @@ -59,7 +63,6 @@ public class DefaultIdentifierGeneratorFactory /** * Constructs a new DefaultIdentifierGeneratorFactory. */ - @SuppressWarnings("deprecation") public DefaultIdentifierGeneratorFactory() { register( "uuid2", UUIDGenerator.class ); register( "guid", GUIDGenerator.class ); // can be done with UUIDGenerator + strategy @@ -109,11 +112,35 @@ public void setDialect(Dialect dialect) { // } } + @SuppressWarnings("unchecked") @Override public IdentifierGenerator createIdentifierGenerator(String strategy, Type type, Properties config) { try { Class clazz = getIdentifierGeneratorClass( strategy ); - IdentifierGenerator identifierGenerator = ( IdentifierGenerator ) clazz.newInstance(); + BeanContainer beanContainer = serviceRegistry.getService(ManagedBeanRegistry.class).getBeanContainer(); + IdentifierGenerator identifierGenerator; + if ( generatorStrategyToClassNameMap.containsKey(strategy) || beanContainer == null ) { + identifierGenerator = ( IdentifierGenerator ) clazz.newInstance(); + } + else { + identifierGenerator = ( IdentifierGenerator ) beanContainer.getBean( + clazz, + new BeanContainer.LifecycleOptions() { + + @Override + public boolean canUseCachedReferences() { + return false; + } + + @Override + public boolean useJpaCompliantCreation() { + return true; + } + + }, + FallbackBeanInstanceProducer.INSTANCE + ).getBeanInstance(); + } if ( identifierGenerator instanceof Configurable ) { ( ( Configurable ) identifierGenerator ).configure( type, config, serviceRegistry ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/idgen/userdefined/UserDefinedGeneratorsTests.java b/hibernate-core/src/test/java/org/hibernate/test/idgen/userdefined/UserDefinedGeneratorsTests.java new file mode 100644 index 000000000000..e84c5681bf0c --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/idgen/userdefined/UserDefinedGeneratorsTests.java @@ -0,0 +1,131 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.idgen.userdefined; + +import static org.hamcrest.CoreMatchers.instanceOf; +import static org.hamcrest.CoreMatchers.is; +import static org.junit.Assert.assertThat; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.same; +import static org.mockito.BDDMockito.given; +import static org.mockito.BDDMockito.then; +import static org.mockito.Mockito.times; + +import java.io.Serializable; +import java.util.concurrent.atomic.AtomicInteger; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Table; + +import org.hibernate.annotations.GenericGenerator; +import org.hibernate.boot.Metadata; +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistry; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.dialect.H2Dialect; +import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.id.IdentifierGenerator; +import org.hibernate.id.factory.internal.DefaultIdentifierGeneratorFactory; +import org.hibernate.mapping.PersistentClass; +import org.hibernate.resource.beans.container.spi.BeanContainer; +import org.hibernate.resource.beans.container.spi.BeanContainer.LifecycleOptions; +import org.hibernate.resource.beans.container.spi.ContainedBean; +import org.hibernate.resource.beans.internal.FallbackBeanInstanceProducer; +import org.hibernate.service.spi.ServiceRegistryImplementor; +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseUnitTestCase; +import org.junit.Test; +import org.mockito.Mockito; + +/** + * @author Yanming Zhou + */ +@TestForIssue(jiraKey = "HHH-14688") +public class UserDefinedGeneratorsTests extends BaseUnitTestCase { + + @Test + public void testCreateGeneratorsByBeanContainer() { + + final BeanContainer beanContainer = Mockito.mock( BeanContainer.class ); + given(beanContainer.getBean( any(), any(), any() ) ).willAnswer( invocation -> { + LifecycleOptions options = (LifecycleOptions) invocation.getArguments()[1]; + assertThat( options.canUseCachedReferences(), is( false ) ); + assertThat( options.useJpaCompliantCreation(), is( true ) ); + return (ContainedBean) TestIdentifierGenerator::new; + } ); + + final StandardServiceRegistryBuilder ssrb = new StandardServiceRegistryBuilder(); + ssrb.applySetting( AvailableSettings.BEAN_CONTAINER, beanContainer ); + + final StandardServiceRegistry ssr = ssrb.build(); + final Metadata metadata = new MetadataSources( ssr ) + .addAnnotatedClass( Entity1.class ) + .addAnnotatedClass( Entity2.class ) + .buildMetadata(); + + final DefaultIdentifierGeneratorFactory generatorFactory = new DefaultIdentifierGeneratorFactory(); + generatorFactory.injectServices( (ServiceRegistryImplementor) ssr ); + + final PersistentClass entityBinding1 = metadata.getEntityBinding( Entity1.class.getName() ); + final PersistentClass entityBinding2 = metadata.getEntityBinding( Entity2.class.getName() ); + final IdentifierGenerator generator1 = entityBinding1.getRootClass().getIdentifier().createIdentifierGenerator( + generatorFactory, + new H2Dialect(), + "", + "", + entityBinding1.getRootClass() + ); + final IdentifierGenerator generator2 = entityBinding2.getRootClass().getIdentifier().createIdentifierGenerator( + generatorFactory, + new H2Dialect(), + "", + "", + entityBinding2.getRootClass() + ); + + then( beanContainer ).should( times( 2 ) ).getBean( same( TestIdentifierGenerator.class ), any( LifecycleOptions.class ), + same( FallbackBeanInstanceProducer.INSTANCE ) ); + + assertThat( generator1, is( instanceOf( TestIdentifierGenerator.class ) ) ); + assertThat( generator2, is( instanceOf( TestIdentifierGenerator.class ) ) ); + assertThat( generator1 == generator2, is( false ) ); // should not be same instance + + } + + @Entity( name = "Entity1" ) + @Table( name = "tbl_1" ) + public static class Entity1 { + @Id + @GeneratedValue( generator = "test" ) + @GenericGenerator( name = "test", strategy = "org.hibernate.test.idgen.userdefined.UserDefinedGeneratorsTests$TestIdentifierGenerator" ) + private Integer id; + } + + @Entity( name = "Entity2" ) + @Table( name = "tbl_2" ) + public static class Entity2 { + @Id + @GeneratedValue( generator = "test" ) + @GenericGenerator( name = "test", strategy = "org.hibernate.test.idgen.userdefined.UserDefinedGeneratorsTests$TestIdentifierGenerator" ) + private Integer id; + } + + public static class TestIdentifierGenerator implements IdentifierGenerator { + + private AtomicInteger count = new AtomicInteger(); + + @Override + public Serializable generate( SharedSessionContractImplementor session, Object obj ) { + return count.incrementAndGet(); + } + + } + +} From 834f125c07c6c1ed487c1f42b62a2c98b037addc Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Thu, 1 Jul 2021 16:10:05 +0100 Subject: [PATCH 235/644] HHH-14706 Improve error message on incompatible types due to mismatched classloader --- .../AbstractSharedSessionContract.java | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java b/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java index 6b7a9277657a..e147da2c29f0 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java @@ -871,12 +871,7 @@ else if ( queryPlan.getTranslators()[0].getReturnTypes().length == 1 ) { // if we have only a single return expression, its java type should match the requested type final Type queryResultType = queryPlan.getTranslators()[0].getReturnTypes()[0]; if ( !resultClass.isAssignableFrom( queryResultType.getReturnedClass() ) ) { - throw new IllegalArgumentException( - "Type specified for TypedQuery [" + - resultClass.getName() + - "] is incompatible with query return type [" + - queryResultType.getReturnedClass() + "]" - ); + throw buildIncompatibleException( resultClass, queryResultType.getReturnedClass() ); } } else { @@ -1001,10 +996,23 @@ else if ( nativeSQLQueryReturn instanceof NativeSQLQueryConstructorReturn ) { } private IllegalArgumentException buildIncompatibleException(Class resultClass, Class actualResultClass) { - return new IllegalArgumentException( - "Type specified for TypedQuery [" + resultClass.getName() + - "] is incompatible with query return type [" + actualResultClass + "]" - ); + final String resultClassName = resultClass.getName(); + final String actualResultClassName = actualResultClass.getName(); + if ( resultClassName.equals( actualResultClassName ) ) { + return new IllegalArgumentException( + "Type specified for TypedQuery [" + resultClassName + + "] is incompatible with the query return type of the same name." + + " Both classes have the same name but are different as they have been loaded respectively by Classloaders " + + resultClass.getClassLoader().toString() + ", " + actualResultClass.getClassLoader().toString() + + ". This suggests a classloader bug in the Runtime executing Hibernate ORM, or in the integration code." + ); + } + else { + return new IllegalArgumentException( + "Type specified for TypedQuery [" + resultClassName + + "] is incompatible with query return type [" + actualResultClass + "]" + ); + } } @Override From 8e68ad2349845ec05837f1ce90ed1ee9b9a253ed Mon Sep 17 00:00:00 2001 From: Sebastian Nohn Date: Thu, 8 Jul 2021 23:12:53 +0200 Subject: [PATCH 236/644] HHH-14719 bump apache-derby to 10.14.2.0 fixing CVE-2015-1832 and CVE-2018-1313 --- databases/derby/matrix.gradle | 2 +- gradle/libraries.gradle | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/databases/derby/matrix.gradle b/databases/derby/matrix.gradle index bedc6e15fab1..6339f7a54eec 100644 --- a/databases/derby/matrix.gradle +++ b/databases/derby/matrix.gradle @@ -5,7 +5,7 @@ * See the lgpl.txt file in the root directory or . */ //databaseProfile { - jdbcDependency 'org.apache.derby:derby:10.11.1.1' + jdbcDependency 'org.apache.derby:derby:10.14.2.0' // testing { // beforeSuite { diff --git a/gradle/libraries.gradle b/gradle/libraries.gradle index 1af583bc6c4e..593a3c644aa9 100644 --- a/gradle/libraries.gradle +++ b/gradle/libraries.gradle @@ -127,7 +127,7 @@ ext { byteman_bmunit: "org.jboss.byteman:byteman-bmunit:${bytemanVersion}", h2: "com.h2database:h2:${h2Version}", hsqldb: "org.hsqldb:hsqldb:2.3.2", - derby: "org.apache.derby:derby:10.11.1.1", + derby: "org.apache.derby:derby:10.14.2.0", postgresql: 'org.postgresql:postgresql:42.2.16', mysql: 'mysql:mysql-connector-java:8.0.17', mariadb: 'org.mariadb.jdbc:mariadb-java-client:2.2.3', From 4e9b96247f90ce97b3597e04e1401474df6e4683 Mon Sep 17 00:00:00 2001 From: Sebastian Nohn Date: Thu, 8 Jul 2021 11:33:23 +0200 Subject: [PATCH 237/644] HHH-14715: Update maven-core to 3.8.1 fixing CVE-201-26291 --- gradle/libraries.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libraries.gradle b/gradle/libraries.gradle index 593a3c644aa9..33d9a7dfddf7 100644 --- a/gradle/libraries.gradle +++ b/gradle/libraries.gradle @@ -113,7 +113,7 @@ ext { java16_signature: 'org.codehaus.mojo.signature:java16:1.0@signature', //Maven plugin framework - maven_core: 'org.apache.maven:maven-core:3.0.5', + maven_core: 'org.apache.maven:maven-core:3.8.1', maven_artifact: 'org.apache.maven:maven-artifact:3.0.5', maven_plugin: 'org.apache.maven:maven-plugin-api:3.0.5', maven_plugin_tools: 'org.apache.maven.plugin-tools:maven-plugin-annotations:3.2', From 15f30bd338a6b1b20c14489cf9914c5213d07661 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Tue, 6 Jul 2021 09:33:23 +0200 Subject: [PATCH 238/644] HHH-14709 Upgrade to Gradle 6.7.1 --- gradle/wrapper/gradle-wrapper.jar | Bin 58910 -> 59203 bytes gradle/wrapper/gradle-wrapper.properties | 2 +- gradlew | 2 +- gradlew.bat | 21 +++------------------ 4 files changed, 5 insertions(+), 20 deletions(-) diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 62d4c053550b91381bbd28b1afc82d634bf73a8a..e708b1c023ec8b20f512888fe07c5bd3ff77bb8f 100644 GIT binary patch delta 6656 zcmY+Ibx_pN*Z*PZ4(U#j1qtbvrOTyO8fghZ8kYJfEe%U|$dV!@ASKczEZq$fg48M@ z;LnHO_j#Uq?%bL4dY^md%$$4Y+&@nKC|1uHR&59YNhubGh72|a#ylPdh9V+akp|I; zPk^W-a00GrFMkz_NSADdv2G2-i6rb=cB_@WnG(**4ZO$=96R=t|NZ@|0_z&q3GwO^ ziUFcuj$a9QaZ3j?xt`5#q`sT-ufrtBP0nt3IA&dr*+VCsBzBVW?vZ6eZr0oD%t33z zm~-5IVsjy(F>;S~Pm@bxX85>Z*@(QL6i3JQc?1ryQFcC@X^2^mZWhFv|v? z49>l|nA&XNQ6#OvccUTyBMB*WO#NA;FW5|eE_K6dtVYP2G?uUZ09!`Iq1IF2gA(aS zLu@G^cQJmh=x?-YsYa@E6QnE5+1@ds&0f#OQRDl^GnIT_m84G5XY%W z;Ck6bk^Oeu*Ma-XmxI5GjqzWNbJMsQF4)WfMZEA{oxW0E32e)*JfG}3otPishIQBw zkBe6N#4pKPN>q1R6G1@5&(u#5yPEToMBB6_oEK|q z@(i5j!?;NNCv~=HvW%zF&1yWBq(nJa_#``G&SRmQvE|jePUPs{J!$TacM|e}Fsceb zx+76|mDp6@w>)^DIl{8?)6XYNRU|2plG8Jy&7(^9SdOWNKKJK&>0!z6XiN4J*Jkao z=E1y5x-XDC==Ub+8fLb#OW&{2ww{h^xlJFYAMOUd)}Xg@j?ak{7Kno6?9S~F?|6Df zHo|ijXX~`Sp;Vf!nR;m%vUhq>zvlRXsL0u*Tt?F#yR}3tF0#of{(UjitqST|!{aBA zicWh+URU}Jnc*sg9iMkf0pggpd?3TI*C-q$2QOdCC7rV+CHBmjS3O%a3VeZ$ZSs5ubJuJp%e%$LHgrj0niYjX;4kt z&2~j%@q3MO)-QGCA{>o%eZu){ou^MgC6~Z8Y=tc!qF=|TOlG3wJXbaLYr-;$Ch=2J z_UcE59Xzq&h0LsjLrcZrQSa}#=0~Lk|4?e4M z6d;v->NCC1oMti)RRc`Ys0?JXQjsZ@VdCy%Z)TptCrI>0Tte$pR!@yJesoU2dtyuW z7iFsE8)CkbiJP+OP28;(%?!9WddQZcAid@R@`*e%3W65$g9ee`zvwb(VPO+uVBq6p z{QDR%CR(2z@?&9Obm3xPi2lzvfip`7q`_7UDD|lRS}4=bsl3xQIOi0@GSvMuDQX}* z4B^(DI<${qUhcLqO`itJU;e<%%iS+R3I^_xIV1O%sp*x~;-dn` zt$8>RnSUh#rU3{-47067W^WNwTdq-t$-U>Hj%r!GD!gLa;kV zW5g6pCqV+!q8LgrI49(}fIc5K_`FLV4_E#XZ6{<>w8wzc%V9k!!Byg5-0WY+J?1*z%9~Aj4WQr1Jsn2(G!U8fFpi(wsy@JLg^d+IB0kl89 z0@Ssqf!L9JjYKK$J=978+NO*5^C)GPH2a%4hm$HROjM|N3g9ch9kDLh*nlwqy{mVM z`P(l#>3NnK%#O8tSb(VmZrG+`dRD#=Cc1P%(y5S?*Hj5E{vg&Eiw!YV>S#7_WRDVoFxT5m=gFi4)}y5V%KT8!xbsH_rmR& zsmM?%J}K$1l8d?2+m(}2c}-G`x>CY%Y&QBJRC$sKM}zN<9{IlF@yJEG<^0={$+`Hc zDodJ)gCADJ_bD#am(c2ojXKb|j+ENJ#58PAA&pZXufrFzBwnuuo+khfMgd!DMlU#v z9|JelQO~E2;d^w!RZJbt%IANIudpKSP)cssoWhq)>({nvcfCr0=9=FAIMuZm8Eo=} z|DND}8_PB5HqG(QwDvaM@orYBZ9kCkHV*rxKTy>q7n~0emErUwLbhq;VN<2nKT&*a2Ajz z;lKBzU2i8KLV`d)Y&ae)!HcGk$dO}Or%8KF@kE@jU1h@zwpw{6p4ME|uC$Za-ERR2 ztQvL&uOZLe(k{w_+J^ng+l}~N8MP>F1Z$fLu}D-WWaeu#XduP@#8JpmH(X>rIL)k3 zyXNyTIB1(IH%S&pQ{rWaTVfB$~-;RnlY z^(y7mR>@=brI>!TrA)BQsQ={b*6$=1Eqbuu6IdhJ&$YD$08AwtNr9*J?%-WT<;O1< zPl1<@yeqfZ>@s4azqTf<=I4(kU^+^Qkstm%WM-0_VLm({jFc8`5Df2Q1Y9zMZu0^! zsO_yh2Sz9K>Jq6fkYbBZocEJ6C!SdEzYDkiEtNJs{?!tA#e|oiN+VaaAobwKef_kUup&4scD?1+}Q8)DaekkMYn-FOS{J%NY za^mmJ^n`t*1p@hF*gl#L+5wr40*(ub4J#L|@oCl~@|4UvCjHBYDQv&S zhyGMAkRO^tF_dyi&XM)4mQ;k>kj?RgRo@-?==oD+ns*>bf@&fPXF|4U0&ib2 zo~1ZdmCPWf!W9#sGP@9X$;Rc`tjbz^&JY}z{}j9bl?;VC{x)TfQH$D^WowKL&4Zx@ zdSn+QV7H(e0xRfN6aBfH)Q=@weoD?dvu6^ZS)zqb>GwMmIuS8zJfaMUQx9>%k~w34 z3}_B2Jj~u=SnJ~vZPj*)UoDi_FtT=UAb#J^b4B%R6z3H%cj-1OCjU5F$ky>By1zsg z>2A0ccp29(Y<;my|J_g-r{1I@+*O$>!R3`_sFNP4e}LD1e1mM&SA`;;TR0I`_hESV zh4U*9ecK$0=lYk`{SR_cm$}iS*?yQR(}T-5ub?Wn^#RTe*^1~ya%`!xWq-F*WH@%nnZTNREA z3eUX2uM9b_w!Zo$nVTotEtzuL(88N)H~v_G=89|(@IFz~Wq6ME);z(!2^PkR2B&kE zxR)xV8PE|Hszyjp#jNf=ZIQ7JR~4Ls#Vd@mPF(7R5VO$akUq8JM+sn>ZVg(lJZ)5qjqdw(*7tuwjY#0tx+|!sTz9yV~%HOdrb#!5w9>*0LrCS z%wF$Yc6~hqVQZzoC^D<(-h0aOtk}kn<<*xF61HQr<5}efY{zXXA+PaJG7vT&{Oz(@Uu!V#Fp9%Ht!~@;6AcD z$lvlPu&yd(YnAHfpN51*)JN0aYw9gGk{NE7!Oqu4rBp}F30669;{zcH-a7w9KSpDQPIE_f9T zit? zJSjTKWbe{f{9BmSDAFO1(K0oqB4578tU0(oRBE^28X>xDA!1C&VJEiYak4_ZTM*7M`hv_ zw3;2ndv3X$zT!wa7TrId{gNE`Vxf}j5wsyX+;Kn<^$EJT`NzznjyYx=pYMkZjizEU zb;Gg8Pl_pqxg)9P)C)Hxh_-mQ;u-I_Ol>d^>q08zFF!>Z3j1-HmuME_TGZ*Ev;O0O z%e(edJfV<6t3&FKwtInnj9EeQhq9;o5oLJoiKwWF5bP2~Feh#P4oN()JT0pdq!9x* ze3D-1%AV#{G=Op$6q?*Z>s{qFn}cl@9#m@DK_Bs@fdwSN`Qe18_WnveRB583mdMG- z?<3pJC!YljOnO8=M=|Cg)jw;4>4sna`uI>Kh&F20jNOk9HX&}Ry|mHJ+?emHnbYLJ zwfkx@slh31+3nq-9G5FVDQBHWWY}&hJ-fpDf!lQdmw8dlTt#=)20X74S>c&kR(?PT zBg)Y%)q&|hW1K;`nJPAGF*c3{3`FvrhD9=Ld{3M*K&5$jRhXNsq$0CLXINax1AmXX ziF39vkNtcK6i^+G^AEY!WalGazOQ$_#tx?BQ{YY$&V&42sICVl8@AI6yv;sGnT;@f zL=}rZcJqNwrEEA=GDdEe8Z=f9>^?($oS8xGdFf1eUWTYtZF<3tu2V%noPBnd=thZ+ zO&xoc?jvXG7Xt!RTw#5VN50UjgqSntw9Y35*~pxz=8OzkXg{@S2J%+{l3Q>B_qbnl z20Deb7JM&ZSp`%X>xWpb>FF8q7Nq&4#a1}A-(-!aMDmVbz05D!NpUzVe{~72h%cOh zwQFNai2a$K|hFgDk(oPF_tuf{BV!=m0*xqSzGAJ(~XUh8rk#{YOg0ReK>4eJl z;-~u5v$}DM)#vER>F)-}y(X6rGkp<{AkiPM7rFgAV^)FUX8XmCKKaWlS4;MSEagj$ z#pvH`vLX1q{&eOm>htnk4hmv=_)ao!MCp}9ql5yfre&Py!~hBAGNBa}PH&J8K=~<% z&?!J-QaH|0bq_uo6rt*r-M>d7jm1cbW^T>s)S?L{n8v`^?VIPA+qi^6e@cM|5boqEO!p1e|_{7U3Yl6K?0xMN1bbjf0@$TE-T))w> zFe?E?g$PUT-)AJ(PS^By^D^Ed!K5iv$*_eW~VA(I3~UMy*ZcgVu0$XZC*_0PgDmUL)qTCn927LD~p$yXR_GCJ&iQ; z4*`%l-dC5pALH!y*nmhdHRh02QjW1vZL4ySucz*w3f|#`=u@@YvMV1?i!&DIa2+S< z8z!gvN3FV4I;%fl;ruFeV{jKjI~?GlgkmGBuJ<7vY|l3xMOc?S@Q#C(zo*m&JLrjT2rU9PYOniB8O~yO5<1CCcQz# z17B2m1Z{R!Y)UO#CU-Y&mOlv4*Gz%rC_YkRcO)jTUEWHDvv!GWmEihE>OKPx1J?Av z8J{-#7NsT>>R#*7**=QL)1@IR77G9JGZZiVt!=jD+i(oRV;I`JkiTSZkAXuHm-VG1 z+2-LD!!2dNEk@1@Rp|C$MD9mH^)H*G*wI(i*Rc6Vvdik+BDycYQ*=0JA3dxxha|Zg zCIW1Ye-DdpMGTEwbA^6hVC<(@0FL4dkDOYcxxC5c%MJQ^)zpA%>>~Q|Y=@)XW!px; z_Fx+xOo7>sz4QX|Ef~igE+uFnzFWP<-#||*V0`0p7E*+n5+awuOWmvR{-M*chIXgo zYiZvQMond#{F8+4Zh_;>MsaZUuhp=onH@P!7W>sq|CWv|u}Wg0vo&f4UtmLzhCwwu zJaR=IO;sQxS}h(K>9VZjnED+>9rGgB3ks+AwTy_EYH{oc)mo`451n&YH%A1@WC{;1 z=fB6n zIYp46_&u`COM&Di?$P}pPAlAF*Ss<)2Xc?=@_2|EMO?(A1u!Vc=-%bDAP#zDiYQvJ z0}+}3GaLxsMIlh6?f=iRs0K=RyvMOcWl*xqe-IBLv?K{S^hP)@K|$I+h_)pdD9r~! zxhw2u66+F(E`&6hY}B_qe>wil|#*0R0B;<@E?L zVrhXKfwRg0l8r>LuNs1QqW&39ME0sOXe8zycivGVqUOjEWpU)h|9fwp@d(8=M-WxY zeazSz6x5e`k821fgylLIbdqx~Kdh^Oj`Q!4vc*Km)^Tr-qRxPHozdvvU^#xNsKVr6aw8={70&S4y*5xeoF@Q^y596*09`XF56-N z1=Rm5?-An178o?$ix}y7gizQ9gEmGHF5AW+92DYaOcwEHnjAr~!vI>CK%h`E_tO8L Yte!%o?r4GTrVtxD61Ym!|5fq-1K$0e!T1w z1SC8j)_dObefzK9b=~*c&wBRW>;B{VGKiBofK!FMN5oJBE0V;;!kWUz!jc1W?5KdY zyZ3mCBHprpchz-9{ASiJJh&&h1|4rdw6wxD2+9= z#6#}Uq8&^1F3wgvGFoNDo?bIeEQXpcuAR0-+w$JWoK-@yUal1M&~W_O)r+Rx;{@hWH5n^oQWR36GMYBDDZyPK4L@WVjRrF+XlSzi4X4!_!U%Uujl6LHQ#|l(sUU%{ zefYd8jnVYP91K}Qn-OmmSLYFK1h~_}RPS~>+Xdz%dpvpJ{ll!IKX=JN99qowqslbO zV3DmqPZ}6>KB!9>jEObpi$u5oGPfO3O5!o3N2Mn`ozpje<}1I1H)m2rJDcB7AwXc6 z6j)tnPiql7#)r+b+p9?MVahp&=qJ^$oG+a^C*);FoJ!+V*^W+|2Olx5{*&$bXth)U zejc7mU6cBp?^Rj|dd{GL-0eHRTBi6_yJ&GLP5kIncv^z{?=0AVy^5{S8_n=rtua!J zFGY=A(yV^ZhB}1J_y(F`3QTu+zkHlw;1GiFeP&pw0N1k%NShHlO(4W+(!wy5phcg4 zA-|}(lE_1@@e6y`veg;v7m;q%(PFG&K3#}eRhJioXUU0jg_8{kn$;KVwf;zpL2X_( zC*_R#5*PaBaY73(x*oZ}oE#HPLJQRQ7brNK=v!lsu==lSG1(&q>F)`adBT~d*lMS| z%!%7(p~<7kWNmpZ5-N31*e=8`kih|g5lVrI%2wnLF-2D+G4k6@FrYsJ_80AJ}KMRi>) z-kIeHp{maorNWkF81v0FKgB==_6blyaF$5GaW)B!i4v*jNk6r)vU6?G$0pV8(Y+UK z5lgRVt%;N_gWp)^osv=h+^07UY6+$4^#t=M3>0i0`{`aEkFLL#a)93uXhYO+aKTtu zckg2T9S&GKNtZmdAS^8PzvDva-%-K&g9eqPXQ4$dM^inr@6Zl z{!Cq&C_+V;g*{>!0cZP}?ogDb$#ZS=n@NHE{>k@84lOkl&$Bt2NF)W%GClViJq14_ zQIfa^q+0aq){}CO8j%g%R9|;G0uJuND*HO$2i&U_uW_a5xJ33~(Vy?;%6_(2_Cuq1 zLhThN@xH7-BaNtkKTn^taQHrs$<<)euc6z(dhps>SM;^Wx=7;O&IfNVJq3wk4<1VS z-`*7W4DR_i^W4=dRh>AXi~J$K>`UqP>CKVVH&+T(ODhRJZO7DScU$F7D)di-%^8?O z6)Ux`zdrVOe1GNkPo0FgrrxSu1AGQkJe@pqu}8LkBDm+V!N_1l}`tjLW8${rgDLv3m@E*#zappt-Mm zSC<$o+6UO~w0C=(0$&*y**@nKe_Q{|eAuD!(0YL0_a{z%+sdfSyP={Nyd$re6Rzbp zvsgTY7~VflX0^Vf7qqomYZ_$ryrFVV2$sFyzw2r%Q8*uYDA+)iQdfKms_5(>!s#!( z!P5S(N0i9CKQKaqg(U%Gk#V3*?)lO6dLv`8KB~F<-%VhbtL8Rl>mEz+PN=qx&t*|= zQHV=qG)YKlPk4iCyWIUGjC?kpeA>hIBK*A?B0)rB=RqAal#D%1C9yVQwBcz${#Jb5 zR{TRmMrOrJsLc&6x9qDo@FJ^=do_Y?3oU0G^nV5_EU&+DS+VA7Tp{^TAF>yZbyM3c zf*1CqHY9T|aL_lyY7c)i!_MtGPA!sdy3|mrsKVj1mi&>dms@-ozSa}OZ?2I*tAndg z@S7er$t^d^-;!wLQbG60nWd@1pQVD7tw-G_B#OscoYyremiZ_hj8*sXqQdchuD^!R zpXGuSj5psk+jR>3rWu3^`17>j&*^9^rWbszP=Mf@5KIEj%b=z98v=Ymp%$FYt>%Ld zm8})EDbNOJu9n)gwhz_RS``#Ag)fr)3<*?(!9O~mTQWeh;8c;0@o=iBLQNqx3d_2#W7S9#FXzr6VXfs>4 z;QXw}-STvK9_-7H=uqgal2{GkbjVLN+=D5ddd)4^WvX;(NYA*X*(JxTdiUzqVJopd zQg#~psX4o<)cF>r=rxP`(Xsf<+HG-pf&7aFPL8z|-&B*P?Vmsu5d>Nlg^2$WRY!S@#`g2{81;(1w#o5HsvN}5pFZi});>|VK^kL{Zkx~wgn ztlZp;HW`H8(GdRfIwc~?#N6}o#h158ohI*GIsK%56I_9sf2k_K@4vD!l{(dX9E7PJ;w>$|Y;-VBJSO4@){07bo-89^LZ9g<<%;dOl zyIq{s8`8Ltp*GDwu(l_Z$6sA2nam$BM$Q~6TpZg)w2TtW?G5whV(lRwaf$6EU86is zBP9Rs&vS_~sk?Nn_b}^HkM8LiO@>J}=g(T4hLmvH@5Jj#2aHa~K)lD9VB0k>$V2BP zgh;(=y9Op(KQ=H5vj+%qs>?s4tYN~-Q|fyQePA)s?HrF~;l!+@t8VMzqUpqMLudFT z)=o~s!MM4XkgbetIsODwtQ=FF$IcIp&!pjh6Q6{tL+l*7GQ%8Wsg(tC#qU3oW$~n) zL=>XIxI}Hi7HS0F_mmi+(c%1HDuKiWm>|6Xa}nW7ei55ggru9)xjBvC#JcEIN*#cp zv*ACvr=HTC?dX9NNo9Yhulu_gX5Z~}QQ2&QZ&C77{(>Y3_ z6j5Z1Uc5FtPEpS_31HsgmSLHZijGb_p$WlRJ1p^_1!ZLP8kr6OtCEK7Qh267o$H>e zf<4cNGQRk{g5h$XfvTFQ@`qm@iju83-~}ebAYpZryARHVR$AEt3229U{y@Fp4 z-8FBBtGG&(hTyUdx5ZOfiz`c=<0F%+w|Fl=rWk{K7>70k04SN?RU(^mrKSeKDqA!K^Hsv8C?#ioj4@WUL zC*?{hTai6q0%_oBTqDHygp_Kl;({sAScYQIwMDM1U>{x0ww zve?_}E;DG?+|zsUrsph5X_G7l#Y~vqkq3@NNDabbw7|`eJBmn`Qrlr%?`va=mm$Mc{+FBbQbogAZ6{MuzT|P%QZZotd21eb1hfj|;GYAX&>bx#D5EB+=XMj2XJkpnyMUykaVo) zj3ZLqEl1&)Rturc8m@+uUuD^vaNaSxGwP4dq0-OSb~62lPv8E_K4usLvG{Qg zdR%z8dd2H!{JaT|X_bfm{##*W$YM;_J8Y8&Z)*ImOAf4+| zEyi)qK%Ld1bHuqD+}-WiCnjszDeC-%8g+8JRpG1bOc!xUGB?@?6f~FTrI%U#5R~YF z%t5(S2Q>?0`(XNHa8xKdTEZ~Z4SJOheit#ldfdg63}#W6j8kO;SjQD`vftxS+#x1B zYu|5szEvkyz|}|B3x|DNlyi$;+n+cW$Hu+?)=X1!sa%{H-^;oBO9XACZJ}wkQ!sTa zQ#J3h|HX{{&WwIG3h7d6aWktuJaO)ie6&=KJBoX@w(rBWfin`*a6OmCC5M0HzL(gv zY<*e4hmW>SWVhxk-`UGOAbD%Hk+uu<^7zJ_ytVXamfqCd0$g+W08>?QAB}Cv{b}eM z@X}ILg+uT%>-6`A25p@uhS3%;u>ccSq}8|H_^o&`nBT5S0y z;2H0I^(4MO*S+(4l$gULc4KSeKvidto5Nl0P|%9CqQ*ikY!w_GUlo}sb9HYB=L^oFpJ zfTQskXW!LFVnUo4(OHPDaZSf3zB|3{RGu1>ueE$(+dr?tT zp!SGlqDU8vu{5xLWSvj+j$arHglg54#Lx&TvuO3LIIU>hF9Uoj&=-b*Q?uYr`#V?xz?2 zhirZrv^eA{k%{hFh%9LYVXEYWd5#PuUd1QqaqB*J!CMXEM>fEB$@#1>mtB`Bfil}t zhhTIObqh5HRvT+4q_Do$Q*Jika?qV=Np-DtPkU z(KoXyWLfPwr@UY1)hBAvR3nCBZgd|CevTG?H~HqDF}dzy%2sd2`f{^CBbTk*^K~RO zN~O0+2EjAJlywF%SjgYz810l&G5AqzI<=Ber{912^PpSPRJl3dm8W@dKHL}7_@k3)Y!SXYkyxQy>Q4I2o zr`ev7fLF$1t96h|sH<-#*YzGD-b^3$_!#wsh(Yw;)b@udLz9mm`mFYh z1Zz24KIQJ(*_-E0(3&1InqG;U?wF)GYd>DFo(em`#|UaaYmkA9;GTX7b?0@C@QkTVpGD#mf$dQoRNV=n{^Zi_W*ps;3?^$s`0;ER7;==~OmQ~9 zS5P=FjxE5%|;xq6h4@!_h?@|aK&FYI2IT(OHXv2%1 zWEo-v!L7x^YT(xLVHlpJttcwaF@1Y;-S*q3CRa!g7xdzl|Jan>2#dI0`LKl!T1GMk zRKe4|bQO&ET}Z^Aiym*HII>cSxIzl|F~JEUGxz;+DB=8fxXhnBI4R12q6ews$lA`Jfi}r@A@-)6TOAUMNYFYJ zZ-Zd?lxFTyjN3mXnL!%#>Z%$0gJ4*9g;e;@zSmQ{eGGDaRRNM3s@6!;hYuVc=c+3B z=qzNNS~n^EsJU4aOGE|mdy={C^lPKEfPL-IJAsTpQsDgZ@~s+eHZYmp9yb=YW_4r?lqQaYZQ`nau){W`LY#P)>i zq^wHEuOYs#FlPZeMuT@Etb@~A6feCebq`miJE3w+gAL%bVF_s*5e*@)?xmKSo%I3? zLELHVdWia$}~s6 zr!^LfxSSB4Td&9iTXrzQpl5ZDo#SdmNr;23QsPHQ!x!UT9xtb!Ycz^JF8x)%cFOXK z^EXw%dRz_VD}7?RU^4{)1+xFO=z!EI8IUa3U*rag=1BpHX$Xi<__kSbS{y_xa*MJv z_`thq0Z^sPzjAk48ssDQj}!$N8Q$XC84(bU$t_Bm69Jf+C!h_}ep zwzpQj9sRA94<{x3{~z&ix-DwX;RAzka)4-#6ZHJqKh|SVuO|>Yrv+m30+!|sK<-|E z=)5E->#y<_1V|T1f%Af!ZYqXg}`O zI$qKOWdnclF`%_Z`WGOe{`A`l-#a?s=Q1a#@BOWmExH2;Wl`OB!B-%lq3nO{4=WO& z#k_x|N&(qzm*6S{G*|GCegF2N2ulC+(58z2DG~yUs}i8zvRf&$CJCaexJ6Xu!`qz( z)*v8*kAE#D0KCo*s{8^Rbg=`*E2MzeIt0|x55%n-gO&yX#$l=3W7-_~&(G8j1E(XB hw}tl`5K!1C(72%nnjQrp<7@!WCh47rWB+@R{{wClNUHz< diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 14e30f7416a5..1f3fdbc52873 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.7-all.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index fbd7c515832d..4f906e0c811f 100755 --- a/gradlew +++ b/gradlew @@ -130,7 +130,7 @@ fi if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then APP_HOME=`cygpath --path --mixed "$APP_HOME"` CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` - + JAVACMD=`cygpath --unix "$JAVACMD"` # We build the pattern for arguments to be converted via cygpath diff --git a/gradlew.bat b/gradlew.bat index a9f778a7a964..ac1b06f93825 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -40,7 +40,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto init +if "%ERRORLEVEL%" == "0" goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -54,7 +54,7 @@ goto fail set JAVA_HOME=%JAVA_HOME:"=% set JAVA_EXE=%JAVA_HOME%/bin/java.exe -if exist "%JAVA_EXE%" goto init +if exist "%JAVA_EXE%" goto execute echo. echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% @@ -64,21 +64,6 @@ echo location of your Java installation. goto fail -:init -@rem Get command-line arguments, handling Windows variants - -if not "%OS%" == "Windows_NT" goto win9xME_args - -:win9xME_args -@rem Slurp the command line arguments. -set CMD_LINE_ARGS= -set _SKIP=2 - -:win9xME_args_slurp -if "x%~1" == "x" goto execute - -set CMD_LINE_ARGS=%* - :execute @rem Setup the command line @@ -86,7 +71,7 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar @rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* :end @rem End local scope for the variables with windows NT shell From c78a0a2b163bf1d9b59392a3d51827aa11d80c31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Tue, 6 Jul 2021 09:49:35 +0200 Subject: [PATCH 239/644] HHH-14709 Move to Gradle's built-in way of testing Java modules --- ...ernate-integrationtest-java-modules.gradle | 51 +++---------------- .../src/main/java/module-info.java | 28 ---------- .../src/test/java/module-info.java | 34 +++++++++++++ .../java/module/test/JavaModulePathIT.java | 2 +- .../java/module/test/ScannerTest.java | 2 +- .../java/module/test}/entity/Author.java | 2 +- .../module/test}/service/AuthorService.java | 4 +- .../resources/META-INF/persistence.xml | 2 +- 8 files changed, 48 insertions(+), 77 deletions(-) delete mode 100644 hibernate-integrationtest-java-modules/src/main/java/module-info.java create mode 100644 hibernate-integrationtest-java-modules/src/test/java/module-info.java rename hibernate-integrationtest-java-modules/src/{main/java/org/hibernate/orm/integrationtest/java/module => test/java/org/hibernate/orm/integrationtest/java/module/test}/entity/Author.java (93%) rename hibernate-integrationtest-java-modules/src/{main/java/org/hibernate/orm/integrationtest/java/module => test/java/org/hibernate/orm/integrationtest/java/module/test}/service/AuthorService.java (95%) rename hibernate-integrationtest-java-modules/src/{main => test}/resources/META-INF/persistence.xml (93%) diff --git a/hibernate-integrationtest-java-modules/hibernate-integrationtest-java-modules.gradle b/hibernate-integrationtest-java-modules/hibernate-integrationtest-java-modules.gradle index 7769ca7fb214..e927efb48d4d 100644 --- a/hibernate-integrationtest-java-modules/hibernate-integrationtest-java-modules.gradle +++ b/hibernate-integrationtest-java-modules/hibernate-integrationtest-java-modules.gradle @@ -7,57 +7,22 @@ description = 'Integration tests for running Hibernate ORM in the Java module path' -buildscript { - repositories { - maven { - url "https://plugins.gradle.org/m2/" - } - } - dependencies { - classpath "org.javamodularity:moduleplugin:1.5.0" - } -} - apply from: rootProject.file( 'gradle/java-module.gradle' ) -// No first-class, built-in support for Java modules in Gradle yet, -// so we have to use https://github.com/java9-modularity/gradle-modules-plugin -apply plugin: "org.javamodularity.moduleplugin" - -// In this module, the "main" code is actually just test code that happens -// to be built independently so as to generate a Java module. -// So, let's override settings for compilation of the main code, just for this particular case. -def testJavaVersions = gradle.ext.javaVersions.test -tasks.compileJava { - if ( !gradle.ext.javaToolchainEnabled ) { - sourceCompatibility = JavaVersion.toVersion( testJavaVersions.release ) - targetCompatibility = JavaVersion.toVersion( testJavaVersions.release ) - } - else { - javaCompiler = javaToolchains.compilerFor { - languageVersion = testJavaVersions.compiler - } - - // Remove JDK8-only options (if any) that are incompatible with options.release - for ( it = options.compilerArgs.listIterator(); it.hasNext(); ) { - if ( it.next() in ['-source', '-target'] ) { - it.remove() - it.next() - it.remove() - } - } - - options.release = testJavaVersions.release.asInt() - } +// See https://docs.gradle.org/6.7.1/userguide/java_testing.html#blackbox_integration_testing +// See https://docs.gradle.org/6.7.1/samples/sample_java_modules_multi_project_with_integration_tests.html +java { + modularity.inferModulePath = true } // Checkstyle fails for module-info checkstyleMain.exclude '**/module-info.java' dependencies { - compile( project( ':hibernate-core' ) ) - compile( project( ':hibernate-envers' ) ) - compile( libraries.jpa ) + testCompile( project( ':hibernate-core' ) ) + testCompile( project( ':hibernate-envers' ) ) + testCompile( libraries.jpa ) + testCompile( libraries.junit ) } test { diff --git a/hibernate-integrationtest-java-modules/src/main/java/module-info.java b/hibernate-integrationtest-java-modules/src/main/java/module-info.java deleted file mode 100644 index 92ed22d401e7..000000000000 --- a/hibernate-integrationtest-java-modules/src/main/java/module-info.java +++ /dev/null @@ -1,28 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -module org.hibernate.orm.integrationtest.java.module { - exports org.hibernate.orm.integrationtest.java.module.service; - opens org.hibernate.orm.integrationtest.java.module.entity to - org.hibernate.orm.core, - javassist; // Necessary for javassist, but not for bytebuddy (the default) - - requires java.persistence; - /* - * IDEA will not find the modules below because it apparently doesn't support automatic module names - * for modules in the current project. - * Everything should work fine when building from the command line, though. - */ - requires org.hibernate.orm.core; - requires org.hibernate.orm.envers; - - /* - * This is necessary in order to use SessionFactory, - * which extends "javax.naming.Referenceable". - * Without this, compilation as a Java module fails. - */ - requires java.naming; -} \ No newline at end of file diff --git a/hibernate-integrationtest-java-modules/src/test/java/module-info.java b/hibernate-integrationtest-java-modules/src/test/java/module-info.java new file mode 100644 index 000000000000..d6fdab1efd00 --- /dev/null +++ b/hibernate-integrationtest-java-modules/src/test/java/module-info.java @@ -0,0 +1,34 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +module org.hibernate.orm.integrationtest.java.module.test { + + /* + * Main configuration, necessary for real client applications. + */ + + opens org.hibernate.orm.integrationtest.java.module.test.entity to + org.hibernate.orm.core, + javassist; // Necessary for javassist, but not for bytebuddy (the default) + + requires java.persistence; + // IDEA will not find the modules below because it apparently doesn't support automatic module names + // for modules in the current project. + // Everything should work fine when building from the command line, though. + requires org.hibernate.orm.core; + requires org.hibernate.orm.envers; + + // Transitive dependencies that leak through the Hibernate ORM API + requires java.sql; + requires java.naming; // SessionFactory extends "javax.naming.Referenceable" + + /* + * Test-only configuration. + */ + + opens org.hibernate.orm.integrationtest.java.module.test to junit; + requires junit; +} \ No newline at end of file diff --git a/hibernate-integrationtest-java-modules/src/test/java/org/hibernate/orm/integrationtest/java/module/test/JavaModulePathIT.java b/hibernate-integrationtest-java-modules/src/test/java/org/hibernate/orm/integrationtest/java/module/test/JavaModulePathIT.java index 6476bfd65ce4..815462f2498a 100644 --- a/hibernate-integrationtest-java-modules/src/test/java/org/hibernate/orm/integrationtest/java/module/test/JavaModulePathIT.java +++ b/hibernate-integrationtest-java-modules/src/test/java/org/hibernate/orm/integrationtest/java/module/test/JavaModulePathIT.java @@ -11,7 +11,7 @@ import org.hibernate.Session; import org.hibernate.envers.boot.internal.EnversIntegrator; -import org.hibernate.orm.integrationtest.java.module.service.AuthorService; +import org.hibernate.orm.integrationtest.java.module.test.service.AuthorService; import org.junit.Assert; import org.junit.Test; diff --git a/hibernate-integrationtest-java-modules/src/test/java/org/hibernate/orm/integrationtest/java/module/test/ScannerTest.java b/hibernate-integrationtest-java-modules/src/test/java/org/hibernate/orm/integrationtest/java/module/test/ScannerTest.java index 7e00d53bd9b0..d26f30827d49 100644 --- a/hibernate-integrationtest-java-modules/src/test/java/org/hibernate/orm/integrationtest/java/module/test/ScannerTest.java +++ b/hibernate-integrationtest-java-modules/src/test/java/org/hibernate/orm/integrationtest/java/module/test/ScannerTest.java @@ -15,7 +15,7 @@ import org.hibernate.boot.archive.scan.internal.StandardScanner; import org.hibernate.boot.archive.scan.spi.ClassDescriptor; import org.hibernate.boot.archive.scan.spi.ScanResult; -import org.hibernate.orm.integrationtest.java.module.entity.Author; +import org.hibernate.orm.integrationtest.java.module.test.entity.Author; import org.junit.Assert; import org.junit.Test; diff --git a/hibernate-integrationtest-java-modules/src/main/java/org/hibernate/orm/integrationtest/java/module/entity/Author.java b/hibernate-integrationtest-java-modules/src/test/java/org/hibernate/orm/integrationtest/java/module/test/entity/Author.java similarity index 93% rename from hibernate-integrationtest-java-modules/src/main/java/org/hibernate/orm/integrationtest/java/module/entity/Author.java rename to hibernate-integrationtest-java-modules/src/test/java/org/hibernate/orm/integrationtest/java/module/test/entity/Author.java index ac7706ef59e6..143ef766d9d4 100644 --- a/hibernate-integrationtest-java-modules/src/main/java/org/hibernate/orm/integrationtest/java/module/entity/Author.java +++ b/hibernate-integrationtest-java-modules/src/test/java/org/hibernate/orm/integrationtest/java/module/test/entity/Author.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.orm.integrationtest.java.module.entity; +package org.hibernate.orm.integrationtest.java.module.test.entity; import javax.persistence.Basic; import javax.persistence.Entity; diff --git a/hibernate-integrationtest-java-modules/src/main/java/org/hibernate/orm/integrationtest/java/module/service/AuthorService.java b/hibernate-integrationtest-java-modules/src/test/java/org/hibernate/orm/integrationtest/java/module/test/service/AuthorService.java similarity index 95% rename from hibernate-integrationtest-java-modules/src/main/java/org/hibernate/orm/integrationtest/java/module/service/AuthorService.java rename to hibernate-integrationtest-java-modules/src/test/java/org/hibernate/orm/integrationtest/java/module/test/service/AuthorService.java index 8f9c3ec40fd8..a3a98ecd6466 100644 --- a/hibernate-integrationtest-java-modules/src/main/java/org/hibernate/orm/integrationtest/java/module/service/AuthorService.java +++ b/hibernate-integrationtest-java-modules/src/test/java/org/hibernate/orm/integrationtest/java/module/test/service/AuthorService.java @@ -4,7 +4,7 @@ * License: GNU Lesser General Public License (LGPL), version 2.1 or later. * See the lgpl.txt file in the root directory or . */ -package org.hibernate.orm.integrationtest.java.module.service; +package org.hibernate.orm.integrationtest.java.module.test.service; import java.util.List; @@ -14,7 +14,7 @@ import org.hibernate.SessionFactory; import org.hibernate.envers.AuditReader; import org.hibernate.envers.AuditReaderFactory; -import org.hibernate.orm.integrationtest.java.module.entity.Author; +import org.hibernate.orm.integrationtest.java.module.test.entity.Author; public class AuthorService implements AutoCloseable { diff --git a/hibernate-integrationtest-java-modules/src/main/resources/META-INF/persistence.xml b/hibernate-integrationtest-java-modules/src/test/resources/META-INF/persistence.xml similarity index 93% rename from hibernate-integrationtest-java-modules/src/main/resources/META-INF/persistence.xml rename to hibernate-integrationtest-java-modules/src/test/resources/META-INF/persistence.xml index 9108b2e832ac..810b4f2d9cac 100644 --- a/hibernate-integrationtest-java-modules/src/main/resources/META-INF/persistence.xml +++ b/hibernate-integrationtest-java-modules/src/test/resources/META-INF/persistence.xml @@ -10,7 +10,7 @@ xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd" version="1.0"> - org.hibernate.orm.integrationtest.java.module.entity.Author + org.hibernate.orm.integrationtest.java.module.test.entity.Author From c4ff6c19ac1bbcc23ce7616aa0e050ba4971a975 Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Thu, 8 Jul 2021 14:55:55 -0700 Subject: [PATCH 240/644] HHH-14720 : Added test case --- .../ColumnLastIndexNotLetterAliasTest.java | 45 +++++++++++++++++++ 1 file changed, 45 insertions(+) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/mapping/ColumnLastIndexNotLetterAliasTest.java diff --git a/hibernate-core/src/test/java/org/hibernate/test/mapping/ColumnLastIndexNotLetterAliasTest.java b/hibernate-core/src/test/java/org/hibernate/test/mapping/ColumnLastIndexNotLetterAliasTest.java new file mode 100644 index 000000000000..5797636f8876 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/mapping/ColumnLastIndexNotLetterAliasTest.java @@ -0,0 +1,45 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.mapping; + +import java.util.Locale; + +import org.hibernate.dialect.Dialect; +import org.hibernate.dialect.PostgreSQL94Dialect; +import org.hibernate.mapping.Column; + +import org.hibernate.testing.TestForIssue; +import org.junit.Test; + +import static org.junit.Assert.assertEquals; + +/** + * Aliases should always be lower-case. This tests that an alias for + * a column name that ends in a character that is not a letter gets + * generated to be all in lower-case. + * + * @author Gail Badner + */ +public class ColumnLastIndexNotLetterAliasTest { + // Arbitrarily choose PostgreSQL + private static final Dialect DIALECT = new PostgreSQL94Dialect();; + + @Test + @TestForIssue(jiraKey = "HHH-14720") + public void testColumnNameEndinWithNonCharacter() { + test( "aColumn1" ); + test( "aColumn_" ); + test( "aVeryVeryVeryLongColumnName1" ); + test( "aVeryVeryVeryLongColumnName_" ); + } + + private void test(String columnName) { + final Column column = new Column( columnName ); + final String alias = column.getAlias( DIALECT ); + assertEquals( alias.toLowerCase( Locale.ROOT ), alias ); + } +} From 6d16d6d32fa7fe3dc5a5bcacb818a810e997c484 Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Thu, 8 Jul 2021 14:56:56 -0700 Subject: [PATCH 241/644] HHH-14720 : Aliases generated for mixed-case column names that end in a number are not all lower-case --- .../src/main/java/org/hibernate/mapping/Column.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Column.java b/hibernate-core/src/main/java/org/hibernate/mapping/Column.java index 997aae316bde..f53b06df62cd 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Column.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Column.java @@ -117,8 +117,8 @@ public String getAlias(Dialect dialect) { if ( lastLetter == -1 ) { alias = "column"; } - else if ( name.length() > lastLetter + 1 ) { - alias = name.substring( 0, lastLetter + 1 ); + else if ( alias.length() > lastLetter + 1 ) { + alias = alias.substring( 0, lastLetter + 1 ); } boolean useRawName = name.length() + suffix.length() <= dialect.getMaxAliasLength() From 1c16d8da971578e121208688c07a110875cc268a Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Thu, 15 Jul 2021 15:39:37 +0100 Subject: [PATCH 242/644] HHH-14728 Include CamelCaseToUnderscoresNamingStrategy from Spring Boot --- .../CamelCaseToUnderscoresNamingStrategy.java | 92 +++++++++++++++++++ 1 file changed, 92 insertions(+) create mode 100644 hibernate-core/src/main/java/org/hibernate/boot/model/naming/CamelCaseToUnderscoresNamingStrategy.java diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/naming/CamelCaseToUnderscoresNamingStrategy.java b/hibernate-core/src/main/java/org/hibernate/boot/model/naming/CamelCaseToUnderscoresNamingStrategy.java new file mode 100644 index 000000000000..06e82fbbf7b9 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/naming/CamelCaseToUnderscoresNamingStrategy.java @@ -0,0 +1,92 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.boot.model.naming; + +import java.util.Locale; + +import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; + +/** + * Originally copied from Spring Boot as this strategy is popular there + * (original name is SpringPhysicalNamingStrategy). + * + * @author Phillip Webb + * @author Madhura Bhave + */ +public class CamelCaseToUnderscoresNamingStrategy implements PhysicalNamingStrategy { + + @Override + public Identifier toPhysicalCatalogName(Identifier name, JdbcEnvironment jdbcEnvironment) { + return apply( name, jdbcEnvironment ); + } + + @Override + public Identifier toPhysicalSchemaName(Identifier name, JdbcEnvironment jdbcEnvironment) { + return apply( name, jdbcEnvironment ); + } + + @Override + public Identifier toPhysicalTableName(Identifier name, JdbcEnvironment jdbcEnvironment) { + return apply( name, jdbcEnvironment ); + } + + @Override + public Identifier toPhysicalSequenceName(Identifier name, JdbcEnvironment jdbcEnvironment) { + return apply( name, jdbcEnvironment ); + } + + @Override + public Identifier toPhysicalColumnName(Identifier name, JdbcEnvironment jdbcEnvironment) { + return apply( name, jdbcEnvironment ); + } + + private Identifier apply(final Identifier name, final JdbcEnvironment jdbcEnvironment) { + if ( name == null ) { + return null; + } + StringBuilder builder = new StringBuilder( name.getText().replace( '.', '_' ) ); + for ( int i = 1; i < builder.length() - 1; i++ ) { + if ( isUnderscoreRequired( builder.charAt( i - 1 ), builder.charAt( i ), builder.charAt( i + 1 ) ) ) { + builder.insert( i++, '_' ); + } + } + return getIdentifier( builder.toString(), name.isQuoted(), jdbcEnvironment ); + } + + /** + * Get an identifier for the specified details. By default this method will return an identifier + * with the name adapted based on the result of {@link #isCaseInsensitive(JdbcEnvironment)} + * + * @param name the name of the identifier + * @param quoted if the identifier is quoted + * @param jdbcEnvironment the JDBC environment + * + * @return an identifier instance + */ + protected Identifier getIdentifier(String name, final boolean quoted, final JdbcEnvironment jdbcEnvironment) { + if ( isCaseInsensitive( jdbcEnvironment ) ) { + name = name.toLowerCase( Locale.ROOT ); + } + return new Identifier( name, quoted ); + } + + /** + * Specify whether the database is case sensitive. + * + * @param jdbcEnvironment the JDBC environment which can be used to determine case + * + * @return true if the database is case insensitive sensitivity + */ + protected boolean isCaseInsensitive(JdbcEnvironment jdbcEnvironment) { + return true; + } + + private boolean isUnderscoreRequired(final char before, final char current, final char after) { + return Character.isLowerCase( before ) && Character.isUpperCase( current ) && Character.isLowerCase( after ); + } + +} From 8dcf6f983b18d1f5d6a6cc3d66b0f7cb84d2d935 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Sun, 16 May 2021 09:33:56 +0200 Subject: [PATCH 243/644] HHH-14608 Add test for issue --- .../jpa/test/ops/MergeJpaComplianceTest.java | 211 ++++++++++++++++++ 1 file changed, 211 insertions(+) create mode 100644 hibernate-core/src/test/java/org/hibernate/jpa/test/ops/MergeJpaComplianceTest.java diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/ops/MergeJpaComplianceTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/ops/MergeJpaComplianceTest.java new file mode 100644 index 000000000000..1da7fd553494 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/ops/MergeJpaComplianceTest.java @@ -0,0 +1,211 @@ +package org.hibernate.jpa.test.ops; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import javax.persistence.CascadeType; +import javax.persistence.Embeddable; +import javax.persistence.EmbeddedId; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; + +import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; + +import org.hibernate.testing.TestForIssue; +import org.junit.Test; + +import static org.hibernate.testing.transaction.TransactionUtil2.fromTransaction; +import static org.hibernate.testing.transaction.TransactionUtil2.inTransaction; + +@TestForIssue( jiraKey = "HHH-14608") +public class MergeJpaComplianceTest extends BaseEntityManagerFunctionalTestCase { + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + Person.class, Occupation.class, PersonOccupation.class + }; + } + + @Override + protected void addConfigOptions(Map config) { + config.put( org.hibernate.cfg.AvailableSettings.JPA_PROXY_COMPLIANCE, true ); + } + + @Test + public void testMerge() { + Person person = fromTransaction( + entityManagerFactory(), + entityManager -> { + Person p; + p = new Person( "1", "Fab" ); + Occupation t = new Occupation( 1l, "Some work" ); + + entityManager.persist( p ); + entityManager.persist( t ); + + entityManager.flush(); + + PersonOccupation participant = new PersonOccupation( p, t ); + entityManager.persist( participant ); + return p; + } + ); + + inTransaction( + entityManagerFactory(), + entityManager -> { + person.setName( "Fabiana" ); + entityManager.merge( person ); + } + ); + } + + @Entity(name = "Person") + public static class Person { + @Id + private String id; + + private String name; + + @OneToMany(mappedBy = "pk.person", cascade = CascadeType.ALL, orphanRemoval = true) + private List occupations; + + public Person() { + + } + + public Person(String id, String name) { + this.id = id; + this.name = name; + } + + protected void setName(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public List getOccupations() { + return occupations; + } + + protected void addOccupationPeoplet(PersonOccupation personOccupation) { + if ( this.occupations == null ) { + occupations = new ArrayList<>(); + } + this.occupations.add( personOccupation ); + personOccupation.getPk().setPerson( this ); + } + + protected void setOccupations(List occupations) { + this.occupations = occupations; + } + } + + @Entity(name = "Occupation") + public static class Occupation { + @Id + private long id; + + private String name; + + @OneToMany(mappedBy = "pk.occupation", cascade = CascadeType.ALL) + private List personOccupations; + + protected Occupation() { + } + + public Occupation(long id, String name) { + this.id = id; + this.name = name; + } + + public long getId() { + return id; + } + + protected void setId(long id) { + this.id = id; + } + + public String getName() { + return name; + } + + protected void setName(String name) { + this.name = name; + } + + public List getPersonOccupations() { + return personOccupations; + } + + protected void addPersonOccupation(PersonOccupation participant) { + if ( personOccupations == null ) { + personOccupations = new ArrayList<>(); + } + personOccupations.add( participant ); + participant.getPk().setOccupation( this ); + } + + protected void setPersonOccupations(List personOccupations) { + this.personOccupations = personOccupations; + } + } + + @Entity(name = "PersonOccupation") + public static class PersonOccupation { + @EmbeddedId + private PersonOccupationPK pk = new PersonOccupationPK(); + + protected PersonOccupation() { + } + + public PersonOccupation(Person person, Occupation occupation) { + person.addOccupationPeoplet( this ); + occupation.addPersonOccupation( this ); + } + + public PersonOccupationPK getPk() { + return pk; + } + + public void setPk(PersonOccupationPK pk) { + this.pk = pk; + } + } + + @Embeddable + public static class PersonOccupationPK implements Serializable { + + @ManyToOne(fetch = FetchType.LAZY) + private Person person; + + @ManyToOne(fetch = FetchType.LAZY) + private Occupation occupation; + + public Person getPerson() { + return person; + } + + public void setPerson(Person person) { + this.person = person; + } + + public Occupation getOccupation() { + return occupation; + } + + public void setOccupation(Occupation occupation) { + this.occupation = occupation; + } + } + +} From 8b02aaf5a8711446457665e96b69161b57026cea Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Sun, 16 May 2021 09:35:06 +0200 Subject: [PATCH 244/644] HHH-14608 Merge causes StackOverflow when JPA proxy compliance is enabled --- .../internal/StatefulPersistenceContext.java | 4 ++-- .../event/internal/DefaultEvictEventListener.java | 2 +- .../event/internal/DefaultMergeEventListener.java | 2 +- .../java/org/hibernate/internal/SessionImpl.java | 4 ++-- .../jpa/internal/PersistenceUnitUtilImpl.java | 2 +- .../hibernate/proxy/AbstractLazyInitializer.java | 15 ++++++++++----- .../java/org/hibernate/proxy/LazyInitializer.java | 11 +++++++++++ .../java/org/hibernate/proxy/map/MapProxy.java | 2 +- .../pojo/bytebuddy/ByteBuddyInterceptor.java | 2 +- .../pojo/javassist/JavassistLazyInitializer.java | 2 +- .../tuple/entity/AbstractEntityTuplizer.java | 4 ++-- .../main/java/org/hibernate/type/EntityType.java | 8 ++++---- .../envers/event/spi/BaseEnversEventListener.java | 2 +- .../internal/entities/EntityInstantiator.java | 2 +- .../entities/mapper/id/SingleIdMapper.java | 4 ++-- .../mapper/id/VirtualEntitySingleIdMapper.java | 2 +- .../envers/internal/tools/EntityTools.java | 4 ++-- .../internal/impl/RevisionsOfEntityQuery.java | 2 +- .../test/integration/proxy/ProxyIdentifier.java | 4 ++-- 19 files changed, 47 insertions(+), 31 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/StatefulPersistenceContext.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/StatefulPersistenceContext.java index 16e71d913c0a..3582c42b77d4 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/internal/StatefulPersistenceContext.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/StatefulPersistenceContext.java @@ -639,7 +639,7 @@ public void reassociateProxy(Object value, Serializable id) throws MappingExcept private void reassociateProxy(LazyInitializer li, HibernateProxy proxy) { if ( li.getSession() != this.getSession() ) { final EntityPersister persister = session.getFactory().getMetamodel().entityPersister( li.getEntityName() ); - final EntityKey key = session.generateEntityKey( li.getIdentifier(), persister ); + final EntityKey key = session.generateEntityKey( li.getInternalIdentifier(), persister ); // any earlier proxy takes precedence getOrInitializeProxiesByKey().putIfAbsent( key, proxy ); proxy.getHibernateLazyInitializer().setSession( session ); @@ -1348,7 +1348,7 @@ && isFoundInParent( propertyName, childEntity, persister, collectionPersister, p ); } if ( found ) { - return proxy.getHibernateLazyInitializer().getIdentifier(); + return proxy.getHibernateLazyInitializer().getInternalIdentifier(); } } } diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultEvictEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultEvictEventListener.java index b14df64aec80..0ef2f2fc3f33 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultEvictEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultEvictEventListener.java @@ -54,7 +54,7 @@ public void onEvict(EvictEvent event) throws HibernateException { if ( object instanceof HibernateProxy ) { final LazyInitializer li = ( (HibernateProxy) object ).getHibernateLazyInitializer(); - final Serializable id = li.getIdentifier(); + final Serializable id = li.getInternalIdentifier(); if ( id == null ) { throw new IllegalArgumentException( "Could not determine identifier of proxy passed to evict()" ); } diff --git a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultMergeEventListener.java b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultMergeEventListener.java index 66902cad0c74..06d384b36114 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultMergeEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/event/internal/DefaultMergeEventListener.java @@ -103,7 +103,7 @@ public void onMerge(MergeEvent event, Map copiedAlready) throws HibernateExcepti LazyInitializer li = ( (HibernateProxy) original ).getHibernateLazyInitializer(); if ( li.isUninitialized() ) { LOG.trace( "Ignoring uninitialized proxy" ); - event.setResult( source.load( li.getEntityName(), li.getIdentifier() ) ); + event.setResult( source.load( li.getEntityName(), li.getInternalIdentifier() ) ); //EARLY EXIT! return; } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java index 6dbb43f3e6c3..10d9719bcb55 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java @@ -1666,7 +1666,7 @@ public Serializable getIdentifier(Object object) throws HibernateException { if ( li.getSession() != this ) { throw new TransientObjectException( "The proxy was not associated with this session" ); } - return li.getIdentifier(); + return li.getInternalIdentifier(); } else { EntityEntry entry = persistenceContext.getEntry( object ); @@ -1694,7 +1694,7 @@ public Serializable getContextEntityIdentifier(Object object) { } private Serializable getProxyIdentifier(Object proxy) { - return ( (HibernateProxy) proxy ).getHibernateLazyInitializer().getIdentifier(); + return ( (HibernateProxy) proxy ).getHibernateLazyInitializer().getInternalIdentifier(); } private FilterQueryPlan getFilterQueryPlan( diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/internal/PersistenceUnitUtilImpl.java b/hibernate-core/src/main/java/org/hibernate/jpa/internal/PersistenceUnitUtilImpl.java index a39f57e52a67..7d26f631be4c 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/internal/PersistenceUnitUtilImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/internal/PersistenceUnitUtilImpl.java @@ -68,7 +68,7 @@ public Object getIdentifier(Object entity) { } if ( entity instanceof HibernateProxy ) { - return ((HibernateProxy) entity).getHibernateLazyInitializer().getIdentifier(); + return ((HibernateProxy) entity).getHibernateLazyInitializer().getInternalIdentifier(); } else if ( entity instanceof ManagedEntity ) { EntityEntry entityEntry = ((ManagedEntity) entity).$$_hibernate_getEntityEntry(); diff --git a/hibernate-core/src/main/java/org/hibernate/proxy/AbstractLazyInitializer.java b/hibernate-core/src/main/java/org/hibernate/proxy/AbstractLazyInitializer.java index 9d481a2d71f9..f7780c2457fd 100644 --- a/hibernate-core/src/main/java/org/hibernate/proxy/AbstractLazyInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/proxy/AbstractLazyInitializer.java @@ -84,6 +84,11 @@ public final String getEntityName() { return entityName; } + @Override + public final Serializable getInternalIdentifier() { + return id; + } + @Override public final Serializable getIdentifier() { if ( isUninitialized() && isInitializeProxyWhenAccessingIdentifier() ) { @@ -93,7 +98,7 @@ public final Serializable getIdentifier() { } private boolean isInitializeProxyWhenAccessingIdentifier() { - return session != null && session.getFactory() + return getSession() != null && getSession().getFactory() .getSessionFactoryOptions() .getJpaCompliance().isJpaProxyComplianceEnabled(); } @@ -260,7 +265,7 @@ else if ( session.isOpenOrWaitingForAutoClose() && session.isConnected() ) { public final void initializeWithoutLoadIfPossible() { if ( !initialized && session != null && session.isOpenOrWaitingForAutoClose() ) { final EntityKey key = session.generateEntityKey( - getIdentifier(), + getInternalIdentifier(), session.getFactory().getMetamodel().entityPersister( getEntityName() ) ); final Object entity = session.getPersistenceContextInternal().getEntity( key ); @@ -305,7 +310,7 @@ protected final boolean isConnectedToSession() { } private Object getProxyOrNull() { - final EntityKey entityKey = generateEntityKeyOrNull( getIdentifier(), session, getEntityName() ); + final EntityKey entityKey = generateEntityKeyOrNull( getInternalIdentifier(), session, getEntityName() ); if ( entityKey != null && session != null && session.isOpenOrWaitingForAutoClose() ) { return session.getPersistenceContextInternal().getProxy( entityKey ); } @@ -326,7 +331,7 @@ public final void setImplementation(Object target) { @Override public final Object getImplementation(SharedSessionContractImplementor s) throws HibernateException { - final EntityKey entityKey = generateEntityKeyOrNull( getIdentifier(), s, getEntityName() ); + final EntityKey entityKey = generateEntityKeyOrNull( getInternalIdentifier(), s, getEntityName() ); return ( entityKey == null ? null : s.getPersistenceContext().getEntity( entityKey ) ); } @@ -376,7 +381,7 @@ public final void setReadOnly(boolean readOnly) { } this.readOnly = readOnly; if ( initialized ) { - EntityKey key = generateEntityKeyOrNull( getIdentifier(), session, getEntityName() ); + EntityKey key = generateEntityKeyOrNull( getInternalIdentifier(), session, getEntityName() ); final PersistenceContext persistenceContext = session.getPersistenceContext(); if ( key != null && persistenceContext.containsEntity( key ) ) { persistenceContext.setReadOnly( target, readOnly ); diff --git a/hibernate-core/src/main/java/org/hibernate/proxy/LazyInitializer.java b/hibernate-core/src/main/java/org/hibernate/proxy/LazyInitializer.java index 36efc4074698..1faefd115356 100644 --- a/hibernate-core/src/main/java/org/hibernate/proxy/LazyInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/proxy/LazyInitializer.java @@ -30,6 +30,17 @@ public interface LazyInitializer { * * @return The identifier value. */ + default Serializable getInternalIdentifier() { + return getIdentifier(); + } + + /** + * Retrieve the identifier value for the entity our owning proxy represents. + * + * When JPA proxy compliance is enabled the proxy is initialized. + * + * @return The identifier value. + */ Serializable getIdentifier(); /** diff --git a/hibernate-core/src/main/java/org/hibernate/proxy/map/MapProxy.java b/hibernate-core/src/main/java/org/hibernate/proxy/map/MapProxy.java index de6e2a2eb48a..448f5c9b2ae3 100644 --- a/hibernate-core/src/main/java/org/hibernate/proxy/map/MapProxy.java +++ b/hibernate-core/src/main/java/org/hibernate/proxy/map/MapProxy.java @@ -116,7 +116,7 @@ public Object writeReplace() { private Object serializableProxy() { return new SerializableMapProxy( li.getEntityName(), - li.getIdentifier(), + li.getInternalIdentifier(), ( li.isReadOnlySettingAvailable() ? Boolean.valueOf( li.isReadOnly() ) : li.isReadOnlyBeforeAttachedToSession() ), li.getSessionFactoryUuid(), li.isAllowLoadOutsideTransaction() diff --git a/hibernate-core/src/main/java/org/hibernate/proxy/pojo/bytebuddy/ByteBuddyInterceptor.java b/hibernate-core/src/main/java/org/hibernate/proxy/pojo/bytebuddy/ByteBuddyInterceptor.java index 744761d6e5d8..21a273327e7f 100644 --- a/hibernate-core/src/main/java/org/hibernate/proxy/pojo/bytebuddy/ByteBuddyInterceptor.java +++ b/hibernate-core/src/main/java/org/hibernate/proxy/pojo/bytebuddy/ByteBuddyInterceptor.java @@ -85,7 +85,7 @@ protected Object serializableProxy() { getEntityName(), persistentClass, interfaces, - getIdentifier(), + getInternalIdentifier(), ( isReadOnlySettingAvailable() ? Boolean.valueOf( isReadOnly() ) : isReadOnlyBeforeAttachedToSession() ), getSessionFactoryUuid(), isAllowLoadOutsideTransaction(), diff --git a/hibernate-core/src/main/java/org/hibernate/proxy/pojo/javassist/JavassistLazyInitializer.java b/hibernate-core/src/main/java/org/hibernate/proxy/pojo/javassist/JavassistLazyInitializer.java index ce460ed151d1..61b15f09a3e6 100644 --- a/hibernate-core/src/main/java/org/hibernate/proxy/pojo/javassist/JavassistLazyInitializer.java +++ b/hibernate-core/src/main/java/org/hibernate/proxy/pojo/javassist/JavassistLazyInitializer.java @@ -123,7 +123,7 @@ protected Object serializableProxy() { getEntityName(), persistentClass, interfaces, - getIdentifier(), + getInternalIdentifier(), ( isReadOnlySettingAvailable() ? Boolean.valueOf( isReadOnly() ) : isReadOnlyBeforeAttachedToSession() ), getSessionFactoryUuid(), isAllowLoadOutsideTransaction(), diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/AbstractEntityTuplizer.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/AbstractEntityTuplizer.java index 07e6e714347c..3d4ea08a4716 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/entity/AbstractEntityTuplizer.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/entity/AbstractEntityTuplizer.java @@ -215,7 +215,7 @@ public Serializable getIdentifier(Object entity, SharedSessionContractImplemento id = entity; } else if ( HibernateProxy.class.isInstance( entity ) ) { - id = ( (HibernateProxy) entity ).getHibernateLazyInitializer().getIdentifier(); + id = ( (HibernateProxy) entity ).getHibernateLazyInitializer().getInternalIdentifier(); } else { if ( idGetter == null ) { @@ -452,7 +452,7 @@ private static Serializable determineEntityId( if ( HibernateProxy.class.isInstance( entity ) ) { // entity is a proxy, so we know it is not transient; just return ID from proxy - return ( (HibernateProxy) entity ).getHibernateLazyInitializer().getIdentifier(); + return ( (HibernateProxy) entity ).getHibernateLazyInitializer().getInternalIdentifier(); } if ( session != null ) { diff --git a/hibernate-core/src/main/java/org/hibernate/type/EntityType.java b/hibernate-core/src/main/java/org/hibernate/type/EntityType.java index a1271c1acdd8..577134dc7851 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/EntityType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/EntityType.java @@ -369,7 +369,7 @@ public int getHashCode(Object x, SessionFactoryImplementor factory) { final Serializable id; if ( x instanceof HibernateProxy ) { - id = ( (HibernateProxy) x ).getHibernateLazyInitializer().getIdentifier(); + id = ( (HibernateProxy) x ).getHibernateLazyInitializer().getInternalIdentifier(); } else { final Class mappedClass = persister.getMappedClass(); @@ -399,7 +399,7 @@ public boolean isEqual(Object x, Object y, SessionFactoryImplementor factory) { Serializable xid; if ( x instanceof HibernateProxy ) { xid = ( (HibernateProxy) x ).getHibernateLazyInitializer() - .getIdentifier(); + .getInternalIdentifier(); } else { if ( mappedClass.isAssignableFrom( x.getClass() ) ) { @@ -414,7 +414,7 @@ public boolean isEqual(Object x, Object y, SessionFactoryImplementor factory) { Serializable yid; if ( y instanceof HibernateProxy ) { yid = ( (HibernateProxy) y ).getHibernateLazyInitializer() - .getIdentifier(); + .getInternalIdentifier(); } else { if ( mappedClass.isAssignableFrom( y.getClass() ) ) { @@ -558,7 +558,7 @@ public String toLoggableString(Object value, SessionFactoryImplementor factory) final Serializable id; if ( value instanceof HibernateProxy ) { HibernateProxy proxy = (HibernateProxy) value; - id = proxy.getHibernateLazyInitializer().getIdentifier(); + id = proxy.getHibernateLazyInitializer().getInternalIdentifier(); } else { id = persister.getIdentifier( value ); diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/event/spi/BaseEnversEventListener.java b/hibernate-envers/src/main/java/org/hibernate/envers/event/spi/BaseEnversEventListener.java index 38738660276a..abe537c5eeb7 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/event/spi/BaseEnversEventListener.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/event/spi/BaseEnversEventListener.java @@ -94,7 +94,7 @@ private void addCollectionChangeWorkUnit( if ( value instanceof HibernateProxy ) { final HibernateProxy hibernateProxy = (HibernateProxy) value; - id = hibernateProxy.getHibernateLazyInitializer().getIdentifier(); + id = hibernateProxy.getHibernateLazyInitializer().getInternalIdentifier(); // We've got to initialize the object from the proxy to later read its state. value = EntityTools.getTargetFromProxy( session.getFactory(), hibernateProxy ); // HHH-7249 diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/EntityInstantiator.java b/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/EntityInstantiator.java index 8a9915c4181a..07ecab6af5e6 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/EntityInstantiator.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/EntityInstantiator.java @@ -111,7 +111,7 @@ private void replaceNonAuditIdProxies(Map versionsEntity, Number revision) { final HibernateProxy hibernateProxy = (HibernateProxy) value; final LazyInitializer initializer = hibernateProxy.getHibernateLazyInitializer(); final String entityName = initializer.getEntityName(); - final Serializable entityId = initializer.getIdentifier(); + final Serializable entityId = initializer.getInternalIdentifier(); if ( enversService.getEntitiesConfigurations().isVersioned( entityName ) ) { final String entityClassName = enversService.getEntitiesConfigurations().get( entityName ).getEntityClassName(); final Class entityClass = ReflectionTools.loadClass( diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/id/SingleIdMapper.java b/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/id/SingleIdMapper.java index fd65a972b3e6..b7690a953b11 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/id/SingleIdMapper.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/id/SingleIdMapper.java @@ -88,7 +88,7 @@ public Object mapToIdFromEntity(final Object data) { if ( data instanceof HibernateProxy ) { final HibernateProxy hibernateProxy = (HibernateProxy) data; - return hibernateProxy.getHibernateLazyInitializer().getIdentifier(); + return hibernateProxy.getHibernateLazyInitializer().getInternalIdentifier(); } else { return AccessController.doPrivileged( @@ -122,7 +122,7 @@ public void mapToMapFromEntity(Map data, final Object obj) { else { if ( obj instanceof HibernateProxy ) { final HibernateProxy hibernateProxy = (HibernateProxy) obj; - data.put( propertyData.getName(), hibernateProxy.getHibernateLazyInitializer().getIdentifier() ); + data.put( propertyData.getName(), hibernateProxy.getHibernateLazyInitializer().getInternalIdentifier() ); } else { final Object value = AccessController.doPrivileged( diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/id/VirtualEntitySingleIdMapper.java b/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/id/VirtualEntitySingleIdMapper.java index 26ec6d35db1a..46de765f3a81 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/id/VirtualEntitySingleIdMapper.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/internal/entities/mapper/id/VirtualEntitySingleIdMapper.java @@ -155,7 +155,7 @@ public void mapToMapFromEntity(Map data, Object obj) { else { if ( obj instanceof HibernateProxy ) { final HibernateProxy proxy = (HibernateProxy) obj; - data.put( propertyData.getName(), proxy.getHibernateLazyInitializer().getIdentifier() ); + data.put( propertyData.getName(), proxy.getHibernateLazyInitializer().getInternalIdentifier() ); } else { final Object value = AccessController.doPrivileged( diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/internal/tools/EntityTools.java b/hibernate-envers/src/main/java/org/hibernate/envers/internal/tools/EntityTools.java index 22438cd16b84..5a287c17577b 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/internal/tools/EntityTools.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/internal/tools/EntityTools.java @@ -33,7 +33,7 @@ public static Object getIdentifier(SessionImplementor session, String entityName if ( obj instanceof HibernateProxy ) { final HibernateProxy hibernateProxy = (HibernateProxy) obj; - return hibernateProxy.getHibernateLazyInitializer().getIdentifier(); + return hibernateProxy.getHibernateLazyInitializer().getInternalIdentifier(); } return session.getEntityPersister( entityName, obj ).getIdentifier( obj, session ); @@ -51,7 +51,7 @@ public static Object getTargetFromProxy(SessionFactoryImplementor sessionFactory try { return tempSession.get( proxy.getHibernateLazyInitializer().getEntityName(), - proxy.getHibernateLazyInitializer().getIdentifier() + proxy.getHibernateLazyInitializer().getInternalIdentifier() ); } finally { diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/query/internal/impl/RevisionsOfEntityQuery.java b/hibernate-envers/src/main/java/org/hibernate/envers/query/internal/impl/RevisionsOfEntityQuery.java index 78f9f24dd67d..43d0a81fec7f 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/query/internal/impl/RevisionsOfEntityQuery.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/query/internal/impl/RevisionsOfEntityQuery.java @@ -80,7 +80,7 @@ private Number getRevisionNumber(Map versionsEntity) { Object revisionInfoObject = ( (Map) versionsEntity.get( originalId ) ).get( revisionPropertyName ); if ( revisionInfoObject instanceof HibernateProxy ) { - return (Number) ( (HibernateProxy) revisionInfoObject ).getHibernateLazyInitializer().getIdentifier(); + return (Number) ( (HibernateProxy) revisionInfoObject ).getHibernateLazyInitializer().getInternalIdentifier(); } else { // Not a proxy - must be read from cache or with a join diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/proxy/ProxyIdentifier.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/proxy/ProxyIdentifier.java index e7140fa88a26..5079e9e711ea 100644 --- a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/proxy/ProxyIdentifier.java +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/proxy/ProxyIdentifier.java @@ -114,8 +114,8 @@ public void testProxyIdentifier() { LazyInitializer lazyInitializer = proxyCreateByEnvers.getHibernateLazyInitializer(); Assert.assertTrue( lazyInitializer.isUninitialized() ); - Assert.assertNotNull( lazyInitializer.getIdentifier() ); - Assert.assertEquals( tnae1.getId(), lazyInitializer.getIdentifier() ); + Assert.assertNotNull( lazyInitializer.getInternalIdentifier() ); + Assert.assertEquals( tnae1.getId(), lazyInitializer.getInternalIdentifier() ); Assert.assertTrue( lazyInitializer.isUninitialized() ); Assert.assertEquals( uste1.getId(), rev1.getReference().getId() ); From 4a2d19a171067a08237d7915bd48efd5238c6955 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Thu, 15 Jul 2021 16:56:59 +0200 Subject: [PATCH 245/644] HHH-14730 Test lazy loading of bytecode-enhancement proxy triggered by loading of a collection with eager references to that proxy --- .../collectioninitializer/Company.java | 25 +++ .../collectioninitializer/CostCenter.java | 39 ++++ ...ollectionInitializationAllowProxyTest.java | 191 ++++++++++++++++++ .../collectioninitializer/Offer.java | 39 ++++ .../lazytoone/collectioninitializer/User.java | 43 ++++ .../UserAuthorization.java | 49 +++++ 6 files changed, 386 insertions(+) create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/collectioninitializer/Company.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/collectioninitializer/CostCenter.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/collectioninitializer/InitLazyToOneWithinPaddedCollectionInitializationAllowProxyTest.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/collectioninitializer/Offer.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/collectioninitializer/User.java create mode 100644 hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/collectioninitializer/UserAuthorization.java diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/collectioninitializer/Company.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/collectioninitializer/Company.java new file mode 100644 index 000000000000..533f9251b258 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/collectioninitializer/Company.java @@ -0,0 +1,25 @@ +package org.hibernate.orm.test.mapping.lazytoone.collectioninitializer; + +import javax.persistence.Entity; +import javax.persistence.Id; + +@Entity +public class Company { + @Id + private Long id; + + @Override + public String toString() { + return "Company{" + + "id=" + id + + '}'; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/collectioninitializer/CostCenter.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/collectioninitializer/CostCenter.java new file mode 100644 index 000000000000..c47eccf766e0 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/collectioninitializer/CostCenter.java @@ -0,0 +1,39 @@ +package org.hibernate.orm.test.mapping.lazytoone.collectioninitializer; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.ManyToOne; + +@Entity +public class CostCenter { + @Id + private Long id; + + @ManyToOne(optional = false) + private Company company; + + @Override + public String toString() { + return "CostCenter{" + + "id=" + id + + ", company=" + company + + '}'; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Company getCompany() { + return company; + } + + public void setCompany(Company company) { + this.company = company; + } + +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/collectioninitializer/InitLazyToOneWithinPaddedCollectionInitializationAllowProxyTest.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/collectioninitializer/InitLazyToOneWithinPaddedCollectionInitializationAllowProxyTest.java new file mode 100644 index 000000000000..689bb21f8163 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/collectioninitializer/InitLazyToOneWithinPaddedCollectionInitializationAllowProxyTest.java @@ -0,0 +1,191 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.orm.test.mapping.lazytoone.collectioninitializer; + +import org.hibernate.Hibernate; +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.engine.spi.SessionFactoryImplementor; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; +import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hibernate.loader.BatchFetchStyle.PADDED; + +/** + * Test lazy-to-one initialization within a collection initialization, + * with the PADDED batch-fetch-style. + *

    + * In particular, with Offer having a lazy to-one association to CostCenter, + * and User having a lazy to-many association to UserAuthorization1 and UserAuthorization2, + * and UserAuthorization1 and UserAuthorization2 having an EAGER association to CostCenter, + * test: + *

      + *
    • Get a reference to Offer (which will create an uninitialized proxy for CostCenter)
    • + *
    • Get a reference to User
    • + *
    • Initialize User's collection containing UserAuthorization1 and UserAuthorization2, + * which will initialize CostCenter DURING the loading, + * which used to fail because we tried to initialize CostCenter twice + * (once for UserAuthorization1, and once for UserAuthorization2)
    • + *
    + */ +@RunWith(BytecodeEnhancerRunner.class) +@TestForIssue(jiraKey = "HHH-14730") +public class InitLazyToOneWithinPaddedCollectionInitializationAllowProxyTest + extends BaseNonConfigCoreFunctionalTestCase { + + @Override + protected void applyMetadataSources(MetadataSources sources) { + super.applyMetadataSources( sources ); + sources.addAnnotatedClass( User.class ); + sources.addAnnotatedClass( UserAuthorization.class ); + sources.addAnnotatedClass( Company.class ); + sources.addAnnotatedClass( CostCenter.class ); + sources.addAnnotatedClass( Offer.class ); + } + + @Override + protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { + super.configureStandardServiceRegistryBuilder( ssrb ); + ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, true ); + ssrb.applySetting( AvailableSettings.BATCH_FETCH_STYLE, PADDED ); + ssrb.applySetting( AvailableSettings.DEFAULT_BATCH_FETCH_SIZE, 10 ); + } + + @Override + protected void afterSessionFactoryBuilt(SessionFactoryImplementor sessionFactory) { + inTransaction( session -> { + User user0 = new User(); + user0.setId( 0L ); + session.persist( user0 ); + + User user1 = new User(); + user1.setId( 1L ); + session.persist( user1 ); + + User user2 = new User(); + user2.setId( 2L ); + session.persist( user2 ); + + Company company = new Company(); + company.setId( 2L ); + session.persist( company ); + + CostCenter costCenter = new CostCenter(); + costCenter.setId( 3L ); + costCenter.setCompany( company ); + session.persist( costCenter ); + + UserAuthorization user0Authorization1 = new UserAuthorization(); + user0Authorization1.setId( 1L ); + user0Authorization1.setUser( user0 ); + user0Authorization1.setCostCenter( costCenter ); + session.persist( user0Authorization1 ); + + UserAuthorization user1Authorization1 = new UserAuthorization(); + user1Authorization1.setId( 11L ); + user1Authorization1.setUser( user1 ); + user1Authorization1.setCostCenter( costCenter ); + session.persist( user1Authorization1 ); + + UserAuthorization user1Authorization2 = new UserAuthorization(); + user1Authorization2.setId( 12L ); + user1Authorization2.setUser( user1 ); + user1Authorization2.setCostCenter( costCenter ); + session.persist( user1Authorization2 ); + + UserAuthorization user2Authorization1 = new UserAuthorization(); + user2Authorization1.setId( 21L ); + user2Authorization1.setUser( user2 ); + user2Authorization1.setCostCenter( costCenter ); + session.persist( user2Authorization1 ); + + UserAuthorization user2Authorization2 = new UserAuthorization(); + user2Authorization2.setId( 22L ); + user2Authorization2.setUser( user2 ); + user2Authorization2.setCostCenter( costCenter ); + session.persist( user2Authorization2 ); + + UserAuthorization user2Authorization3 = new UserAuthorization(); + user2Authorization3.setId( 23L ); + user2Authorization3.setUser( user2 ); + user2Authorization3.setCostCenter( costCenter ); + session.persist( user2Authorization3 ); + + Offer offer = new Offer(); + offer.setId( 6L ); + offer.setCostCenter( costCenter ); + session.persist( offer ); + } ); + } + + @Test + public void testOneReference() { + inTransaction( (session) -> { + // Add a lazy proxy of the cost center to the persistence context + // through the lazy to-one association from the offer. + Offer offer = session.find( Offer.class, 6L ); + + User user = session.find( User.class, 0L ); + + assertThat( Hibernate.isInitialized( offer.getCostCenter() ) ).isFalse(); + + // Trigger lazy-loading of the cost center + // through the loading of the authorization, + // which contains an eager reference to the cost center. + assertThat( user.getAuthorizations().size() ).isEqualTo( 1 ); + + assertThat( Hibernate.isInitialized( offer.getCostCenter() ) ).isTrue(); + } ); + } + + @Test + public void testTwoReferences() { + inTransaction( (session) -> { + // Add a lazy proxy of the cost center to the persistence context + // through the lazy to-one association from the offer. + Offer offer = session.find( Offer.class, 6L ); + + User user = session.find( User.class, 1L ); + + assertThat( Hibernate.isInitialized( offer.getCostCenter() ) ).isFalse(); + + // Trigger lazy-loading of the cost center + // through the loading of the 2 authorizations, + // which both contain an eager reference to the cost center. + assertThat( user.getAuthorizations().size() ).isEqualTo( 2 ); + + assertThat( Hibernate.isInitialized( offer.getCostCenter() ) ).isTrue(); + } ); + } + + @Test + public void testThreeReferences() { + inTransaction( (session) -> { + // Add a lazy proxy of the cost center to the persistence context + // through the lazy to-one association from the offer. + Offer offer = session.find( Offer.class, 6L ); + + User user = session.find( User.class, 2L ); + + assertThat( Hibernate.isInitialized( offer.getCostCenter() ) ).isFalse(); + + // Trigger lazy-loading of the cost center + // through the loading of the 3 authorizations, + // which all contain an eager reference to the cost center. + assertThat( user.getAuthorizations().size() ).isEqualTo( 3 ); + + assertThat( Hibernate.isInitialized( offer.getCostCenter() ) ).isTrue(); + } ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/collectioninitializer/Offer.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/collectioninitializer/Offer.java new file mode 100644 index 000000000000..676d77305bb3 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/collectioninitializer/Offer.java @@ -0,0 +1,39 @@ +package org.hibernate.orm.test.mapping.lazytoone.collectioninitializer; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.ManyToOne; + +import static javax.persistence.FetchType.LAZY; + +@Entity +public class Offer { + @Id + private Long id; + + @ManyToOne(fetch = LAZY, optional = false) + private CostCenter costCenter; + + @Override + public String toString() { + return "Offer{" + + "id=" + getId() + + '}'; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public CostCenter getCostCenter() { + return costCenter; + } + + public void setCostCenter(CostCenter costCenter) { + this.costCenter = costCenter; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/collectioninitializer/User.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/collectioninitializer/User.java new file mode 100644 index 000000000000..20fdaa966187 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/collectioninitializer/User.java @@ -0,0 +1,43 @@ +package org.hibernate.orm.test.mapping.lazytoone.collectioninitializer; + +import java.util.ArrayList; +import java.util.List; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.OneToMany; +import javax.persistence.Table; + +import static javax.persistence.CascadeType.ALL; + +@Entity +@Table(name = "users") +public class User { + @Id + private Long id; + + @OneToMany(mappedBy = "user", cascade = ALL, orphanRemoval = true) + private List authorizations = new ArrayList<>(); + + @Override + public String toString() { + return "User{" + + "id='" + getId() + '\'' + + '}'; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public List getAuthorizations() { + return authorizations; + } + + public void setAuthorizations(List authorizations) { + this.authorizations = authorizations; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/collectioninitializer/UserAuthorization.java b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/collectioninitializer/UserAuthorization.java new file mode 100644 index 000000000000..5386fa65ab78 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/mapping/lazytoone/collectioninitializer/UserAuthorization.java @@ -0,0 +1,49 @@ +package org.hibernate.orm.test.mapping.lazytoone.collectioninitializer; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.ManyToOne; + +@Entity +public class UserAuthorization { + @Id + private Long id; + + @ManyToOne(optional = false) + private User user; + + @ManyToOne(optional = false) + private CostCenter costCenter; + + @Override + public String toString() { + return "UserAuthorization{" + + "id='" + getId() + '\'' + + '}'; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public User getUser() { + return user; + } + + public void setUser(User user) { + this.user = user; + } + + public CostCenter getCostCenter() { + return costCenter; + } + + public void setCostCenter(CostCenter costCenter) { + this.costCenter = costCenter; + } + +} From 0a16e341c9e4b64d703e89b500a0cab115b4d8d0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Thu, 15 Jul 2021 18:19:16 +0200 Subject: [PATCH 246/644] HHH-14730 Avoid loading the same entity proxy twice for the same result set --- .../java/org/hibernate/loader/Loader.java | 42 +++++++++++-------- 1 file changed, 24 insertions(+), 18 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/loader/Loader.java b/hibernate-core/src/main/java/org/hibernate/loader/Loader.java index 2adef4848117..e00d06e3b36b 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/Loader.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/Loader.java @@ -60,6 +60,7 @@ import org.hibernate.engine.spi.RowSelection; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.engine.spi.Status; import org.hibernate.engine.spi.SubselectFetch; import org.hibernate.engine.spi.TypedValue; import org.hibernate.event.spi.EventSource; @@ -1669,24 +1670,29 @@ protected void instanceAlreadyLoaded( // perform the hydration just as if it were "not yet loaded" final PersistentAttributeInterceptor interceptor = ( (PersistentAttributeInterceptable) object ).$$_hibernate_getInterceptor(); if ( interceptor instanceof EnhancementAsProxyLazinessInterceptor ) { - hydrateEntityState( - rs, - i, - persister, - getEntityAliases()[i].getRowIdAlias(), - key, - hydratedObjects, - session, - getInstanceClass( - rs, - i, - persister, - key.getIdentifier(), - session - ), - object, - requestedLockMode - ); + EntityEntry entry = session.getPersistenceContextInternal().getEntry( object ); + // Avoid loading the same entity proxy twice for the same result set: it could lead to errors, + // because some code writes to its input (ID in hydrated state replaced by the loaded entity, in particular). + if ( entry != null && entry.getStatus() != Status.LOADING ) { + hydrateEntityState( + rs, + i, + persister, + getEntityAliases()[i].getRowIdAlias(), + key, + hydratedObjects, + session, + getInstanceClass( + rs, + i, + persister, + key.getIdentifier(), + session + ), + object, + requestedLockMode + ); + } // EARLY EXIT!!! // - to skip the version check From e4199decb5852a8de58a1d71f1510d6894877f27 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Mon, 5 Jul 2021 15:29:43 +0200 Subject: [PATCH 247/644] HHH-14707 Upgrade to Byte Buddy 1.11.8 --- gradle/java-module.gradle | 4 ++-- gradle/libraries.gradle | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/gradle/java-module.gradle b/gradle/java-module.gradle index 582c5078d8b2..d8d7a1586bb3 100644 --- a/gradle/java-module.gradle +++ b/gradle/java-module.gradle @@ -294,9 +294,9 @@ test { jvmArgs '-XX:+StartAttachListener' } -// Enable the experimental features of ByteBuddy with JDK 18+ +// Enable the experimental features of ByteBuddy with JDK 19+ test { - if ( gradle.ext.javaVersions.test.release.asInt() >= 18 ) { + if ( gradle.ext.javaVersions.test.release.asInt() >= 19 ) { logger.warn( "The version of Java bytecode that will be tested is not supported by Bytebuddy by default. " + " Setting 'net.bytebuddy.experimental=true'." ) systemProperty 'net.bytebuddy.experimental', true diff --git a/gradle/libraries.gradle b/gradle/libraries.gradle index 33d9a7dfddf7..c6a0121320bc 100644 --- a/gradle/libraries.gradle +++ b/gradle/libraries.gradle @@ -25,7 +25,7 @@ ext { jakartaWeldVersion = '4.0.1.SP1' javassistVersion = '3.27.0-GA' - byteBuddyVersion = '1.10.22' + byteBuddyVersion = '1.11.8' agroalVersion = '1.9' From 5616284a12fd53f06d336c2d75f851d8dcacfd8f Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Tue, 13 Jul 2021 16:36:39 +0100 Subject: [PATCH 248/644] HHH-14727 Minor code cleanup in StandardSQLExceptionConverter --- .../internal/StandardSQLExceptionConverter.java | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/exception/internal/StandardSQLExceptionConverter.java b/hibernate-core/src/main/java/org/hibernate/exception/internal/StandardSQLExceptionConverter.java index 855305bb9ec9..175835d992e7 100644 --- a/hibernate-core/src/main/java/org/hibernate/exception/internal/StandardSQLExceptionConverter.java +++ b/hibernate-core/src/main/java/org/hibernate/exception/internal/StandardSQLExceptionConverter.java @@ -19,21 +19,14 @@ * @author Steve Ebersole */ public class StandardSQLExceptionConverter implements SQLExceptionConverter { - private ArrayList delegates = new ArrayList(); - public StandardSQLExceptionConverter() { - } + private final ArrayList delegates = new ArrayList(4); - public StandardSQLExceptionConverter(SQLExceptionConversionDelegate... delegates) { - if ( delegates != null ) { - this.delegates.addAll( Arrays.asList( delegates ) ); - } + public StandardSQLExceptionConverter() { } public void addDelegate(SQLExceptionConversionDelegate delegate) { - if ( delegate != null ) { - this.delegates.add( delegate ); - } + this.delegates.add( delegate ); } @Override From 0768663895803b8b93aaf27eab4092c7efd36e3b Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Fri, 25 Jun 2021 14:27:32 +0100 Subject: [PATCH 249/644] HHH-14731 Simplify SPI ProxyFactoryFactory#buildBasicProxyFactory to accept a single class or interface only And deprecate method org.hibernate.bytecode.spi.ProxyFactoryFactory#buildBasicProxyFactory(java.lang.Class, java.lang.Class[]) --- .../bytebuddy/BasicProxyFactoryImpl.java | 25 +++++++------------ .../bytebuddy/ProxyFactoryFactoryImpl.java | 23 ++++++++++++++++- .../javassist/ProxyFactoryFactoryImpl.java | 13 ++++++++++ .../internal/none/NoProxyFactoryFactory.java | 5 ++++ .../internal/none/NoneBasicProxyFactory.java | 25 +++++++++++++------ .../bytecode/spi/ProxyFactoryFactory.java | 19 ++++++++++++++ .../component/PojoComponentTuplizer.java | 10 ++------ .../ByteBuddyBasicProxyFactoryTest.java | 2 +- .../bytebuddy/GenerateProxiesTest.java | 2 +- 9 files changed, 90 insertions(+), 34 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/bytebuddy/BasicProxyFactoryImpl.java b/hibernate-core/src/main/java/org/hibernate/bytecode/internal/bytebuddy/BasicProxyFactoryImpl.java index a2004408e57c..a72db37666f5 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/bytebuddy/BasicProxyFactoryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/internal/bytebuddy/BasicProxyFactoryImpl.java @@ -32,18 +32,22 @@ public class BasicProxyFactoryImpl implements BasicProxyFactory { private final Constructor proxyClassConstructor; @SuppressWarnings({ "unchecked", "rawtypes" }) - public BasicProxyFactoryImpl(Class superClass, Class[] interfaces, ByteBuddyState byteBuddyState) { - if ( superClass == null && ( interfaces == null || interfaces.length < 1 ) ) { + public BasicProxyFactoryImpl(final Class superClass, final Class interfaceClass, final ByteBuddyState byteBuddyState) { + if ( superClass == null && interfaceClass == null ) { throw new AssertionFailure( "attempting to build proxy without any superclass or interfaces" ); } + if ( superClass != null && interfaceClass != null ) { + //TODO cleanup this case + throw new AssertionFailure( "Ambiguous call: we assume invocation with EITHER a superClass OR an interfaceClass" ); + } - final Class superClassOrMainInterface = superClass != null ? superClass : interfaces[0]; - final TypeCache.SimpleKey cacheKey = getCacheKey( superClass, interfaces ); + final Class superClassOrMainInterface = superClass != null ? superClass : interfaceClass; + final TypeCache.SimpleKey cacheKey = new TypeCache.SimpleKey( superClassOrMainInterface ); this.proxyClass = byteBuddyState.loadBasicProxy( superClassOrMainInterface, cacheKey, byteBuddy -> byteBuddy .with( new NamingStrategy.SuffixingRandom( PROXY_NAMING_SUFFIX, new NamingStrategy.SuffixingRandom.BaseNameResolver.ForFixedValue( superClassOrMainInterface.getName() ) ) ) .subclass( superClass == null ? Object.class : superClass, ConstructorStrategy.Default.DEFAULT_CONSTRUCTOR ) - .implement( interfaces == null ? NO_INTERFACES : interfaces ) + .implement( interfaceClass == null ? NO_INTERFACES : new Class[]{ interfaceClass } ) .defineField( ProxyConfiguration.INTERCEPTOR_FIELD_NAME, ProxyConfiguration.Interceptor.class, Visibility.PRIVATE ) .method( byteBuddyState.getProxyDefinitionHelpers().getVirtualNotFinalizerFilter() ) .intercept( byteBuddyState.getProxyDefinitionHelpers().getDelegateToInterceptorDispatcherMethodDelegation() ) @@ -75,15 +79,4 @@ public boolean isInstance(Object object) { return proxyClass.isInstance( object ); } - private TypeCache.SimpleKey getCacheKey(Class superClass, Class[] interfaces) { - Set> key = new HashSet>(); - if ( superClass != null ) { - key.add( superClass ); - } - if ( interfaces != null ) { - key.addAll( Arrays.>asList( interfaces ) ); - } - - return new TypeCache.SimpleKey( key ); - } } diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/bytebuddy/ProxyFactoryFactoryImpl.java b/hibernate-core/src/main/java/org/hibernate/bytecode/internal/bytebuddy/ProxyFactoryFactoryImpl.java index 0f68aead89c6..6f05d8a00f3e 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/bytebuddy/ProxyFactoryFactoryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/internal/bytebuddy/ProxyFactoryFactoryImpl.java @@ -6,6 +6,7 @@ */ package org.hibernate.bytecode.internal.bytebuddy; +import org.hibernate.AssertionFailure; import org.hibernate.bytecode.spi.BasicProxyFactory; import org.hibernate.bytecode.spi.ProxyFactoryFactory; import org.hibernate.engine.spi.SessionFactoryImplementor; @@ -30,7 +31,27 @@ public ProxyFactory buildProxyFactory(SessionFactoryImplementor sessionFactory) } @Override + @Deprecated public BasicProxyFactory buildBasicProxyFactory(Class superClass, Class[] interfaces) { - return new BasicProxyFactoryImpl( superClass, interfaces, byteBuddyState ); + if ( superClass == null && ( interfaces == null || interfaces.length == 0 ) ) { + throw new AssertionFailure( "Attempting to build proxy without any superclass or interfaces" ); + } + if ( superClass != null && ( interfaces != null && interfaces.length > 0 ) ) { + throw new AssertionFailure( "Ambiguous call: this method can only be invoked with either a superClass or interfaces, not both" ); + } + if ( interfaces != null && interfaces.length > 1 ) { + throw new AssertionFailure( "Ambiguous call: this method can only accept a single interfaces, not multiple in the array (legacy expectation)" ); + } + return buildBasicProxyFactory( superClass == null ? interfaces[0] : superClass ); } + + public BasicProxyFactory buildBasicProxyFactory(Class superClassOrInterface) { + if ( superClassOrInterface.isInterface() ) { + return new BasicProxyFactoryImpl( null, superClassOrInterface, byteBuddyState ); + } + else { + return new BasicProxyFactoryImpl( superClassOrInterface, null, byteBuddyState ); + } + } + } diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/ProxyFactoryFactoryImpl.java b/hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/ProxyFactoryFactoryImpl.java index 1c0eb8cdbc40..01bd7d107cdd 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/ProxyFactoryFactoryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/ProxyFactoryFactoryImpl.java @@ -15,6 +15,7 @@ import org.hibernate.AssertionFailure; import org.hibernate.HibernateException; +import org.hibernate.bytecode.internal.bytebuddy.BasicProxyFactoryImpl; import org.hibernate.bytecode.spi.BasicProxyFactory; import org.hibernate.bytecode.spi.ProxyFactoryFactory; import org.hibernate.engine.spi.SessionFactoryImplementor; @@ -43,14 +44,26 @@ public ProxyFactory buildProxyFactory(SessionFactoryImplementor sessionFactory) * * @param superClass The abstract super class (or null if none). * @param interfaces Interfaces to be proxied (or null if none). + * @deprecated use {@link #buildBasicProxyFactory(Class)} * * @return The constructed BasicProxyFactoryImpl */ @Override + @Deprecated public BasicProxyFactory buildBasicProxyFactory(Class superClass, Class[] interfaces) { return new BasicProxyFactoryImpl( superClass, interfaces ); } + @Override + public BasicProxyFactory buildBasicProxyFactory(Class superClassOrInterface) { + if ( superClassOrInterface.isInterface() ) { + return new BasicProxyFactoryImpl( null, new Class[]{ superClassOrInterface } ); + } + else { + return new BasicProxyFactoryImpl( superClassOrInterface, null ); + } + } + private static class BasicProxyFactoryImpl implements BasicProxyFactory { private final Class proxyClass; diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/none/NoProxyFactoryFactory.java b/hibernate-core/src/main/java/org/hibernate/bytecode/internal/none/NoProxyFactoryFactory.java index 40b9b9e253f4..e01d97ac8725 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/none/NoProxyFactoryFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/internal/none/NoProxyFactoryFactory.java @@ -26,4 +26,9 @@ public ProxyFactory buildProxyFactory(SessionFactoryImplementor sessionFactory) public BasicProxyFactory buildBasicProxyFactory(Class superClass, Class[] interfaces) { return new NoneBasicProxyFactory( superClass, interfaces ); } + + @Override + public BasicProxyFactory buildBasicProxyFactory(Class superClassOrInterface) { + return new NoneBasicProxyFactory( superClassOrInterface ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/none/NoneBasicProxyFactory.java b/hibernate-core/src/main/java/org/hibernate/bytecode/internal/none/NoneBasicProxyFactory.java index 5d1986d16ce7..bd440c81707d 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/none/NoneBasicProxyFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/internal/none/NoneBasicProxyFactory.java @@ -6,8 +6,7 @@ */ package org.hibernate.bytecode.internal.none; -import java.util.Arrays; - +import org.hibernate.AssertionFailure; import org.hibernate.HibernateException; import org.hibernate.bytecode.spi.BasicProxyFactory; @@ -16,17 +15,29 @@ */ final class NoneBasicProxyFactory implements BasicProxyFactory { - private final Class superClass; - private final Class[] interfaces; + private final Class superClassOrInterface; + @Deprecated public NoneBasicProxyFactory(Class superClass, Class[] interfaces) { - this.superClass = superClass; - this.interfaces = interfaces; + if ( superClass == null && ( interfaces == null || interfaces.length == 0 ) ) { + throw new AssertionFailure( "Attempting to build proxy without any superclass or interfaces" ); + } + if ( superClass != null && ( interfaces != null && interfaces.length > 0 ) ) { + throw new AssertionFailure( "Ambiguous call: this method can only be invoked with either a superClass or interfaces, not both" ); + } + if ( interfaces != null && interfaces.length > 1 ) { + throw new AssertionFailure( "Ambiguous call: this method can only accept a single interface, not multiple in the array (legacy expectation now being enforced)" ); + } + this.superClassOrInterface = superClass != null ? superClass : interfaces[0]; + } + + public NoneBasicProxyFactory(Class superClassOrInterface) { + this.superClassOrInterface = superClassOrInterface; } @Override public Object getProxy() { - throw new HibernateException( "NoneBasicProxyFactory is unable to generate a BasicProxy for type " + superClass + " and interfaces " + Arrays.toString( interfaces ) + ". Enable a different BytecodeProvider." ); + throw new HibernateException( "NoneBasicProxyFactory is unable to generate a BasicProxy for type " + superClassOrInterface + ". Enable a different BytecodeProvider." ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/spi/ProxyFactoryFactory.java b/hibernate-core/src/main/java/org/hibernate/bytecode/spi/ProxyFactoryFactory.java index 52429d3f0589..75907cdab814 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/spi/ProxyFactoryFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/spi/ProxyFactoryFactory.java @@ -39,7 +39,26 @@ public interface ProxyFactoryFactory extends Service { * * @param superClass The abstract super class (or null if none). * @param interfaces Interfaces to be proxied (or null if none). + * @deprecated Use {@link #buildBasicProxyFactory(Class)} instead. * @return The proxy class */ + @Deprecated public BasicProxyFactory buildBasicProxyFactory(Class superClass, Class[] interfaces); + + /** + * Build a proxy factory for basic proxy concerns. The return + * should be capable of properly handling newInstance() calls. + *

    + * Should build basic proxies essentially equivalent to JDK proxies in + * terms of capabilities, but should be able to deal with abstract super + * classes in addition to proxy interfaces. + *

    + * Must pass in either a superClass or an interface. + * + * @param superClassOrInterface The abstract super class, or the + * interface to be proxied. + * @return The proxy class + */ + public BasicProxyFactory buildBasicProxyFactory(Class superClassOrInterface); + } diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/component/PojoComponentTuplizer.java b/hibernate-core/src/main/java/org/hibernate/tuple/component/PojoComponentTuplizer.java index d8b771aa4c7a..acaf5a2e7685 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/component/PojoComponentTuplizer.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/component/PojoComponentTuplizer.java @@ -156,14 +156,8 @@ private static class ProxiedInstantiator implements Instantiator { public ProxiedInstantiator(Class componentClass, ProxyFactoryFactory proxyFactoryFactory) { proxiedClass = componentClass; - if ( proxiedClass.isInterface() ) { - factory = proxyFactoryFactory - .buildBasicProxyFactory( null, new Class[] { proxiedClass } ); - } - else { - factory = proxyFactoryFactory - .buildBasicProxyFactory( proxiedClass, null ); - } + factory = proxyFactoryFactory + .buildBasicProxyFactory( proxiedClass ); } public Object instantiate(Serializable id) { diff --git a/hibernate-core/src/test/java/org/hibernate/bytecode/internal/bytebuddy/ByteBuddyBasicProxyFactoryTest.java b/hibernate-core/src/test/java/org/hibernate/bytecode/internal/bytebuddy/ByteBuddyBasicProxyFactoryTest.java index afc655116b2c..e2d4126ed9ab 100644 --- a/hibernate-core/src/test/java/org/hibernate/bytecode/internal/bytebuddy/ByteBuddyBasicProxyFactoryTest.java +++ b/hibernate-core/src/test/java/org/hibernate/bytecode/internal/bytebuddy/ByteBuddyBasicProxyFactoryTest.java @@ -20,7 +20,7 @@ @TestForIssue(jiraKey = "HHH-12786") public class ByteBuddyBasicProxyFactoryTest { - private static final BasicProxyFactoryImpl BASIC_PROXY_FACTORY = new BasicProxyFactoryImpl( Entity.class, new Class[0], new ByteBuddyState() ); + private static final BasicProxyFactoryImpl BASIC_PROXY_FACTORY = new BasicProxyFactoryImpl( Entity.class, null, new ByteBuddyState() ); @Test public void testEqualsHashCode() { diff --git a/hibernate-core/src/test/java/org/hibernate/bytecode/internal/bytebuddy/GenerateProxiesTest.java b/hibernate-core/src/test/java/org/hibernate/bytecode/internal/bytebuddy/GenerateProxiesTest.java index 3c016a2e949e..7b7e52ec8716 100644 --- a/hibernate-core/src/test/java/org/hibernate/bytecode/internal/bytebuddy/GenerateProxiesTest.java +++ b/hibernate-core/src/test/java/org/hibernate/bytecode/internal/bytebuddy/GenerateProxiesTest.java @@ -19,7 +19,7 @@ public class GenerateProxiesTest { @Test public void generateBasicProxy() { - BasicProxyFactoryImpl basicProxyFactory = new BasicProxyFactoryImpl( SimpleEntity.class, new Class[0], + BasicProxyFactoryImpl basicProxyFactory = new BasicProxyFactoryImpl( SimpleEntity.class, null, new ByteBuddyState() ); assertNotNull( basicProxyFactory.getProxy() ); } From 6608d03bfc86088b0d658e583fb0372d44d240f6 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Fri, 25 Jun 2021 18:19:43 +0100 Subject: [PATCH 250/644] HHH-14732 ProxyDefinitionHelpers are immutable and can be declared static --- .../hibernate/bytecode/internal/bytebuddy/ByteBuddyState.java | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/bytebuddy/ByteBuddyState.java b/hibernate-core/src/main/java/org/hibernate/bytecode/internal/bytebuddy/ByteBuddyState.java index 4894848cd989..138ced85c4b0 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/bytebuddy/ByteBuddyState.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/internal/bytebuddy/ByteBuddyState.java @@ -58,7 +58,7 @@ public final class ByteBuddyState { private final ByteBuddy byteBuddy; - private final ProxyDefinitionHelpers proxyDefinitionHelpers; + private static final ProxyDefinitionHelpers proxyDefinitionHelpers = new ProxyDefinitionHelpers(); private final ClassRewriter classRewriter; @@ -87,8 +87,6 @@ public final class ByteBuddyState { else { this.classRewriter = new StandardClassRewriter(); } - - this.proxyDefinitionHelpers = new ProxyDefinitionHelpers(); } /** From e782ddf8f9591d21c09889c3456db22580f70acc Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Fri, 25 Jun 2021 11:19:56 +0100 Subject: [PATCH 251/644] HHH-14733 Not useful to clear the bycodeprovider caches on sessionFactoryClosing --- .../internal/SessionFactoryObserverForBytecodeEnhancer.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/SessionFactoryObserverForBytecodeEnhancer.java b/hibernate-core/src/main/java/org/hibernate/bytecode/internal/SessionFactoryObserverForBytecodeEnhancer.java index 7a84b3b0382b..360273d70636 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/SessionFactoryObserverForBytecodeEnhancer.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/internal/SessionFactoryObserverForBytecodeEnhancer.java @@ -25,7 +25,7 @@ public void sessionFactoryCreated(final SessionFactory factory) { @Override public void sessionFactoryClosing(final SessionFactory factory) { - this.bytecodeProvider.resetCaches(); + //unnecessary } @Override From f60d8bcd1245ac62271d82408a13a37a3de3febf Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Fri, 25 Jun 2021 18:23:24 +0100 Subject: [PATCH 252/644] HHH-14734 No good reason tu use TypeCache(s) with WithInlineExpunction --- .../hibernate/bytecode/internal/bytebuddy/ByteBuddyState.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/bytebuddy/ByteBuddyState.java b/hibernate-core/src/main/java/org/hibernate/bytecode/internal/bytebuddy/ByteBuddyState.java index 138ced85c4b0..90c5b78a0890 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/bytebuddy/ByteBuddyState.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/internal/bytebuddy/ByteBuddyState.java @@ -78,8 +78,8 @@ public final class ByteBuddyState { ByteBuddyState(ClassFileVersion classFileVersion) { this.byteBuddy = new ByteBuddy( classFileVersion ).with( TypeValidation.DISABLED ); - this.proxyCache = new TypeCache.WithInlineExpunction( TypeCache.Sort.WEAK ); - this.basicProxyCache = new TypeCache.WithInlineExpunction( TypeCache.Sort.WEAK ); + this.proxyCache = new TypeCache( TypeCache.Sort.WEAK ); + this.basicProxyCache = new TypeCache( TypeCache.Sort.WEAK ); if ( System.getSecurityManager() != null ) { this.classRewriter = new SecurityManagerClassRewriter(); From c0041ba07350808cc4e621cabd773541ddcd4b69 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Fri, 9 Jul 2021 14:47:58 +0200 Subject: [PATCH 253/644] HHH-14772 InformationExtractorJdbcDatabaseMetaDataImpl#getCurrentSchema() method returns currentCatalog if schema == null --- .../internal/InformationExtractorJdbcDatabaseMetaDataImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/InformationExtractorJdbcDatabaseMetaDataImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/InformationExtractorJdbcDatabaseMetaDataImpl.java index 4a67ba2d3ca2..7e7ed7c04f68 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/InformationExtractorJdbcDatabaseMetaDataImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/InformationExtractorJdbcDatabaseMetaDataImpl.java @@ -325,7 +325,7 @@ private Identifier getCurrentSchema(JdbcEnvironment jdbcEnvironment) { log.sqlWarning( ignore.getErrorCode(), ignore.getSQLState() ); } } - return currentCatalog; + return currentSchema; } private Identifier getCurrentCatalog(JdbcEnvironment jdbcEnvironment) { From fb36fe25413b3701661472bc1c1ca602660b83ef Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Mon, 19 Jul 2021 09:29:02 +0000 Subject: [PATCH 254/644] 5.5.4.Final --- changelog.txt | 28 ++++++++++++++++++++++++++++ gradle/version.properties | 2 +- 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 12ad9644f32d..0886f09ff35a 100644 --- a/changelog.txt +++ b/changelog.txt @@ -3,6 +3,34 @@ Hibernate 5 Changelog Note: Please refer to JIRA to learn more about each issue. +Changes in 5.5.4.Final (July 19, 2021) +------------------------------------------------------------------------------------------------------------------------ + +https://hibernate.atlassian.net/projects/HHH/versions/31959 + +** Bug + * [HHH-14730] - Failure during lazy loading of bytecode-enhancement proxy triggered by the loading of a collection with eager references to that proxy + * [HHH-14722] - InformationExtractorJdbcDatabaseMetaDataImpl#getCurrentSchema() method returns currentCatalog if schema == null + * [HHH-14720] - Aliases generated for mixed-case column names that end in a number are not all lower-case + * [HHH-14719] - Hibernate has a dependency on apache-derby:10.11.1.1 that is vulnerable to CVE-2015-1832 with a CVSS of 9.1 and CVE-2018-1313 with a CVSS of 5.3 + * [HHH-14715] - Hibernate has a dependency to maven-core:3.0.5 that is vulnerable to CVE-2021-26291 with a CVSS of 9.1 + * [HHH-14608] - Merge causes StackOverflow when JPA proxy compliance is enabled + +** Improvement + * [HHH-14734] - No good reason tu use TypeCache(s) with WithInlineExpunction in ByteBuddy proxy generation + * [HHH-14733] - Not useful to clear the bycodeprovider caches on sessionFactoryClosing + * [HHH-14732] - ProxyDefinitionHelpers are immutable and can be declared static + * [HHH-14731] - Simplify SPI ProxyFactoryFactory#buildBasicProxyFactory to accept a single class or interface only + * [HHH-14728] - Include CamelCaseToUnderscoresNamingStrategy from Spring Boot + * [HHH-14727] - Minor code cleanup in StandardSQLExceptionConverter + * [HHH-14706] - Improve error message on incompatible types due to mismatched classloader + * [HHH-14688] - Get IdentifierGenerator from BeanContainer if not registered + +** Task + * [HHH-14709] - Upgrade to Gradle 6.7.1 and move to Gradle's built-in way of testing Java modules + * [HHH-14707] - Upgrade to Byte Buddy 1.11.8 + + Changes in 5.5.3.Final (June 22, 2021) ------------------------------------------------------------------------------------------------------------------------ diff --git a/gradle/version.properties b/gradle/version.properties index 73d49076c20d..9d5ef8996d70 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -hibernateVersion=5.5.4-SNAPSHOT \ No newline at end of file +hibernateVersion=5.5.4.Final \ No newline at end of file From 4454f170fac9d94adbcf71932c1a964fb0cb7046 Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Mon, 19 Jul 2021 09:33:59 +0000 Subject: [PATCH 255/644] 5.5.5-SNAPSHOT --- gradle/version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/version.properties b/gradle/version.properties index 9d5ef8996d70..0e3ce8ec399b 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -hibernateVersion=5.5.4.Final \ No newline at end of file +hibernateVersion=5.5.5-SNAPSHOT \ No newline at end of file From 0325cd632a704ff82b789544bfefb7e11ac97cd9 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Tue, 20 Jul 2021 11:32:40 +0100 Subject: [PATCH 256/644] HHH-14740 Still need the nullcheck removed in HHH-14727 --- .../exception/internal/StandardSQLExceptionConverter.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/exception/internal/StandardSQLExceptionConverter.java b/hibernate-core/src/main/java/org/hibernate/exception/internal/StandardSQLExceptionConverter.java index 175835d992e7..16f594b32d9c 100644 --- a/hibernate-core/src/main/java/org/hibernate/exception/internal/StandardSQLExceptionConverter.java +++ b/hibernate-core/src/main/java/org/hibernate/exception/internal/StandardSQLExceptionConverter.java @@ -20,13 +20,15 @@ */ public class StandardSQLExceptionConverter implements SQLExceptionConverter { - private final ArrayList delegates = new ArrayList(4); + private final ArrayList delegates = new ArrayList<>(); public StandardSQLExceptionConverter() { } public void addDelegate(SQLExceptionConversionDelegate delegate) { - this.delegates.add( delegate ); + if ( delegate != null ) { + this.delegates.add( delegate ); + } } @Override From 787f0a44ea752f9f24aef5740936415f2c8c9116 Mon Sep 17 00:00:00 2001 From: Dariush Moshiri Date: Sat, 24 Jul 2021 17:01:29 +0200 Subject: [PATCH 257/644] HHH-11413: Native named query creation fails unintuitively when no resultClass is specified --- .../AbstractSharedSessionContract.java | 4 ++++ .../jpa/test/query/NamedQueryTest.java | 18 ++++++++++++++++-- 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java b/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java index e147da2c29f0..118e78ab33bc 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java @@ -966,6 +966,10 @@ else if ( namedQueryDefinition.getResultSetRef() != null ) { throw new IllegalArgumentException( "Cannot create TypedQuery for query with more than one return" ); } + if ( queryReturns.length == 0 ) { + throw new IllegalArgumentException("Named query exists but its result type is not compatible"); + } + final NativeSQLQueryReturn nativeSQLQueryReturn = queryReturns[0]; if ( nativeSQLQueryReturn instanceof NativeSQLQueryRootReturn ) { diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/query/NamedQueryTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/query/NamedQueryTest.java index 682996be9183..309976b4f840 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/query/NamedQueryTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/query/NamedQueryTest.java @@ -19,6 +19,7 @@ import org.hibernate.Session; import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; import org.hibernate.query.NativeQuery; + import org.hibernate.testing.TestForIssue; import org.junit.After; import org.junit.Before; @@ -26,6 +27,7 @@ import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertThrows; /** * @author Andrea Boriero @@ -33,11 +35,11 @@ @TestForIssue(jiraKey = "HHH-11092") public class NamedQueryTest extends BaseEntityManagerFunctionalTestCase { - private static final String[] GAME_TITLES = {"Halo", "Grand Theft Auto", "NetHack"}; + private static final String[] GAME_TITLES = { "Halo", "Grand Theft Auto", "NetHack" }; @Override public Class[] getAnnotatedClasses() { - return new Class[] {Game.class}; + return new Class[] { Game.class }; } @Before @@ -178,6 +180,18 @@ public void testNativeQueriesFromNamedQueriesDoNotShareQuerySpaces() { } ); } + @Test + @TestForIssue(jiraKey = "HHH-11413") + public void testNamedNativeQueryExceptionNoRedultDefined() { + doInJPA( this::entityManagerFactory, entityManager -> { + assertThrows( + "Named query exists but its result type is not compatible", + IllegalArgumentException.class, + () -> entityManager.createNamedQuery( "NamedNativeQuery", Game.class ) + ); + } ); + } + @Entity(name = "Game") @NamedQueries(@NamedQuery(name = "NamedQuery", query = "select g from Game g where title = ?1")) @NamedNativeQueries(@NamedNativeQuery(name = "NamedNativeQuery", query = "select * from Game g where title = ?")) From ff9f6efc0dff90778e3470bb439fe446924bb355 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Tue, 27 Jul 2021 14:12:55 +0100 Subject: [PATCH 258/644] HHH-11413 Fixing code style --- .../org/hibernate/internal/AbstractSharedSessionContract.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java b/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java index 118e78ab33bc..aeaf0634d181 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java @@ -959,7 +959,7 @@ else if ( namedQueryDefinition.getResultSetRef() != null ) { queryReturns = rsMapping.getQueryReturns(); } else { - throw new AssertionFailure( "Unsupported named query model. Please report the bug in Hibernate EntityManager"); + throw new AssertionFailure( "Unsupported named query model. Please report the bug in Hibernate EntityManager" ); } if ( queryReturns.length > 1 ) { @@ -967,7 +967,7 @@ else if ( namedQueryDefinition.getResultSetRef() != null ) { } if ( queryReturns.length == 0 ) { - throw new IllegalArgumentException("Named query exists but its result type is not compatible"); + throw new IllegalArgumentException( "Named query exists but its result type is not compatible" ); } final NativeSQLQueryReturn nativeSQLQueryReturn = queryReturns[0]; From aa5d40852c2a5fcb82002fc9906ac142e78317cc Mon Sep 17 00:00:00 2001 From: Alvaro Esteban Pedraza Date: Tue, 19 Jun 2018 18:10:20 -0300 Subject: [PATCH 259/644] HHH-10661 Reduce code duplication in serialize method of StatefulPersistenceContext --- .../internal/StatefulPersistenceContext.java | 167 +++++++----------- 1 file changed, 68 insertions(+), 99 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/engine/internal/StatefulPersistenceContext.java b/hibernate-core/src/main/java/org/hibernate/engine/internal/StatefulPersistenceContext.java index 3582c42b77d4..8233e275bae4 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/internal/StatefulPersistenceContext.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/internal/StatefulPersistenceContext.java @@ -1572,117 +1572,86 @@ public void serialize(ObjectOutputStream oos) throws IOException { oos.writeBoolean( defaultReadOnly ); oos.writeBoolean( hasNonReadOnlyEntities ); - if ( entitiesByKey == null ) { - oos.writeInt( 0 ); - } - else { - oos.writeInt( entitiesByKey.size() ); - if ( LOG.isTraceEnabled() ) { - LOG.trace( "Starting serialization of [" + entitiesByKey.size() + "] entitiesByKey entries" ); - } - for ( Map.Entry entry : entitiesByKey.entrySet() ) { - entry.getKey().serialize( oos ); - oos.writeObject( entry.getValue() ); - } - } - - if ( entitiesByUniqueKey == null ) { - oos.writeInt( 0 ); - } - else { - oos.writeInt( entitiesByUniqueKey.size() ); - if ( LOG.isTraceEnabled() ) { - LOG.trace( "Starting serialization of [" + entitiesByUniqueKey.size() + "] entitiesByUniqueKey entries" ); - } - for ( Map.Entry entry : entitiesByUniqueKey.entrySet() ) { - entry.getKey().serialize( oos ); - oos.writeObject( entry.getValue() ); - } - } - - if ( proxiesByKey == null ) { - oos.writeInt( 0 ); - } - else { - oos.writeInt( proxiesByKey.size() ); - if ( LOG.isTraceEnabled() ) { - LOG.trace( "Starting serialization of [" + proxiesByKey.size() + "] proxiesByKey entries" ); - } - for ( Map.Entry entry : proxiesByKey.entrySet() ) { - entry.getKey().serialize( oos ); - oos.writeObject( entry.getValue() ); - } - } - - if ( entitySnapshotsByKey == null ) { - oos.writeInt( 0 ); - } - else { - oos.writeInt( entitySnapshotsByKey.size() ); - if ( LOG.isTraceEnabled() ) { - LOG.trace( "Starting serialization of [" + entitySnapshotsByKey.size() + "] entitySnapshotsByKey entries" ); - } - for ( Map.Entry entry : entitySnapshotsByKey.entrySet() ) { - entry.getKey().serialize( oos ); - oos.writeObject( entry.getValue() ); - } - } + final Serializer> entityKeySerializer = (entry, stream) -> { + entry.getKey().serialize( stream ); + stream.writeObject( entry.getValue() ); + }; + + writeMapToStream( entitiesByKey, oos, "entitiesByKey", entityKeySerializer ); + writeMapToStream( + entitiesByUniqueKey, + oos, "entitiesByUniqueKey", (entry, stream) -> { + entry.getKey().serialize( stream ); + stream.writeObject( entry.getValue() ); + } + ); + writeMapToStream( proxiesByKey, oos, "proxiesByKey", entityKeySerializer ); + writeMapToStream( entitySnapshotsByKey, oos, "entitySnapshotsByKey", entityKeySerializer ); entityEntryContext.serialize( oos ); + writeMapToStream( + collectionsByKey, + oos, + "collectionsByKey", + (entry, stream) -> { + entry.getKey().serialize( stream ); + stream.writeObject( entry.getValue() ); + } + ); + writeMapToStream( + collectionEntries, + oos, + "collectionEntries", + (entry, stream) -> { + stream.writeObject( entry.getKey() ); + entry.getValue().serialize( stream ); + } + ); + writeMapToStream( + arrayHolders, + oos, + "arrayHolders", + (entry, stream) -> { + stream.writeObject( entry.getKey() ); + stream.writeObject( entry.getValue() ); + } + ); + writeCollectionToStream( nullifiableEntityKeys, oos, "nullifiableEntityKey", EntityKey::serialize ); + } - if ( collectionsByKey == null ) { - oos.writeInt( 0 ); - } - else { - oos.writeInt( collectionsByKey.size() ); - if ( LOG.isTraceEnabled() ) { - LOG.trace( "Starting serialization of [" + collectionsByKey.size() + "] collectionsByKey entries" ); - } - for ( Map.Entry entry : collectionsByKey.entrySet() ) { - entry.getKey().serialize( oos ); - oos.writeObject( entry.getValue() ); - } - } + private interface Serializer { - if ( collectionEntries == null ) { - oos.writeInt( 0 ); - } - else { - oos.writeInt( collectionEntries.size() ); - if ( LOG.isTraceEnabled() ) { - LOG.trace( "Starting serialization of [" + collectionEntries.size() + "] collectionEntries entries" ); - } - for ( Map.Entry entry : collectionEntries.entrySet() ) { - oos.writeObject( entry.getKey() ); - entry.getValue().serialize( oos ); - } - } + void serialize(E element, ObjectOutputStream oos) throws IOException; + } - if ( arrayHolders == null ) { + private void writeMapToStream( + Map map, + ObjectOutputStream oos, + String keysName, + Serializer> serializer) throws IOException { + if ( map == null ) { oos.writeInt( 0 ); } else { - oos.writeInt( arrayHolders.size() ); - if ( LOG.isTraceEnabled() ) { - LOG.trace( "Starting serialization of [" + arrayHolders.size() + "] arrayHolders entries" ); - } - for ( Map.Entry entry : arrayHolders.entrySet() ) { - oos.writeObject( entry.getKey() ); - oos.writeObject( entry.getValue() ); - } + writeCollectionToStream( map.entrySet(), oos, keysName, serializer ); } + } - if ( nullifiableEntityKeys == null ) { + private void writeCollectionToStream( + Collection collection, + ObjectOutputStream oos, + String keysName, + Serializer serializer) throws IOException { + if ( collection == null ) { oos.writeInt( 0 ); } else { - final int size = nullifiableEntityKeys.size(); + oos.writeInt( collection.size() ); if ( LOG.isTraceEnabled() ) { - LOG.trace( "Starting serialization of [" + size + "] nullifiableEntityKey entries" ); + LOG.trace( "Starting serialization of [" + collection.size() + "] " + keysName + " entries" ); } - oos.writeInt( size ); - for ( EntityKey entry : nullifiableEntityKeys ) { - entry.serialize( oos ); + for ( E entry : collection ) { + serializer.serialize( entry, oos ); } } } @@ -2142,9 +2111,9 @@ public Object[] removeLocalNaturalIdCrossReference(EntityPersister persister, Se final Object[] naturalIdValues = getNaturalIdValues( state, persister ); final Object[] localNaturalIdValues = getNaturalIdXrefDelegate().removeNaturalIdCrossReference( - persister, - id, - naturalIdValues + persister, + id, + naturalIdValues ); return localNaturalIdValues != null ? localNaturalIdValues : naturalIdValues; From e868e61cecf723598eefd3baf087018bfe64016f Mon Sep 17 00:00:00 2001 From: Thomas Heigl Date: Sun, 11 Jul 2021 11:57:53 +0200 Subject: [PATCH 260/644] HHH-14724 Test-case demonstrating compilation issues with converters and validation --- tooling/metamodel-generator/hibernate-jpamodelgen.gradle | 1 + .../hibernate/jpamodelgen/test/collectionbasictype/Goods.java | 2 ++ 2 files changed, 3 insertions(+) diff --git a/tooling/metamodel-generator/hibernate-jpamodelgen.gradle b/tooling/metamodel-generator/hibernate-jpamodelgen.gradle index 6b979a476fec..e6b7fde363dc 100644 --- a/tooling/metamodel-generator/hibernate-jpamodelgen.gradle +++ b/tooling/metamodel-generator/hibernate-jpamodelgen.gradle @@ -30,6 +30,7 @@ dependencies { testCompile libraries.junit testCompile libraries.jpa + testCompile libraries.validation testCompile project( ':hibernate-core' ) } diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/collectionbasictype/Goods.java b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/collectionbasictype/Goods.java index b494b62fe02b..c1ddafefe961 100644 --- a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/collectionbasictype/Goods.java +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/collectionbasictype/Goods.java @@ -10,6 +10,7 @@ import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.OneToMany; +import javax.validation.constraints.NotNull; import java.util.List; /** @@ -39,6 +40,7 @@ public void setProductList(List productList) { this.productList = productList; } + @NotNull @Convert(converter = StringToListConverter.class) public List getTags() { return tags; From 0fdf431715a5421d07f8d9a0a8f48ca822b668aa Mon Sep 17 00:00:00 2001 From: Thomas Heigl Date: Thu, 29 Jul 2021 11:18:56 +0200 Subject: [PATCH 261/644] HHH-14724 Add test for intersection types --- .../CollectionAsBasicTypeTest.java | 11 +++++-- .../collectionbasictype/ConcreteLike.java | 15 ++++++++++ .../test/collectionbasictype/Like.java | 29 +++++++++++++++++++ 3 files changed, 53 insertions(+), 2 deletions(-) create mode 100644 tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/collectionbasictype/ConcreteLike.java create mode 100644 tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/collectionbasictype/Like.java diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/collectionbasictype/CollectionAsBasicTypeTest.java b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/collectionbasictype/CollectionAsBasicTypeTest.java index 10b436c51090..b00743c4dad2 100644 --- a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/collectionbasictype/CollectionAsBasicTypeTest.java +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/collectionbasictype/CollectionAsBasicTypeTest.java @@ -76,14 +76,21 @@ public void testListTypeWithImport() throws ClassNotFoundException, NoSuchFieldE @TestForIssue(jiraKey = "HHH-12338") @WithClasses({PhoneBook.class}) public void testMapType() throws ClassNotFoundException, NoSuchFieldException { - assertMetamodelClassGeneratedFor(PhoneBook.class); + assertMetamodelClassGeneratedFor( PhoneBook.class ); assertAttributeTypeInMetaModelFor( PhoneBook.class, "phones", - PhoneBook.class.getDeclaredField("phones").getGenericType(), + PhoneBook.class.getDeclaredField( "phones" ).getGenericType(), "Wrong meta model type" ); } + + @Test + @TestForIssue(jiraKey = "HHH-14724") + @WithClasses({ Like.class, ConcreteLike.class }) + public void testIntersectionType() { + assertMetamodelClassGeneratedFor( ConcreteLike.class ); + } } diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/collectionbasictype/ConcreteLike.java b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/collectionbasictype/ConcreteLike.java new file mode 100644 index 000000000000..7cbb14ea8eee --- /dev/null +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/collectionbasictype/ConcreteLike.java @@ -0,0 +1,15 @@ +package org.hibernate.jpamodelgen.test.collectionbasictype; + +import javax.persistence.Entity; + +@Entity(name = "ConcreteLike") +public class ConcreteLike extends Like { + + @Override + public Reference getObject() { + return new Reference<>(); + } + + public static class Target implements Like.I1, Like.I2 { + } +} diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/collectionbasictype/Like.java b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/collectionbasictype/Like.java new file mode 100644 index 000000000000..a7f12494a3dd --- /dev/null +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/collectionbasictype/Like.java @@ -0,0 +1,29 @@ +package org.hibernate.jpamodelgen.test.collectionbasictype; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Inheritance; +import javax.persistence.InheritanceType; + +/** + * @author Thomas Heigl + */ +@Entity +@Inheritance(strategy = InheritanceType.SINGLE_TABLE) +public abstract class Like { + + @Id + private Long id; + + public abstract Reference getObject(); + + interface I1 { + } + + interface I2 { + } + + public static class Reference { + } + +} From 1a6924c2977481fa5f0bf7c8d975bfdd33988aba Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Wed, 28 Jul 2021 11:55:27 +0200 Subject: [PATCH 262/644] HHH-14724 Fix generation of problematic metamodel classes which use TYPE_USE annotations --- .../hibernate-jpamodelgen.gradle | 2 +- .../util/TypeRenderingVisitor.java | 182 ++++++++++++++++++ .../hibernate/jpamodelgen/util/TypeUtils.java | 2 +- 3 files changed, 184 insertions(+), 2 deletions(-) create mode 100644 tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/util/TypeRenderingVisitor.java diff --git a/tooling/metamodel-generator/hibernate-jpamodelgen.gradle b/tooling/metamodel-generator/hibernate-jpamodelgen.gradle index e6b7fde363dc..9f3330401cdc 100644 --- a/tooling/metamodel-generator/hibernate-jpamodelgen.gradle +++ b/tooling/metamodel-generator/hibernate-jpamodelgen.gradle @@ -30,7 +30,7 @@ dependencies { testCompile libraries.junit testCompile libraries.jpa - testCompile libraries.validation + testCompile libraries.validation testCompile project( ':hibernate-core' ) } diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/util/TypeRenderingVisitor.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/util/TypeRenderingVisitor.java new file mode 100644 index 000000000000..5652b3799161 --- /dev/null +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/util/TypeRenderingVisitor.java @@ -0,0 +1,182 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.jpamodelgen.util; + +import java.util.List; +import javax.lang.model.element.Element; +import javax.lang.model.element.ElementKind; +import javax.lang.model.element.TypeParameterElement; +import javax.lang.model.type.ArrayType; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.ExecutableType; +import javax.lang.model.type.IntersectionType; +import javax.lang.model.type.NoType; +import javax.lang.model.type.NullType; +import javax.lang.model.type.PrimitiveType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.type.TypeVariable; +import javax.lang.model.type.UnionType; +import javax.lang.model.type.WildcardType; +import javax.lang.model.util.SimpleTypeVisitor8; + +/** + * @author Christian Beikov + */ +public final class TypeRenderingVisitor extends SimpleTypeVisitor8 { + + private final StringBuilder sb = new StringBuilder(); + + private TypeRenderingVisitor() { + } + + public static String toString(TypeMirror typeMirror) { + if ( typeMirror instanceof TypeVariable ) { + // Top level type variables don't need to render the upper bound as `T extends Type` + final Element typeVariableElement = ( (TypeVariable) typeMirror ).asElement(); + if ( typeVariableElement instanceof TypeParameterElement ) { + final TypeParameterElement typeParameter = (TypeParameterElement) typeVariableElement; + if ( typeParameter.getEnclosingElement().getKind() == ElementKind.METHOD ) { + // But for method level type variable we return the upper bound + // because the type variable has no meaning except for that method + typeMirror = ( (TypeVariable) typeMirror ).getUpperBound(); + } + else { + return typeParameter.toString(); + } + } + else { + typeMirror = typeVariableElement.asType(); + } + } + else if ( typeMirror instanceof IntersectionType ) { + // For top level type only the first type is relevant + typeMirror = ( (IntersectionType) typeMirror ).getBounds().get( 0 ); + } + final TypeRenderingVisitor typeRenderingVisitor = new TypeRenderingVisitor(); + typeMirror.accept( typeRenderingVisitor, null ); + return typeRenderingVisitor.sb.toString(); + } + + @Override + public Object visitPrimitive(PrimitiveType t, Object o) { + final String primitiveTypeName = getPrimitiveTypeName( t.getKind() ); + if ( primitiveTypeName != null ) { + sb.append( primitiveTypeName ); + } + return null; + } + + private static String getPrimitiveTypeName(TypeKind kind) { + switch ( kind ) { + case INT: + return "int"; + case BOOLEAN: + return "boolean"; + case BYTE: + return "byte"; + case CHAR: + return "char"; + case DOUBLE: + return "double"; + case FLOAT: + return "float"; + case LONG: + return "long"; + case SHORT: + return "short"; + case VOID: + return "void"; + } + return null; + } + + @Override + public Object visitNull(NullType t, Object o) { + return null; + } + + @Override + public Object visitArray(ArrayType t, Object o) { + t.getComponentType().accept( this, null ); + sb.append( "[]" ); + return t; + } + + @Override + public Object visitDeclared(DeclaredType t, Object o) { + sb.append( t.asElement().toString() ); + List typeArguments = t.getTypeArguments(); + if ( !typeArguments.isEmpty() ) { + sb.append( '<' ); + typeArguments.get( 0 ).accept( this, null ); + for ( int i = 1; i < typeArguments.size(); i++ ) { + sb.append( ", " ); + typeArguments.get( i ).accept( this, null ); + } + sb.append( '>' ); + } + return null; + } + + @Override + public Object visitTypeVariable(TypeVariable t, Object o) { + final Element typeVariableElement = t.asElement(); + if ( typeVariableElement instanceof TypeParameterElement ) { + final TypeParameterElement typeParameter = (TypeParameterElement) typeVariableElement; + sb.append( typeParameter ); + if ( !"java.lang.Object".equals( t.getUpperBound().toString() ) ) { + sb.append( " extends " ); + t.getUpperBound().accept( this, null ); + } + } + else { + typeVariableElement.asType().accept( this, null ); + } + return null; + } + + @Override + public Object visitWildcard(WildcardType t, Object o) { + sb.append( '?' ); + if ( t.getExtendsBound() != null ) { + sb.append( " extends " ); + t.getExtendsBound().accept( this, null ); + } + if ( t.getSuperBound() != null ) { + sb.append( " super " ); + t.getSuperBound().accept( this, null ); + } + return null; + } + + @Override + public Object visitUnion(UnionType t, Object o) { + return null; + } + + @Override + public Object visitIntersection(IntersectionType t, Object o) { + final List bounds = t.getBounds(); + bounds.get( 0 ).accept( this, null ); + for ( int i = 0; i < bounds.size(); i++ ) { + sb.append( " & " ); + bounds.get( i ).accept( this, null ); + } + return null; + } + + @Override + public Object visitExecutable(ExecutableType t, Object o) { + return null; + } + + @Override + public Object visitNoType(NoType t, Object o) { + return null; + } +} diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/util/TypeUtils.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/util/TypeUtils.java index 5c7610d4f3aa..ea5b1ac888b9 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/util/TypeUtils.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/util/TypeUtils.java @@ -74,7 +74,7 @@ public static String toTypeString(TypeMirror type) { if ( type.getKind().isPrimitive() ) { return PRIMITIVE_WRAPPERS.get( type.getKind() ); } - return type.toString(); + return TypeRenderingVisitor.toString( type ); } public static String toArrayTypeString(ArrayType type, Context context) { From d4ed42149b2be6bc05b68fb83ef5ba0340520f4e Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Tue, 27 Jul 2021 16:21:05 +0100 Subject: [PATCH 263/644] HHH-14755 Remove some dead code from DefaultIdentifierGeneratorFactory --- .../DefaultIdentifierGeneratorFactory.java | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/id/factory/internal/DefaultIdentifierGeneratorFactory.java b/hibernate-core/src/main/java/org/hibernate/id/factory/internal/DefaultIdentifierGeneratorFactory.java index c2b80042ab9d..828499190920 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/factory/internal/DefaultIdentifierGeneratorFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/id/factory/internal/DefaultIdentifierGeneratorFactory.java @@ -95,21 +95,6 @@ public Dialect getDialect() { @Override public void setDialect(Dialect dialect) { -// LOG.debugf( "Setting dialect [%s]", dialect ); -// this.dialect = dialect; -// -// if ( dialect == jdbcEnvironment.getDialect() ) { -// LOG.debugf( -// "Call to unsupported method IdentifierGeneratorFactory#setDialect; " + -// "ignoring as passed Dialect matches internal Dialect" -// ); -// } -// else { -// throw new UnsupportedOperationException( -// "Call to unsupported method IdentifierGeneratorFactory#setDialect attempting to" + -// "set a non-matching Dialect : " + dialect.getClass().getName() -// ); -// } } @SuppressWarnings("unchecked") From 83975eaddf7f04680f12a1059eb737730da5ce6b Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Tue, 27 Jul 2021 16:20:53 +0100 Subject: [PATCH 264/644] HHH-14755 Allow configuring the DefaultIdentifierGeneratorFactory to ignore BeanContainer(s) --- .../DefaultIdentifierGeneratorFactory.java | 26 ++++++++++++++++--- 1 file changed, 22 insertions(+), 4 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/id/factory/internal/DefaultIdentifierGeneratorFactory.java b/hibernate-core/src/main/java/org/hibernate/id/factory/internal/DefaultIdentifierGeneratorFactory.java index 828499190920..5d433606e632 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/factory/internal/DefaultIdentifierGeneratorFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/id/factory/internal/DefaultIdentifierGeneratorFactory.java @@ -55,15 +55,30 @@ public class DefaultIdentifierGeneratorFactory private static final CoreMessageLogger LOG = CoreLogging.messageLogger( DefaultIdentifierGeneratorFactory.class ); + private final boolean ignoreBeanContainer; + private ServiceRegistry serviceRegistry; private Dialect dialect; - private ConcurrentHashMap generatorStrategyToClassNameMap = new ConcurrentHashMap(); + private final ConcurrentHashMap generatorStrategyToClassNameMap = new ConcurrentHashMap<>(); + + private BeanContainer beanContainer; /** * Constructs a new DefaultIdentifierGeneratorFactory. */ public DefaultIdentifierGeneratorFactory() { + this( false ); + } + + /** + * Allows to explicitly control if the BeanContainer should be ignored + * (if there is one registered) when initializing any new IdentifierGenerator + * instances. + * @param ignoreBeanContainer + */ + public DefaultIdentifierGeneratorFactory(boolean ignoreBeanContainer) { + this.ignoreBeanContainer = ignoreBeanContainer; register( "uuid2", UUIDGenerator.class ); register( "guid", GUIDGenerator.class ); // can be done with UUIDGenerator + strategy register( "uuid", UUIDHexGenerator.class ); // "deprecated" for new use @@ -102,9 +117,8 @@ public void setDialect(Dialect dialect) { public IdentifierGenerator createIdentifierGenerator(String strategy, Type type, Properties config) { try { Class clazz = getIdentifierGeneratorClass( strategy ); - BeanContainer beanContainer = serviceRegistry.getService(ManagedBeanRegistry.class).getBeanContainer(); IdentifierGenerator identifierGenerator; - if ( generatorStrategyToClassNameMap.containsKey(strategy) || beanContainer == null ) { + if ( beanContainer == null || generatorStrategyToClassNameMap.containsKey( strategy ) ) { identifierGenerator = ( IdentifierGenerator ) clazz.newInstance(); } else { @@ -163,6 +177,10 @@ public void injectServices(ServiceRegistryImplementor serviceRegistry) { this.serviceRegistry = serviceRegistry; this.dialect = serviceRegistry.getService( JdbcEnvironment.class ).getDialect(); final ConfigurationService configService = serviceRegistry.getService( ConfigurationService.class ); + if ( ! this.ignoreBeanContainer ) { + this.beanContainer = serviceRegistry.getService( ManagedBeanRegistry.class ).getBeanContainer(); + //else we just have beanContainer = null; + } final boolean useNewIdentifierGenerators = configService.getSetting( AvailableSettings.USE_NEW_ID_GENERATOR_MAPPINGS, @@ -170,7 +188,7 @@ public void injectServices(ServiceRegistryImplementor serviceRegistry) { true ); - if(!useNewIdentifierGenerators) { + if ( ! useNewIdentifierGenerators ) { register( "sequence", SequenceGenerator.class ); } } From b1975ba05d0305b49c51f80d4b021557e3f93044 Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Wed, 28 Jul 2021 11:48:56 -0700 Subject: [PATCH 265/644] HHH-11926 : Add FailureExpected test --- .../EmptyInitializedNestedCompositesTest.java | 112 ++++++++++++++++++ 1 file changed, 112 insertions(+) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/component/empty/EmptyInitializedNestedCompositesTest.java diff --git a/hibernate-core/src/test/java/org/hibernate/test/component/empty/EmptyInitializedNestedCompositesTest.java b/hibernate-core/src/test/java/org/hibernate/test/component/empty/EmptyInitializedNestedCompositesTest.java new file mode 100644 index 000000000000..b5d01da35fd3 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/component/empty/EmptyInitializedNestedCompositesTest.java @@ -0,0 +1,112 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.component.empty; + +import javax.persistence.Embeddable; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +import org.hibernate.Session; +import org.hibernate.cfg.Configuration; +import org.hibernate.cfg.Environment; + +import org.hibernate.testing.FailureExpected; +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.Test; + +import static org.junit.Assert.assertNotNull; + +/** + * Tests that an empty embeddable that is nested inside an embeddable is initialized. + * + * @author Gail Badner + */ +@TestForIssue(jiraKey = "HHH-11926") +public class EmptyInitializedNestedCompositesTest extends BaseCoreFunctionalTestCase { + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { ComponentEmptyNestedEmbeddedOwner.class }; + } + + @Override + protected void configure(Configuration configuration) { + super.configure( configuration ); + configuration.getProperties().put( Environment.CREATE_EMPTY_COMPOSITES_ENABLED, Boolean.valueOf( true ) ); + } + + /** + * Test empty nested composite initialization. + */ + @Test + @FailureExpected( jiraKey = "HHH-11926" ) + public void testCompositesEmpty() { + Session s = openSession(); + try { + s.getTransaction().begin(); + + ComponentEmptyNestedEmbeddedOwner owner = new ComponentEmptyNestedEmbeddedOwner(); + s.persist( owner ); + + s.flush(); + s.getTransaction().commit(); + + s.clear(); + s.getTransaction().begin(); + owner = s.get( ComponentEmptyNestedEmbeddedOwner.class, owner.getId() ); + assertNotNull( owner.getEmbedded() ); + assertNotNull( owner.getEmbedded().getNestedEmbedded() ); + + s.getTransaction().rollback(); + } + finally { + s.close(); + } + } + + @Entity(name = "EmptyNestedOwner") + public static class ComponentEmptyNestedEmbeddedOwner { + + @Id + @GeneratedValue + private Integer id; + + private EmptyNestedEmbeddedContainer embedded; + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public EmptyNestedEmbeddedContainer getEmbedded() { + return embedded; + } + + public void setEmbedded(EmptyNestedEmbeddedContainer embedded) { + this.embedded = embedded; + } + + } + + @Embeddable + public static class EmptyNestedEmbeddedContainer { + public ComponentEmptyEmbedded getNestedEmbedded() { + return nestedEmbedded; + } + + public void setNestedEmbedded(ComponentEmptyEmbedded nestedEmbedded) { + this.nestedEmbedded = nestedEmbedded; + } + + private ComponentEmptyEmbedded nestedEmbedded; + } +} From 3de90a261fdae6f9b41b0184a40d7412f6a096fe Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Thu, 29 Jul 2021 14:13:58 +0000 Subject: [PATCH 266/644] 5.5.5.Final --- changelog.txt | 16 ++++++++++++++++ gradle/version.properties | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 0886f09ff35a..df25d7c8452d 100644 --- a/changelog.txt +++ b/changelog.txt @@ -3,6 +3,22 @@ Hibernate 5 Changelog Note: Please refer to JIRA to learn more about each issue. +Changes in 5.5.5.Final (July 29, 2021) +------------------------------------------------------------------------------------------------------------------------ + +https://hibernate.atlassian.net/projects/HHH/versions/31963 + +** Bug + * [HHH-14740] - HHH-14740 Still need the nullcheck removed in HHH-14727 + * [HHH-14724] - Metamodel generates invalid model classes for converters and user types + +** Improvement + * [HHH-14755] - Allow to instantiate a DefaultIdentifierGeneratorFactory which does not bind to the BeanManager + +** Task + * [HHH-10661] - Method serialize() in StatefulPersistenceContext has duplicate code + + Changes in 5.5.4.Final (July 19, 2021) ------------------------------------------------------------------------------------------------------------------------ diff --git a/gradle/version.properties b/gradle/version.properties index 0e3ce8ec399b..a852cb8e4f8f 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -hibernateVersion=5.5.5-SNAPSHOT \ No newline at end of file +hibernateVersion=5.5.5.Final \ No newline at end of file From c1f28b4d091e5c6c798d50fde23955700a43c92b Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Thu, 29 Jul 2021 14:18:40 +0000 Subject: [PATCH 267/644] 5.5.6-SNAPSHOT --- gradle/version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/version.properties b/gradle/version.properties index a852cb8e4f8f..dcd794a4d338 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -hibernateVersion=5.5.5.Final \ No newline at end of file +hibernateVersion=5.5.6-SNAPSHOT \ No newline at end of file From e528a1ab538c31b7d1cb151c43d07e617e1a3101 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Mon, 2 Aug 2021 09:32:15 +0200 Subject: [PATCH 268/644] HHH-14768 Fix recursive type variable rendering --- .../jpamodelgen/util/TypeRenderingVisitor.java | 6 +++++- .../CollectionAsBasicTypeTest.java | 7 +++++++ .../test/collectionbasictype/EnumHolder.java | 11 +++++++++++ 3 files changed, 23 insertions(+), 1 deletion(-) create mode 100644 tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/collectionbasictype/EnumHolder.java diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/util/TypeRenderingVisitor.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/util/TypeRenderingVisitor.java index 5652b3799161..8654c95d848f 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/util/TypeRenderingVisitor.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/util/TypeRenderingVisitor.java @@ -6,7 +6,9 @@ */ package org.hibernate.jpamodelgen.util; +import java.util.HashSet; import java.util.List; +import java.util.Set; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; import javax.lang.model.element.TypeParameterElement; @@ -30,6 +32,7 @@ public final class TypeRenderingVisitor extends SimpleTypeVisitor8 { private final StringBuilder sb = new StringBuilder(); + private final Set visitedTypeVariables = new HashSet<>(); private TypeRenderingVisitor() { } @@ -129,9 +132,10 @@ public Object visitTypeVariable(TypeVariable t, Object o) { if ( typeVariableElement instanceof TypeParameterElement ) { final TypeParameterElement typeParameter = (TypeParameterElement) typeVariableElement; sb.append( typeParameter ); - if ( !"java.lang.Object".equals( t.getUpperBound().toString() ) ) { + if ( !"java.lang.Object".equals( t.getUpperBound().toString() ) && visitedTypeVariables.add( t ) ) { sb.append( " extends " ); t.getUpperBound().accept( this, null ); + visitedTypeVariables.remove( t ); } } else { diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/collectionbasictype/CollectionAsBasicTypeTest.java b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/collectionbasictype/CollectionAsBasicTypeTest.java index b00743c4dad2..5fd388e6ea9e 100644 --- a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/collectionbasictype/CollectionAsBasicTypeTest.java +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/collectionbasictype/CollectionAsBasicTypeTest.java @@ -93,4 +93,11 @@ public void testMapType() throws ClassNotFoundException, NoSuchFieldException { public void testIntersectionType() { assertMetamodelClassGeneratedFor( ConcreteLike.class ); } + + @Test + @TestForIssue(jiraKey = "HHH-14724") + @WithClasses({ EnumHolder.class }) + public void testRecursiveTypeVariable() { + assertMetamodelClassGeneratedFor( EnumHolder.class ); + } } diff --git a/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/collectionbasictype/EnumHolder.java b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/collectionbasictype/EnumHolder.java new file mode 100644 index 000000000000..7f8ea324a4ac --- /dev/null +++ b/tooling/metamodel-generator/src/test/java/org/hibernate/jpamodelgen/test/collectionbasictype/EnumHolder.java @@ -0,0 +1,11 @@ +package org.hibernate.jpamodelgen.test.collectionbasictype; + +import javax.persistence.Entity; + +@Entity +public class EnumHolder { + + public > E getMyEnum() { + return null; + } +} From 6cdab40f67d21ed20c71ce213d469a7c03691cc6 Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Wed, 4 Aug 2021 20:18:14 +0000 Subject: [PATCH 269/644] 5.5.6.Final --- changelog.txt | 9 +++++++++ gradle/version.properties | 2 +- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index df25d7c8452d..e60eba5c9592 100644 --- a/changelog.txt +++ b/changelog.txt @@ -3,6 +3,15 @@ Hibernate 5 Changelog Note: Please refer to JIRA to learn more about each issue. +Changes in 5.5.6.Final (August 04, 2021) +------------------------------------------------------------------------------------------------------------------------ + +https://hibernate.atlassian.net/projects/HHH/versions/31968 + +** Bug + * [HHH-14768] - hibernate-jpamodelgen fails to generate metamodel for recursive type variable definition + + Changes in 5.5.5.Final (July 29, 2021) ------------------------------------------------------------------------------------------------------------------------ diff --git a/gradle/version.properties b/gradle/version.properties index dcd794a4d338..f099395d9001 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -hibernateVersion=5.5.6-SNAPSHOT \ No newline at end of file +hibernateVersion=5.5.6.Final \ No newline at end of file From d4584827ed60eadbba1809c88318f2b97e6d00ad Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Wed, 4 Aug 2021 20:23:31 +0000 Subject: [PATCH 270/644] 5.5.7-SNAPSHOT --- gradle/version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/version.properties b/gradle/version.properties index f099395d9001..23c7290f7358 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -hibernateVersion=5.5.6.Final \ No newline at end of file +hibernateVersion=5.5.7-SNAPSHOT \ No newline at end of file From 42ff387193a3eb68eaee76005667af76be387461 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Thu, 5 Aug 2021 23:57:52 +0100 Subject: [PATCH 271/644] HHH-14771 Upgrade to Byte Buddy 1.11.12 --- gradle/libraries.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libraries.gradle b/gradle/libraries.gradle index c6a0121320bc..8636f33e982d 100644 --- a/gradle/libraries.gradle +++ b/gradle/libraries.gradle @@ -25,7 +25,7 @@ ext { jakartaWeldVersion = '4.0.1.SP1' javassistVersion = '3.27.0-GA' - byteBuddyVersion = '1.11.8' + byteBuddyVersion = '1.11.12' agroalVersion = '1.9' From c9b8776d3aed4b4d1271065a7eb878a4b4a71f0d Mon Sep 17 00:00:00 2001 From: boris-unckel Date: Thu, 29 Jul 2021 08:09:13 +0200 Subject: [PATCH 272/644] HHH-14760 Close resource - potential resource leak Fixes https://hibernate.atlassian.net/browse/HHH-14760 --- .../main/java/org/hibernate/tool/hbm2ddl/SchemaExport.java | 4 +++- .../main/java/org/hibernate/tool/hbm2ddl/SchemaUpdate.java | 4 +++- .../java/org/hibernate/tool/hbm2ddl/SchemaValidator.java | 4 +++- .../org/hibernate/tool/hbm2ddl/SchemaValidatorTask.java | 4 +++- .../org/hibernate/jpamodelgen/xml/JpaDescriptorParser.java | 6 ++---- 5 files changed, 14 insertions(+), 8 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaExport.java b/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaExport.java index 33d3e680949e..9009e83aa835 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaExport.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaExport.java @@ -414,7 +414,9 @@ private static StandardServiceRegistry buildStandardServiceRegistry(CommandLineA Properties properties = new Properties(); if ( commandLineArgs.propertiesFile != null ) { - properties.load( new FileInputStream( commandLineArgs.propertiesFile ) ); + try ( final FileInputStream fis = new FileInputStream( commandLineArgs.propertiesFile ) ) { + properties.load( fis ); + } } ssrBuilder.applySettings( properties ); diff --git a/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaUpdate.java b/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaUpdate.java index 4fe27c453ea2..b88c2fd831fd 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaUpdate.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaUpdate.java @@ -179,7 +179,9 @@ private static StandardServiceRegistry buildStandardServiceRegistry(CommandLineA if ( parsedArgs.propertiesFile != null ) { Properties props = new Properties(); - props.load( new FileInputStream( parsedArgs.propertiesFile ) ); + try ( final FileInputStream fis = new FileInputStream( parsedArgs.propertiesFile ) ) { + props.load( fis ); + } ssrBuilder.applySettings( props ); } diff --git a/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaValidator.java b/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaValidator.java index 4470c4e5f5ca..e5cf8f3fb054 100755 --- a/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaValidator.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaValidator.java @@ -136,7 +136,9 @@ private static StandardServiceRegistry buildStandardServiceRegistry(CommandLineA if ( parsedArgs.propertiesFile != null ) { Properties properties = new Properties(); - properties.load( new FileInputStream( parsedArgs.propertiesFile ) ); + try ( final FileInputStream fis = new FileInputStream( parsedArgs.propertiesFile ) ) { + properties.load( fis ); + } ssrBuilder.applySettings( properties ); } diff --git a/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaValidatorTask.java b/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaValidatorTask.java index e489695098f6..bce76f5b49fe 100755 --- a/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaValidatorTask.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/hbm2ddl/SchemaValidatorTask.java @@ -160,7 +160,9 @@ private void configure(StandardServiceRegistryBuilder registryBuilder) throws IO properties.putAll( getProject().getProperties() ); } else { - properties.load( new FileInputStream( propertiesFile ) ); + try ( final FileInputStream fis = new FileInputStream( propertiesFile ) ) { + properties.load( fis ); + } } registryBuilder.applySettings( properties ); diff --git a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/xml/JpaDescriptorParser.java b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/xml/JpaDescriptorParser.java index 2eb8c5af530c..537a963fcdce 100644 --- a/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/xml/JpaDescriptorParser.java +++ b/tooling/metamodel-generator/src/main/java/org/hibernate/jpamodelgen/xml/JpaDescriptorParser.java @@ -197,11 +197,9 @@ private boolean mappingFilesUnchanged(Collection mappingFileNames) { } private void saveTimeStampCache(FileTimeStampChecker fileStampCheck) { - try { - File file = getSerializationTmpFile(); - ObjectOutput out = new ObjectOutputStream( new FileOutputStream( file ) ); + final File file = getSerializationTmpFile(); + try ( final ObjectOutput out = new ObjectOutputStream( new FileOutputStream( file ) ) ) { out.writeObject( fileStampCheck ); - out.close(); context.logMessage( Diagnostic.Kind.OTHER, "Serialized " + fileStampCheck + " into " + file.getAbsolutePath() ); From 23904163188a9d09c19897d795c68e32fe8e91f1 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Thu, 5 Aug 2021 23:56:36 +0100 Subject: [PATCH 273/644] HHH-14773 JdbcCoordinatorImpl micro improvement: unguarded tracev parameters should be constant --- .../hibernate/engine/jdbc/internal/JdbcCoordinatorImpl.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/JdbcCoordinatorImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/JdbcCoordinatorImpl.java index 2d0dae12e242..5ed9b06e891b 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/JdbcCoordinatorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/internal/JdbcCoordinatorImpl.java @@ -252,8 +252,9 @@ public int determineRemainingTransactionTimeOutPeriod() { @Override public void afterStatementExecution() { - LOG.tracev( "Starting after statement execution processing [{0}]", getConnectionReleaseMode() ); - if ( getConnectionReleaseMode() == ConnectionReleaseMode.AFTER_STATEMENT ) { + final ConnectionReleaseMode connectionReleaseMode = getConnectionReleaseMode(); + LOG.tracev( "Starting after statement execution processing [{0}]", connectionReleaseMode ); + if ( connectionReleaseMode == ConnectionReleaseMode.AFTER_STATEMENT ) { if ( ! releasesEnabled ) { LOG.debug( "Skipping aggressive release due to manual disabling" ); return; From 9a335c1c04dca581caedb1e0b55c6ecf34d33433 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Thu, 5 Aug 2021 22:12:56 +0100 Subject: [PATCH 274/644] HHH-14770 Optimise access to EntityPersister in Metamodel via Class type --- .../internal/StatelessSessionImpl.java | 13 ++++--- .../metamodel/internal/MetamodelImpl.java | 38 +++++++++++++------ 2 files changed, 34 insertions(+), 17 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java index 14cc081a13a6..c66a377b5a0d 100755 --- a/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java @@ -167,12 +167,12 @@ public void update(String entityName, Object entity) { @Override public Object get(Class entityClass, Serializable id) { - return get( entityClass.getName(), id ); + return get( entityClass, id, LockMode.NONE ); } @Override public Object get(Class entityClass, Serializable id, LockMode lockMode) { - return get( entityClass.getName(), id, lockMode ); + return get( getFactory().getMetamodel().entityPersister( entityClass ), id, lockMode ); } @Override @@ -182,10 +182,13 @@ public Object get(String entityName, Serializable id) { @Override public Object get(String entityName, Serializable id, LockMode lockMode) { + return get( getFactory().getMetamodel().entityPersister( entityName ), id, lockMode ); + } + + protected Object get(final EntityPersister ep, final Serializable id, final LockMode lockMode) { checkOpen(); - Object result = getFactory().getMetamodel().entityPersister( entityName ) - .load( id, null, getNullSafeLockMode( lockMode ), this ); + Object result = ep.load( id, null, getNullSafeLockMode( lockMode ), this ); if ( temporaryPersistenceContext.isLoadFinished() ) { temporaryPersistenceContext.clear(); } @@ -491,7 +494,7 @@ public EntityPersister getEntityPersister(String entityName, Object object) throws HibernateException { checkOpen(); if ( entityName == null ) { - return getFactory().getMetamodel().entityPersister( guessEntityName( object ) ); + return getFactory().getMetamodel().entityPersister( object.getClass() ); } else { return getFactory().getMetamodel().entityPersister( entityName ).getSubclassEntityPersister( object, getFactory() ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetamodelImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetamodelImpl.java index 055485700e8d..60e16f220ba4 100755 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetamodelImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetamodelImpl.java @@ -142,6 +142,29 @@ public class MetamodelImpl implements MetamodelImplementor, Serializable { private final Map implementorsCache = new ConcurrentHashMap<>(); + // EntityPersister by Class is very hot: optimize access with a ClassValue + private final ClassValue entityPersisterMapByClass = new ClassValue() { + @Override + protected EntityPersister computeValue(final Class type) { + return entityPersisterMap.get( type.getName() ); + } + }; + + // "full location" of an EntityPersister by Class is also hot: optimize access with a ClassValue + private final ClassValue locateEntityPersisterMapByClass = new ClassValue() { + @Override + protected EntityPersister computeValue(final Class type) { + EntityPersister entityPersister = entityPersisterMapByClass.get( type ); + if ( entityPersister == null ) { + String mappedEntityName = entityProxyInterfaceMap.get( type ); + if ( mappedEntityName != null ) { + entityPersister = entityPersisterMap.get( mappedEntityName ); + } + } + return entityPersister; + } + }; + public MetamodelImpl(SessionFactoryImplementor sessionFactory, TypeConfiguration typeConfiguration) { this.sessionFactory = sessionFactory; this.typeConfiguration = typeConfiguration; @@ -694,7 +717,7 @@ public Map collectionPersisters() { @Override public EntityPersister entityPersister(Class entityClass) { - return entityPersister( entityClass.getName() ); + return entityPersisterMapByClass.get( entityClass ); } @Override @@ -706,21 +729,12 @@ public EntityPersister entityPersister(String entityName) throws MappingExceptio return result; } - @Override - public EntityPersister locateEntityPersister(Class byClass) { - EntityPersister entityPersister = entityPersisterMap.get( byClass.getName() ); - if ( entityPersister == null ) { - String mappedEntityName = entityProxyInterfaceMap.get( byClass ); - if ( mappedEntityName != null ) { - entityPersister = entityPersisterMap.get( mappedEntityName ); - } - } - + public EntityPersister locateEntityPersister(final Class byClass) { + EntityPersister entityPersister = locateEntityPersisterMapByClass.get( byClass ); if ( entityPersister == null ) { throw new UnknownEntityTypeException( "Unable to locate persister: " + byClass.getName() ); } - return entityPersister; } From edcce3e1c22aa88ca60f69a90f438d8878b4ff87 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Mon, 9 Aug 2021 11:45:40 +0100 Subject: [PATCH 275/644] HHH-14776 Promote method instantiate(EntityPersister, Serializable) from SessionImplementor to SharedSessionContractImplementor --- .../java/org/hibernate/engine/spi/SessionImplementor.java | 2 -- .../engine/spi/SharedSessionContractImplementor.java | 7 +++++++ .../java/org/hibernate/internal/StatelessSessionImpl.java | 7 ++++++- 3 files changed, 13 insertions(+), 3 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionImplementor.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionImplementor.java index ac8e6acf3d34..fcae06dbf6ed 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionImplementor.java @@ -78,8 +78,6 @@ public interface SessionImplementor ActionQueue getActionQueue(); - Object instantiate(EntityPersister persister, Serializable id) throws HibernateException; - void forceFlush(EntityEntry e) throws HibernateException; @Override diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionContractImplementor.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionContractImplementor.java index af3a11840756..faf3394df49f 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionContractImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SharedSessionContractImplementor.java @@ -333,6 +333,13 @@ Iterator iterateFilter(Object collection, String filter, QueryParameters queryPa */ Object instantiate(String entityName, Serializable id) throws HibernateException; + /** + * Instantiate the entity class of an EntityPersister, initializing with the given identifier. + * This is more efficient than {@link #instantiate(String, Serializable)} but not always + * interchangeable: a single persister might be responsible for multiple types. + */ + Object instantiate(EntityPersister persister, Serializable id) throws HibernateException; + /** * Execute an SQL Query */ diff --git a/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java index c66a377b5a0d..9af560381468 100755 --- a/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java @@ -275,8 +275,13 @@ public void initializeCollection( public Object instantiate( String entityName, Serializable id) throws HibernateException { + return instantiate( getFactory().getMetamodel().entityPersister( entityName ), id ); + } + + @Override + public Object instantiate(EntityPersister persister, Serializable id) throws HibernateException { checkOpen(); - return getFactory().getMetamodel().entityPersister( entityName ).instantiate( id, this ); + return persister.instantiate( id, this ); } @Override From 135361a6b8c03144be3ffcc592962388ed14b61b Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Mon, 9 Aug 2021 14:23:04 +0100 Subject: [PATCH 276/644] HHH-14776 Optimise Loader operations by using the Persister directly --- .../src/main/java/org/hibernate/loader/Loader.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/hibernate-core/src/main/java/org/hibernate/loader/Loader.java b/hibernate-core/src/main/java/org/hibernate/loader/Loader.java index e00d06e3b36b..85f572a7d1ed 100644 --- a/hibernate-core/src/main/java/org/hibernate/loader/Loader.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/Loader.java @@ -1765,7 +1765,14 @@ protected Object instanceNotYetLoaded( } else { // instantiate a new instance - object = session.instantiate( instanceClass, key.getIdentifier() ); + if ( persister.hasSubclasses() ) { + object = session.instantiate( instanceClass , key.getIdentifier() ); + } + else { + //When there are no subclasses, use the persister instance directly + //so to short-circuit the persister lookup: + object = session.instantiate( persister, key.getIdentifier() ); + } } //need to hydrate it. From fb0279e3a7e5e0daef1330aeb7cd2d17ff98cde2 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Mon, 9 Aug 2021 16:09:34 +0100 Subject: [PATCH 277/644] HHH-14625 Avoid performing a ServiceRegistryLookup in JtaTransactionCoordinatorImpl constructor --- .../JtaTransactionCoordinatorBuilderImpl.java | 17 +++++++++++++++-- .../internal/JtaTransactionCoordinatorImpl.java | 5 +++-- 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/resource/transaction/backend/jta/internal/JtaTransactionCoordinatorBuilderImpl.java b/hibernate-core/src/main/java/org/hibernate/resource/transaction/backend/jta/internal/JtaTransactionCoordinatorBuilderImpl.java index 412daf5b972d..3320e50b9f2f 100644 --- a/hibernate-core/src/main/java/org/hibernate/resource/transaction/backend/jta/internal/JtaTransactionCoordinatorBuilderImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/resource/transaction/backend/jta/internal/JtaTransactionCoordinatorBuilderImpl.java @@ -6,11 +6,14 @@ */ package org.hibernate.resource.transaction.backend.jta.internal; +import org.hibernate.engine.transaction.jta.platform.spi.JtaPlatform; import org.hibernate.resource.jdbc.spi.PhysicalConnectionHandlingMode; import org.hibernate.resource.transaction.spi.DdlTransactionIsolator; import org.hibernate.resource.transaction.spi.TransactionCoordinator; import org.hibernate.resource.transaction.spi.TransactionCoordinatorBuilder; import org.hibernate.resource.transaction.spi.TransactionCoordinatorOwner; +import org.hibernate.service.spi.ServiceRegistryAwareService; +import org.hibernate.service.spi.ServiceRegistryImplementor; import org.hibernate.tool.schema.internal.exec.JdbcContext; /** @@ -18,15 +21,19 @@ * * @author Steve Ebersole */ -public class JtaTransactionCoordinatorBuilderImpl implements TransactionCoordinatorBuilder { +public class JtaTransactionCoordinatorBuilderImpl implements TransactionCoordinatorBuilder, ServiceRegistryAwareService { + public static final String SHORT_NAME = "jta"; + private JtaPlatform jtaPlatform; + @Override public TransactionCoordinator buildTransactionCoordinator(TransactionCoordinatorOwner owner, Options options) { return new JtaTransactionCoordinatorImpl( this, owner, - options.shouldAutoJoinTransaction() + options.shouldAutoJoinTransaction(), + jtaPlatform ); } @@ -45,4 +52,10 @@ public PhysicalConnectionHandlingMode getDefaultConnectionHandlingMode() { public DdlTransactionIsolator buildDdlTransactionIsolator(JdbcContext jdbcContext) { return new DdlTransactionIsolatorJtaImpl( jdbcContext ); } + + @Override + public void injectServices(ServiceRegistryImplementor serviceRegistry) { + this.jtaPlatform = serviceRegistry.getService( JtaPlatform.class ); + } + } diff --git a/hibernate-core/src/main/java/org/hibernate/resource/transaction/backend/jta/internal/JtaTransactionCoordinatorImpl.java b/hibernate-core/src/main/java/org/hibernate/resource/transaction/backend/jta/internal/JtaTransactionCoordinatorImpl.java index 13f2edaba562..3617c3f183cf 100644 --- a/hibernate-core/src/main/java/org/hibernate/resource/transaction/backend/jta/internal/JtaTransactionCoordinatorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/resource/transaction/backend/jta/internal/JtaTransactionCoordinatorImpl.java @@ -74,14 +74,15 @@ public class JtaTransactionCoordinatorImpl implements TransactionCoordinator, Sy JtaTransactionCoordinatorImpl( TransactionCoordinatorBuilder transactionCoordinatorBuilder, TransactionCoordinatorOwner owner, - boolean autoJoinTransactions) { + boolean autoJoinTransactions, + JtaPlatform jtaPlatform) { this.transactionCoordinatorBuilder = transactionCoordinatorBuilder; this.transactionCoordinatorOwner = owner; this.autoJoinTransactions = autoJoinTransactions; final JdbcSessionContext jdbcSessionContext = owner.getJdbcSessionOwner().getJdbcSessionContext(); - this.jtaPlatform = jdbcSessionContext.getServiceRegistry().getService( JtaPlatform.class ); + this.jtaPlatform = jtaPlatform; final SessionFactoryOptions sessionFactoryOptions = jdbcSessionContext.getSessionFactory().getSessionFactoryOptions(); this.preferUserTransactions = sessionFactoryOptions.isPreferUserTransaction(); From 544dbbf762bb64ec4d631a76dc52ed03a809418d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Wed, 11 Aug 2021 10:27:51 +0200 Subject: [PATCH 278/644] HHH-14770 Revert "HHH-14770 Optimise access to EntityPersister in Metamodel via Class type" This reverts commit 9a335c1c04dca581caedb1e0b55c6ecf34d33433. --- .../internal/StatelessSessionImpl.java | 13 +++---- .../metamodel/internal/MetamodelImpl.java | 38 ++++++------------- 2 files changed, 17 insertions(+), 34 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java index 9af560381468..46260d9f4422 100755 --- a/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/StatelessSessionImpl.java @@ -167,12 +167,12 @@ public void update(String entityName, Object entity) { @Override public Object get(Class entityClass, Serializable id) { - return get( entityClass, id, LockMode.NONE ); + return get( entityClass.getName(), id ); } @Override public Object get(Class entityClass, Serializable id, LockMode lockMode) { - return get( getFactory().getMetamodel().entityPersister( entityClass ), id, lockMode ); + return get( entityClass.getName(), id, lockMode ); } @Override @@ -182,13 +182,10 @@ public Object get(String entityName, Serializable id) { @Override public Object get(String entityName, Serializable id, LockMode lockMode) { - return get( getFactory().getMetamodel().entityPersister( entityName ), id, lockMode ); - } - - protected Object get(final EntityPersister ep, final Serializable id, final LockMode lockMode) { checkOpen(); - Object result = ep.load( id, null, getNullSafeLockMode( lockMode ), this ); + Object result = getFactory().getMetamodel().entityPersister( entityName ) + .load( id, null, getNullSafeLockMode( lockMode ), this ); if ( temporaryPersistenceContext.isLoadFinished() ) { temporaryPersistenceContext.clear(); } @@ -499,7 +496,7 @@ public EntityPersister getEntityPersister(String entityName, Object object) throws HibernateException { checkOpen(); if ( entityName == null ) { - return getFactory().getMetamodel().entityPersister( object.getClass() ); + return getFactory().getMetamodel().entityPersister( guessEntityName( object ) ); } else { return getFactory().getMetamodel().entityPersister( entityName ).getSubclassEntityPersister( object, getFactory() ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetamodelImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetamodelImpl.java index 60e16f220ba4..055485700e8d 100755 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetamodelImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetamodelImpl.java @@ -142,29 +142,6 @@ public class MetamodelImpl implements MetamodelImplementor, Serializable { private final Map implementorsCache = new ConcurrentHashMap<>(); - // EntityPersister by Class is very hot: optimize access with a ClassValue - private final ClassValue entityPersisterMapByClass = new ClassValue() { - @Override - protected EntityPersister computeValue(final Class type) { - return entityPersisterMap.get( type.getName() ); - } - }; - - // "full location" of an EntityPersister by Class is also hot: optimize access with a ClassValue - private final ClassValue locateEntityPersisterMapByClass = new ClassValue() { - @Override - protected EntityPersister computeValue(final Class type) { - EntityPersister entityPersister = entityPersisterMapByClass.get( type ); - if ( entityPersister == null ) { - String mappedEntityName = entityProxyInterfaceMap.get( type ); - if ( mappedEntityName != null ) { - entityPersister = entityPersisterMap.get( mappedEntityName ); - } - } - return entityPersister; - } - }; - public MetamodelImpl(SessionFactoryImplementor sessionFactory, TypeConfiguration typeConfiguration) { this.sessionFactory = sessionFactory; this.typeConfiguration = typeConfiguration; @@ -717,7 +694,7 @@ public Map collectionPersisters() { @Override public EntityPersister entityPersister(Class entityClass) { - return entityPersisterMapByClass.get( entityClass ); + return entityPersister( entityClass.getName() ); } @Override @@ -729,12 +706,21 @@ public EntityPersister entityPersister(String entityName) throws MappingExceptio return result; } + @Override - public EntityPersister locateEntityPersister(final Class byClass) { - EntityPersister entityPersister = locateEntityPersisterMapByClass.get( byClass ); + public EntityPersister locateEntityPersister(Class byClass) { + EntityPersister entityPersister = entityPersisterMap.get( byClass.getName() ); + if ( entityPersister == null ) { + String mappedEntityName = entityProxyInterfaceMap.get( byClass ); + if ( mappedEntityName != null ) { + entityPersister = entityPersisterMap.get( mappedEntityName ); + } + } + if ( entityPersister == null ) { throw new UnknownEntityTypeException( "Unable to locate persister: " + byClass.getName() ); } + return entityPersister; } From 971d0f1fc5f7a31d373a4b806f4e9b16789eb1fb Mon Sep 17 00:00:00 2001 From: The Geeky Asian Date: Fri, 7 Feb 2020 02:55:30 +0400 Subject: [PATCH 279/644] HHH-13848 - Fix for potential NullPointerException The callers of the convert() method in ResourceRegistryStandardImpl expect an exception which is then thrown. This me produce NullPointerException, which has been fixed in this commit. --- .../resource/jdbc/internal/ResourceRegistryStandardImpl.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/resource/jdbc/internal/ResourceRegistryStandardImpl.java b/hibernate-core/src/main/java/org/hibernate/resource/jdbc/internal/ResourceRegistryStandardImpl.java index f8dbe76362a0..4a2ee8f41312 100644 --- a/hibernate-core/src/main/java/org/hibernate/resource/jdbc/internal/ResourceRegistryStandardImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/resource/jdbc/internal/ResourceRegistryStandardImpl.java @@ -245,8 +245,7 @@ public void register(ResultSet resultSet, Statement statement) { } private JDBCException convert(SQLException e, String s) { - // todo : implement - return null; + return new JDBCException(s, e); } @Override From 1ba359529222ac8e5dc4dbe5b5bd7a63e3bf9fe2 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Mon, 16 Aug 2021 17:12:01 +0200 Subject: [PATCH 280/644] HHH-14777 Enabled skip locked rendering for MariaDB 10.6+ --- .../java/org/hibernate/dialect/Database.java | 5 +++- .../hibernate/dialect/MariaDB106Dialect.java | 24 +++++++++++++++++++ 2 files changed, 28 insertions(+), 1 deletion(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/dialect/MariaDB106Dialect.java diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/Database.java b/hibernate-core/src/main/java/org/hibernate/dialect/Database.java index db752b6a550e..309986ff24ab 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/Database.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/Database.java @@ -280,7 +280,10 @@ public Dialect resolveDialect(DialectResolutionInfo info) { final int minorVersion = info.getDatabaseMinorVersion(); if ( majorVersion == 10 ) { - if ( minorVersion >= 3 ) { + if ( minorVersion >= 6 ) { + return new MariaDB106Dialect(); + } + else if ( minorVersion >= 3 ) { return new MariaDB103Dialect(); } else if ( minorVersion == 2 ) { diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/MariaDB106Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/MariaDB106Dialect.java new file mode 100644 index 000000000000..fc5c161e4c04 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/dialect/MariaDB106Dialect.java @@ -0,0 +1,24 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.dialect; + +/** + * An SQL dialect for MariaDB 10.6 and later, provides skip locked support. + * + * @author Christian Beikov + */ +public class MariaDB106Dialect extends MariaDB103Dialect { + + public MariaDB106Dialect() { + super(); + } + + @Override + public boolean supportsSkipLocked() { + return true; + } +} From 6e6b6eb0ae72c438bb6d51a90f82a89d299f4ba4 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Thu, 19 Aug 2021 17:42:33 +0100 Subject: [PATCH 281/644] HHH-14788 Upgrade to Byteman 4.0.16 --- gradle/libraries.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libraries.gradle b/gradle/libraries.gradle index 8636f33e982d..d3c755de9e61 100644 --- a/gradle/libraries.gradle +++ b/gradle/libraries.gradle @@ -11,7 +11,7 @@ ext { junitVersion = '4.13.2' h2Version = '1.4.197' - bytemanVersion = '4.0.13' //Compatible with JDK16 + bytemanVersion = '4.0.16' //Compatible with JDK 17 jnpVersion = '5.0.6.CR1' hibernateCommonsVersion = '5.1.2.Final' From 180af749c6a9d4febaddad752ceb331c6044d601 Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Wed, 25 Aug 2021 14:02:51 +0000 Subject: [PATCH 282/644] 5.5.7.Final --- changelog.txt | 19 +++++++++++++++++++ gradle/version.properties | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index e60eba5c9592..2eff0cc75cfc 100644 --- a/changelog.txt +++ b/changelog.txt @@ -3,6 +3,25 @@ Hibernate 5 Changelog Note: Please refer to JIRA to learn more about each issue. +Changes in 5.5.7.Final (August 25, 2021) +------------------------------------------------------------------------------------------------------------------------ + +https://hibernate.atlassian.net/projects/HHH/versions/31970 + +** Bug + * [HHH-14760] - Close resource - potential resource leak + +** Improvement + * [HHH-14777] - Support LockOptions.SKIP_LOCKED for MariaDB 10.6+ + * [HHH-14625] - Avoid performing a ServiceRegistryLookup in JtaTransactionCoordinatorImpl constructor + +** Task + * [HHH-14788] - Upgrade to Byteman 4.0.16 + * [HHH-14776] - Optimize Loader instantiate when EntityPersister is known + * [HHH-14773] - JdbcCoordinatorImpl micro improvement: unguarded tracev parameters should be constant + * [HHH-14771] - Upgrade to Byte Buddy 1.11.12 + + Changes in 5.5.6.Final (August 04, 2021) ------------------------------------------------------------------------------------------------------------------------ diff --git a/gradle/version.properties b/gradle/version.properties index 23c7290f7358..5b8505192219 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -hibernateVersion=5.5.7-SNAPSHOT \ No newline at end of file +hibernateVersion=5.5.7.Final \ No newline at end of file From a083481c5b8d795c20c8a0a4892406351e7a46b1 Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Wed, 25 Aug 2021 14:07:42 +0000 Subject: [PATCH 283/644] 5.6.0-SNAPSHOT --- gradle/version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/version.properties b/gradle/version.properties index 5b8505192219..b6875391f169 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -hibernateVersion=5.5.7.Final \ No newline at end of file +hibernateVersion=5.6.0-SNAPSHOT \ No newline at end of file From 4bb3de09a1af8b9e237e222f20f4f807b8511d88 Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Fri, 11 Jun 2021 12:09:35 -0700 Subject: [PATCH 284/644] HHH-14744 : Refactor contextual information for SchemaManagementTool to be more easily extended by Hibernate Reactive HHH-14744 : Restore databases/pgsql/resources/hibernate.properties and gradle/databases.gradle --- .../pgsql/resources/hibernate.properties | 3 +- .../dialect/PostgreSQL10Dialect.java | 45 + .../AbstractInformationExtractorImpl.java | 1133 +++++++++++++++++ .../internal/DatabaseInformationImpl.java | 12 +- ...tionExtractorJdbcDatabaseMetaDataImpl.java | 1041 ++------------- ...equenceInformationExtractorLegacyImpl.java | 67 +- ...formationExtractorMariaDBDatabaseImpl.java | 73 +- ...ationExtractorPostgresSQLDatabaseImpl.java | 40 + .../schema/extract/spi/ExtractionContext.java | 26 + .../internal/AbstractSchemaMigrator.java | 3 +- .../internal/AbstractSchemaValidator.java | 4 +- .../tool/schema/internal/Helper.java | 7 +- .../HibernateSchemaManagementTool.java | 7 +- .../tool/schema/spi/SchemaManagementTool.java | 32 + .../TestExtraPhysicalTableTypes.java | 7 +- .../test/schemaupdate/SchemaUpdateTest.java | 9 + 16 files changed, 1466 insertions(+), 1043 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/AbstractInformationExtractorImpl.java create mode 100644 hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorPostgresSQLDatabaseImpl.java diff --git a/databases/pgsql/resources/hibernate.properties b/databases/pgsql/resources/hibernate.properties index 8481c507db1d..90df1cef1afa 100644 --- a/databases/pgsql/resources/hibernate.properties +++ b/databases/pgsql/resources/hibernate.properties @@ -22,4 +22,5 @@ hibernate.cache.region_prefix hibernate.test hibernate.cache.region.factory_class org.hibernate.testing.cache.CachingRegionFactory hibernate.service.allow_crawling=false -hibernate.session.events.log=true \ No newline at end of file +hibernate.session.events.log=true + diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL10Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL10Dialect.java index 69d99b246f8d..e610796a7f5b 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL10Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL10Dialect.java @@ -6,10 +6,19 @@ */ package org.hibernate.dialect; +import java.sql.DatabaseMetaData; +import java.sql.SQLException; import java.util.List; import org.hibernate.dialect.identity.IdentityColumnSupport; import org.hibernate.dialect.identity.PostgreSQL10IdentityColumnSupport; +import org.hibernate.engine.jdbc.env.spi.AnsiSqlKeywords; +import org.hibernate.engine.jdbc.env.spi.IdentifierCaseStrategy; +import org.hibernate.engine.jdbc.env.spi.IdentifierHelper; +import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder; +import org.hibernate.engine.jdbc.env.spi.NameQualifierSupport; +import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorPostgresSQLDatabaseImpl; +import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor; /** * An SQL dialect for Postgres 10 and later. @@ -31,4 +40,40 @@ public void augmentRecognizedTableTypes(List tableTypesList) { super.augmentRecognizedTableTypes( tableTypesList ); tableTypesList.add( "PARTITIONED TABLE" ); } + + public IdentifierHelper buildIdentifierHelper( + IdentifierHelperBuilder builder, + DatabaseMetaData dbMetaData) throws SQLException { + + if ( dbMetaData != null ) { + builder.applyIdentifierCasing( dbMetaData ); + builder.applyReservedWords( dbMetaData ); + } + else { + builder.setUnquotedCaseStrategy( IdentifierCaseStrategy.LOWER ); + builder.setQuotedCaseStrategy( IdentifierCaseStrategy.MIXED ); + } + builder.applyReservedWords( AnsiSqlKeywords.INSTANCE.sql2003() ); + builder.applyReservedWords( getKeywords() ); + + builder.setNameQualifierSupport( getNameQualifierSupport() ); + + return builder.build(); + } + + @Override + public NameQualifierSupport getNameQualifierSupport() { + return NameQualifierSupport.SCHEMA; + } + + + @Override + public SequenceInformationExtractor getSequenceInformationExtractor() { + return SequenceInformationExtractorPostgresSQLDatabaseImpl.INSTANCE; + } + + @Override + public String getCurrentSchemaCommand() { + return "select current_schema from sys.dummy"; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/AbstractInformationExtractorImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/AbstractInformationExtractorImpl.java new file mode 100644 index 000000000000..cee3d506a8f9 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/AbstractInformationExtractorImpl.java @@ -0,0 +1,1133 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.tool.schema.extract.internal; + +import java.sql.DatabaseMetaData; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Locale; +import java.util.Map; +import java.util.Objects; +import java.util.StringTokenizer; + +import org.hibernate.JDBCException; +import org.hibernate.boot.model.TruthValue; +import org.hibernate.boot.model.naming.DatabaseIdentifier; +import org.hibernate.boot.model.naming.Identifier; +import org.hibernate.boot.model.relational.QualifiedTableName; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.engine.config.spi.ConfigurationService; +import org.hibernate.engine.config.spi.StandardConverters; +import org.hibernate.engine.jdbc.env.spi.IdentifierHelper; +import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; +import org.hibernate.engine.jdbc.env.spi.NameQualifierSupport; +import org.hibernate.internal.CoreLogging; +import org.hibernate.internal.CoreMessageLogger; +import org.hibernate.internal.util.StringHelper; +import org.hibernate.internal.util.config.ConfigurationHelper; +import org.hibernate.tool.schema.extract.spi.ColumnInformation; +import org.hibernate.tool.schema.extract.spi.ExtractionContext; +import org.hibernate.tool.schema.extract.spi.ForeignKeyInformation; +import org.hibernate.tool.schema.extract.spi.IndexInformation; +import org.hibernate.tool.schema.extract.spi.InformationExtractor; +import org.hibernate.tool.schema.extract.spi.NameSpaceTablesInformation; +import org.hibernate.tool.schema.extract.spi.PrimaryKeyInformation; +import org.hibernate.tool.schema.extract.spi.SchemaExtractionException; +import org.hibernate.tool.schema.extract.spi.TableInformation; +import org.hibernate.tool.schema.spi.SchemaManagementException; + +public abstract class AbstractInformationExtractorImpl implements InformationExtractor { + private static final CoreMessageLogger LOG = CoreLogging.messageLogger( AbstractInformationExtractorImpl.class ); + + private final String[] tableTypes; + + private String[] extraPhysicalTableTypes; + + private final ExtractionContext extractionContext; + + private final boolean useJdbcMetadataDefaultsSetting; + + private Identifier currentCatalog; + private Identifier currentSchema; + + private String currentCatalogFilter; + private String currentSchemaFilter; + + + public AbstractInformationExtractorImpl(ExtractionContext extractionContext) { + this.extractionContext = extractionContext; + + ConfigurationService configService = extractionContext.getServiceRegistry() + .getService( ConfigurationService.class ); + + useJdbcMetadataDefaultsSetting = configService.getSetting( + "hibernate.temp.use_jdbc_metadata_defaults", + StandardConverters.BOOLEAN, + Boolean.TRUE + ); + + final String extraPhysicalTableTypesConfig = configService.getSetting( + AvailableSettings.EXTRA_PHYSICAL_TABLE_TYPES, + StandardConverters.STRING, + configService.getSetting( + AvailableSettings.DEPRECATED_EXTRA_PHYSICAL_TABLE_TYPES, + StandardConverters.STRING, + "" + ) + ); + if ( ! StringHelper.isBlank( extraPhysicalTableTypesConfig ) ) { + this.extraPhysicalTableTypes = StringHelper.splitTrimmingTokens( + ",;", + extraPhysicalTableTypesConfig, + false + ); + } + + final List tableTypesList = new ArrayList<>(); + tableTypesList.add( "TABLE" ); + tableTypesList.add( "VIEW" ); + if ( ConfigurationHelper.getBoolean( AvailableSettings.ENABLE_SYNONYMS, configService.getSettings(), false ) ) { + tableTypesList.add( "SYNONYM" ); + } + if ( extraPhysicalTableTypes != null ) { + Collections.addAll( tableTypesList, extraPhysicalTableTypes ); + } + extractionContext.getJdbcEnvironment().getDialect().augmentRecognizedTableTypes( tableTypesList ); + + this.tableTypes = tableTypesList.toArray( new String[ tableTypesList.size() ] ); + } + + protected IdentifierHelper identifierHelper() { + return extractionContext.getJdbcEnvironment().getIdentifierHelper(); + } + + protected JDBCException convertSQLException(SQLException sqlException, String message) { + return extractionContext.getJdbcEnvironment().getSqlExceptionHelper().convert( sqlException, message ); + } + + protected String toMetaDataObjectName(Identifier identifier) { + return extractionContext.getJdbcEnvironment().getIdentifierHelper().toMetaDataObjectName( identifier ); + } + + protected ExtractionContext getExtractionContext() { + return extractionContext; + } + + protected String getResultSetCatalogLabel() { + return "TABLE_CAT"; + } + protected String getResultSetSchemaLabel() { + return "TABLE_SCHEM"; + } + protected String getResultSetTableNameLabel() { + return "TABLE_NAME"; + } + protected String getResultSetTableTypeLabel() { + return "TABLE_TYPE"; + } + protected String getResultSetRemarksLabel() { + return "REMARKS"; + } + protected String getResultSetPrimaryKeyCatalogLabel() { + return "PKTABLE_CAT"; + } + protected String getResultSetPrimaryKeySchemaLabel() { + return "PKTABLE_SCHEM"; + } + protected String getResultSetPrimaryKeyTableLabel() { + return "PKTABLE_NAME"; + } + protected String getResultSetColumnNameLabel() { + return "COLUMN_NAME"; + } + protected String getResultSetSqlTypeCodeLabel() { + return "DATA_TYPE"; + } + protected String getResultSetTypeNameLabel() { + return "TYPE_NAME"; + } + protected String getResultSetColumnSizeLabel() { + return "COLUMN_SIZE"; + } + protected String getResultSetDecimalDigitsLabel() { + return "DECIMAL_DIGITS"; + } + protected String getResultSetIsNullableLabel() { + return "IS_NULLABLE"; + } + protected String getResultSetIndexTypeLabel() { + return "TYPE"; + } + protected String getResultSetIndexNameLabel() { + return "INDEX_NAME"; + } + protected String getResultSetForeignKeyLabel() { + return "FK_NAME"; + } + protected String getResultSetPrimaryKeyNameLabel() { + return "PK_NAME"; + } + protected String getResultSetColumnPositionColumn() { + return "KEY_SEQ" ; + } + protected String getResultSetPrimaryKeyColumnNameLabel() { + return "PKCOLUMN_NAME" ; + } + protected String getResultSetForeignKeyColumnNameLabel() { + return "FKCOLUMN_NAME" ; + } + + protected String determineCatalogFilter(Identifier catalog) { + Identifier identifierToUse = catalog; + if ( identifierToUse == null ) { + identifierToUse = extractionContext.getDefaultCatalog(); + } + + return extractionContext.getJdbcEnvironment().getIdentifierHelper().toMetaDataCatalogName( identifierToUse ); + } + + protected String determineSchemaFilter(Identifier schema) { + Identifier identifierToUse = schema; + if ( identifierToUse == null ) { + identifierToUse = extractionContext.getDefaultSchema(); + } + + return extractionContext.getJdbcEnvironment().getIdentifierHelper().toMetaDataSchemaName( identifierToUse ); + } + + protected abstract T processCatalogsResultSet(ExtractionContext.ResultSetProcessor processor) throws SQLException; + + @Override + public boolean catalogExists(Identifier catalog) { + try { + return processCatalogsResultSet( resultSet -> { + + while ( resultSet.next() ) { + final String existingCatalogName = resultSet.getString( getResultSetCatalogLabel() ); + + // todo : hmm.. case sensitive or insensitive match... + // for now, match any case... + + if ( catalog.getText().equalsIgnoreCase( existingCatalogName ) ) { + return true; + } + } + + return false; + }); + } + catch (SQLException sqlException) { + throw convertSQLException( sqlException, "Unable to query ResultSet for existing catalogs" ); + } + } + + protected abstract T processSchemaResultSet( + String catalogFilter, + String schemaFilter, + ExtractionContext.ResultSetProcessor processor) throws SQLException; + + @Override + public boolean schemaExists(Identifier catalog, Identifier schema) { + final String catalogFilter = determineCatalogFilter( catalog ); + final String schemaFilter = determineSchemaFilter( schema ); + + try { + return processSchemaResultSet( + catalogFilter, + schemaFilter, + resultSet -> { + + if ( !resultSet.next() ) { + return false; + } + + if ( resultSet.next() ) { + final String catalogName = catalog == null ? "" : catalog.getCanonicalName(); + final String schemaName = schema == null ? "" : schema.getCanonicalName(); + + LOG.debugf( + "Multiple schemas found with that name [%s.%s]", + catalogName, + schemaName + ); + } + return true; + } + ); + } + catch (SQLException sqlException) { + throw convertSQLException( sqlException, "Unable to query ResultSet for existing schemas" ); + } + } + + private TableInformation extractTableInformation(ResultSet resultSet) throws SQLException { + final QualifiedTableName tableName = extractTableName( resultSet ); + + final TableInformationImpl tableInformation = new TableInformationImpl( + this, + identifierHelper(), + tableName, + isPhysicalTableType( resultSet.getString( getResultSetTableTypeLabel() ) ), + resultSet.getString( getResultSetRemarksLabel() ) + ); + return tableInformation; + } + + @Override + public TableInformation getTable(Identifier catalog, Identifier schema, Identifier tableName) { + if ( catalog != null || schema != null ) { + // The table defined an explicit namespace. In such cases we only ever want to look + // in the identified namespace + + return locateTableInNamespace( catalog, schema, tableName ); + } + else { + // The table did not define an explicit namespace: + // 1) look in current namespace + // 2) look in default namespace + // 3) look in all namespaces - multiple hits is considered an error + + TableInformation tableInfo; + + // 1) look in current namespace + final JdbcEnvironment jdbcEnvironment = extractionContext.getJdbcEnvironment(); + final Identifier currentSchema = getCurrentSchema( jdbcEnvironment ); + final Identifier currentCatalog = getCurrentCatalog( jdbcEnvironment ); + if ( currentCatalog != null + || currentSchema != null ) { + tableInfo = locateTableInNamespace( + currentCatalog, + currentSchema, + tableName + ); + + if ( tableInfo != null ) { + return tableInfo; + } + } + + // 2) look in default namespace + if ( extractionContext.getDefaultCatalog() != null || extractionContext.getDefaultSchema() != null ) { + tableInfo = locateTableInNamespace( + extractionContext.getDefaultCatalog(), + extractionContext.getDefaultSchema(), + tableName + ); + + if ( tableInfo != null ) { + return tableInfo; + } + } + + // 3) look in all namespaces + + final String tableNameFilter = toMetaDataObjectName( tableName ); + + try { + return processTableResultSet( + null, + null, + tableNameFilter, + tableTypes, + resultSet -> extractTableInformation( + null, + null, + tableName, + resultSet + ) + ); + } + catch (SQLException sqlException) { + throw convertSQLException( sqlException, "Error accessing table metadata" ); + } + } + } + + private Identifier getCurrentSchema(JdbcEnvironment jdbcEnvironment) { + if ( currentSchema != null ) { + return currentSchema; + } + final Identifier schema = jdbcEnvironment.getCurrentSchema(); + if ( schema != null ) { + currentSchema = schema; + } + if ( !useJdbcMetadataDefaultsSetting ) { + try { + currentSchema = extractionContext.getJdbcEnvironment() + .getIdentifierHelper() + .toIdentifier( extractionContext.getJdbcConnection().getSchema() ); + } + catch (SQLException ignore) { + LOG.sqlWarning( ignore.getErrorCode(), ignore.getSQLState() ); + } + } + return currentSchema; + } + + private Identifier getCurrentCatalog(JdbcEnvironment jdbcEnvironment) { + if ( currentCatalog != null ) { + return currentCatalog; + } + final Identifier catalog = jdbcEnvironment.getCurrentCatalog(); + if ( catalog != null ) { + currentCatalog = catalog; + } + if ( !useJdbcMetadataDefaultsSetting ) { + try { + currentCatalog = extractionContext.getJdbcEnvironment() + .getIdentifierHelper() + .toIdentifier( extractionContext.getJdbcConnection().getCatalog() ); + } + catch (SQLException ignore) { + LOG.sqlWarning( ignore.getErrorCode(), ignore.getSQLState() ); + } + } + return currentCatalog; + } + + private String getCurrentCatalogFilter(JdbcEnvironment jdbcEnvironment) { + if ( currentCatalogFilter != null ) { + return currentCatalogFilter; + } + final Identifier currentCatalog = jdbcEnvironment.getCurrentCatalog(); + if ( currentCatalog != null ) { + currentCatalogFilter = toMetaDataObjectName( currentCatalog ); + } + if ( !useJdbcMetadataDefaultsSetting ) { + try { + currentCatalogFilter = extractionContext.getJdbcConnection().getCatalog(); + } + catch (SQLException ignore) { + LOG.sqlWarning( ignore.getErrorCode(), ignore.getSQLState() ); + } + } + return currentCatalogFilter; + } + + private String getCurrentSchemaFilter(JdbcEnvironment jdbcEnvironment) { + if ( currentSchemaFilter != null ) { + return currentSchemaFilter; + } + final Identifier currentSchema = jdbcEnvironment.getCurrentSchema(); + if ( currentSchema != null ) { + currentSchemaFilter = toMetaDataObjectName( currentSchema ); + } + + if ( !useJdbcMetadataDefaultsSetting ) { + try { + currentSchemaFilter = extractionContext.getJdbcConnection().getSchema(); + } + catch (SQLException ignore) { + LOG.sqlWarning( ignore.getErrorCode(), ignore.getSQLState() ); + } + } + return currentSchemaFilter; + } + + @Override + public NameSpaceTablesInformation getTables(Identifier catalog, Identifier schema) { + + final String catalogFilter; + final String schemaFilter; + + final JdbcEnvironment jdbcEnvironment = extractionContext.getJdbcEnvironment(); + final NameQualifierSupport nameQualifierSupport = jdbcEnvironment.getNameQualifierSupport(); + if ( nameQualifierSupport.supportsCatalogs() ) { + if ( catalog == null ) { + // look in the current namespace + final String currentCatalogFilter = getCurrentCatalogFilter(jdbcEnvironment); + if ( currentCatalogFilter != null ) { + catalogFilter = currentCatalogFilter; + } + else { + if ( extractionContext.getDefaultCatalog() != null ) { + // 2) look in default namespace + catalogFilter = toMetaDataObjectName( extractionContext.getDefaultCatalog() ); + } + else { + catalogFilter = ""; + } + } + } + else { + catalogFilter = toMetaDataObjectName( catalog ); + } + } + else { + catalogFilter = null; + } + + if ( nameQualifierSupport.supportsSchemas() ) { + if ( schema == null ) { + // 1) look in current namespace + final String currentSchemaFilter = getCurrentSchemaFilter( jdbcEnvironment ); + if ( currentSchemaFilter != null ) { + schemaFilter = currentSchemaFilter; + } + else { + if ( extractionContext.getDefaultSchema() != null ) { + // 2) look in default namespace + schemaFilter = toMetaDataObjectName( extractionContext.getDefaultSchema() ); + } + else { + schemaFilter = ""; + } + } + } + else { + schemaFilter = toMetaDataObjectName( schema ); + } + } + else { + schemaFilter = null; + } + + try { + return processTableResultSet( + catalogFilter, + schemaFilter, + null, + tableTypes, + resultSet -> { + final NameSpaceTablesInformation tablesInformation = extractNameSpaceTablesInformation( resultSet ); + populateTablesWithColumns( catalogFilter, schemaFilter, tablesInformation ); + return tablesInformation; + } ); + } + catch (SQLException sqlException) { + throw convertSQLException( sqlException, "Error accessing table metadata" ); + } + } + + protected abstract T processColumnsResultSet( + String catalogFilter, + String schemaFilter, + String tableFilter, + ExtractionContext.ResultSetProcessor processor) throws SQLException; + + private void populateTablesWithColumns( + String catalogFilter, + String schemaFilter, + NameSpaceTablesInformation tables) { + try { + processColumnsResultSet( + catalogFilter, + schemaFilter, + null, + resultSet -> { + String currentTableName = ""; + TableInformation currentTable = null; + while ( resultSet.next() ) { + if ( !currentTableName.equals( resultSet.getString( getResultSetTableNameLabel() ) ) ) { + currentTableName = resultSet.getString( getResultSetTableNameLabel() ); + currentTable = tables.getTableInformation( currentTableName ); + } + if ( currentTable != null ) { + addExtractedColumnInformation( currentTable, resultSet ); + } + } + return null; + } + ); + } + catch (SQLException e) { + throw convertSQLException( + e, + "Error accessing tables metadata" + ); + } + } + + protected void addExtractedColumnInformation(TableInformation tableInformation, ResultSet resultSet) + throws SQLException { + final ColumnInformation columnInformation = new ColumnInformationImpl( + tableInformation, + DatabaseIdentifier.toIdentifier( resultSet.getString( getResultSetColumnNameLabel() ) ), + resultSet.getInt( getResultSetSqlTypeCodeLabel() ), + new StringTokenizer( resultSet.getString( getResultSetTypeNameLabel() ), "() " ).nextToken(), + resultSet.getInt( getResultSetColumnSizeLabel() ), + resultSet.getInt( getResultSetDecimalDigitsLabel() ), + interpretTruthValue( resultSet.getString( getResultSetIsNullableLabel() ) ) + ); + tableInformation.addColumn( columnInformation ); + } + + private NameSpaceTablesInformation extractNameSpaceTablesInformation(ResultSet resultSet) throws SQLException { + NameSpaceTablesInformation tables = new NameSpaceTablesInformation(identifierHelper()); + while ( resultSet.next() ) { + final TableInformation tableInformation = extractTableInformation( resultSet ); + tables.addTableInformation( tableInformation ); + } + return tables; + } + + /** + * Returns a {@link ResultSet} having the following column aliases: + *

    + * TABLE_CAT String => table catalog (may be null) + * TABLE_SCHEM String => table schema (may be null) + * TABLE_NAME String => table name + * TABLE_TYPE String => table type. Typical types are "TABLE", "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS", "SYNONYM". + * REMARKS String => explanatory comment on the table (may be null) + *

    + * These column aliases are purposely consistent with those defined by {@link DatabaseMetaData#getTables}, + * although the {@link ResultSet} need not have been returned by that method. + * + * @param catalogFilter + * @param schemaFilter + * @param tableNameFilter + * @param tableTypes + * @return + * @throws SQLException + */ + protected abstract T processTableResultSet( + String catalogFilter, + String schemaFilter, + String tableNameFilter, + String[] tableTypes, + ExtractionContext.ResultSetProcessor processor + ) throws SQLException; + + private TableInformation locateTableInNamespace( + Identifier catalog, + Identifier schema, + Identifier tableName) { + final Identifier catalogToUse; + final Identifier schemaToUse; + + final String catalogFilter; + final String schemaFilter; + + if ( extractionContext.getJdbcEnvironment().getNameQualifierSupport().supportsCatalogs() ) { + if ( catalog == null ) { + String defaultCatalog = ""; + if ( extractionContext.getJdbcEnvironment().getNameQualifierSupport().supportsCatalogs() ) { + try { + defaultCatalog = extractionContext.getJdbcConnection().getCatalog(); + } + catch (SQLException ignore) { + } + } + catalogToUse = null; + catalogFilter = defaultCatalog; + } + else { + catalogToUse = catalog; + catalogFilter = toMetaDataObjectName( catalog ); + } + } + else { + catalogToUse = null; + catalogFilter = null; + } + + if ( extractionContext.getJdbcEnvironment().getNameQualifierSupport().supportsSchemas() ) { + if ( schema == null ) { + schemaToUse = null; + schemaFilter = ""; + } + else { + schemaToUse = schema; + schemaFilter = toMetaDataObjectName( schema ); + } + } + else { + schemaToUse = null; + schemaFilter = null; + } + + final String tableNameFilter = toMetaDataObjectName( tableName ); + + try { + return processTableResultSet( + catalogFilter, + schemaFilter, + tableNameFilter, + tableTypes, + resultSet -> extractTableInformation( + catalogToUse, + schemaToUse, + tableName, + resultSet + ) + ); + + } + catch (SQLException sqlException) { + throw convertSQLException( sqlException, "Error accessing table metadata" ); + } + } + + private TableInformation extractTableInformation( + Identifier catalog, + Identifier schema, + Identifier tableName, + ResultSet resultSet) throws SQLException { + + boolean found = false; + TableInformation tableInformation = null; + + while ( resultSet.next() ) { + + if ( tableName.equals( Identifier.toIdentifier( + resultSet.getString( getResultSetTableNameLabel() ), + tableName.isQuoted() + ) ) ) { + if ( found ) { + LOG.multipleTablesFound( tableName.render() ); + final String catalogName = catalog == null ? "" : catalog.render(); + final String schemaName = schema == null ? "" : schema.render(); + throw new SchemaExtractionException( + String.format( + Locale.ENGLISH, + "More than one table found in namespace (%s, %s) : %s", + catalogName, + schemaName, + tableName.render() + ) + ); + } + else { + found = true; + tableInformation = extractTableInformation( resultSet ); + addColumns( tableInformation ); + } + } + } + if ( !found ) { + LOG.tableNotFound( tableName.render() ); + } + return tableInformation; + } + + protected abstract String getResultSetTableTypesPhysicalTableConstant(); + + protected boolean isPhysicalTableType(String tableType) { + if ( extraPhysicalTableTypes == null ) { + return getResultSetTableTypesPhysicalTableConstant().equalsIgnoreCase( tableType ); + } + else { + if ( getResultSetTableTypesPhysicalTableConstant().equalsIgnoreCase( tableType ) ) { + return true; + } + for ( String extraPhysicalTableType : extraPhysicalTableTypes ) { + if ( extraPhysicalTableType.equalsIgnoreCase( tableType ) ) { + return true; + } + } + return false; + } + } + + protected void addColumns(TableInformation tableInformation) { + final QualifiedTableName tableName = tableInformation.getName(); + final Identifier catalog = tableName.getCatalogName(); + final Identifier schema = tableName.getSchemaName(); + + final String catalogFilter = catalog == null ? "" : catalog.getText(); + final String schemaFilter = schema == null ? "" : schema.getText(); + + try { + processColumnsResultSet( + catalogFilter, + schemaFilter, + tableName.getTableName().getText(), + resultSet -> { + + while ( resultSet.next() ) { + addExtractedColumnInformation( tableInformation, resultSet ); + } + return null; + } + ); + + } + catch (SQLException e) { + throw convertSQLException( + e, + "Error accessing tables metadata" + ); + } + } + + protected TruthValue interpretNullable(int nullable) { + switch ( nullable ) { + case ResultSetMetaData.columnNullable: + return TruthValue.TRUE; + case ResultSetMetaData.columnNoNulls: + return TruthValue.FALSE; + default: + return TruthValue.UNKNOWN; + } + } + + private TruthValue interpretTruthValue(String nullable) { + if ( "yes".equalsIgnoreCase( nullable ) ) { + return TruthValue.TRUE; + } + else if ( "no".equalsIgnoreCase( nullable ) ) { + return TruthValue.FALSE; + } + return TruthValue.UNKNOWN; + } + + protected abstract T processPrimaryKeysResultSet( + String catalogFilter, + String schemaFilter, + Identifier tableName, + ExtractionContext.ResultSetProcessor processor) throws SQLException; + + @Override + public PrimaryKeyInformation getPrimaryKey(TableInformationImpl tableInformation) { + final QualifiedTableName tableName = tableInformation.getName(); + final Identifier catalog = tableName.getCatalogName(); + final Identifier schema = tableName.getSchemaName(); + + final String catalogFilter; + final String schemaFilter; + + if ( catalog == null ) { + catalogFilter = ""; + } + else { + catalogFilter = catalog.getText(); + } + + if ( schema == null ) { + schemaFilter = ""; + } + else { + schemaFilter = schema.getText(); + } + + try { + return processPrimaryKeysResultSet( + catalogFilter, + schemaFilter, + tableInformation.getName().getTableName(), + resultSet -> extractPrimaryKeyInformation( tableInformation, resultSet ) + ); + } + catch (SQLException e) { + throw convertSQLException( e, "Error while reading primary key meta data for " + tableInformation.getName().toString() ); + } + } + + private PrimaryKeyInformation extractPrimaryKeyInformation( + TableInformation tableInformation, + ResultSet resultSet + ) throws SQLException { + + final List pkColumns = new ArrayList<>(); + boolean firstPass = true; + Identifier pkIdentifier = null; + + while ( resultSet.next() ) { + final String currentPkName = resultSet.getString( getResultSetPrimaryKeyNameLabel() ); + final Identifier currentPkIdentifier = currentPkName == null + ? null + : DatabaseIdentifier.toIdentifier( currentPkName ); + if ( firstPass ) { + pkIdentifier = currentPkIdentifier; + firstPass = false; + } + else { + if ( !Objects.equals( pkIdentifier, currentPkIdentifier ) ) { + throw new SchemaExtractionException( + String.format( + "Encountered primary keys differing name on table %s", + tableInformation.getName().toString() + ) + ); + } + } + + final int columnPosition = resultSet.getInt( getResultSetColumnPositionColumn() ); + + final Identifier columnIdentifier = DatabaseIdentifier.toIdentifier( + resultSet.getString( getResultSetColumnNameLabel() ) + ); + final ColumnInformation column = tableInformation.getColumn( columnIdentifier ); + pkColumns.add( columnPosition-1, column ); + } + if ( firstPass ) { + // we did not find any results (no pk) + return null; + } + else { + // validate column list is properly contiguous + for ( int i = 0; i < pkColumns.size(); i++ ) { + if ( pkColumns.get( i ) == null ) { + throw new SchemaExtractionException( "Primary Key information was missing for KEY_SEQ = " + ( i+1) ); + } + } + + // build the return + return new PrimaryKeyInformationImpl( pkIdentifier, pkColumns ); + } + } + + /** + * Requires the following: + * + * index_type result must be one of the constants from DatabaseMetaData + * (e.g., #tableIndexStatistic, tableIndexClustered, tableIndexHashed, or tableIndexOther) + * index_name + * column_name + * + * @param catalogFilter + * @param schemaFilter + * @param tableName + * @param approximate + * @return + * @throws SQLException + */ + protected abstract T processIndexInfoResultSet( + String catalogFilter, + String schemaFilter, + Identifier tableName, + boolean approximate, + ExtractionContext.ResultSetProcessor processor) throws SQLException; + + @Override + public Iterable getIndexes(TableInformation tableInformation) { + final Map builders = new HashMap<>(); + final QualifiedTableName tableName = tableInformation.getName(); + final Identifier catalog = tableName.getCatalogName(); + final Identifier schema = tableName.getSchemaName(); + + final String catalogFilter; + final String schemaFilter; + + if ( catalog == null ) { + catalogFilter = ""; + } + else { + catalogFilter = catalog.getText(); + } + + if ( schema == null ) { + schemaFilter = ""; + } + else { + schemaFilter = schema.getText(); + } + + try { + processIndexInfoResultSet( + catalogFilter, + schemaFilter, + tableName.getTableName(), + true, // DO require up-to-date results + resultSet -> { + while ( resultSet.next() ) { + if ( resultSet.getShort(getResultSetIndexTypeLabel() ) == DatabaseMetaData.tableIndexStatistic ) { + continue; + } + + final Identifier indexIdentifier = DatabaseIdentifier.toIdentifier( + resultSet.getString( getResultSetIndexNameLabel() ) + ); + IndexInformationImpl.Builder builder = builders.get( indexIdentifier ); + if ( builder == null ) { + builder = IndexInformationImpl.builder( indexIdentifier ); + builders.put( indexIdentifier, builder ); + } + + final Identifier columnIdentifier = DatabaseIdentifier.toIdentifier( + resultSet.getString( getResultSetColumnNameLabel() ) + ); + final ColumnInformation columnInformation = tableInformation.getColumn( columnIdentifier ); + if ( columnInformation == null ) { + // See HHH-10191: this may happen when dealing with Oracle/PostgreSQL function indexes + LOG.logCannotLocateIndexColumnInformation( + columnIdentifier.getText(), + indexIdentifier.getText() + ); + } + builder.addColumn( columnInformation ); + } + return null; + } + ); + + } + catch (SQLException e) { + throw convertSQLException( + e, + "Error accessing index information: " + tableInformation.getName().toString() + ); + } + + final List indexes = new ArrayList<>(); + for ( IndexInformationImpl.Builder builder : builders.values() ) { + IndexInformationImpl index = builder.build(); + indexes.add( index ); + } + return indexes; + } + + protected abstract T processImportedKeysResultSet( + String catalogFilter, + String schemaFilter, + String tableName, + ExtractionContext.ResultSetProcessor processor + ) throws SQLException; + + @Override + public Iterable getForeignKeys(TableInformation tableInformation) { + final Map fkBuilders = new HashMap<>(); + final QualifiedTableName tableName = tableInformation.getName(); + final Identifier catalog = tableName.getCatalogName(); + final Identifier schema = tableName.getSchemaName(); + + final String catalogFilter; + final String schemaFilter; + + if ( catalog == null ) { + catalogFilter = ""; + } + else { + catalogFilter = catalog.getText(); + } + + if ( schema == null ) { + schemaFilter = ""; + } + else { + schemaFilter = schema.getText(); + } + + try { + processImportedKeysResultSet( + catalogFilter, + schemaFilter, + tableInformation.getName().getTableName().getText(), + resultSet -> { + // todo : need to account for getCrossReference() as well... + + while ( resultSet.next() ) { + // IMPL NOTE : The builder is mainly used to collect the column reference mappings + final Identifier fkIdentifier = DatabaseIdentifier.toIdentifier( + resultSet.getString( getResultSetForeignKeyLabel() ) + ); + ForeignKeyBuilder fkBuilder = fkBuilders.get( fkIdentifier ); + if ( fkBuilder == null ) { + fkBuilder = generateForeignKeyBuilder( fkIdentifier ); + fkBuilders.put( fkIdentifier, fkBuilder ); + } + + final QualifiedTableName incomingPkTableName = extractPrimaryKeyTableName( resultSet ); + + final TableInformation pkTableInformation = extractionContext.getDatabaseObjectAccess() + .locateTableInformation( incomingPkTableName ); + + if ( pkTableInformation == null ) { + // the assumption here is that we have not seen this table already based on fully-qualified name + // during previous step of building all table metadata so most likely this is + // not a match based solely on schema/catalog and that another row in this result set + // should match. + continue; + } + + final Identifier fkColumnIdentifier = DatabaseIdentifier.toIdentifier( + resultSet.getString( getResultSetForeignKeyColumnNameLabel() ) + ); + final Identifier pkColumnIdentifier = DatabaseIdentifier.toIdentifier( + resultSet.getString( getResultSetPrimaryKeyColumnNameLabel() ) + ); + + fkBuilder.addColumnMapping( + tableInformation.getColumn( fkColumnIdentifier ), + pkTableInformation.getColumn( pkColumnIdentifier ) + ); + } + return null; + } + ); + } + catch (SQLException e) { + throw convertSQLException( + e, + "Error accessing column metadata: " + tableInformation.getName().toString() + ); + } + + final List fks = new ArrayList<>(); + for ( ForeignKeyBuilder fkBuilder : fkBuilders.values() ) { + ForeignKeyInformation fk = fkBuilder.build(); + fks.add( fk ); + } + return fks; + } + + private ForeignKeyBuilder generateForeignKeyBuilder(Identifier fkIdentifier) { + return new ForeignKeyBuilderImpl( fkIdentifier ); + } + + protected interface ForeignKeyBuilder { + ForeignKeyBuilder addColumnMapping(ColumnInformation referencing, ColumnInformation referenced); + + ForeignKeyInformation build(); + } + + protected static class ForeignKeyBuilderImpl implements ForeignKeyBuilder { + private final Identifier fkIdentifier; + private final List columnMappingList = new ArrayList<>(); + + public ForeignKeyBuilderImpl(Identifier fkIdentifier) { + this.fkIdentifier = fkIdentifier; + } + + @Override + public ForeignKeyBuilder addColumnMapping(ColumnInformation referencing, ColumnInformation referenced) { + columnMappingList.add( new ForeignKeyInformationImpl.ColumnReferenceMappingImpl( referencing, referenced ) ); + return this; + } + + @Override + public ForeignKeyInformationImpl build() { + if ( columnMappingList.isEmpty() ) { + throw new SchemaManagementException( + "Attempt to resolve foreign key metadata from JDBC metadata failed to find " + + "column mappings for foreign key named [" + fkIdentifier.getText() + "]" + ); + } + return new ForeignKeyInformationImpl( fkIdentifier, columnMappingList ); + } + } + + private QualifiedTableName extractPrimaryKeyTableName(ResultSet resultSet) throws SQLException { + final String incomingCatalogName = resultSet.getString( getResultSetPrimaryKeyCatalogLabel() ); + final String incomingSchemaName = resultSet.getString( getResultSetPrimaryKeySchemaLabel() ); + final String incomingTableName = resultSet.getString( getResultSetPrimaryKeyTableLabel() ); + + final DatabaseIdentifier catalog = DatabaseIdentifier.toIdentifier( incomingCatalogName ); + final DatabaseIdentifier schema = DatabaseIdentifier.toIdentifier( incomingSchemaName ); + final DatabaseIdentifier table = DatabaseIdentifier.toIdentifier( incomingTableName ); + + return new QualifiedTableName( catalog, schema, table ); + } + + private QualifiedTableName extractTableName(ResultSet resultSet) throws SQLException { + final String incomingCatalogName = resultSet.getString( getResultSetCatalogLabel() ); + final String incomingSchemaName = resultSet.getString( getResultSetSchemaLabel() ); + final String incomingTableName = resultSet.getString( getResultSetTableNameLabel() ); + + final DatabaseIdentifier catalog = DatabaseIdentifier.toIdentifier( incomingCatalogName ); + final DatabaseIdentifier schema = DatabaseIdentifier.toIdentifier( incomingSchemaName ); + final DatabaseIdentifier table = DatabaseIdentifier.toIdentifier( incomingTableName ); + + return new QualifiedTableName( catalog, schema, table ); + } + +} diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/DatabaseInformationImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/DatabaseInformationImpl.java index e049dfd9278d..7d968b92dc11 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/DatabaseInformationImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/DatabaseInformationImpl.java @@ -23,7 +23,7 @@ import org.hibernate.tool.schema.extract.spi.NameSpaceTablesInformation; import org.hibernate.tool.schema.extract.spi.SequenceInformation; import org.hibernate.tool.schema.extract.spi.TableInformation; -import org.hibernate.tool.schema.internal.exec.ImprovedExtractionContextImpl; +import org.hibernate.tool.schema.spi.SchemaManagementTool; /** * @author Steve Ebersole @@ -31,7 +31,7 @@ public class DatabaseInformationImpl implements DatabaseInformation, ExtractionContext.DatabaseObjectAccess { private final JdbcEnvironment jdbcEnvironment; - private final ImprovedExtractionContextImpl extractionContext; + private final ExtractionContext extractionContext; private final InformationExtractor extractor; private final Map sequenceInformationMap = new HashMap(); @@ -40,10 +40,10 @@ public DatabaseInformationImpl( ServiceRegistry serviceRegistry, JdbcEnvironment jdbcEnvironment, DdlTransactionIsolator ddlTransactionIsolator, - Namespace.Name defaultNamespace) throws SQLException { + Namespace.Name defaultNamespace, + SchemaManagementTool tool) throws SQLException { this.jdbcEnvironment = jdbcEnvironment; - - this.extractionContext = new ImprovedExtractionContextImpl( + this.extractionContext = tool.createExtractionContext( serviceRegistry, jdbcEnvironment, ddlTransactionIsolator, @@ -53,7 +53,7 @@ public DatabaseInformationImpl( ); // todo : make this pluggable - this.extractor = new InformationExtractorJdbcDatabaseMetaDataImpl( extractionContext ); + this.extractor = tool.createInformationExtractor( extractionContext ); // because we do not have defined a way to locate sequence info by name initializeSequences(); diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/InformationExtractorJdbcDatabaseMetaDataImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/InformationExtractorJdbcDatabaseMetaDataImpl.java index 7e7ed7c04f68..dc5927286dbd 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/InformationExtractorJdbcDatabaseMetaDataImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/InformationExtractorJdbcDatabaseMetaDataImpl.java @@ -6,1017 +6,172 @@ */ package org.hibernate.tool.schema.extract.internal; -import java.sql.DatabaseMetaData; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; -import java.sql.Statement; -import java.util.ArrayList; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Locale; -import java.util.Map; -import java.util.Objects; import java.util.StringTokenizer; -import org.hibernate.JDBCException; -import org.hibernate.boot.model.TruthValue; import org.hibernate.boot.model.naming.DatabaseIdentifier; import org.hibernate.boot.model.naming.Identifier; -import org.hibernate.boot.model.relational.QualifiedTableName; -import org.hibernate.cfg.AvailableSettings; -import org.hibernate.engine.config.spi.ConfigurationService; -import org.hibernate.engine.config.spi.StandardConverters; -import org.hibernate.engine.jdbc.env.spi.IdentifierHelper; -import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; -import org.hibernate.engine.jdbc.env.spi.NameQualifierSupport; -import org.hibernate.internal.CoreLogging; -import org.hibernate.internal.CoreMessageLogger; -import org.hibernate.internal.util.StringHelper; -import org.hibernate.internal.util.config.ConfigurationHelper; -import org.hibernate.tool.schema.extract.spi.ColumnInformation; import org.hibernate.tool.schema.extract.spi.ExtractionContext; -import org.hibernate.tool.schema.extract.spi.ForeignKeyInformation; -import org.hibernate.tool.schema.extract.spi.IndexInformation; -import org.hibernate.tool.schema.extract.spi.InformationExtractor; -import org.hibernate.tool.schema.extract.spi.NameSpaceTablesInformation; -import org.hibernate.tool.schema.extract.spi.PrimaryKeyInformation; -import org.hibernate.tool.schema.extract.spi.SchemaExtractionException; import org.hibernate.tool.schema.extract.spi.TableInformation; -import org.hibernate.tool.schema.spi.SchemaManagementException; /** * Implementation of the SchemaMetaDataExtractor contract which uses the standard JDBC {@link java.sql.DatabaseMetaData} * API for extraction. * * @author Steve Ebersole + * @author Gail Badner */ -public class InformationExtractorJdbcDatabaseMetaDataImpl implements InformationExtractor { - private static final CoreMessageLogger log = CoreLogging.messageLogger( InformationExtractorJdbcDatabaseMetaDataImpl.class ); - - private final String[] tableTypes; - - private String[] extraPhysicalTableTypes; - - private final ExtractionContext extractionContext; - - private final boolean useJdbcMetadataDefaultsSetting; - - private Identifier currentCatalog; - private Identifier currentSchema; - - private String currentCatalogFilter; - private String currentSchemaFilter; +public class InformationExtractorJdbcDatabaseMetaDataImpl extends AbstractInformationExtractorImpl { public InformationExtractorJdbcDatabaseMetaDataImpl(ExtractionContext extractionContext) { - this.extractionContext = extractionContext; - - ConfigurationService configService = extractionContext.getServiceRegistry() - .getService( ConfigurationService.class ); - - useJdbcMetadataDefaultsSetting = configService.getSetting( - "hibernate.temp.use_jdbc_metadata_defaults", - StandardConverters.BOOLEAN, - Boolean.TRUE - ); - - final String extraPhysycalTableTypesConfig = configService.getSetting( - AvailableSettings.EXTRA_PHYSICAL_TABLE_TYPES, - StandardConverters.STRING, - configService.getSetting( - AvailableSettings.DEPRECATED_EXTRA_PHYSICAL_TABLE_TYPES, - StandardConverters.STRING, - "" - ) - ); - if ( ! StringHelper.isBlank( extraPhysycalTableTypesConfig ) ) { - this.extraPhysicalTableTypes = StringHelper.splitTrimmingTokens( - ",;", - extraPhysycalTableTypesConfig, - false - ); - } - - final List tableTypesList = new ArrayList<>(); - tableTypesList.add( "TABLE" ); - tableTypesList.add( "VIEW" ); - if ( ConfigurationHelper.getBoolean( AvailableSettings.ENABLE_SYNONYMS, configService.getSettings(), false ) ) { - tableTypesList.add( "SYNONYM" ); - } - if ( extraPhysicalTableTypes != null ) { - Collections.addAll( tableTypesList, extraPhysicalTableTypes ); - } - extractionContext.getJdbcEnvironment().getDialect().augmentRecognizedTableTypes( tableTypesList ); - - this.tableTypes = tableTypesList.toArray( new String[ tableTypesList.size() ] ); - } - - protected IdentifierHelper identifierHelper() { - return extractionContext.getJdbcEnvironment().getIdentifierHelper(); - } - - protected JDBCException convertSQLException(SQLException sqlException, String message) { - return extractionContext.getJdbcEnvironment().getSqlExceptionHelper().convert( sqlException, message ); - } - - protected String toMetaDataObjectName(Identifier identifier) { - return extractionContext.getJdbcEnvironment().getIdentifierHelper().toMetaDataObjectName( identifier ); + super( extractionContext ); } @Override - public boolean catalogExists(Identifier catalog) { - try { - final ResultSet resultSet = extractionContext.getJdbcDatabaseMetaData().getCatalogs(); - - try { - while ( resultSet.next() ) { - final String existingCatalogName = resultSet.getString( "TABLE_CAT" ); - - // todo : hmm.. case sensitive or insensitive match... - // for now, match any case... - - if ( catalog.getText().equalsIgnoreCase( existingCatalogName ) ) { - return true; - } - } - - return false; - } - finally { - try { - resultSet.close(); - } - catch (SQLException ignore) { - } - } - } - catch (SQLException sqlException) { - throw convertSQLException( sqlException, "Unable to query DatabaseMetaData for existing catalogs" ); - } + protected String getResultSetTableTypesPhysicalTableConstant() { + return "TABLE"; } @Override - public boolean schemaExists(Identifier catalog, Identifier schema) { - try { - final String catalogFilter = determineCatalogFilter( catalog ); - final String schemaFilter = determineSchemaFilter( schema ); - - final ResultSet resultSet = extractionContext.getJdbcDatabaseMetaData().getSchemas( - catalogFilter, - schemaFilter - ); - - try { - if ( !resultSet.next() ) { - return false; - } - - if ( resultSet.next() ) { - final String catalogName = catalog == null ? "" : catalog.getCanonicalName(); - final String schemaName = schema == null ? "" : schema.getCanonicalName(); - - log.debugf( - "Multiple schemas found with that name [%s.%s]", - catalogName, - schemaName - ); - } - return true; - } - finally { - try { - resultSet.close(); - } - catch (SQLException ignore) { - } - } - } - catch (SQLException sqlException) { - throw convertSQLException( sqlException, "Unable to query DatabaseMetaData for existing schemas" ); + public T processCatalogsResultSet(ExtractionContext.ResultSetProcessor processor) throws SQLException { + try (ResultSet resultSet = getExtractionContext().getJdbcDatabaseMetaData().getCatalogs() ) { + return processor.process( resultSet ); } } - private String determineCatalogFilter(Identifier catalog) throws SQLException { - Identifier identifierToUse = catalog; - if ( identifierToUse == null ) { - identifierToUse = extractionContext.getDefaultCatalog(); - } - - return extractionContext.getJdbcEnvironment().getIdentifierHelper().toMetaDataCatalogName( identifierToUse ); - } - - private String determineSchemaFilter(Identifier schema) throws SQLException { - Identifier identifierToUse = schema; - if ( identifierToUse == null ) { - identifierToUse = extractionContext.getDefaultSchema(); - } - - return extractionContext.getJdbcEnvironment().getIdentifierHelper().toMetaDataSchemaName( identifierToUse ); - } - - private TableInformation extractTableInformation(ResultSet resultSet) throws SQLException { - final QualifiedTableName tableName = extractTableName( resultSet ); - - final TableInformationImpl tableInformation = new TableInformationImpl( - this, - identifierHelper(), - tableName, - isPhysicalTableType( resultSet.getString( "TABLE_TYPE" ) ), - resultSet.getString( "REMARKS" ) - ); - return tableInformation; - } - @Override - public TableInformation getTable(Identifier catalog, Identifier schema, Identifier tableName) { - if ( catalog != null || schema != null ) { - // The table defined an explicit namespace. In such cases we only ever want to look - // in the identified namespace - - return locateTableInNamespace( catalog, schema, tableName ); - } - else { - // The table did not define an explicit namespace: - // 1) look in current namespace - // 2) look in default namespace - // 3) look in all namespaces - multiple hits is considered an error - - TableInformation tableInfo = null; - - // 1) look in current namespace - final JdbcEnvironment jdbcEnvironment = extractionContext.getJdbcEnvironment(); - final Identifier currentSchema = getCurrentSchema( jdbcEnvironment ); - final Identifier currentCatalog = getCurrentCatalog( jdbcEnvironment ); - if ( currentCatalog != null - || currentSchema != null ) { - tableInfo = locateTableInNamespace( - currentCatalog, - currentSchema, - tableName - ); - - if ( tableInfo != null ) { - return tableInfo; - } - } - - // 2) look in default namespace - if ( extractionContext.getDefaultCatalog() != null || extractionContext.getDefaultSchema() != null ) { - tableInfo = locateTableInNamespace( - extractionContext.getDefaultCatalog(), - extractionContext.getDefaultSchema(), - tableName - ); - - if ( tableInfo != null ) { - return tableInfo; - } - } - - // 3) look in all namespaces - try { - final String tableNameFilter = toMetaDataObjectName( tableName ); - - final ResultSet resultSet = extractionContext.getJdbcDatabaseMetaData().getTables( - null, - null, - tableNameFilter, - tableTypes - ); - - try { - return processTableResults( - null, - null, - tableName, - resultSet - ); - } - finally { - try { - resultSet.close(); - } - catch (SQLException ignore) { - } - } - } - catch (SQLException sqlException) { - throw convertSQLException( sqlException, "Error accessing table metadata" ); - } - } - } - - private Identifier getCurrentSchema(JdbcEnvironment jdbcEnvironment) { - if ( currentSchema != null ) { - return currentSchema; - } - final Identifier schema = jdbcEnvironment.getCurrentSchema(); - if ( schema != null ) { - currentSchema = schema; - } - if ( !useJdbcMetadataDefaultsSetting ) { - try { - currentSchema = extractionContext.getJdbcEnvironment() - .getIdentifierHelper() - .toIdentifier( extractionContext.getJdbcConnection().getSchema() ); - } - catch (SQLException ignore) { - log.sqlWarning( ignore.getErrorCode(), ignore.getSQLState() ); - } - } - return currentSchema; - } - - private Identifier getCurrentCatalog(JdbcEnvironment jdbcEnvironment) { - if ( currentCatalog != null ) { - return currentCatalog; - } - final Identifier catalog = jdbcEnvironment.getCurrentCatalog(); - if ( catalog != null ) { - currentCatalog = catalog; - } - if ( !useJdbcMetadataDefaultsSetting ) { - try { - currentCatalog = extractionContext.getJdbcEnvironment() - .getIdentifierHelper() - .toIdentifier( extractionContext.getJdbcConnection().getCatalog() ); - } - catch (SQLException ignore) { - log.sqlWarning( ignore.getErrorCode(), ignore.getSQLState() ); - } - } - return currentCatalog; - } - - private String getCurrentCatalogFilter(JdbcEnvironment jdbcEnvironment) { - if ( currentCatalogFilter != null ) { - return currentCatalogFilter; - } - final Identifier currentCatalog = jdbcEnvironment.getCurrentCatalog(); - if ( currentCatalog != null ) { - currentCatalogFilter = toMetaDataObjectName( currentCatalog ); - } - if ( !useJdbcMetadataDefaultsSetting ) { - try { - currentCatalogFilter = extractionContext.getJdbcConnection().getCatalog(); - } - catch (SQLException ignore) { - log.sqlWarning( ignore.getErrorCode(), ignore.getSQLState() ); - } - } - return currentCatalogFilter; - } - - private String getCurrentSchemaFilter(JdbcEnvironment jdbcEnvironment) { - if ( currentSchemaFilter != null ) { - return currentSchemaFilter; - } - final Identifier currentSchema = jdbcEnvironment.getCurrentSchema(); - if ( currentSchema != null ) { - currentSchemaFilter = toMetaDataObjectName( currentSchema ); - } - - if ( !useJdbcMetadataDefaultsSetting ) { - try { - currentSchemaFilter = extractionContext.getJdbcConnection().getSchema(); - } - catch (SQLException ignore) { - log.sqlWarning( ignore.getErrorCode(), ignore.getSQLState() ); - } - } - return currentSchemaFilter; - } - - public NameSpaceTablesInformation getTables(Identifier catalog, Identifier schema) { - - String catalogFilter = null; - String schemaFilter = null; - - final JdbcEnvironment jdbcEnvironment = extractionContext.getJdbcEnvironment(); - final NameQualifierSupport nameQualifierSupport = jdbcEnvironment.getNameQualifierSupport(); - if ( nameQualifierSupport.supportsCatalogs() ) { - if ( catalog == null ) { - // look in the current namespace - catalogFilter = getCurrentCatalogFilter(jdbcEnvironment); - if ( catalogFilter == null ) { - if ( extractionContext.getDefaultCatalog() != null ) { - // 2) look in default namespace - catalogFilter = toMetaDataObjectName( extractionContext.getDefaultCatalog() ); - } - else { - catalogFilter = ""; - } - } - } - else { - catalogFilter = toMetaDataObjectName( catalog ); - } - } - - if ( nameQualifierSupport.supportsSchemas() ) { - if ( schema == null ) { - // 1) look in current namespace - schemaFilter = getCurrentSchemaFilter( jdbcEnvironment ); - if ( schemaFilter == null ) { - if ( extractionContext.getDefaultSchema() != null ) { - // 2) look in default namespace - schemaFilter = toMetaDataObjectName( extractionContext.getDefaultSchema() ); - } - else { - schemaFilter = ""; - } - } - } - else { - schemaFilter = toMetaDataObjectName( schema ); - } - } - - try { - ResultSet resultSet = extractionContext.getJdbcDatabaseMetaData().getTables( - catalogFilter, - schemaFilter, - "%", - tableTypes - ); - - final NameSpaceTablesInformation tablesInformation = processTableResults( resultSet ); - populateTablesWithColumns( catalogFilter, schemaFilter, tablesInformation ); - return tablesInformation; - } - catch (SQLException sqlException) { - throw convertSQLException( sqlException, "Error accessing table metadata" ); + protected T processSchemaResultSet( + String catalogFilter, + String schemaFilter, + ExtractionContext.ResultSetProcessor processor) throws SQLException { + try (ResultSet resultSet = getExtractionContext().getJdbcDatabaseMetaData().getSchemas( + catalogFilter, + schemaFilter ) ) { + return processor.process( resultSet ); } } - private void populateTablesWithColumns( + @Override + protected T processTableResultSet( String catalogFilter, String schemaFilter, - NameSpaceTablesInformation tables) { - try { - ResultSet resultSet = extractionContext.getJdbcDatabaseMetaData().getColumns( - catalogFilter, - schemaFilter, - null, - "%" - ); - try { - String currentTableName = ""; - TableInformation currentTable = null; - while ( resultSet.next() ) { - if ( !currentTableName.equals( resultSet.getString( "TABLE_NAME" ) ) ) { - currentTableName = resultSet.getString( "TABLE_NAME" ); - currentTable = tables.getTableInformation( currentTableName ); - } - if ( currentTable != null ) { - final ColumnInformationImpl columnInformation = new ColumnInformationImpl( - currentTable, - DatabaseIdentifier.toIdentifier( resultSet.getString( "COLUMN_NAME" ) ), - resultSet.getInt( "DATA_TYPE" ), - new StringTokenizer( resultSet.getString( "TYPE_NAME" ), "() " ).nextToken(), - resultSet.getInt( "COLUMN_SIZE" ), - resultSet.getInt( "DECIMAL_DIGITS" ), - interpretTruthValue( resultSet.getString( "IS_NULLABLE" ) ) - ); - currentTable.addColumn( columnInformation ); - } - } - } - finally { - resultSet.close(); - } - } - catch (SQLException e) { - throw convertSQLException( - e, - "Error accessing tables metadata" - ); + String tableNameFilter, + String[] tableTypes, + ExtractionContext.ResultSetProcessor processor + ) throws SQLException { + try (ResultSet resultSet = getExtractionContext().getJdbcDatabaseMetaData().getTables( + catalogFilter, + schemaFilter, + tableNameFilter, + tableTypes)) { + return processor.process( resultSet ); } } - private NameSpaceTablesInformation processTableResults(ResultSet resultSet) throws SQLException { - try { - NameSpaceTablesInformation tables = new NameSpaceTablesInformation(identifierHelper()); - while ( resultSet.next() ) { - final TableInformation tableInformation = extractTableInformation( resultSet ); - tables.addTableInformation( tableInformation ); - } - - return tables; - } - finally { - try { - resultSet.close(); - } - catch (SQLException ignore) { - } + @Override + protected T processColumnsResultSet( + String catalogFilter, + String schemaFilter, + String tableFilter, + ExtractionContext.ResultSetProcessor processor) throws SQLException { + try (ResultSet resultSet = getExtractionContext().getJdbcDatabaseMetaData().getColumns( + catalogFilter, + schemaFilter, + tableFilter, + "%" )) { + return processor.process( resultSet ); } } - private TableInformation locateTableInNamespace( - Identifier catalog, - Identifier schema, - Identifier tableName) { - Identifier catalogToUse = null; - Identifier schemaToUse = null; - - final String catalogFilter; - final String schemaFilter; - - if ( extractionContext.getJdbcEnvironment().getNameQualifierSupport().supportsCatalogs() ) { - if ( catalog == null ) { - String defaultCatalog = ""; - if ( extractionContext.getJdbcEnvironment().getNameQualifierSupport().supportsCatalogs() ) { - try { - defaultCatalog = extractionContext.getJdbcConnection().getCatalog(); - } - catch (SQLException ignore) { - } - } - catalogFilter = defaultCatalog; - } - else { - catalogToUse = catalog; - catalogFilter = toMetaDataObjectName( catalog ); - } - } - else { - catalogFilter = null; - } - - if ( extractionContext.getJdbcEnvironment().getNameQualifierSupport().supportsSchemas() ) { - if ( schema == null ) { - schemaFilter = ""; - } - else { - schemaToUse = schema; - schemaFilter = toMetaDataObjectName( schema ); - } - } - else { - schemaFilter = null; - } - - final String tableNameFilter = toMetaDataObjectName( tableName ); - - try { - ResultSet resultSet = extractionContext.getJdbcDatabaseMetaData().getTables( - catalogFilter, - schemaFilter, - tableNameFilter, - tableTypes - ); - - return processTableResults( - catalogToUse, - schemaToUse, - tableName, - resultSet - ); - } - catch (SQLException sqlException) { - throw convertSQLException( sqlException, "Error accessing table metadata" ); + @Override + protected T processPrimaryKeysResultSet( + String catalogFilter, + String schemaFilter, + Identifier tableName, + ExtractionContext.ResultSetProcessor processor) throws SQLException { + try( ResultSet resultSet = getExtractionContext().getJdbcDatabaseMetaData().getPrimaryKeys( + catalogFilter, + schemaFilter, + tableName.getText() ) ) { + return processor.process( resultSet ); } } - private TableInformation processTableResults( - Identifier catalog, - Identifier schema, + @Override + protected T processIndexInfoResultSet( + String catalogFilter, + String schemaFilter, Identifier tableName, - ResultSet resultSet) throws SQLException { - try { - boolean found = false; - TableInformation tableInformation = null; - while ( resultSet.next() ) { - if ( tableName.equals( Identifier.toIdentifier( resultSet.getString( "TABLE_NAME" ), - tableName.isQuoted() ) ) ) { - if ( found ) { - log.multipleTablesFound( tableName.render() ); - final String catalogName = catalog == null ? "" : catalog.render(); - final String schemaName = schema == null ? "" : schema.render(); - throw new SchemaExtractionException( - String.format( - Locale.ENGLISH, - "More than one table found in namespace (%s, %s) : %s", - catalogName, - schemaName, - tableName.render() - ) - ); - } - else { - found = true; - tableInformation = extractTableInformation( resultSet ); - addColumns( tableInformation ); - } - } - } - if ( !found ) { - log.tableNotFound( tableName.render() ); - } - return tableInformation; - } - finally { - try { - resultSet.close(); - } - catch (SQLException ignore) { - } + boolean approximate, + ExtractionContext.ResultSetProcessor processor) throws SQLException { + + try (ResultSet resultSet = getExtractionContext().getJdbcDatabaseMetaData().getIndexInfo( + catalogFilter, + schemaFilter, + tableName.getText(), + false, // DO NOT limit to just unique + approximate ) ) { + return processor.process( resultSet ); } } - protected boolean isPhysicalTableType(String tableType) { - if ( extraPhysicalTableTypes == null ) { - return "TABLE".equalsIgnoreCase( tableType ); - } - else { - if ( "TABLE".equalsIgnoreCase( tableType ) ) { - return true; - } - for ( String extraPhysicalTableType : extraPhysicalTableTypes ) { - if ( extraPhysicalTableType.equalsIgnoreCase( tableType ) ) { - return true; - } - } - return false; + @Override + protected T processImportedKeysResultSet( + String catalogFilter, + String schemaFilter, + String tableName, + ExtractionContext.ResultSetProcessor processor) throws SQLException { + try (ResultSet resultSet = getExtractionContext().getJdbcDatabaseMetaData().getImportedKeys( + catalogFilter, + schemaFilter, + tableName ) ) { + return processor.process( resultSet ); } } - private void addColumns(TableInformation tableInformation) { + protected void addColumns(TableInformation tableInformation) { + final ExtractionContext extractionContext = getExtractionContext(); // We use this dummy query to retrieve the table information through the ResultSetMetaData - // This is significantly better than to use the DatabaseMetaData especially on Oracle with synonyms enabled + // This is significantly better than to use the DatabaseMetaData especially on Oracle with synonyms enable final String tableName = extractionContext.getJdbcEnvironment().getQualifiedObjectNameFormatter().format( // The name comes from the database, so the case is correct // But we quote here to avoid issues with reserved words tableInformation.getName().quote(), extractionContext.getJdbcEnvironment().getDialect() ); - final String query = "select * from " + tableName + " where 1=0"; - try (Statement statement = extractionContext.getJdbcConnection() - .createStatement(); ResultSet resultSet = statement.executeQuery( query )) { - final ResultSetMetaData metaData = resultSet.getMetaData(); - final int columnCount = metaData.getColumnCount(); - - for ( int i = 1; i <= columnCount; i++ ) { - final String columnName = metaData.getColumnName( i ); - final ColumnInformationImpl columnInformation = new ColumnInformationImpl( - tableInformation, - DatabaseIdentifier.toIdentifier( columnName ), - metaData.getColumnType( i ), - new StringTokenizer( metaData.getColumnTypeName( i ), "() " ).nextToken(), - metaData.getPrecision( i ), - metaData.getScale( i ), - interpretNullable( metaData.isNullable( i ) ) - ); - tableInformation.addColumn( columnInformation ); - } - } - catch (SQLException e) { - throw convertSQLException( - e, - "Error accessing column metadata: " + tableInformation.getName().toString() - ); - } - } - - private TruthValue interpretNullable(int nullable) { - switch ( nullable ) { - case ResultSetMetaData.columnNullable: - return TruthValue.TRUE; - case ResultSetMetaData.columnNoNulls: - return TruthValue.FALSE; - default: - return TruthValue.UNKNOWN; - } - } - - private TruthValue interpretTruthValue(String nullable) { - if ( "yes".equalsIgnoreCase( nullable ) ) { - return TruthValue.TRUE; - } - else if ( "no".equalsIgnoreCase( nullable ) ) { - return TruthValue.FALSE; - } - return TruthValue.UNKNOWN; - } - - @Override - public PrimaryKeyInformation getPrimaryKey(TableInformationImpl tableInformation) { - final QualifiedTableName tableName = tableInformation.getName(); - final Identifier catalog = tableName.getCatalogName(); - final Identifier schema = tableName.getSchemaName(); - - final String catalogFilter; - final String schemaFilter; - - if ( catalog == null ) { - catalogFilter = ""; - } - else { - catalogFilter = catalog.getText(); - } - - if ( schema == null ) { - schemaFilter = ""; - } - else { - schemaFilter = schema.getText(); - } try { - ResultSet resultSet = extractionContext.getJdbcDatabaseMetaData().getPrimaryKeys( - catalogFilter, - schemaFilter, - tableInformation.getName().getTableName().getText() - ); - - final List pkColumns = new ArrayList(); - boolean firstPass = true; - Identifier pkIdentifier = null; - - try { - while ( resultSet.next() ) { - final String currentPkName = resultSet.getString( "PK_NAME" ); - final Identifier currentPkIdentifier = currentPkName == null - ? null - : DatabaseIdentifier.toIdentifier( currentPkName ); - if ( firstPass ) { - pkIdentifier = currentPkIdentifier; - firstPass = false; - } - else { - if ( !Objects.equals( pkIdentifier, currentPkIdentifier ) ) { - throw new SchemaExtractionException( - String.format( - "Encountered primary keys differing name on table %s", - tableInformation.getName().toString() - ) + extractionContext.getQueryResults( + "select * from " + tableName + " where 1=0", + null, + resultSet -> { + final ResultSetMetaData metaData = resultSet.getMetaData(); + final int columnCount = metaData.getColumnCount(); + + for ( int i = 1; i <= columnCount; i++ ) { + final String columnName = metaData.getColumnName( i ); + final ColumnInformationImpl columnInformation = new ColumnInformationImpl( + tableInformation, + DatabaseIdentifier.toIdentifier( columnName ), + metaData.getColumnType( i ), + new StringTokenizer( metaData.getColumnTypeName( i ), "() " ).nextToken(), + metaData.getPrecision( i ), + metaData.getScale( i ), + interpretNullable( metaData.isNullable( i ) ) ); + tableInformation.addColumn( columnInformation ); } + return null; } - - final int columnPosition = resultSet.getInt( "KEY_SEQ" ); - - final Identifier columnIdentifier = DatabaseIdentifier.toIdentifier( - resultSet.getString( "COLUMN_NAME" ) - ); - final ColumnInformation column = tableInformation.getColumn( columnIdentifier ); - pkColumns.add( columnPosition-1, column ); - } - } - finally { - resultSet.close(); - } - - if ( firstPass ) { - // we did not find any results (no pk) - return null; - } - else { - // validate column list is properly contiguous - for ( int i = 0; i < pkColumns.size(); i++ ) { - if ( pkColumns.get( i ) == null ) { - throw new SchemaExtractionException( "Primary Key information was missing for KEY_SEQ = " + ( i+1) ); - } - } - - // build the return - return new PrimaryKeyInformationImpl( pkIdentifier, pkColumns ); - } - } - catch (SQLException e) { - throw convertSQLException( e, "Error while reading primary key meta data for " + tableInformation.getName().toString() ); - } - } - - @Override - public Iterable getIndexes(TableInformation tableInformation) { - final Map builders = new HashMap<>(); - final QualifiedTableName tableName = tableInformation.getName(); - final Identifier catalog = tableName.getCatalogName(); - final Identifier schema = tableName.getSchemaName(); - - final String catalogFilter; - final String schemaFilter; - - if ( catalog == null ) { - catalogFilter = ""; - } - else { - catalogFilter = catalog.getText(); - } - - if ( schema == null ) { - schemaFilter = ""; - } - else { - schemaFilter = schema.getText(); - } - - try { - ResultSet resultSet = extractionContext.getJdbcDatabaseMetaData().getIndexInfo( - catalogFilter, - schemaFilter, - tableName.getTableName().getText(), - false, // DO NOT limit to just unique - true // DO require up-to-date results - ); - - try { - while ( resultSet.next() ) { - if ( resultSet.getShort("TYPE") == DatabaseMetaData.tableIndexStatistic ) { - continue; - } - - final Identifier indexIdentifier = DatabaseIdentifier.toIdentifier( - resultSet.getString( "INDEX_NAME" ) - ); - IndexInformationImpl.Builder builder = builders.get( indexIdentifier ); - if ( builder == null ) { - builder = IndexInformationImpl.builder( indexIdentifier ); - builders.put( indexIdentifier, builder ); - } - - final Identifier columnIdentifier = DatabaseIdentifier.toIdentifier( resultSet.getString( "COLUMN_NAME" ) ); - final ColumnInformation columnInformation = tableInformation.getColumn( columnIdentifier ); - if ( columnInformation == null ) { - // See HHH-10191: this may happen when dealing with Oracle/PostgreSQL function indexes - log.logCannotLocateIndexColumnInformation( - columnIdentifier.getText(), - indexIdentifier.getText() - ); - } - builder.addColumn( columnInformation ); - } - } - finally { - resultSet.close(); - } - } - catch (SQLException e) { - throw convertSQLException( - e, - "Error accessing index information: " + tableInformation.getName().toString() ); } - - final List indexes = new ArrayList(); - for ( IndexInformationImpl.Builder builder : builders.values() ) { - IndexInformationImpl index = builder.build(); - indexes.add( index ); - } - return indexes; - } - - @Override - public Iterable getForeignKeys(TableInformation tableInformation) { - final Map fkBuilders = new HashMap<>(); - final QualifiedTableName tableName = tableInformation.getName(); - final Identifier catalog = tableName.getCatalogName(); - final Identifier schema = tableName.getSchemaName(); - - final String catalogFilter; - final String schemaFilter; - - if ( catalog == null ) { - catalogFilter = ""; - } - else { - catalogFilter = catalog.getText(); - } - - if ( schema == null ) { - schemaFilter = ""; - } - else { - schemaFilter = schema.getText(); - } - - try { - ResultSet resultSet = extractionContext.getJdbcDatabaseMetaData().getImportedKeys( - catalogFilter, - schemaFilter, - tableInformation.getName().getTableName().getText() - ); - - // todo : need to account for getCrossReference() as well... - - try { - while ( resultSet.next() ) { - // IMPL NOTE : The builder is mainly used to collect the column reference mappings - final Identifier fkIdentifier = DatabaseIdentifier.toIdentifier( - resultSet.getString( "FK_NAME" ) - ); - ForeignKeyBuilder fkBuilder = fkBuilders.get( fkIdentifier ); - if ( fkBuilder == null ) { - fkBuilder = generateForeignKeyBuilder( fkIdentifier ); - fkBuilders.put( fkIdentifier, fkBuilder ); - } - - final QualifiedTableName incomingPkTableName = extractKeyTableName( resultSet, "PK" ); - - final TableInformation pkTableInformation = extractionContext.getDatabaseObjectAccess() - .locateTableInformation( incomingPkTableName ); - - if ( pkTableInformation == null ) { - // the assumption here is that we have not seen this table already based on fully-qualified name - // during previous step of building all table metadata so most likely this is - // not a match based solely on schema/catalog and that another row in this result set - // should match. - continue; - } - - final Identifier fkColumnIdentifier = DatabaseIdentifier.toIdentifier( - resultSet.getString( "FKCOLUMN_NAME" ) - ); - final Identifier pkColumnIdentifier = DatabaseIdentifier.toIdentifier( - resultSet.getString( "PKCOLUMN_NAME" ) - ); - - fkBuilder.addColumnMapping( - tableInformation.getColumn( fkColumnIdentifier ), - pkTableInformation.getColumn( pkColumnIdentifier ) - ); - } - } - finally { - resultSet.close(); - } - } catch (SQLException e) { throw convertSQLException( e, "Error accessing column metadata: " + tableInformation.getName().toString() ); } - - final List fks = new ArrayList(); - for ( ForeignKeyBuilder fkBuilder : fkBuilders.values() ) { - ForeignKeyInformation fk = fkBuilder.build(); - fks.add( fk ); - } - return fks; - } - - - private ForeignKeyBuilder generateForeignKeyBuilder(Identifier fkIdentifier) { - return new ForeignKeyBuilderImpl( fkIdentifier ); - } - - protected interface ForeignKeyBuilder { - ForeignKeyBuilder addColumnMapping(ColumnInformation referencing, ColumnInformation referenced); - - ForeignKeyInformation build(); - } - - protected static class ForeignKeyBuilderImpl implements ForeignKeyBuilder { - private final Identifier fkIdentifier; - private final List columnMappingList = new ArrayList(); - - public ForeignKeyBuilderImpl(Identifier fkIdentifier) { - this.fkIdentifier = fkIdentifier; - } - - @Override - public ForeignKeyBuilder addColumnMapping(ColumnInformation referencing, ColumnInformation referenced) { - columnMappingList.add( new ForeignKeyInformationImpl.ColumnReferenceMappingImpl( referencing, referenced ) ); - return this; - } - - @Override - public ForeignKeyInformationImpl build() { - if ( columnMappingList.isEmpty() ) { - throw new SchemaManagementException( - "Attempt to resolve foreign key metadata from JDBC metadata failed to find " + - "column mappings for foreign key named [" + fkIdentifier.getText() + "]" - ); - } - return new ForeignKeyInformationImpl( fkIdentifier, columnMappingList ); - } - } - - private QualifiedTableName extractKeyTableName(ResultSet resultSet, String prefix) throws SQLException { - final String incomingCatalogName = resultSet.getString( prefix + "TABLE_CAT" ); - final String incomingSchemaName = resultSet.getString( prefix + "TABLE_SCHEM" ); - final String incomingTableName = resultSet.getString( prefix + "TABLE_NAME" ); - - final DatabaseIdentifier catalog = DatabaseIdentifier.toIdentifier( incomingCatalogName ); - final DatabaseIdentifier schema = DatabaseIdentifier.toIdentifier( incomingSchemaName ); - final DatabaseIdentifier table = DatabaseIdentifier.toIdentifier( incomingTableName ); - - return new QualifiedTableName( catalog, schema, table ); - } - - private QualifiedTableName extractTableName(ResultSet resultSet) throws SQLException { - final String incomingCatalogName = resultSet.getString( "TABLE_CAT" ); - final String incomingSchemaName = resultSet.getString( "TABLE_SCHEM" ); - final String incomingTableName = resultSet.getString( "TABLE_NAME" ); - - final DatabaseIdentifier catalog = DatabaseIdentifier.toIdentifier( incomingCatalogName ); - final DatabaseIdentifier schema = DatabaseIdentifier.toIdentifier( incomingSchemaName ); - final DatabaseIdentifier table = DatabaseIdentifier.toIdentifier( incomingTableName ); - - return new QualifiedTableName( catalog, schema, table ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorLegacyImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorLegacyImpl.java index c8e4ae09abe3..a99f94938c6a 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorLegacyImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorLegacyImpl.java @@ -36,50 +36,31 @@ public Iterable extractMetadata(ExtractionContext extractio return SequenceInformationExtractorNoOpImpl.INSTANCE.extractMetadata( extractionContext ); } - final IdentifierHelper identifierHelper = extractionContext.getJdbcEnvironment().getIdentifierHelper(); - final Statement statement = extractionContext.getJdbcConnection().createStatement(); - try { - final ResultSet resultSet = statement.executeQuery( lookupSql ); - try { - final List sequenceInformationList = new ArrayList<>(); - while ( resultSet.next() ) { - sequenceInformationList.add( - new SequenceInformationImpl( - new QualifiedSequenceName( - identifierHelper.toIdentifier( - resultSetCatalogName( resultSet ) - ), - identifierHelper.toIdentifier( - resultSetSchemaName( resultSet ) - ), - identifierHelper.toIdentifier( - resultSetSequenceName( resultSet ) - ) - ), - resultSetStartValueSize( resultSet ), - resultSetMinValue( resultSet ), - resultSetMaxValue( resultSet ), - resultSetIncrementValue( resultSet ) - ) - ); + return extractionContext.getQueryResults( + lookupSql, + null, + (ExtractionContext.ResultSetProcessor>) resultSet -> { + final IdentifierHelper identifierHelper = extractionContext.getJdbcEnvironment() + .getIdentifierHelper(); + final List sequenceInformationList = new ArrayList<>(); + while ( resultSet.next() ) { + sequenceInformationList.add( + new SequenceInformationImpl( + new QualifiedSequenceName( + identifierHelper.toIdentifier( resultSetCatalogName( resultSet ) ), + identifierHelper.toIdentifier( resultSetSchemaName( resultSet ) ), + identifierHelper.toIdentifier( resultSetSequenceName( resultSet ) ) + ), + resultSetStartValueSize( resultSet ), + resultSetMinValue( resultSet ), + resultSetMaxValue( resultSet ), + resultSetIncrementValue( resultSet ) + ) + ); + } + return sequenceInformationList; } - return sequenceInformationList; - } - finally { - try { - resultSet.close(); - } - catch (SQLException ignore) { - } - } - } - finally { - try { - statement.close(); - } - catch (SQLException ignore) { - } - } + ); } protected String sequenceNameColumn() { diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorMariaDBDatabaseImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorMariaDBDatabaseImpl.java index a5e0f4f054d1..e58f5fb19671 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorMariaDBDatabaseImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorMariaDBDatabaseImpl.java @@ -8,8 +8,8 @@ import java.sql.ResultSet; import java.sql.SQLException; -import java.sql.Statement; import java.util.ArrayList; +import java.util.Collections; import java.util.List; import org.hibernate.boot.model.relational.QualifiedSequenceName; @@ -42,60 +42,49 @@ public Iterable extractMetadata(ExtractionContext extractio return SequenceInformationExtractorNoOpImpl.INSTANCE.extractMetadata(extractionContext); } - final IdentifierHelper identifierHelper = extractionContext.getJdbcEnvironment().getIdentifierHelper(); - - final List sequenceInformationList = new ArrayList<>(); - final List sequenceNames = new ArrayList<>(); - - try ( - final Statement statement = extractionContext.getJdbcConnection().createStatement(); - final ResultSet resultSet = statement.executeQuery( lookupSql ); - ) { + final List sequenceNames = extractionContext.getQueryResults( lookupSql, null, resultSet -> { + final List sequences = new ArrayList<>(); while ( resultSet.next() ) { - sequenceNames.add( resultSetSequenceName( resultSet ) ); + sequences.add( resultSetSequenceName( resultSet ) ); } - } + return sequences; + }); if ( !sequenceNames.isEmpty() ) { StringBuilder sequenceInfoQueryBuilder = new StringBuilder(); - for ( String sequenceName : sequenceNames ) { if ( sequenceInfoQueryBuilder.length() > 0 ) { sequenceInfoQueryBuilder.append( UNION_ALL ); } sequenceInfoQueryBuilder.append( String.format( SQL_SEQUENCE_QUERY, sequenceName ) ); } - - int index = 0; - - try ( - final Statement statement = extractionContext.getJdbcConnection().createStatement(); - final ResultSet resultSet = statement.executeQuery( sequenceInfoQueryBuilder.toString() ); - ) { - - while ( resultSet.next() ) { - - SequenceInformation sequenceInformation = new SequenceInformationImpl( - new QualifiedSequenceName( - null, - null, - identifierHelper.toIdentifier( - resultSetSequenceName(resultSet) - ) - ), - resultSetStartValueSize(resultSet), - resultSetMinValue(resultSet), - resultSetMaxValue(resultSet), - resultSetIncrementValue(resultSet) - ); - - sequenceInformationList.add(sequenceInformation); - } - - } + return extractionContext.getQueryResults( + sequenceInfoQueryBuilder.toString(), + null, + (ExtractionContext.ResultSetProcessor>) resultSet -> { + final List sequenceInformationList = new ArrayList<>(); + final IdentifierHelper identifierHelper = extractionContext.getJdbcEnvironment() + .getIdentifierHelper(); + + while ( resultSet.next() ) { + SequenceInformation sequenceInformation = new SequenceInformationImpl( + new QualifiedSequenceName( + null, + null, + identifierHelper.toIdentifier( resultSetSequenceName(resultSet) ) + ), + resultSetStartValueSize(resultSet), + resultSetMinValue(resultSet), + resultSetMaxValue(resultSet), + resultSetIncrementValue(resultSet) + ); + sequenceInformationList.add(sequenceInformation); + } + return sequenceInformationList; + }); } - return sequenceInformationList; + return Collections.emptyList(); } protected String resultSetSequenceName(ResultSet resultSet) throws SQLException { diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorPostgresSQLDatabaseImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorPostgresSQLDatabaseImpl.java new file mode 100644 index 000000000000..1b466567f38e --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorPostgresSQLDatabaseImpl.java @@ -0,0 +1,40 @@ +package org.hibernate.tool.schema.extract.internal; + +import java.sql.ResultSet; +import java.sql.SQLException; + +/** + * PostgreSQL stores the sequence metadata as strings. PostgreSQL's JDBC driver does the + * conversion automatically, but, unfortunately Vert.x driver does not do this conversion. + * + * This class is intended to make this functionality work with both the JDBC and Vert.X + * drivers. + * + * @author Gail Badner + */ +public class SequenceInformationExtractorPostgresSQLDatabaseImpl extends SequenceInformationExtractorLegacyImpl { + //Singleton access + public static final SequenceInformationExtractorPostgresSQLDatabaseImpl INSTANCE = new SequenceInformationExtractorPostgresSQLDatabaseImpl(); + + protected Long resultSetStartValueSize(ResultSet resultSet) throws SQLException { + return convertStringValueToLong( resultSet, sequenceStartValueColumn() ); + } + + protected Long resultSetMinValue(ResultSet resultSet) throws SQLException { + return convertStringValueToLong( resultSet, sequenceMinValueColumn() ); + } + + protected Long resultSetMaxValue(ResultSet resultSet) throws SQLException { + return convertStringValueToLong( resultSet, sequenceMaxValueColumn() ); + } + + protected Long resultSetIncrementValue(ResultSet resultSet) throws SQLException { + return convertStringValueToLong( resultSet, sequenceIncrementColumn() ); + } + + private Long convertStringValueToLong(ResultSet resultSet, String columnLabel) throws SQLException { + // column value is of type character_data so get it as a String + final String stringValue = resultSet.getString( columnLabel ); + return stringValue != null ? Long.valueOf( stringValue ) : null; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/ExtractionContext.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/ExtractionContext.java index 6709039b2d82..ab1c7c4d597d 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/ExtractionContext.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/ExtractionContext.java @@ -8,6 +8,9 @@ import java.sql.Connection; import java.sql.DatabaseMetaData; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; import org.hibernate.Incubating; import org.hibernate.boot.model.naming.Identifier; @@ -21,6 +24,7 @@ * well as to delegates needed in performing extraction. * * @author Steve Ebersole + * @author Gail Badner */ @Incubating public interface ExtractionContext { @@ -29,9 +33,31 @@ public interface ExtractionContext { Connection getJdbcConnection(); DatabaseMetaData getJdbcDatabaseMetaData(); + @Incubating + default T getQueryResults( + String queryString, + Object[] positionalParameters, + ResultSetProcessor resultSetProcessor) throws SQLException { + try (PreparedStatement statement = getJdbcConnection().prepareStatement( queryString )) { + if ( positionalParameters != null ) { + for ( int i = 0 ; i < positionalParameters.length ; i++ ) { + statement.setObject( i + 1, positionalParameters[i] ); + } + } + try (ResultSet resultSet = statement.executeQuery()) { + return resultSetProcessor.process( resultSet ); + } + } + } + Identifier getDefaultCatalog(); Identifier getDefaultSchema(); + @Incubating + interface ResultSetProcessor { + T process(ResultSet resultSet) throws SQLException; + } + /** * In conjunction with {@link #getDatabaseObjectAccess()} provides access to * information about known database objects to the extractor. diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/AbstractSchemaMigrator.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/AbstractSchemaMigrator.java index 0f58cfee5099..6acbc9fe73e5 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/AbstractSchemaMigrator.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/AbstractSchemaMigrator.java @@ -96,7 +96,8 @@ public void doMigration(Metadata metadata, ExecutionOptions options, TargetDescr final DatabaseInformation databaseInformation = Helper.buildDatabaseInformation( tool.getServiceRegistry(), ddlTransactionIsolator, - metadata.getDatabase().getDefaultNamespace().getName() + metadata.getDatabase().getDefaultNamespace().getName(), + tool ); final GenerationTarget[] targets = tool.buildGenerationTargets( diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/AbstractSchemaValidator.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/AbstractSchemaValidator.java index b8abdec81639..ffe60ab61686 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/AbstractSchemaValidator.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/AbstractSchemaValidator.java @@ -57,11 +57,11 @@ public void doValidation(Metadata metadata, ExecutionOptions options) { final JdbcContext jdbcContext = tool.resolveJdbcContext( options.getConfigurationValues() ); final DdlTransactionIsolator isolator = tool.getDdlTransactionIsolator( jdbcContext ); - final DatabaseInformation databaseInformation = Helper.buildDatabaseInformation( tool.getServiceRegistry(), isolator, - metadata.getDatabase().getDefaultNamespace().getName() + metadata.getDatabase().getDefaultNamespace().getName(), + tool ); try { diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/Helper.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/Helper.java index f4513baccdee..131a961a074a 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/Helper.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/Helper.java @@ -32,6 +32,7 @@ import org.hibernate.tool.schema.internal.exec.ScriptTargetOutputToFile; import org.hibernate.tool.schema.internal.exec.ScriptTargetOutputToUrl; import org.hibernate.tool.schema.internal.exec.ScriptTargetOutputToWriter; +import org.hibernate.tool.schema.spi.SchemaManagementTool; import org.hibernate.tool.schema.spi.ScriptSourceInput; import org.hibernate.tool.schema.spi.ScriptTargetOutput; @@ -175,14 +176,16 @@ public static boolean interpretFormattingEnabled(Map configurationValues) { public static DatabaseInformation buildDatabaseInformation( ServiceRegistry serviceRegistry, DdlTransactionIsolator ddlTransactionIsolator, - Namespace.Name defaultNamespace) { + Namespace.Name defaultNamespace, + SchemaManagementTool tool) { final JdbcEnvironment jdbcEnvironment = serviceRegistry.getService( JdbcEnvironment.class ); try { return new DatabaseInformationImpl( serviceRegistry, jdbcEnvironment, ddlTransactionIsolator, - defaultNamespace + defaultNamespace, + tool ); } catch (SQLException e) { diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/HibernateSchemaManagementTool.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/HibernateSchemaManagementTool.java index 7765e9248f77..2fea2a4d71d8 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/HibernateSchemaManagementTool.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/HibernateSchemaManagementTool.java @@ -93,7 +93,7 @@ public SchemaValidator getSchemaValidator(Map options) { return new IndividuallySchemaValidatorImpl( this, getSchemaFilterProvider( options ).getValidateFilter() ); } } - + private SchemaFilterProvider getSchemaFilterProvider(Map options) { final Object configuredOption = (options == null) ? null @@ -176,7 +176,10 @@ GenerationTarget[] buildGenerationTargets( } if ( targetDescriptor.getTargetTypes().contains( TargetType.DATABASE ) ) { - targets[index] = new GenerationTargetToDatabase( ddlTransactionIsolator, false ); + targets[index] = customTarget == null + ? new GenerationTargetToDatabase( ddlTransactionIsolator, false ) + : customTarget; + index++; } return targets; diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/SchemaManagementTool.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/SchemaManagementTool.java index 65dc3379c33a..8d046383febc 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/SchemaManagementTool.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/SchemaManagementTool.java @@ -7,10 +7,21 @@ package org.hibernate.tool.schema.spi; import java.util.Map; +import java.util.function.BiFunction; +import java.util.function.Function; import org.hibernate.Incubating; +import org.hibernate.boot.model.naming.Identifier; +import org.hibernate.boot.model.relational.Namespace; +import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; +import org.hibernate.resource.transaction.spi.DdlTransactionIsolator; import org.hibernate.service.Service; +import org.hibernate.service.ServiceRegistry; +import org.hibernate.tool.schema.extract.internal.InformationExtractorJdbcDatabaseMetaDataImpl; +import org.hibernate.tool.schema.extract.spi.ExtractionContext; +import org.hibernate.tool.schema.extract.spi.InformationExtractor; import org.hibernate.tool.schema.internal.exec.GenerationTarget; +import org.hibernate.tool.schema.internal.exec.ImprovedExtractionContextImpl; /** * Contract for schema management tool integration. @@ -32,4 +43,25 @@ public interface SchemaManagementTool extends Service { * @param generationTarget the custom instance to use. */ void setCustomDatabaseGenerationTarget(GenerationTarget generationTarget); + + default ExtractionContext createExtractionContext( + ServiceRegistry serviceRegistry, + JdbcEnvironment jdbcEnvironment, + DdlTransactionIsolator ddlTransactionIsolator, + Identifier defaultCatalog, + Identifier defaultSchema, + ExtractionContext.DatabaseObjectAccess databaseObjectAccess) { + return new ImprovedExtractionContextImpl( + serviceRegistry, + jdbcEnvironment, + ddlTransactionIsolator, + defaultCatalog, + defaultSchema, + databaseObjectAccess + ); + } + + default InformationExtractor createInformationExtractor(ExtractionContext extractionContext) { + return new InformationExtractorJdbcDatabaseMetaDataImpl( extractionContext ); + } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/schematools/TestExtraPhysicalTableTypes.java b/hibernate-core/src/test/java/org/hibernate/test/schematools/TestExtraPhysicalTableTypes.java index 6547c7adf349..7a5a6d0b637d 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/schematools/TestExtraPhysicalTableTypes.java +++ b/hibernate-core/src/test/java/org/hibernate/test/schematools/TestExtraPhysicalTableTypes.java @@ -17,6 +17,7 @@ import org.hibernate.cfg.Environment; import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider; import org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator; +import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.resource.transaction.spi.DdlTransactionIsolator; import org.hibernate.tool.schema.extract.internal.DatabaseInformationImpl; @@ -24,7 +25,9 @@ import org.hibernate.tool.schema.extract.internal.InformationExtractorJdbcDatabaseMetaDataImpl; import org.hibernate.tool.schema.extract.spi.DatabaseInformation; import org.hibernate.tool.schema.extract.spi.ExtractionContext; +import org.hibernate.tool.schema.internal.exec.ImprovedExtractionContextImpl; import org.hibernate.tool.schema.internal.exec.JdbcContext; +import org.hibernate.tool.schema.spi.SchemaManagementTool; import org.junit.After; import org.junit.Test; @@ -122,8 +125,10 @@ private InformationExtractorJdbcDatabaseMetaDataImplTest buildInformationExtract ssr, database.getJdbcEnvironment(), ddlTransactionIsolator, - database.getDefaultNamespace().getName() + database.getDefaultNamespace().getName(), + database.getServiceRegistry().getService( SchemaManagementTool.class ) ); + ExtractionContextImpl extractionContext = new ExtractionContextImpl( ssr, database.getJdbcEnvironment(), diff --git a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaUpdateTest.java b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaUpdateTest.java index 8d3c544767fc..12db48628c04 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaUpdateTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaUpdateTest.java @@ -21,6 +21,7 @@ import javax.persistence.ElementCollection; import javax.persistence.Entity; import javax.persistence.ForeignKey; +import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Index; import javax.persistence.Inheritance; @@ -163,6 +164,7 @@ public void testSchemaUpdateAndValidation() throws Exception { @Table(name = "`testentity`") public static class LowercaseTableNameEntity { @Id + @GeneratedValue long id; String field1; @@ -173,6 +175,7 @@ public static class LowercaseTableNameEntity { @Entity(name = "TestEntity1") public static class TestEntity { @Id + @GeneratedValue @Column(name = "`Id`") long id; String field1; @@ -192,6 +195,7 @@ public static class TestEntity { @Table(name = "`TESTENTITY`") public static class UppercaseTableNameEntity { @Id + @GeneratedValue long id; String field1; @@ -207,6 +211,7 @@ public static class UppercaseTableNameEntity { @Table(name = "`TESTentity`", indexes = {@Index(name = "index1", columnList = "`FieLd1`"), @Index(name = "Index2", columnList = "`FIELD_2`")}) public static class MixedCaseTableNameEntity { @Id + @GeneratedValue long id; @Column(name = "`FieLd1`") String field1; @@ -224,6 +229,8 @@ public static class MixedCaseTableNameEntity { @Entity(name = "Match") public static class Match { @Id + @GeneratedValue + long id; String match; @@ -236,6 +243,8 @@ public static class Match { @Inheritance(strategy = InheritanceType.JOINED) public static class InheritanceRootEntity { @Id + @GeneratedValue + protected Long id; } From 800436ee88da1892a2df9f7b6e47e152e0bfa52e Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Fri, 23 Jul 2021 17:35:43 -0700 Subject: [PATCH 285/644] HHH-14744 : Checkstyle fixes --- .../extract/internal/AbstractInformationExtractorImpl.java | 6 +++--- ...SequenceInformationExtractorPostgresSQLDatabaseImpl.java | 6 ++++++ 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/AbstractInformationExtractorImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/AbstractInformationExtractorImpl.java index cee3d506a8f9..499fb24be222 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/AbstractInformationExtractorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/AbstractInformationExtractorImpl.java @@ -586,7 +586,7 @@ private NameSpaceTablesInformation extractNameSpaceTablesInformation(ResultSet r * @param schemaFilter * @param tableNameFilter * @param tableTypes - * @return + * @return results of type {@code T} * @throws SQLException */ protected abstract T processTableResultSet( @@ -888,7 +888,7 @@ private PrimaryKeyInformation extractPrimaryKeyInformation( * @param schemaFilter * @param tableName * @param approximate - * @return + * @return results of type {@code T} * @throws SQLException */ protected abstract T processIndexInfoResultSet( @@ -923,7 +923,7 @@ public Iterable getIndexes(TableInformation tableInformation) } try { - processIndexInfoResultSet( + processIndexInfoResultSet( catalogFilter, schemaFilter, tableName.getTableName(), diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorPostgresSQLDatabaseImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorPostgresSQLDatabaseImpl.java index 1b466567f38e..b262e4180505 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorPostgresSQLDatabaseImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorPostgresSQLDatabaseImpl.java @@ -1,3 +1,9 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ package org.hibernate.tool.schema.extract.internal; import java.sql.ResultSet; From 8aae155c50fa3e26daa59be41ab2c8a05fb57d72 Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Thu, 29 Jul 2021 14:08:30 -0700 Subject: [PATCH 286/644] HHH-14744 : Refactor contextual information for SchemaManagementTool to be more easily extended by Hibernate Reactive Move new methods out of SchemaManagementTool and into ExtractionTool --- .../internal/DatabaseInformationImpl.java | 7 ++-- .../HibernateSchemaManagementTool.java | 42 +++++++++++++++++++ .../tool/schema/spi/ExtractionTool.java | 30 +++++++++++++ .../tool/schema/spi/SchemaManagementTool.java | 32 +------------- 4 files changed, 76 insertions(+), 35 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/tool/schema/spi/ExtractionTool.java diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/DatabaseInformationImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/DatabaseInformationImpl.java index 7d968b92dc11..9af4d368df98 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/DatabaseInformationImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/DatabaseInformationImpl.java @@ -34,7 +34,7 @@ public class DatabaseInformationImpl private final ExtractionContext extractionContext; private final InformationExtractor extractor; - private final Map sequenceInformationMap = new HashMap(); + private final Map sequenceInformationMap = new HashMap<>(); public DatabaseInformationImpl( ServiceRegistry serviceRegistry, @@ -43,7 +43,7 @@ public DatabaseInformationImpl( Namespace.Name defaultNamespace, SchemaManagementTool tool) throws SQLException { this.jdbcEnvironment = jdbcEnvironment; - this.extractionContext = tool.createExtractionContext( + this.extractionContext = tool.getExtractionTool().createExtractionContext( serviceRegistry, jdbcEnvironment, ddlTransactionIsolator, @@ -52,8 +52,7 @@ public DatabaseInformationImpl( this ); - // todo : make this pluggable - this.extractor = tool.createInformationExtractor( extractionContext ); + this.extractor = tool.getExtractionTool().createInformationExtractor( extractionContext ); // because we do not have defined a way to locate sequence info by name initializeSequences(); diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/HibernateSchemaManagementTool.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/HibernateSchemaManagementTool.java index 2fea2a4d71d8..7741de5d8f5f 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/HibernateSchemaManagementTool.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/HibernateSchemaManagementTool.java @@ -9,12 +9,14 @@ import java.sql.Connection; import java.util.Map; +import org.hibernate.boot.model.naming.Identifier; import org.hibernate.boot.registry.selector.spi.StrategySelector; import org.hibernate.cfg.AvailableSettings; import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess; import org.hibernate.engine.jdbc.dialect.spi.DialectResolutionInfo; import org.hibernate.engine.jdbc.dialect.spi.DialectResolver; +import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.engine.jdbc.spi.SqlExceptionHelper; import org.hibernate.engine.jdbc.spi.SqlStatementLogger; @@ -27,12 +29,17 @@ import org.hibernate.service.spi.ServiceRegistryImplementor; import org.hibernate.tool.schema.JdbcMetadaAccessStrategy; import org.hibernate.tool.schema.TargetType; +import org.hibernate.tool.schema.extract.internal.InformationExtractorJdbcDatabaseMetaDataImpl; +import org.hibernate.tool.schema.extract.spi.ExtractionContext; +import org.hibernate.tool.schema.extract.spi.InformationExtractor; import org.hibernate.tool.schema.internal.exec.GenerationTarget; import org.hibernate.tool.schema.internal.exec.GenerationTargetToDatabase; import org.hibernate.tool.schema.internal.exec.GenerationTargetToScript; import org.hibernate.tool.schema.internal.exec.GenerationTargetToStdout; +import org.hibernate.tool.schema.internal.exec.ImprovedExtractionContextImpl; import org.hibernate.tool.schema.internal.exec.JdbcConnectionAccessProvidedConnectionImpl; import org.hibernate.tool.schema.internal.exec.JdbcContext; +import org.hibernate.tool.schema.spi.ExtractionTool; import org.hibernate.tool.schema.spi.SchemaCreator; import org.hibernate.tool.schema.spi.SchemaDropper; import org.hibernate.tool.schema.spi.SchemaFilterProvider; @@ -114,6 +121,11 @@ public void setCustomDatabaseGenerationTarget(GenerationTarget generationTarget) this.customTarget = generationTarget; } + @Override + public ExtractionTool getExtractionTool() { + return HibernateExtractionTool.INSTANCE; + } + GenerationTarget getCustomDatabaseGenerationTarget() { return customTarget; } @@ -352,4 +364,34 @@ public ServiceRegistry getServiceRegistry() { } } + private static class HibernateExtractionTool implements ExtractionTool { + + private static final HibernateExtractionTool INSTANCE = new HibernateExtractionTool(); + + private HibernateExtractionTool() { + } + + @Override + public ExtractionContext createExtractionContext( + ServiceRegistry serviceRegistry, + JdbcEnvironment jdbcEnvironment, + DdlTransactionIsolator ddlTransactionIsolator, + Identifier defaultCatalog, + Identifier defaultSchema, + ExtractionContext.DatabaseObjectAccess databaseObjectAccess) { + return new ImprovedExtractionContextImpl( + serviceRegistry, + jdbcEnvironment, + ddlTransactionIsolator, + defaultCatalog, + defaultSchema, + databaseObjectAccess + ); + } + + @Override + public InformationExtractor createInformationExtractor(ExtractionContext extractionContext) { + return new InformationExtractorJdbcDatabaseMetaDataImpl( extractionContext ); + } + } } diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/ExtractionTool.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/ExtractionTool.java new file mode 100644 index 000000000000..2b7da672ac63 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/ExtractionTool.java @@ -0,0 +1,30 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.tool.schema.spi; + +import org.hibernate.boot.model.naming.Identifier; +import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; +import org.hibernate.resource.transaction.spi.DdlTransactionIsolator; +import org.hibernate.service.ServiceRegistry; +import org.hibernate.tool.schema.extract.spi.ExtractionContext; +import org.hibernate.tool.schema.extract.spi.InformationExtractor; + +/** + * @author Gail Badner + */ +public interface ExtractionTool { + + ExtractionContext createExtractionContext( + ServiceRegistry serviceRegistry, + JdbcEnvironment jdbcEnvironment, + DdlTransactionIsolator ddlTransactionIsolator, + Identifier defaultCatalog, + Identifier defaultSchema, + ExtractionContext.DatabaseObjectAccess databaseObjectAccess); + + InformationExtractor createInformationExtractor(ExtractionContext extractionContext); +} diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/SchemaManagementTool.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/SchemaManagementTool.java index 8d046383febc..9fc88b8e5698 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/SchemaManagementTool.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/SchemaManagementTool.java @@ -7,21 +7,10 @@ package org.hibernate.tool.schema.spi; import java.util.Map; -import java.util.function.BiFunction; -import java.util.function.Function; import org.hibernate.Incubating; -import org.hibernate.boot.model.naming.Identifier; -import org.hibernate.boot.model.relational.Namespace; -import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; -import org.hibernate.resource.transaction.spi.DdlTransactionIsolator; import org.hibernate.service.Service; -import org.hibernate.service.ServiceRegistry; -import org.hibernate.tool.schema.extract.internal.InformationExtractorJdbcDatabaseMetaDataImpl; -import org.hibernate.tool.schema.extract.spi.ExtractionContext; -import org.hibernate.tool.schema.extract.spi.InformationExtractor; import org.hibernate.tool.schema.internal.exec.GenerationTarget; -import org.hibernate.tool.schema.internal.exec.ImprovedExtractionContextImpl; /** * Contract for schema management tool integration. @@ -44,24 +33,5 @@ public interface SchemaManagementTool extends Service { */ void setCustomDatabaseGenerationTarget(GenerationTarget generationTarget); - default ExtractionContext createExtractionContext( - ServiceRegistry serviceRegistry, - JdbcEnvironment jdbcEnvironment, - DdlTransactionIsolator ddlTransactionIsolator, - Identifier defaultCatalog, - Identifier defaultSchema, - ExtractionContext.DatabaseObjectAccess databaseObjectAccess) { - return new ImprovedExtractionContextImpl( - serviceRegistry, - jdbcEnvironment, - ddlTransactionIsolator, - defaultCatalog, - defaultSchema, - databaseObjectAccess - ); - } - - default InformationExtractor createInformationExtractor(ExtractionContext extractionContext) { - return new InformationExtractorJdbcDatabaseMetaDataImpl( extractionContext ); - } + ExtractionTool getExtractionTool(); } From 95ef2ae41da28ad0629ca412868f3d06547b336c Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Mon, 2 Aug 2021 21:48:58 -0700 Subject: [PATCH 287/644] HHH-14744 : Refactor contextual information for SchemaManagementTool to be more easily extended by Hibernate Reactive Add Javadoc and other minor changes to make it easier to review --- .../dialect/PostgreSQL10Dialect.java | 7 +- .../AbstractInformationExtractorImpl.java | 392 +++++++++++++++--- ...tionExtractorJdbcDatabaseMetaDataImpl.java | 68 +-- .../tool/schema/spi/ExtractionTool.java | 5 + .../test/schemaupdate/SchemaUpdateTest.java | 4 +- 5 files changed, 372 insertions(+), 104 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL10Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL10Dialect.java index e610796a7f5b..6f5767125cbb 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL10Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL10Dialect.java @@ -41,10 +41,12 @@ public void augmentRecognizedTableTypes(List tableTypesList) { tableTypesList.add( "PARTITIONED TABLE" ); } + @Override public IdentifierHelper buildIdentifierHelper( IdentifierHelperBuilder builder, DatabaseMetaData dbMetaData) throws SQLException { - + // This method is overridden so the information will be set properly when + // DatabaseMetaData is not available. if ( dbMetaData != null ) { builder.applyIdentifierCasing( dbMetaData ); builder.applyReservedWords( dbMetaData ); @@ -63,10 +65,11 @@ public IdentifierHelper buildIdentifierHelper( @Override public NameQualifierSupport getNameQualifierSupport() { + // This method is overridden so the correct value will be returned when + // DatabaseMetaData is not available. return NameQualifierSupport.SCHEMA; } - @Override public SequenceInformationExtractor getSequenceInformationExtractor() { return SequenceInformationExtractorPostgresSQLDatabaseImpl.INSTANCE; diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/AbstractInformationExtractorImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/AbstractInformationExtractorImpl.java index 499fb24be222..977c598ad7b9 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/AbstractInformationExtractorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/AbstractInformationExtractorImpl.java @@ -122,6 +122,10 @@ protected ExtractionContext getExtractionContext() { return extractionContext; } + // The following methods purposely return the column labels that are defined by + // DatabaseMetaData methods that return a ResultSet. Subclasses that do not rely + // on DatabaseMetaData may override these methods to use different column labels. + protected String getResultSetCatalogLabel() { return "TABLE_CAT"; } @@ -186,24 +190,25 @@ protected String getResultSetForeignKeyColumnNameLabel() { return "FKCOLUMN_NAME" ; } - protected String determineCatalogFilter(Identifier catalog) { - Identifier identifierToUse = catalog; - if ( identifierToUse == null ) { - identifierToUse = extractionContext.getDefaultCatalog(); - } - - return extractionContext.getJdbcEnvironment().getIdentifierHelper().toMetaDataCatalogName( identifierToUse ); - } - - protected String determineSchemaFilter(Identifier schema) { - Identifier identifierToUse = schema; - if ( identifierToUse == null ) { - identifierToUse = extractionContext.getDefaultSchema(); - } - - return extractionContext.getJdbcEnvironment().getIdentifierHelper().toMetaDataSchemaName( identifierToUse ); - } - + /** + * Must do the following: + *

      + *
    1. + * obtain a {@link ResultSet} containing a column of existing catalog + * names. The column label must be the same as returned by + * {@link #getResultSetCatalogLabel}. + *
    2. + *
    3. execute {@code processor.process( resultSet )};
    4. + *
    5. + * release resources whether {@code processor.process( resultSet )} + * executes successfully or not. + *
    6. + *
    + * @param processor - the provided ResultSetProcessor. + * @param - defined by {@code processor} + * @return - defined by {@code processor} + * @throws SQLException - if a database error occurs + */ protected abstract T processCatalogsResultSet(ExtractionContext.ResultSetProcessor processor) throws SQLException; @Override @@ -230,9 +235,41 @@ public boolean catalogExists(Identifier catalog) { } } + /** + * Must do the following: + *
      + *
    1. + * obtain a {@link ResultSet} containing a row for any existing + * catalog/schema combination as specified by the {@code catalog} + * and {@code schemaPattern} parameters described below. The row + * contents will not be examined by {@code processor.process( resultSet )}, + * so column label names are not specified; + *
    2. + *
    3. execute {@code processor.process( resultSet )};
    4. + *
    5. + * release resources whether {@code processor.process( resultSet )} + * executes successfully or not. + *
    6. + *
    + *

    + * The {@code catalog} and {@code schemaPattern} parameters are as + * specified by {@link DatabaseMetaData#getSchemas(String, String)}, + * and are copied here: + * @param catalog – a catalog name; must match the catalog name as it is + * stored in the database; "" retrieves those without + * a catalog; null means catalog name should not be + * used to narrow down the search. + * @param schemaPattern – a schema name; must match the schema name as + * it is stored in the database; null means schema + * name should not be used to narrow down the search. + * @param processor - the provided ResultSetProcessor. + * @param - defined by {@code processor} + * @return - defined by {@code processor} + * @throws SQLException - if a database error occurs + */ protected abstract T processSchemaResultSet( - String catalogFilter, - String schemaFilter, + String catalog, + String schemaPattern, ExtractionContext.ResultSetProcessor processor) throws SQLException; @Override @@ -269,6 +306,24 @@ public boolean schemaExists(Identifier catalog, Identifier schema) { } } + protected String determineCatalogFilter(Identifier catalog) { + Identifier identifierToUse = catalog; + if ( identifierToUse == null ) { + identifierToUse = extractionContext.getDefaultCatalog(); + } + + return extractionContext.getJdbcEnvironment().getIdentifierHelper().toMetaDataCatalogName( identifierToUse ); + } + + protected String determineSchemaFilter(Identifier schema) { + Identifier identifierToUse = schema; + if ( identifierToUse == null ) { + identifierToUse = extractionContext.getDefaultSchema(); + } + + return extractionContext.getJdbcEnvironment().getIdentifierHelper().toMetaDataSchemaName( identifierToUse ); + } + private TableInformation extractTableInformation(ResultSet resultSet) throws SQLException { final QualifiedTableName tableName = extractTableName( resultSet ); @@ -329,10 +384,9 @@ public TableInformation getTable(Identifier catalog, Identifier schema, Identifi } // 3) look in all namespaces - - final String tableNameFilter = toMetaDataObjectName( tableName ); - try { + final String tableNameFilter = toMetaDataObjectName( tableName ); + return processTableResultSet( null, null, @@ -495,7 +549,7 @@ public NameSpaceTablesInformation getTables(Identifier catalog, Identifier schem return processTableResultSet( catalogFilter, schemaFilter, - null, + "%", tableTypes, resultSet -> { final NameSpaceTablesInformation tablesInformation = extractNameSpaceTablesInformation( resultSet ); @@ -508,10 +562,62 @@ public NameSpaceTablesInformation getTables(Identifier catalog, Identifier schem } } + /** + * Must do the following: + *

      + *
    1. + * obtain a {@link ResultSet} containing a row for any existing + * catalog/schema/table/column combination as specified by the + * {@code catalog}, {@code schemaPattern}, {@code tableNamePattern}, + * and {@code columnNamePattern} parameters described below. + * The {@link ResultSet} must contain the following, consistent with the + * corresponding columns returned by {@link DatabaseMetaData#getColumns} + *
        + *
      • column label {@link #getResultSetTableNameLabel} for table name
      • + *
      • column label {@link #getResultSetColumnNameLabel} for column name
      • + *
      • column label {@link #getResultSetSqlTypeCodeLabel} SQL type code from java.sql.Types
      • + *
      • column label {@link #getResultSetTypeNameLabel} for database column type name
      • + *
      • column label {@link #getResultSetColumnSizeLabel} for column size
      • + *
      • column label {@link #getResultSetDecimalDigitsLabel} for number of fractional digits
      • + *
      • column label {@link #getResultSetIsNullableLabel} for nullability
      • + *
      + * Rows must be ordered by catalog, schema, table name, and column position. + *
    2. + *
    3. execute {@code processor.process( resultSet )};
    4. + *
    5. + * release resources whether {@code processor.process( resultSet )} + * executes successfully or not. + *
    6. + *
    + *

    + * The {@code catalog}, {@code schemaPattern}, {@code tableNamePattern}, + * and {@code columnNamePattern} parameters are as + * specified by {@link DatabaseMetaData#getColumns(String, String, String, String)}, + * and are copied here: + *

    + * @param catalog – a catalog name; must match the catalog name as it is + * stored in the database; "" retrieves those without + * a catalog; null means that the catalog name should + * not be used to narrow the search + * @param schemaPattern – a schema name pattern; must match the schema + * name as it is stored in the database; "" + * retrieves those without a schema; null means + * that the schema name should not be used to + * narrow the search + * @param tableNamePattern – a table name pattern; must match the table + * name as it is stored in the database + * @param columnNamePattern – a column name pattern; must match the + * column name as it is stored in the database + * @param processor - the provided ResultSetProcessor. + * @param - defined by {@code processor} + * @return - defined by {@code processor} + * @throws SQLException - if a database error occurs + */ protected abstract T processColumnsResultSet( - String catalogFilter, - String schemaFilter, - String tableFilter, + String catalog, + String schemaPattern, + String tableNamePattern, + String columnNamePattern, ExtractionContext.ResultSetProcessor processor) throws SQLException; private void populateTablesWithColumns( @@ -523,6 +629,7 @@ private void populateTablesWithColumns( catalogFilter, schemaFilter, null, + "%", resultSet -> { String currentTableName = ""; TableInformation currentTable = null; @@ -571,29 +678,54 @@ private NameSpaceTablesInformation extractNameSpaceTablesInformation(ResultSet r } /** - * Returns a {@link ResultSet} having the following column aliases: + * Must do the following: + *

      + *
    1. + * obtain a {@link ResultSet} containing a row for any existing + * catalog/schema/table/table type combination as specified by the + * {@code catalogFilter}, {@code schemaFilter}, {@code tableNameFilter}, + * and {@code tableTypes} parameters described below. + * The {@link ResultSet} must contain the following, consistent with the + * corresponding columns returned by {@link DatabaseMetaData#getTables(String, String, String, String[])} + *
        + *
      • column label {@link #getResultSetTableNameLabel} for table name
      • + *
      • column label {@link #getResultSetTableTypeLabel} for table type
      • + *
      • column label {@link #getResultSetRemarksLabel} for table comment
      • + *
      + *
    2. + *
    3. execute {@code processor.process( resultSet )};
    4. + *
    5. + * release resources whether {@code processor.process( resultSet )} + * executes successfully or not. + *
    6. + *
    *

    - * TABLE_CAT String => table catalog (may be null) - * TABLE_SCHEM String => table schema (may be null) - * TABLE_NAME String => table name - * TABLE_TYPE String => table type. Typical types are "TABLE", "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL TEMPORARY", "ALIAS", "SYNONYM". - * REMARKS String => explanatory comment on the table (may be null) - *

    - * These column aliases are purposely consistent with those defined by {@link DatabaseMetaData#getTables}, - * although the {@link ResultSet} need not have been returned by that method. + * The {@code catalog}, {@code schemaPattern}, {@code tableNamePattern}, + * and {@code columnNamePattern} parameters are as + * specified by {@link DatabaseMetaData#getTables(String, String, String, String[])}, + * and are copied here: * - * @param catalogFilter - * @param schemaFilter - * @param tableNameFilter - * @param tableTypes - * @return results of type {@code T} - * @throws SQLException + * @param catalog - a catalog name; must match the catalog name as it is + * stored in the database; "" retrieves those without a + * catalog; null means that the catalog name should not + * be used to narrow the search + * @param schemaPattern - a schema name pattern; must match the schema name + * as it is stored in the database; "" retrieves + * those without a schema; null means that the schema + * name should not be used to narrow the search + * @param tableNamePattern - a table name pattern; must match the table name + * as it is stored in the database + * @param types - a list of table types + * @param processor - the provided ResultSetProcessor. + * @param - defined by {@code processor} + * @return - defined by {@code processor} + * @throws SQLException - if a database error occurs */ protected abstract T processTableResultSet( - String catalogFilter, - String schemaFilter, - String tableNameFilter, - String[] tableTypes, + String catalog, + String schemaPattern, + String tableNamePattern, + String[] types, ExtractionContext.ResultSetProcessor processor ) throws SQLException; @@ -741,6 +873,7 @@ protected void addColumns(TableInformation tableInformation) { catalogFilter, schemaFilter, tableName.getTableName().getText(), + "%", resultSet -> { while ( resultSet.next() ) { @@ -780,6 +913,7 @@ else if ( "no".equalsIgnoreCase( nullable ) ) { return TruthValue.UNKNOWN; } + // This method is not currently used. protected abstract T processPrimaryKeysResultSet( String catalogFilter, String schemaFilter, @@ -877,24 +1011,83 @@ private PrimaryKeyInformation extractPrimaryKeyInformation( } /** - * Requires the following: - * - * index_type result must be one of the constants from DatabaseMetaData - * (e.g., #tableIndexStatistic, tableIndexClustered, tableIndexHashed, or tableIndexOther) - * index_name - * column_name - * - * @param catalogFilter - * @param schemaFilter - * @param tableName - * @param approximate - * @return results of type {@code T} - * @throws SQLException + * Must do the following: + *

      + *
    1. + * obtain a {@link ResultSet} containing a row for each column + * defined in an index. The {@link ResultSet} must contain the + * following, consistent with the corresponding columns returned + * by {@link DatabaseMetaData#getIndexInfo(String, String, String, boolean, boolean)} + *
        + *
      • column label {@link #getResultSetIndexNameLabel} for index name; + * null when TYPE is tableIndexStatistic
      • + *
      • column label {@link #getResultSetIndexTypeLabel} index type: + *
          + *
        • + * {@link DatabaseMetaData#tableIndexStatistic} - + * this identifies table statistics that are returned + * in conjunction with a table's index descriptions + *
        • + *
        • + * {@link DatabaseMetaData#tableIndexClustered} - + * this is a clustered index + *
        • + *
        • + * {@link DatabaseMetaData#tableIndexHashed} - + * this is a hashed index + *
        • + *
        • + * {@link DatabaseMetaData#tableIndexOther} - + * this is some other style of index + *
        • + *
        + *
      • + *
      • + * column label {@link #getResultSetColumnNameLabel} - + * column name; null when TYPE is + * {@link DatabaseMetaData#tableIndexStatistic} + *
      • + *
      + * The ResultSet must be ordered by non-uniqueness, index type, + * index name, and index column position. + *
    2. + *
    3. execute {@code processor.process( resultSet )};
    4. + *
    5. + * release resources whether {@code processor.process( resultSet )} + * executes successfully or not. + *
    6. + *
    + *

    + * The {@code catalog}, {@code schemaPattern}, {@code tableNamePattern}, + * and {@code columnNamePattern} parameters are as + * specified by {@link DatabaseMetaData#getIndexInfo(String, String, String, boolean, boolean)}, + * and are copied here: + *

    + * @param catalog – a catalog name; must match the catalog name as it is + * stored in this database; "" retrieves those without + * a catalog; null means that the catalog name should + * not be used to narrow the search + * @param schema – a schema name; must match the schema name as it is + * stored in this database; "" retrieves those without + * a schema; null means that the schema name should not + * be used to narrow the search + * @param table – a table name; must match the table name as it is stored + * in this database + * @param unique – when true, return only indices for unique values; when + * false, return indices regardless of whether unique or not + * @param approximate – when true, result is allowed to reflect approximate + * or out of data values; when false, results are + * requested to be accurate + * @param processor - the provided ResultSetProcessor. + * @param - defined by {@code processor} + * @return - defined by {@code processor} + * @throws SQLException - if a database error occurs */ protected abstract T processIndexInfoResultSet( - String catalogFilter, - String schemaFilter, - Identifier tableName, + String catalog, + String schema, + String table, + boolean unique, boolean approximate, ExtractionContext.ResultSetProcessor processor) throws SQLException; @@ -926,7 +1119,8 @@ public Iterable getIndexes(TableInformation tableInformation) processIndexInfoResultSet( catalogFilter, schemaFilter, - tableName.getTableName(), + tableName.getTableName().getText(), + false, // DO NOT limit to just unique true, // DO require up-to-date results resultSet -> { while ( resultSet.next() ) { @@ -976,10 +1170,76 @@ public Iterable getIndexes(TableInformation tableInformation) return indexes; } + /** + * Must do the following: + *

      + *
    1. + * obtain a {@link ResultSet} containing a row for each foreign key/ + * primary key column making up a foreign key for any existing + * catalog/schema/table combination as specified by the + * {@code catalog}, {@code schema}, and {@code table} + * parameters described below. + * The {@link ResultSet} must contain the following, consistent + * with the corresponding columns returned by {@link DatabaseMetaData#getImportedKeys}: + *
        + *
      • + * column label {@link #getResultSetForeignKeyLabel} - + * foreign key name (may be null) + *
      • + *
      • + * column label {@link #getResultSetPrimaryKeyCatalogLabel} - + * primary key table catalog being imported (may be null) + *
      • + *
      • + * column label {@link #getResultSetPrimaryKeySchemaLabel} - + * primary key table schema being imported (may be null) + *
      • + *
      • + * column label {@link #getResultSetPrimaryKeyTableLabel} - + * primary key table name being imported + *
      • + *
      • + * column label {@link #getResultSetForeignKeyColumnNameLabel} - + * foreign key column name + *
      • + *
      • + * column label {@link #getResultSetPrimaryKeyColumnNameLabel} - + * primary key column name being imported + *
      • + *
      , + * The ResultSet must be ordered by the primary key + * catalog/schema/table and column position within the key. + *
    2. + *
    3. execute {@code processor.process( resultSet )};
    4. + *
    5. + * release resources whether {@code processor.process( resultSet )} + * executes successfully or not. + *
    6. + *
    + *

    + * The {@code catalog}, {@code schema}, and {@code table} + * parameters are as specified by {@link DatabaseMetaData#getImportedKeys(String, String, String)} + * and are copied here: + * + * @param catalog – a catalog name; must match the catalog name as it is + * stored in the database; "" retrieves those without a + * catalog; null means that the catalog name should not + * be used to narrow the search + * @param schema – a schema name; must match the schema name as it is + * stored in the database; "" retrieves those without a + * schema; null means that the schema name should not be + * used to narrow the search + * @param table – a table name; must match the table name as it is stored + * in the database + * @param processor - the provided ResultSetProcessor. + * @param - defined by {@code processor} + * @return - defined by {@code processor} + * @throws SQLException - if a database error occurs + */ protected abstract T processImportedKeysResultSet( - String catalogFilter, - String schemaFilter, - String tableName, + String catalog, + String schema, + String table, ExtractionContext.ResultSetProcessor processor ) throws SQLException; diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/InformationExtractorJdbcDatabaseMetaDataImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/InformationExtractorJdbcDatabaseMetaDataImpl.java index dc5927286dbd..25d9f9c03e88 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/InformationExtractorJdbcDatabaseMetaDataImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/InformationExtractorJdbcDatabaseMetaDataImpl.java @@ -17,7 +17,7 @@ import org.hibernate.tool.schema.extract.spi.TableInformation; /** - * Implementation of the SchemaMetaDataExtractor contract which uses the standard JDBC {@link java.sql.DatabaseMetaData} + * Implementation of the InformationExtractor contract which uses the standard JDBC {@link java.sql.DatabaseMetaData} * API for extraction. * * @author Steve Ebersole @@ -43,44 +43,45 @@ public T processCatalogsResultSet(ExtractionContext.ResultSetProcessor pr @Override protected T processSchemaResultSet( - String catalogFilter, - String schemaFilter, + String catalog, + String schemaPattern, ExtractionContext.ResultSetProcessor processor) throws SQLException { try (ResultSet resultSet = getExtractionContext().getJdbcDatabaseMetaData().getSchemas( - catalogFilter, - schemaFilter ) ) { + catalog, + schemaPattern ) ) { return processor.process( resultSet ); } } @Override protected T processTableResultSet( - String catalogFilter, - String schemaFilter, - String tableNameFilter, - String[] tableTypes, + String catalog, + String schemaPattern, + String tableNamePattern, + String[] types, ExtractionContext.ResultSetProcessor processor ) throws SQLException { try (ResultSet resultSet = getExtractionContext().getJdbcDatabaseMetaData().getTables( - catalogFilter, - schemaFilter, - tableNameFilter, - tableTypes)) { + catalog, + schemaPattern, + tableNamePattern, + types)) { return processor.process( resultSet ); } } @Override protected T processColumnsResultSet( - String catalogFilter, - String schemaFilter, - String tableFilter, + String catalog, + String schemaPattern, + String tableNamePattern, + String columnNamePattern, ExtractionContext.ResultSetProcessor processor) throws SQLException { try (ResultSet resultSet = getExtractionContext().getJdbcDatabaseMetaData().getColumns( - catalogFilter, - schemaFilter, - tableFilter, - "%" )) { + catalog, + schemaPattern, + tableNamePattern, + columnNamePattern )) { return processor.process( resultSet ); } } @@ -101,17 +102,18 @@ protected T processPrimaryKeysResultSet( @Override protected T processIndexInfoResultSet( - String catalogFilter, - String schemaFilter, - Identifier tableName, + String catalog, + String schema, + String table, + boolean unique, boolean approximate, ExtractionContext.ResultSetProcessor processor) throws SQLException { try (ResultSet resultSet = getExtractionContext().getJdbcDatabaseMetaData().getIndexInfo( - catalogFilter, - schemaFilter, - tableName.getText(), - false, // DO NOT limit to just unique + catalog, + schema, + table, + unique, approximate ) ) { return processor.process( resultSet ); } @@ -119,14 +121,14 @@ protected T processIndexInfoResultSet( @Override protected T processImportedKeysResultSet( - String catalogFilter, - String schemaFilter, - String tableName, + String catalog, + String schema, + String table, ExtractionContext.ResultSetProcessor processor) throws SQLException { try (ResultSet resultSet = getExtractionContext().getJdbcDatabaseMetaData().getImportedKeys( - catalogFilter, - schemaFilter, - tableName ) ) { + catalog, + schema, + table ) ) { return processor.process( resultSet ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/ExtractionTool.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/ExtractionTool.java index 2b7da672ac63..e0b35cd58d4b 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/ExtractionTool.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/ExtractionTool.java @@ -6,6 +6,7 @@ */ package org.hibernate.tool.schema.spi; +import org.hibernate.Incubating; import org.hibernate.boot.model.naming.Identifier; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.resource.transaction.spi.DdlTransactionIsolator; @@ -14,8 +15,12 @@ import org.hibernate.tool.schema.extract.spi.InformationExtractor; /** + * Encapsulates the functionality for extracting database metadata used by + * {@link SchemaManagementTool}. + * * @author Gail Badner */ +@Incubating public interface ExtractionTool { ExtractionContext createExtractionContext( diff --git a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaUpdateTest.java b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaUpdateTest.java index 12db48628c04..e0cb4d6756ab 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaUpdateTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaUpdateTest.java @@ -164,7 +164,7 @@ public void testSchemaUpdateAndValidation() throws Exception { @Table(name = "`testentity`") public static class LowercaseTableNameEntity { @Id - @GeneratedValue + @GeneratedValue long id; String field1; @@ -230,7 +230,6 @@ public static class MixedCaseTableNameEntity { public static class Match { @Id @GeneratedValue - long id; String match; @@ -244,7 +243,6 @@ public static class Match { public static class InheritanceRootEntity { @Id @GeneratedValue - protected Long id; } From 42b8be78520b6a44b99e102dd1f3c7fdc1c31fbb Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Tue, 3 Aug 2021 16:58:35 -0700 Subject: [PATCH 288/644] HHH-14744 : Refactor contextual information for SchemaManagementTool to be more easily extended by Hibernate Reactive Correct specifications for row order of some ResultSets. --- .../extract/internal/AbstractInformationExtractorImpl.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/AbstractInformationExtractorImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/AbstractInformationExtractorImpl.java index 977c598ad7b9..095af1afbf00 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/AbstractInformationExtractorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/AbstractInformationExtractorImpl.java @@ -1048,8 +1048,9 @@ private PrimaryKeyInformation extractPrimaryKeyInformation( * {@link DatabaseMetaData#tableIndexStatistic} * * - * The ResultSet must be ordered by non-uniqueness, index type, - * index name, and index column position. + * The ResultSet must be ordered so that the columns for a + * particular index are in contiguous rows in order of column + * position. * *

  • execute {@code processor.process( resultSet )};
  • *
  • From 3720e5fac4ca798d94ab736c88f85a60f501be5a Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Wed, 4 Aug 2021 23:40:40 -0700 Subject: [PATCH 289/644] HHH-14744 : HHH-14744 : Refactor contextual information for SchemaManagementTool to be more easily extended by Hibernate Reactive Remove PostgreSQL10Dialect#buildIdentifierHelper since it is no longer needed. --- .../dialect/PostgreSQL10Dialect.java | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL10Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL10Dialect.java index 6f5767125cbb..37dfba3f923b 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL10Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL10Dialect.java @@ -41,28 +41,6 @@ public void augmentRecognizedTableTypes(List tableTypesList) { tableTypesList.add( "PARTITIONED TABLE" ); } - @Override - public IdentifierHelper buildIdentifierHelper( - IdentifierHelperBuilder builder, - DatabaseMetaData dbMetaData) throws SQLException { - // This method is overridden so the information will be set properly when - // DatabaseMetaData is not available. - if ( dbMetaData != null ) { - builder.applyIdentifierCasing( dbMetaData ); - builder.applyReservedWords( dbMetaData ); - } - else { - builder.setUnquotedCaseStrategy( IdentifierCaseStrategy.LOWER ); - builder.setQuotedCaseStrategy( IdentifierCaseStrategy.MIXED ); - } - builder.applyReservedWords( AnsiSqlKeywords.INSTANCE.sql2003() ); - builder.applyReservedWords( getKeywords() ); - - builder.setNameQualifierSupport( getNameQualifierSupport() ); - - return builder.build(); - } - @Override public NameQualifierSupport getNameQualifierSupport() { // This method is overridden so the correct value will be returned when From 352eb2fae16ec614d50da59fd52514b2a20186a1 Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Thu, 12 Aug 2021 18:47:51 -0700 Subject: [PATCH 290/644] HHH-14744 : HHH-14744 : Refactor contextual information for SchemaManagementTool to be more easily extended by Hibernate Reactive Move methods from PostgreSQL10Dialect into PostgreSQL81Dialect; remove @GeneratedValue from SchemaUpdateTest --- .../org/hibernate/dialect/PostgreSQL10Dialect.java | 12 ------------ .../org/hibernate/dialect/PostgreSQL81Dialect.java | 13 +++++++++++++ .../test/schemaupdate/SchemaUpdateTest.java | 7 ------- 3 files changed, 13 insertions(+), 19 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL10Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL10Dialect.java index 37dfba3f923b..336bdd41d3c7 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL10Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL10Dialect.java @@ -41,20 +41,8 @@ public void augmentRecognizedTableTypes(List tableTypesList) { tableTypesList.add( "PARTITIONED TABLE" ); } - @Override - public NameQualifierSupport getNameQualifierSupport() { - // This method is overridden so the correct value will be returned when - // DatabaseMetaData is not available. - return NameQualifierSupport.SCHEMA; - } - @Override public SequenceInformationExtractor getSequenceInformationExtractor() { return SequenceInformationExtractorPostgresSQLDatabaseImpl.INSTANCE; } - - @Override - public String getCurrentSchemaCommand() { - return "select current_schema from sys.dummy"; - } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL81Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL81Dialect.java index 95ea786bf336..aee33307bcf8 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL81Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL81Dialect.java @@ -32,6 +32,7 @@ import org.hibernate.engine.jdbc.env.spi.IdentifierCaseStrategy; import org.hibernate.engine.jdbc.env.spi.IdentifierHelper; import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder; +import org.hibernate.engine.jdbc.env.spi.NameQualifierSupport; import org.hibernate.engine.spi.RowSelection; import org.hibernate.exception.LockAcquisitionException; import org.hibernate.exception.spi.SQLExceptionConversionDelegate; @@ -215,6 +216,18 @@ public SqlTypeDescriptor getSqlTypeDescriptorOverride(int sqlCode) { return descriptor; } + @Override + public NameQualifierSupport getNameQualifierSupport() { + // This method is overridden so the correct value will be returned when + // DatabaseMetaData is not available. + return NameQualifierSupport.SCHEMA; + } + + @Override + public String getCurrentSchemaCommand() { + return "select current_schema()"; + } + @Override public String getAddColumnString() { return "add column"; diff --git a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaUpdateTest.java b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaUpdateTest.java index e0cb4d6756ab..8d3c544767fc 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaUpdateTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaUpdateTest.java @@ -21,7 +21,6 @@ import javax.persistence.ElementCollection; import javax.persistence.Entity; import javax.persistence.ForeignKey; -import javax.persistence.GeneratedValue; import javax.persistence.Id; import javax.persistence.Index; import javax.persistence.Inheritance; @@ -164,7 +163,6 @@ public void testSchemaUpdateAndValidation() throws Exception { @Table(name = "`testentity`") public static class LowercaseTableNameEntity { @Id - @GeneratedValue long id; String field1; @@ -175,7 +173,6 @@ public static class LowercaseTableNameEntity { @Entity(name = "TestEntity1") public static class TestEntity { @Id - @GeneratedValue @Column(name = "`Id`") long id; String field1; @@ -195,7 +192,6 @@ public static class TestEntity { @Table(name = "`TESTENTITY`") public static class UppercaseTableNameEntity { @Id - @GeneratedValue long id; String field1; @@ -211,7 +207,6 @@ public static class UppercaseTableNameEntity { @Table(name = "`TESTentity`", indexes = {@Index(name = "index1", columnList = "`FieLd1`"), @Index(name = "Index2", columnList = "`FIELD_2`")}) public static class MixedCaseTableNameEntity { @Id - @GeneratedValue long id; @Column(name = "`FieLd1`") String field1; @@ -229,7 +224,6 @@ public static class MixedCaseTableNameEntity { @Entity(name = "Match") public static class Match { @Id - @GeneratedValue long id; String match; @@ -242,7 +236,6 @@ public static class Match { @Inheritance(strategy = InheritanceType.JOINED) public static class InheritanceRootEntity { @Id - @GeneratedValue protected Long id; } From b17a46cbd575871708e832458c9b02a9470b7b16 Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Thu, 12 Aug 2021 19:38:18 -0700 Subject: [PATCH 291/644] HHH-14744 : Refactor contextual information for SchemaManagementTool to be more easily extended by Hibernate Reactive Remove SequenceInformationExtractorPostgresSQLDatabaseImpl and PostgreSQL10Dialect#getSequenceInformationExtractor --- .../dialect/PostgreSQL10Dialect.java | 14 ------ ...ationExtractorPostgresSQLDatabaseImpl.java | 46 ------------------- 2 files changed, 60 deletions(-) delete mode 100644 hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorPostgresSQLDatabaseImpl.java diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL10Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL10Dialect.java index 336bdd41d3c7..69d99b246f8d 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL10Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL10Dialect.java @@ -6,19 +6,10 @@ */ package org.hibernate.dialect; -import java.sql.DatabaseMetaData; -import java.sql.SQLException; import java.util.List; import org.hibernate.dialect.identity.IdentityColumnSupport; import org.hibernate.dialect.identity.PostgreSQL10IdentityColumnSupport; -import org.hibernate.engine.jdbc.env.spi.AnsiSqlKeywords; -import org.hibernate.engine.jdbc.env.spi.IdentifierCaseStrategy; -import org.hibernate.engine.jdbc.env.spi.IdentifierHelper; -import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder; -import org.hibernate.engine.jdbc.env.spi.NameQualifierSupport; -import org.hibernate.tool.schema.extract.internal.SequenceInformationExtractorPostgresSQLDatabaseImpl; -import org.hibernate.tool.schema.extract.spi.SequenceInformationExtractor; /** * An SQL dialect for Postgres 10 and later. @@ -40,9 +31,4 @@ public void augmentRecognizedTableTypes(List tableTypesList) { super.augmentRecognizedTableTypes( tableTypesList ); tableTypesList.add( "PARTITIONED TABLE" ); } - - @Override - public SequenceInformationExtractor getSequenceInformationExtractor() { - return SequenceInformationExtractorPostgresSQLDatabaseImpl.INSTANCE; - } } diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorPostgresSQLDatabaseImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorPostgresSQLDatabaseImpl.java deleted file mode 100644 index b262e4180505..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/SequenceInformationExtractorPostgresSQLDatabaseImpl.java +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.tool.schema.extract.internal; - -import java.sql.ResultSet; -import java.sql.SQLException; - -/** - * PostgreSQL stores the sequence metadata as strings. PostgreSQL's JDBC driver does the - * conversion automatically, but, unfortunately Vert.x driver does not do this conversion. - * - * This class is intended to make this functionality work with both the JDBC and Vert.X - * drivers. - * - * @author Gail Badner - */ -public class SequenceInformationExtractorPostgresSQLDatabaseImpl extends SequenceInformationExtractorLegacyImpl { - //Singleton access - public static final SequenceInformationExtractorPostgresSQLDatabaseImpl INSTANCE = new SequenceInformationExtractorPostgresSQLDatabaseImpl(); - - protected Long resultSetStartValueSize(ResultSet resultSet) throws SQLException { - return convertStringValueToLong( resultSet, sequenceStartValueColumn() ); - } - - protected Long resultSetMinValue(ResultSet resultSet) throws SQLException { - return convertStringValueToLong( resultSet, sequenceMinValueColumn() ); - } - - protected Long resultSetMaxValue(ResultSet resultSet) throws SQLException { - return convertStringValueToLong( resultSet, sequenceMaxValueColumn() ); - } - - protected Long resultSetIncrementValue(ResultSet resultSet) throws SQLException { - return convertStringValueToLong( resultSet, sequenceIncrementColumn() ); - } - - private Long convertStringValueToLong(ResultSet resultSet, String columnLabel) throws SQLException { - // column value is of type character_data so get it as a String - final String stringValue = resultSet.getString( columnLabel ); - return stringValue != null ? Long.valueOf( stringValue ) : null; - } -} From f4f4d49da0de10b96cb52829de2315722fb148eb Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Mon, 16 Aug 2021 10:40:22 -0700 Subject: [PATCH 292/644] HHH-14744 : Refactor contextual information for SchemaManagementTool to be more easily extended by Hibernate Reactive Add MySQLDialect#getNameQualifierSupport --- .../src/main/java/org/hibernate/dialect/MySQLDialect.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java index 945b44320686..301b57974477 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/MySQLDialect.java @@ -31,6 +31,7 @@ import org.hibernate.engine.jdbc.env.spi.IdentifierCaseStrategy; import org.hibernate.engine.jdbc.env.spi.IdentifierHelper; import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder; +import org.hibernate.engine.jdbc.env.spi.NameQualifierSupport; import org.hibernate.engine.spi.RowSelection; import org.hibernate.exception.LockAcquisitionException; import org.hibernate.exception.LockTimeoutException; @@ -566,6 +567,11 @@ public JDBCException convert(SQLException sqlException, String message, String s }; } + @Override + public NameQualifierSupport getNameQualifierSupport() { + return NameQualifierSupport.CATALOG; + } + @Override public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData dbMetaData) throws SQLException { From a70b99452649bed57804adef8455add8f349327d Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Mon, 16 Aug 2021 18:18:01 -0700 Subject: [PATCH 293/644] HHH-14744 : Refactor contextual information for SchemaManagementTool to be more easily extended by Hibernate Reactive 1. Add CockroachDB192Dialect#getNameQualifierSupport and #buildIdentifierHelper. 2. Change semantics for AbstractInformationExtractorImpl#processIndexInfoResultSet to be more friendly to subclasses. --- .../dialect/CockroachDB192Dialect.java | 23 +++++++++++++++++++ .../AbstractInformationExtractorImpl.java | 15 ++++-------- 2 files changed, 28 insertions(+), 10 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/CockroachDB192Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/CockroachDB192Dialect.java index 18ad31c3388d..d0978cbe8466 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/CockroachDB192Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/CockroachDB192Dialect.java @@ -28,6 +28,10 @@ import org.hibernate.dialect.pagination.AbstractLimitHandler; import org.hibernate.dialect.pagination.LimitHandler; import org.hibernate.dialect.pagination.LimitHelper; +import org.hibernate.engine.jdbc.env.spi.IdentifierCaseStrategy; +import org.hibernate.engine.jdbc.env.spi.IdentifierHelper; +import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder; +import org.hibernate.engine.jdbc.env.spi.NameQualifierSupport; import org.hibernate.engine.spi.RowSelection; import org.hibernate.exception.LockAcquisitionException; import org.hibernate.exception.spi.SQLExceptionConversionDelegate; @@ -658,4 +662,23 @@ public boolean doesReadCommittedCauseWritersToBlockReaders() { public boolean canCreateSchema() { return false; } + + @Override + public NameQualifierSupport getNameQualifierSupport() { + // This method is overridden so the correct value will be returned when + // DatabaseMetaData is not available. + return NameQualifierSupport.SCHEMA; + } + + @Override + public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData dbMetaData) + throws SQLException { + + if ( dbMetaData == null ) { + builder.setUnquotedCaseStrategy( IdentifierCaseStrategy.LOWER ); + builder.setQuotedCaseStrategy( IdentifierCaseStrategy.MIXED ); + } + + return super.buildIdentifierHelper( builder, dbMetaData ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/AbstractInformationExtractorImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/AbstractInformationExtractorImpl.java index 095af1afbf00..6bb723c2c0d1 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/AbstractInformationExtractorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/AbstractInformationExtractorImpl.java @@ -1029,18 +1029,13 @@ private PrimaryKeyInformation extractPrimaryKeyInformation( * in conjunction with a table's index descriptions *
  • *
  • - * {@link DatabaseMetaData#tableIndexClustered} - - * this is a clustered index - *
  • - *
  • - * {@link DatabaseMetaData#tableIndexHashed} - - * this is a hashed index - *
  • - *
  • - * {@link DatabaseMetaData#tableIndexOther} - - * this is some other style of index + * Any value other than {@link DatabaseMetaData#tableIndexStatistic} - + * this indicates that a table's index description + * (not statisics) is being returned. *
  • * + * NOTE: Hibernate ignores statistics and does not + * care about the actual type of index. * *
  • * column label {@link #getResultSetColumnNameLabel} - From 9267c5e6a64f9f1d128af219230ec58b6d4d42ab Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Wed, 25 Aug 2021 16:11:38 +0100 Subject: [PATCH 294/644] HHH-14792 Remove support for bytecode enhancement via Javassist --- .../tutorials/osgi/managed-jpa/features.xml | 1 - .../tutorials/osgi/managed-jpa/pom.xml | 3 - .../tutorials/osgi/unmanaged-jpa/features.xml | 1 - .../tutorials/osgi/unmanaged-jpa/pom.xml | 3 - .../osgi/unmanaged-native/features.xml | 1 - .../tutorials/osgi/unmanaged-native/pom.xml | 3 - .../userguide/appendices/Configurations.adoc | 2 +- .../userguide/chapters/domain/entity.adoc | 3 +- .../userguide/chapters/osgi/OSGi.adoc | 3 - gradle/java-module.gradle | 1 - gradle/libraries.gradle | 4 - .../hibernate-core-jakarta.gradle | 3 - hibernate-core/hibernate-core.gradle | 50 -- .../javassist/AttributeTypeDescriptor.java | 279 ------- .../internal/javassist/CompositeEnhancer.java | 77 -- .../internal/javassist/EnhancerImpl.java | 212 ----- .../internal/javassist/EntityEnhancer.java | 448 ----------- .../internal/javassist/FieldWriter.java | 83 -- .../JavassistEnhancementContext.java | 79 -- .../javassist/MappedSuperclassEnhancer.java | 61 -- .../internal/javassist/MethodWriter.java | 109 --- .../PersistentAttributesEnhancer.java | 745 ------------------ .../javassist/PersistentAttributesHelper.java | 412 ---------- .../internal/javassist/UnloadedCtClass.java | 32 - .../internal/javassist/UnloadedCtField.java | 32 - .../internal/javassist/package-info.java | 11 - .../javassist/AccessOptimizerAdapter.java | 101 --- .../internal/javassist/BulkAccessor.java | 109 --- .../javassist/BulkAccessorException.java | 69 -- .../javassist/BulkAccessorFactory.java | 423 ---------- .../javassist/BytecodeProviderImpl.java | 106 --- .../internal/javassist/FastClass.java | 247 ------ .../InstantiationOptimizerAdapter.java | 45 -- .../javassist/ProxyFactoryFactoryImpl.java | 160 ---- .../javassist/ReflectionOptimizerImpl.java | 45 -- .../internal/javassist/package-info.java | 11 - .../bytecode/spi/ProxyFactoryFactory.java | 2 +- .../org/hibernate/cfg/AvailableSettings.java | 3 +- .../java/org/hibernate/cfg/Environment.java | 3 +- .../org/hibernate/cfg/PropertyContainer.java | 3 +- .../hibernate/internal/CoreMessageLogger.java | 6 +- .../javassist/JavassistLazyInitializer.java | 135 ---- .../pojo/javassist/JavassistProxyFactory.java | 224 ------ .../pojo/javassist/SerializableProxy.java | 141 ---- .../instrument/javassist/InstrumentTask.java | 34 - .../callbacks/PrivateConstructorTest.java | 4 - .../ProxyInterfaceClassLoaderTest.java | 2 +- .../javassist/EnhancerFileNotFoundTest.java | 67 -- .../test/bytecode/javassist/Bean.java | 83 -- .../javassist/BeanReflectionHelper.java | 92 --- .../bytecode/javassist/BulkAccessorTest.java | 30 - .../hibernate-envers-jakarta.gradle | 7 +- hibernate-envers/hibernate-envers.gradle | 5 +- .../envers/internal/tools/EntityTools.java | 2 +- .../src/test/java/module-info.java | 7 +- .../hibernate-micrometer.gradle | 7 - .../osgi/test/OsgiIntegrationTest.java | 1 - release/release.gradle | 2 - .../hibernate-enhance-maven-plugin.gradle | 3 - .../hibernate-gradle-plugin.gradle | 1 - 60 files changed, 16 insertions(+), 4822 deletions(-) delete mode 100644 hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/AttributeTypeDescriptor.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/CompositeEnhancer.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/EnhancerImpl.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/EntityEnhancer.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/FieldWriter.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/JavassistEnhancementContext.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/MappedSuperclassEnhancer.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/MethodWriter.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/PersistentAttributesEnhancer.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/PersistentAttributesHelper.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/UnloadedCtClass.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/UnloadedCtField.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/package-info.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/AccessOptimizerAdapter.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/BulkAccessor.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/BulkAccessorException.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/BulkAccessorFactory.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/BytecodeProviderImpl.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/FastClass.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/InstantiationOptimizerAdapter.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/ProxyFactoryFactoryImpl.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/ReflectionOptimizerImpl.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/package-info.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/proxy/pojo/javassist/JavassistLazyInitializer.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/proxy/pojo/javassist/JavassistProxyFactory.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/proxy/pojo/javassist/SerializableProxy.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/tool/instrument/javassist/InstrumentTask.java delete mode 100644 hibernate-core/src/testJavassist/java/org/hibernate/test/bytecode/enhancement/javassist/EnhancerFileNotFoundTest.java delete mode 100644 hibernate-core/src/testJavassist/java/org/hibernate/test/bytecode/javassist/Bean.java delete mode 100644 hibernate-core/src/testJavassist/java/org/hibernate/test/bytecode/javassist/BeanReflectionHelper.java delete mode 100644 hibernate-core/src/testJavassist/java/org/hibernate/test/bytecode/javassist/BulkAccessorTest.java diff --git a/documentation/src/main/asciidoc/quickstart/tutorials/osgi/managed-jpa/features.xml b/documentation/src/main/asciidoc/quickstart/tutorials/osgi/managed-jpa/features.xml index 1df06fe5b907..f11fa0618e0c 100644 --- a/documentation/src/main/asciidoc/quickstart/tutorials/osgi/managed-jpa/features.xml +++ b/documentation/src/main/asciidoc/quickstart/tutorials/osgi/managed-jpa/features.xml @@ -60,7 +60,6 @@ mvn:com.fasterxml/classmate/0.8.0 mvn:org.apache.logging.log4j/log4j-api/2.0 mvn:org.jboss.logging/jboss-logging/3.2.1.Final - mvn:org.javassist/javassist/3.18.1-GA mvn:org.hibernate.common/hibernate-commons-annotations/4.0.5.Final diff --git a/documentation/src/main/asciidoc/quickstart/tutorials/osgi/managed-jpa/pom.xml b/documentation/src/main/asciidoc/quickstart/tutorials/osgi/managed-jpa/pom.xml index 55ccacd3c9bd..7240eeba5d70 100644 --- a/documentation/src/main/asciidoc/quickstart/tutorials/osgi/managed-jpa/pom.xml +++ b/documentation/src/main/asciidoc/quickstart/tutorials/osgi/managed-jpa/pom.xml @@ -56,9 +56,6 @@ org.apache.karaf.shell.console, org.apache.karaf.shell.commands, javax.persistence;version="[1.0.0,2.1.0]", - - org.hibernate.proxy, - javassist.util.proxy, * META-INF/persistence.xml diff --git a/documentation/src/main/asciidoc/quickstart/tutorials/osgi/unmanaged-jpa/features.xml b/documentation/src/main/asciidoc/quickstart/tutorials/osgi/unmanaged-jpa/features.xml index f3f240a28223..27fb7fe27f72 100644 --- a/documentation/src/main/asciidoc/quickstart/tutorials/osgi/unmanaged-jpa/features.xml +++ b/documentation/src/main/asciidoc/quickstart/tutorials/osgi/unmanaged-jpa/features.xml @@ -33,7 +33,6 @@ mvn:com.fasterxml/classmate/0.8.0 mvn:org.apache.logging.log4j/log4j-api/2.0 mvn:org.jboss.logging/jboss-logging/3.2.1.Final - mvn:org.javassist/javassist/3.18.1-GA mvn:org.hibernate.common/hibernate-commons-annotations/4.0.5.Final diff --git a/documentation/src/main/asciidoc/quickstart/tutorials/osgi/unmanaged-jpa/pom.xml b/documentation/src/main/asciidoc/quickstart/tutorials/osgi/unmanaged-jpa/pom.xml index 736108ea4b2e..dfa514894965 100644 --- a/documentation/src/main/asciidoc/quickstart/tutorials/osgi/unmanaged-jpa/pom.xml +++ b/documentation/src/main/asciidoc/quickstart/tutorials/osgi/unmanaged-jpa/pom.xml @@ -68,9 +68,6 @@ org.apache.karaf.shell.commands, org.h2, javax.persistence;version="[1.0.0,2.1.0]", - - org.hibernate.proxy, - javassist.util.proxy, * diff --git a/documentation/src/main/asciidoc/quickstart/tutorials/osgi/unmanaged-native/features.xml b/documentation/src/main/asciidoc/quickstart/tutorials/osgi/unmanaged-native/features.xml index cd4d665d40cc..88eb28f6b3be 100644 --- a/documentation/src/main/asciidoc/quickstart/tutorials/osgi/unmanaged-native/features.xml +++ b/documentation/src/main/asciidoc/quickstart/tutorials/osgi/unmanaged-native/features.xml @@ -41,7 +41,6 @@ mvn:com.fasterxml/classmate/0.8.0 mvn:org.apache.logging.log4j/log4j-api/2.0 mvn:org.jboss.logging/jboss-logging/3.2.1.Final - mvn:org.javassist/javassist/3.18.1-GA mvn:org.hibernate.common/hibernate-commons-annotations/4.0.5.Final diff --git a/documentation/src/main/asciidoc/quickstart/tutorials/osgi/unmanaged-native/pom.xml b/documentation/src/main/asciidoc/quickstart/tutorials/osgi/unmanaged-native/pom.xml index 07cf7f484b6b..a2db99adc486 100644 --- a/documentation/src/main/asciidoc/quickstart/tutorials/osgi/unmanaged-native/pom.xml +++ b/documentation/src/main/asciidoc/quickstart/tutorials/osgi/unmanaged-native/pom.xml @@ -76,9 +76,6 @@ org.hibernate.cfg, org.hibernate.service, javax.persistence;version="[1.0.0,2.1.0]", - - org.hibernate.proxy, - javassist.util.proxy, * diff --git a/documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc b/documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc index d896314c5c70..625dfe10095c 100644 --- a/documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc +++ b/documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc @@ -434,7 +434,7 @@ Enable lazy loading feature in runtime bytecode enhancement. This way, even basi Enable association management feature in runtime bytecode enhancement which automatically synchronizes a bidirectional association when only one side is changed. `*hibernate.bytecode.provider*` (e.g. `bytebuddy` (default value)):: -The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/bytecode/spi/BytecodeProvider.html[`BytecodeProvider`] built-in implementation flavor. Currently, only `bytebuddy` and `javassist` are valid values; `bytebuddy` is the default and recommended choice; `javassist` will be removed soon. +The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/bytecode/spi/BytecodeProvider.html[`BytecodeProvider`] built-in implementation flavor. Currently, only `bytebuddy` is a valid value, as older deprecated options have been removed. `*hibernate.bytecode.use_reflection_optimizer*` (e.g. `true` or `false` (default value)):: Should we use reflection optimization? The reflection optimizer implements the https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/bytecode/spi/ReflectionOptimizer.html[`ReflectionOptimizer`] interface and improves entity instantiation and property getter/setter calls. diff --git a/documentation/src/main/asciidoc/userguide/chapters/domain/entity.adoc b/documentation/src/main/asciidoc/userguide/chapters/domain/entity.adoc index 4b7235f33e8f..b014708cacbf 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/domain/entity.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/domain/entity.adoc @@ -455,10 +455,9 @@ Hibernate will trigger a Persistence Context flush if there are pending `Account ==== Define a custom entity proxy By default, when it needs to use a proxy instead of the actual POJO, Hibernate is going to use a Bytecode manipulation library like -https://jboss-javassist.github.io/javassist/[Javassist] or https://bytebuddy.net/[Byte Buddy]. -However, if the entity class is final, Javassist will not create a proxy and you will get a POJO even when you only need a proxy reference. +However, if the entity class is final, a proxy will not be created; you will get a POJO even when you only need a proxy reference. In this case, you could proxy an interface that this particular entity implements, as illustrated by the following example. [[entity-proxy-interface-mapping]] diff --git a/documentation/src/main/asciidoc/userguide/chapters/osgi/OSGi.adoc b/documentation/src/main/asciidoc/userguide/chapters/osgi/OSGi.adoc index 0df3e9b60134..bd8dec29e8f4 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/osgi/OSGi.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/osgi/OSGi.adoc @@ -93,7 +93,6 @@ That `DataSource` is then used by your `persistence.xml` persistence-unit. The f Your bundle's manifest will need to import, at a minimum: * `javax.persistence` -* `org.hibernate.proxy` and `javassist.util.proxy`, due to Hibernate's ability to return proxies for lazy initialization (Javassist enhancement occurs on the entity's `ClassLoader` during runtime). === Obtaining an EntityManger @@ -123,7 +122,6 @@ Similar to any other JPA setup, your bundle must include a `persistence.xml` fil Your bundle's manifest will need to import, at a minimum: * `javax.persistence` -* `org.hibernate.proxy` and `javassist.util.proxy`, due to Hibernate's ability to return proxies for lazy initialization (Javassist enhancement occurs on the entity's `ClassLoader` during runtime) * JDBC driver package (example: `org.h2`) * `org.osgi.framework`, necessary to discover the `EntityManagerFactory` (described below) @@ -157,7 +155,6 @@ Native Hibernate use is also supported. The client bundle is responsible for man Your bundle's manifest will need to import, at a minimum: * `javax.persistence` -* `org.hibernate.proxy` and `javassist.util.proxy`, due to Hibernate's ability to return proxies for lazy initialization (Javassist enhancement occurs on the entity's `ClassLoader` during runtime) * JDBC driver package (example: `org.h2`) * `org.osgi.framework`, necessary to discover the `SessionFactory` (described below) * `org.hibernate.*` packages, as necessary (ex: cfg, criterion, service, etc.) diff --git a/gradle/java-module.gradle b/gradle/java-module.gradle index d8d7a1586bb3..f4bb0dbfce63 100644 --- a/gradle/java-module.gradle +++ b/gradle/java-module.gradle @@ -72,7 +72,6 @@ dependencies { testCompile( libraries.byteman_bmunit ) testRuntime( libraries.log4j2 ) - testRuntime( libraries.javassist ) testRuntime( libraries.byteBuddy ) //Databases diff --git a/gradle/libraries.gradle b/gradle/libraries.gradle index d3c755de9e61..7923d39e2cab 100644 --- a/gradle/libraries.gradle +++ b/gradle/libraries.gradle @@ -24,7 +24,6 @@ ext { weldVersion = '3.1.5.Final' jakartaWeldVersion = '4.0.1.SP1' - javassistVersion = '3.27.0-GA' byteBuddyVersion = '1.11.12' agroalVersion = '1.9' @@ -64,9 +63,6 @@ ext { // Dom4J dom4j: 'org.dom4j:dom4j:2.1.3@jar', - // Javassist - javassist: "org.javassist:javassist:${javassistVersion}", - // Byte Buddy byteBuddy: "net.bytebuddy:byte-buddy:${byteBuddyVersion}", diff --git a/hibernate-core-jakarta/hibernate-core-jakarta.gradle b/hibernate-core-jakarta/hibernate-core-jakarta.gradle index 6dbe272e27e8..e9b091c0c98a 100644 --- a/hibernate-core-jakarta/hibernate-core-jakarta.gradle +++ b/hibernate-core-jakarta/hibernate-core-jakarta.gradle @@ -20,8 +20,6 @@ configurations { dependencies { compile( libraries.jakarta_jpa ) - // This can now be made provided - compile( libraries.javassist ) // Could be made optional? compile( libraries.byteBuddy ) compile( libraries.antlr ) @@ -75,7 +73,6 @@ dependencies { testRuntime( "org.jboss.spec.javax.ejb:jboss-ejb-api_3.2_spec:1.0.0.Final" ) testRuntime( libraries.jakarta_el ) testRuntime( 'jaxen:jaxen:1.1' ) - testRuntime( libraries.javassist ) testRuntime( libraries.byteBuddy ) testRuntime( libraries.jakarta_weld ) testRuntime( libraries.atomikos ) diff --git a/hibernate-core/hibernate-core.gradle b/hibernate-core/hibernate-core.gradle index c04f082d21c1..f2a1c3c0f862 100644 --- a/hibernate-core/hibernate-core.gradle +++ b/hibernate-core/hibernate-core.gradle @@ -28,31 +28,17 @@ sourceSets { setSrcDirs( ['src/test/java','src/test/resources','src/test/bundles'] ) } } - - testJavassist { - java { - compileClasspath += main.output + test.output - runtimeClasspath += main.output + test.output - } - } } configurations { tests { description = 'Configuration for the produced test jar' } - - //Configures the compile and runtime configurations for our javassist tests - //and includes the dependencies of the test task. - testJavassistCompile.extendsFrom testCompile - testJavassistRuntime.extendsFrom testRuntime } dependencies { compile( libraries.jpa ) - // This can now be made provided - compile( libraries.javassist ) // Could be made optional? compile( libraries.byteBuddy ) compile( libraries.antlr ) @@ -103,7 +89,6 @@ dependencies { testRuntime( "org.jboss.spec.javax.ejb:jboss-ejb-api_3.2_spec:1.0.0.Final" ) testRuntime( libraries.expression_language ) testRuntime( 'jaxen:jaxen:1.1' ) - testRuntime( libraries.javassist ) testRuntime( libraries.byteBuddy ) testRuntime( libraries.weld ) testRuntime( libraries.atomikos ) @@ -118,9 +103,6 @@ dependencies { testCompile libraries.jboss_ejb_spec_jar testCompile libraries.jboss_annotation_spec_jar - // Additional tests requiring Javassist - // folder in src/javassist/java - testJavassistCompile libraries.javassist } jar { @@ -265,35 +247,3 @@ test { } } -//Create the task that runs the integration tests found from the -//configured source directory and uses the correct classpath. -task testJavassist(type: Test) { - testClassesDirs = sourceSets.testJavassist.output.classesDirs - classpath = sourceSets.testJavassist.runtimeClasspath - //If you want to ensure that integration tests are run every time when you invoke - //this task, uncomment the following line. - //outputs.upToDateWhen { false } - - if ( gradle.ext.javaToolchainEnabled ) { - // Configure version of Java tools - javaLauncher = javaToolchains.launcherFor { - languageVersion = gradle.ext.javaVersions.test.launcher - } - - // Configure JVM Options - jvmArgs( getProperty( 'toolchain.launcher.jvmargs' ).toString().split( ' ' ) ) - - // Display version of Java tools - doFirst { - logger.lifecycle "Testing javassist with '${javaLauncher.get().metadata.installationPath}'" - } - } - - if ( gradle.ext.javaVersions.test.launcher.asInt() >= 9 ) { - // Javassist needs this to generate proxies - jvmArgs( ['--add-opens', 'java.base/java.lang=ALL-UNNAMED'] ) - } -} - -check.dependsOn testJavassist -testJavassist.mustRunAfter test diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/AttributeTypeDescriptor.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/AttributeTypeDescriptor.java deleted file mode 100644 index 4c4d7462bc7a..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/AttributeTypeDescriptor.java +++ /dev/null @@ -1,279 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.bytecode.enhance.internal.javassist; - -import java.util.Collection; -import java.util.Locale; -import java.util.Objects; - -import javax.persistence.EmbeddedId; -import javax.persistence.Id; - -import javassist.CtClass; -import javassist.CtField; -import javassist.NotFoundException; - -import org.hibernate.bytecode.enhance.spi.EnhancerConstants; - -/** - * utility class to generate interceptor methods - * @see org.hibernate.engine.spi.PersistentAttributeInterceptor - * - * @author Luis Barreiro - */ -public abstract class AttributeTypeDescriptor { - - protected InheritanceMetadata inheritanceMetadata; - - protected AttributeTypeDescriptor(InheritanceMetadata inheritanceMetadata) { - this.inheritanceMetadata = inheritanceMetadata; - } - - public abstract String buildReadInterceptionBodyFragment(String fieldName); - - public abstract String buildWriteInterceptionBodyFragment(String fieldName); - - public String buildInLineDirtyCheckingBodyFragment(JavassistEnhancementContext context, CtField currentValue) { - StringBuilder builder = new StringBuilder(); - try { - // should ignore primary keys - if ( PersistentAttributesHelper.hasAnnotation( currentValue, Id.class ) - || PersistentAttributesHelper.hasAnnotation( currentValue, EmbeddedId.class ) ) { - return ""; - } - - String readFragment = inheritanceMetadata.isInherited() && !inheritanceMetadata.isVisible() - ? "super." + inheritanceMetadata.getReaderName() + "()" - : "this." + currentValue.getName(); - - if ( currentValue.getType().isPrimitive() || currentValue.getType().isEnum() ) { - // primitives || enums - builder.append( String.format( " if ( %s != $1 )", readFragment ) ); - } - else { - // if the field is a collection we return since we handle that in a separate method - for ( CtClass ctClass : currentValue.getType().getInterfaces() ) { - if ( ctClass.getName().equals( Collection.class.getName() ) ) { - // if the collection is not managed we should write it to the tracker - if ( context.isMappedCollection( currentValue ) ) { - return ""; - } - } - } - builder.append( - String.format( - " if ( !%s.deepEquals( %s, $1 ) )", - Objects.class.getName(), - readFragment - ) - ); - } - builder.append( String.format( " { %s(\"%s\"); }", EnhancerConstants.TRACKER_CHANGER_NAME, currentValue.getName() ) ); - } - catch (NotFoundException ignore) { - } - return builder.toString(); - } - - /* --- */ - - /** - * factory method to get the AttributeTypeDescriptor for a particular field type - */ - public static AttributeTypeDescriptor resolve(CtClass managedCtClass, CtField persistentField) throws NotFoundException { - boolean inherited = !managedCtClass.equals( persistentField.getDeclaringClass() ); - boolean visible = persistentField.visibleFrom( managedCtClass ); - String readerName = EnhancerConstants.PERSISTENT_FIELD_READER_PREFIX + persistentField.getName(); - String writerName = EnhancerConstants.PERSISTENT_FIELD_WRITER_PREFIX + persistentField.getName(); - InheritanceMetadata inheritanceMetadata = new InheritanceMetadata( inherited, visible, readerName, writerName ); - - if ( CtClass.booleanType.equals( persistentField.getType() ) ) { - return new PrimitiveAttributeTypeDescriptor( inheritanceMetadata, Boolean.TYPE ); - } - else if ( CtClass.byteType.equals( persistentField.getType() )) { - return new PrimitiveAttributeTypeDescriptor( inheritanceMetadata, Byte.TYPE ); - } - else if ( CtClass.charType.equals( persistentField.getType() ) ) { - return new PrimitiveAttributeTypeDescriptor( inheritanceMetadata, Character.TYPE ); - } - else if ( CtClass.shortType.equals( persistentField.getType() ) ) { - return new PrimitiveAttributeTypeDescriptor( inheritanceMetadata, Short.TYPE ); - } - else if ( CtClass.intType.equals( persistentField.getType() ) ) { - return new PrimitiveAttributeTypeDescriptor( inheritanceMetadata, Integer.TYPE ); - } - else if ( CtClass.longType.equals( persistentField.getType() ) ) { - return new PrimitiveAttributeTypeDescriptor( inheritanceMetadata, Long.TYPE ); - } - else if ( CtClass.doubleType.equals( persistentField.getType() ) ) { - return new PrimitiveAttributeTypeDescriptor( inheritanceMetadata, Double.TYPE ); - } - else if ( CtClass.floatType.equals( persistentField.getType() ) ) { - return new PrimitiveAttributeTypeDescriptor( inheritanceMetadata, Float.TYPE ); - } - else { - return new ObjectAttributeTypeDescriptor( inheritanceMetadata, persistentField.getType() ); - } - } - - /* --- */ - - /** - * AttributeTypeDescriptor for non primitive types - */ - private static class ObjectAttributeTypeDescriptor extends AttributeTypeDescriptor { - - private final String type; - - private ObjectAttributeTypeDescriptor(InheritanceMetadata inheritanceMetadata, CtClass concreteType) { - super( inheritanceMetadata ); - this.type = concreteType.getName(); - } - - @Override - public String buildReadInterceptionBodyFragment(String fieldName) { - if ( inheritanceMetadata.isInherited() && !inheritanceMetadata.isVisible() ) { - return String.format( - " if( %3$s() != null ) { super.%5$s( (%2$s) %3$s().readObject(this, \"%1$s\", super.%4$s())); }%n", - fieldName, - type, - EnhancerConstants.INTERCEPTOR_GETTER_NAME, - inheritanceMetadata.getReaderName(), - inheritanceMetadata.getWriterName() ); - } - else { - return String.format( - " if ( %3$s() != null ) { this.%1$s = (%2$s) %3$s().readObject(this, \"%1$s\", this.%1$s); }%n", - fieldName, - type, - EnhancerConstants.INTERCEPTOR_GETTER_NAME ); - } - } - - @Override - public String buildWriteInterceptionBodyFragment(String fieldName) { - if ( inheritanceMetadata.isInherited() && !inheritanceMetadata.isVisible() ) { - return String.format( - " %2$s localVar = $1;%n" + - " if ( %3$s() != null ) { localVar = (%2$s) %3$s().writeObject(this, \"%1$s\", super.%4$s(), $1); }%n" + - " super.%5$s(localVar);", - fieldName, - type, - EnhancerConstants.INTERCEPTOR_GETTER_NAME, - inheritanceMetadata.getReaderName(), - inheritanceMetadata.getWriterName() ); - } - else { - return String.format( - " %2$s localVar = $1;%n" + - " if ( %3$s() != null ) { localVar = (%2$s) %3$s().writeObject(this, \"%1$s\", this.%1$s, $1); }%n" + - " this.%1$s = localVar;", - fieldName, - type, - EnhancerConstants.INTERCEPTOR_GETTER_NAME ); - } - } - } - - /** - * AttributeTypeDescriptor for primitive types - */ - private static class PrimitiveAttributeTypeDescriptor extends AttributeTypeDescriptor { - - private final String type; - - private PrimitiveAttributeTypeDescriptor(InheritanceMetadata inheritanceMetadata, Class primitiveType) { - super( inheritanceMetadata ); - if ( !primitiveType.isPrimitive() ) { - throw new IllegalArgumentException( "Primitive attribute type descriptor can only be used on primitive types" ); - } - // capitalize first letter - this.type = primitiveType.getSimpleName().substring( 0, 1 ).toUpperCase( Locale.ROOT ) + primitiveType.getSimpleName().substring( 1 ); - } - - @Override - public String buildReadInterceptionBodyFragment(String fieldName) { - if ( inheritanceMetadata.isInherited() && !inheritanceMetadata.isVisible() ) { - return String.format( - " if (%3$s() != null ) { super.%5$s( %3$s().read%2$s(this, \"%1$s\", super.%4$s())); }", - fieldName, - type, - EnhancerConstants.INTERCEPTOR_GETTER_NAME, - inheritanceMetadata.getReaderName(), - inheritanceMetadata.getWriterName() ); - } - else { - return String.format( - " if (%3$s() != null ) { this.%1$s = %3$s().read%2$s(this, \"%1$s\", this.%1$s); }", - fieldName, - type, - EnhancerConstants.INTERCEPTOR_GETTER_NAME ); - } - } - - @Override - public String buildWriteInterceptionBodyFragment(String fieldName) { - if ( inheritanceMetadata.isInherited() && !inheritanceMetadata.isVisible() ) { - return String.format( - " %2$s localVar = $1;%n" + - " if ( %4$s() != null ) { localVar = %4$s().write%3$s(this, \"%1$s\", super.%5$s(), $1); }%n" + - " super.%6$s(localVar);", - fieldName, - type.toLowerCase( Locale.ROOT ), - type, - EnhancerConstants.INTERCEPTOR_GETTER_NAME, - inheritanceMetadata.getReaderName(), - inheritanceMetadata.getWriterName() ); - } - else { - return String.format( - " %2$s localVar = $1;%n" + - " if ( %4$s() != null ) { localVar = %4$s().write%3$s(this, \"%1$s\", this.%1$s, $1); }%n" + - " this.%1$s = localVar;", - fieldName, - type.toLowerCase( Locale.ROOT ), - type, - EnhancerConstants.INTERCEPTOR_GETTER_NAME - ); - } - } - } - - // - - private static class InheritanceMetadata { - - private boolean inherited; - private boolean visible; - private String readerName; - private String writerName; - - public InheritanceMetadata(boolean inherited, boolean visible, String readerName, String writerName) { - this.inherited = inherited; - this.visible = visible; - this.readerName = readerName; - this.writerName = writerName; - } - - public boolean isInherited() { - return inherited; - } - - public boolean isVisible() { - return visible; - } - - public String getReaderName() { - return readerName; - } - - public String getWriterName() { - return writerName; - } - } - -} diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/CompositeEnhancer.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/CompositeEnhancer.java deleted file mode 100644 index c88e0745ccc3..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/CompositeEnhancer.java +++ /dev/null @@ -1,77 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.bytecode.enhance.internal.javassist; - -import javassist.CannotCompileException; -import javassist.CtClass; - -import org.hibernate.bytecode.enhance.internal.tracker.CompositeOwnerTracker; -import org.hibernate.bytecode.enhance.spi.EnhancerConstants; -import org.hibernate.engine.spi.CompositeOwner; -import org.hibernate.engine.spi.CompositeTracker; -import org.hibernate.engine.spi.ManagedComposite; - -/** - * enhancer for composite (embeddable) entities - * - * @author Luis Barreiro - */ -public class CompositeEnhancer extends PersistentAttributesEnhancer { - - public CompositeEnhancer(JavassistEnhancementContext context) { - super( context ); - } - - public void enhance(CtClass managedCtClass) { - // add the ManagedComposite interface - managedCtClass.addInterface( loadCtClassFromClass( ManagedComposite.class ) ); - - addInterceptorHandling( managedCtClass ); - - if ( enhancementContext.doDirtyCheckingInline( managedCtClass ) ) { - addInLineDirtyHandling( managedCtClass ); - } - - super.enhance( managedCtClass ); - } - - /* --- */ - - private void addInLineDirtyHandling(CtClass managedCtClass) { - managedCtClass.addInterface( loadCtClassFromClass( CompositeTracker.class ) ); - - final CtClass compositeCtType = loadCtClassFromClass( CompositeOwnerTracker.class ); - FieldWriter.addField( managedCtClass, compositeCtType, EnhancerConstants.TRACKER_COMPOSITE_FIELD_NAME ); - - createCompositeTrackerMethod( managedCtClass ); - } - - private void createCompositeTrackerMethod(CtClass managedCtClass) { - try { - MethodWriter.write( managedCtClass, "" + - "public void %1$s(String name, %3$s tracker) {%n" + - " if (%2$s == null) { %2$s = new %4$s(); }%n" + - " %2$s.add(name, tracker);%n" + - "}", - EnhancerConstants.TRACKER_COMPOSITE_SET_OWNER, - EnhancerConstants.TRACKER_COMPOSITE_FIELD_NAME, - CompositeOwner.class.getName(), - CompositeOwnerTracker.class.getName() ); - - MethodWriter.write( managedCtClass, "" + - "public void %1$s(String name) {%n" + - " if (%2$s != null) { %2$s.removeOwner(name); }%n" + - "}", - EnhancerConstants.TRACKER_COMPOSITE_CLEAR_OWNER, - EnhancerConstants.TRACKER_COMPOSITE_FIELD_NAME ); - } - catch (CannotCompileException cce) { - throw new RuntimeException( "createCompositeTrackerMethod failed", cce ); - } - } - -} diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/EnhancerImpl.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/EnhancerImpl.java deleted file mode 100644 index c42ea704e591..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/EnhancerImpl.java +++ /dev/null @@ -1,212 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.bytecode.enhance.internal.javassist; - -import java.io.ByteArrayInputStream; -import java.io.ByteArrayOutputStream; -import java.io.DataOutputStream; -import java.io.FileNotFoundException; -import java.io.IOException; -import java.io.InputStream; -import java.io.UncheckedIOException; - -import javassist.ClassPool; -import javassist.CtClass; -import javassist.LoaderClassPath; - -import javassist.NotFoundException; -import org.hibernate.HibernateException; -import org.hibernate.bytecode.enhance.spi.EnhancementContext; -import org.hibernate.bytecode.enhance.spi.EnhancementException; -import org.hibernate.bytecode.enhance.spi.Enhancer; -import org.hibernate.bytecode.enhance.spi.EnhancerConstants; -import org.hibernate.engine.spi.Managed; -import org.hibernate.engine.spi.PersistentAttributeInterceptable; -import org.hibernate.engine.spi.PersistentAttributeInterceptor; -import org.hibernate.internal.CoreLogging; -import org.hibernate.internal.CoreMessageLogger; - -public class EnhancerImpl implements Enhancer { - - private static final CoreMessageLogger log = CoreLogging.messageLogger( Enhancer.class ); - - protected final JavassistEnhancementContext enhancementContext; - private final ClassPool classPool; - - /** - * Constructs the Enhancer, using the given context. - * - * @param enhancementContext Describes the context in which enhancement will occur so as to give access - * to contextual/environmental information. - */ - public EnhancerImpl(EnhancementContext enhancementContext) { - this.enhancementContext = new JavassistEnhancementContext( enhancementContext ); - this.classPool = buildClassPool( this.enhancementContext ); - } - - EnhancerImpl(JavassistEnhancementContext enhancementContext) { - this.enhancementContext = enhancementContext; - this.classPool = buildClassPool( enhancementContext ); - } - - /** - * Performs the enhancement. - * - * @param className The name of the class whose bytecode is being enhanced. - * @param originalBytes The class's original (pre-enhancement) byte code - * - * @return The enhanced bytecode. Could be the same as the original bytecode if the original was - * already enhanced or we could not enhance it for some reason. - * - * @throws EnhancementException Indicates a problem performing the enhancement - */ - @Override - public synchronized byte[] enhance(String className, byte[] originalBytes) throws EnhancementException { - CtClass managedCtClass = null; - try { - managedCtClass = classPool.makeClassIfNew( new ByteArrayInputStream( originalBytes ) ); - return enhance( managedCtClass ) ? getByteCode( managedCtClass ) : null; - } - catch (IOException e) { - log.unableToBuildEnhancementMetamodel( className ); - return null; - } - finally { - if ( managedCtClass != null ) { - managedCtClass.detach(); - } - } - } - - private ClassPool buildClassPool(JavassistEnhancementContext enhancementContext) { - ClassPool classPool = new ClassPool( false ) { - @Override - public ClassLoader getClassLoader() { - return enhancementContext.getLoadingClassLoader(); - } - }; - - ClassLoader loadingClassLoader = enhancementContext.getLoadingClassLoader(); - if ( loadingClassLoader != null ) { - classPool.appendClassPath( new LoaderClassPath( loadingClassLoader ) ); - } - return classPool; - } - - protected CtClass loadCtClassFromClass(Class aClass) { - String resourceName = aClass.getName().replace( '.', '/' ) + ".class"; - InputStream resourceAsStream = aClass.getClassLoader().getResourceAsStream( resourceName ); - if ( resourceAsStream == null ) { - throw new UncheckedIOException( new FileNotFoundException ( "Not found: " + resourceName ) ); - } - try { - return classPool.makeClass( resourceAsStream ); - } - catch (IOException e) { - throw new EnhancementException( "Could not prepare Javassist ClassPool", e ); - } - finally { - try { - resourceAsStream.close(); - } - catch (IOException ioe) { - log.debugf( "An error occurs closing InputStream for class [%s]", aClass.getName() ); - } - } - } - - private boolean enhance(CtClass managedCtClass) { - // can't effectively enhance interfaces - if ( managedCtClass.isInterface() ) { - log.debugf( "Skipping enhancement of [%s]: it's an interface!", managedCtClass.getName() ); - return false; - } - // skip already enhanced classes - if ( alreadyEnhanced( managedCtClass ) ) { - log.debugf( "Skipping enhancement of [%s]: already enhanced", managedCtClass.getName() ); - return false; - } - - if ( enhancementContext.isEntityClass( managedCtClass ) ) { - log.debugf( "Enhancing [%s] as Entity", managedCtClass.getName() ); - new EntityEnhancer( enhancementContext ).enhance( managedCtClass ); - return true; - } - else if ( enhancementContext.isCompositeClass( managedCtClass ) ) { - log.debugf( "Enhancing [%s] as Composite", managedCtClass.getName() ); - new CompositeEnhancer( enhancementContext ).enhance( managedCtClass ); - return true; - } - else if ( enhancementContext.isMappedSuperclassClass( managedCtClass ) ) { - log.debugf( "Enhancing [%s] as MappedSuperclass", managedCtClass.getName() ); - new MappedSuperclassEnhancer( enhancementContext ).enhance( managedCtClass ); - return true; - } - else if ( enhancementContext.doExtendedEnhancement( managedCtClass ) ) { - log.debugf( "Extended enhancement of [%s]", managedCtClass.getName() ); - new PersistentAttributesEnhancer( enhancementContext ).extendedEnhancement( managedCtClass ); - return true; - } - else { - log.debugf( "Skipping enhancement of [%s]: not entity or composite", managedCtClass.getName() ); - return false; - } - } - - // See HHH-10977 HHH-11284 HHH-11404 --- check for declaration of Managed interface on the class, not inherited - private boolean alreadyEnhanced(CtClass managedCtClass) { - try { - for ( CtClass declaredInterface : managedCtClass.getInterfaces() ) { - if ( PersistentAttributesHelper.isAssignable( declaredInterface, Managed.class.getName() ) ) { - return true; - } - } - return false; - } - catch ( NotFoundException e ) { - throw new HibernateException( "Unable to transform class: " + e.getMessage() , e ); - } - } - - private byte[] getByteCode(CtClass managedCtClass) { - ByteArrayOutputStream byteStream = new ByteArrayOutputStream(); - DataOutputStream out = new DataOutputStream( byteStream ); - try { - managedCtClass.toBytecode( out ); - return byteStream.toByteArray(); - } - catch (Exception e) { - log.unableToTransformClass( e.getMessage() ); - throw new HibernateException( "Unable to transform class: " + e.getMessage() , e ); - } - finally { - try { - out.close(); - } - catch (IOException ignored) { - } - } - } - - protected void addInterceptorHandling(CtClass managedCtClass) { - // interceptor handling is only needed if class has lazy-loadable attributes - if ( !enhancementContext.hasLazyLoadableAttributes( managedCtClass ) ) { - return; - } - log.debugf( "Weaving in PersistentAttributeInterceptable implementation on [%s]", managedCtClass.getName() ); - - managedCtClass.addInterface( loadCtClassFromClass( PersistentAttributeInterceptable.class ) ); - - FieldWriter.addFieldWithGetterAndSetter( - managedCtClass, - loadCtClassFromClass( PersistentAttributeInterceptor.class ), - EnhancerConstants.INTERCEPTOR_FIELD_NAME, - EnhancerConstants.INTERCEPTOR_GETTER_NAME, - EnhancerConstants.INTERCEPTOR_SETTER_NAME - ); - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/EntityEnhancer.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/EntityEnhancer.java deleted file mode 100644 index 5da39fb16acf..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/EntityEnhancer.java +++ /dev/null @@ -1,448 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.bytecode.enhance.internal.javassist; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.Collections; -import java.util.List; -import java.util.Locale; -import java.util.Map; - -import javassist.CannotCompileException; -import javassist.CtClass; -import javassist.CtField; -import javassist.Modifier; -import javassist.NotFoundException; - -import org.hibernate.bytecode.enhance.internal.tracker.DirtyTracker; -import org.hibernate.bytecode.enhance.internal.tracker.NoopCollectionTracker; -import org.hibernate.bytecode.enhance.internal.tracker.SimpleCollectionTracker; -import org.hibernate.bytecode.enhance.internal.tracker.SimpleFieldTracker; -import org.hibernate.bytecode.enhance.spi.CollectionTracker; -import org.hibernate.bytecode.enhance.spi.EnhancementException; -import org.hibernate.bytecode.enhance.spi.EnhancerConstants; -import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor; -import org.hibernate.engine.spi.EntityEntry; -import org.hibernate.engine.spi.ManagedEntity; -import org.hibernate.engine.spi.PersistentAttributeInterceptable; -import org.hibernate.engine.spi.SelfDirtinessTracker; - -/** - * enhancer for regular entities - * - * @author Luis Barreiro - */ -public class EntityEnhancer extends PersistentAttributesEnhancer { - - public EntityEnhancer(JavassistEnhancementContext context) { - super( context ); - } - - // assuming the number of fields is not very high, SimpleFieldTracker implementation it's the fastest - private static final String DIRTY_TRACKER_IMPL = SimpleFieldTracker.class.getName(); - private static final String COLLECTION_TRACKER_IMPL = SimpleCollectionTracker.class.getName(); - - public void enhance(CtClass managedCtClass) { - // add the ManagedEntity interface - managedCtClass.addInterface( loadCtClassFromClass( ManagedEntity.class ) ); - - addEntityInstanceHandling( managedCtClass ); - addEntityEntryHandling( managedCtClass ); - addLinkedPreviousHandling( managedCtClass ); - addLinkedNextHandling( managedCtClass ); - addInterceptorHandling( managedCtClass ); - - if ( enhancementContext.doDirtyCheckingInline( managedCtClass ) ) { - addInLineDirtyHandling( managedCtClass ); - } - - super.enhance( managedCtClass ); - } - - private void addEntityInstanceHandling(CtClass managedCtClass) { - try { - MethodWriter.write( - managedCtClass, - "public Object %s() { return this; }", - EnhancerConstants.ENTITY_INSTANCE_GETTER_NAME - ); - } - catch (CannotCompileException cce) { - throw new EnhancementException( - String.format( - Locale.ROOT, - "Could not enhance entity class [%s] to add EntityEntry getter", - managedCtClass.getName() - ), - cce - ); - } - } - - private void addEntityEntryHandling(CtClass managedCtClass) { - FieldWriter.addFieldWithGetterAndSetter( - managedCtClass, loadCtClassFromClass( EntityEntry.class ), - EnhancerConstants.ENTITY_ENTRY_FIELD_NAME, - EnhancerConstants.ENTITY_ENTRY_GETTER_NAME, - EnhancerConstants.ENTITY_ENTRY_SETTER_NAME - ); - } - - private void addLinkedPreviousHandling(CtClass managedCtClass) { - FieldWriter.addFieldWithGetterAndSetter( - managedCtClass, loadCtClassFromClass( ManagedEntity.class ), - EnhancerConstants.PREVIOUS_FIELD_NAME, - EnhancerConstants.PREVIOUS_GETTER_NAME, - EnhancerConstants.PREVIOUS_SETTER_NAME - ); - } - - private void addLinkedNextHandling(CtClass managedCtClass) { - FieldWriter.addFieldWithGetterAndSetter( - managedCtClass, loadCtClassFromClass( ManagedEntity.class ), - EnhancerConstants.NEXT_FIELD_NAME, - EnhancerConstants.NEXT_GETTER_NAME, - EnhancerConstants.NEXT_SETTER_NAME - ); - } - - private void addInLineDirtyHandling(CtClass managedCtClass) { - managedCtClass.addInterface( loadCtClassFromClass( SelfDirtinessTracker.class ) ); - - FieldWriter.addField( - managedCtClass, - loadCtClassFromClass( DirtyTracker.class ), - EnhancerConstants.TRACKER_FIELD_NAME - ); - - if ( collectCollectionFields( managedCtClass ).isEmpty() ) { - createDirtyTrackerMethodsWithoutCollections( managedCtClass ); - } - else { - FieldWriter.addField( - managedCtClass, - loadCtClassFromClass( CollectionTracker.class ), - EnhancerConstants.TRACKER_COLLECTION_NAME - ); - createDirtyTrackerMethodsWithCollections( managedCtClass ); - } - } - - private void createDirtyTrackerMethodsWithoutCollections(CtClass managedCtClass) { - try { - MethodWriter.write( - managedCtClass, - "public void %1$s(String name) {%n" + - " if (%2$s == null) { %2$s = new %3$s(); }%n" + - " %2$s.add(name);%n" + - "}", - EnhancerConstants.TRACKER_CHANGER_NAME, - EnhancerConstants.TRACKER_FIELD_NAME, - DIRTY_TRACKER_IMPL - ); - - MethodWriter.write( - managedCtClass, - "public String[] %1$s() {%n" + - " return (%2$s == null) ? new String[0] : %2$s.get();%n" + - "}", - EnhancerConstants.TRACKER_GET_NAME, - EnhancerConstants.TRACKER_FIELD_NAME - ); - - MethodWriter.write( - managedCtClass, - "public boolean %1$s() {%n" + - " return (%2$s != null && !%2$s.isEmpty());%n" + - "}", - EnhancerConstants.TRACKER_HAS_CHANGED_NAME, - EnhancerConstants.TRACKER_FIELD_NAME - ); - - MethodWriter.write( - managedCtClass, - "public void %1$s() {%n" + - " if (%2$s != null) { %2$s.clear(); }%n" + - "}", - EnhancerConstants.TRACKER_CLEAR_NAME, - EnhancerConstants.TRACKER_FIELD_NAME - ); - - MethodWriter.write( - managedCtClass, - "public void %1$s(boolean f) {%n" + - " if (%2$s == null) %2$s = new %3$s();%n %2$s.suspend(f);%n" + - "}", - EnhancerConstants.TRACKER_SUSPEND_NAME, - EnhancerConstants.TRACKER_FIELD_NAME , - DIRTY_TRACKER_IMPL - ); - - MethodWriter.write( - managedCtClass, - "public %s %s() { return %s.INSTANCE; }", - CollectionTracker.class.getName(), - EnhancerConstants.TRACKER_COLLECTION_GET_NAME, - NoopCollectionTracker.class.getName() - ); - } - catch (CannotCompileException cce) { - throw new RuntimeException( "createDirtyTrackerMethodsWithoutCollections failed", cce ); - } - } - - private void createDirtyTrackerMethodsWithCollections(CtClass managedCtClass) { - try { - MethodWriter.write( - managedCtClass, - "public void %1$s(String name) {%n" + - " if (%2$s == null) { %2$s = new %3$s(); }%n" + - " %2$s.add(name);%n" + - "}", - EnhancerConstants.TRACKER_CHANGER_NAME, - EnhancerConstants.TRACKER_FIELD_NAME, - DIRTY_TRACKER_IMPL - ); - - createCollectionDirtyCheckMethod( managedCtClass ); - createCollectionDirtyCheckGetFieldsMethod( managedCtClass ); - createClearDirtyCollectionMethod( managedCtClass ); - - MethodWriter.write( - managedCtClass, - "public String[] %1$s() {%n" + - " if(%3$s == null) {%n" + - " return (%2$s == null) ? new String[0] : %2$s.get();%n" + - " } else {%n" + - " if (%2$s == null) %2$s = new %5$s();%n" + - " %4$s(%2$s);%n" + - " return %2$s.get();%n" + - " }%n" + - "}", - EnhancerConstants.TRACKER_GET_NAME, - EnhancerConstants.TRACKER_FIELD_NAME, - EnhancerConstants.TRACKER_COLLECTION_NAME, - EnhancerConstants.TRACKER_COLLECTION_CHANGED_FIELD_NAME, - DIRTY_TRACKER_IMPL - ); - - MethodWriter.write( - managedCtClass, - "public boolean %1$s() {%n" + - " return (%2$s != null && !%2$s.isEmpty()) || %3$s();%n" + - "}", - EnhancerConstants.TRACKER_HAS_CHANGED_NAME, - EnhancerConstants.TRACKER_FIELD_NAME, - EnhancerConstants.TRACKER_COLLECTION_CHANGED_NAME - ); - - MethodWriter.write( - managedCtClass, - "public void %1$s() {%n" + - " if (%2$s != null) { %2$s.clear(); }%n" + - " %3$s();%n" + - "}", - EnhancerConstants.TRACKER_CLEAR_NAME, - EnhancerConstants.TRACKER_FIELD_NAME, - EnhancerConstants.TRACKER_COLLECTION_CLEAR_NAME - ); - - MethodWriter.write( - managedCtClass, - "public void %1$s(boolean f) {%n" + - " if (%2$s == null) %2$s = new %3$s();%n %2$s.suspend(f);%n" + - "}", - EnhancerConstants.TRACKER_SUSPEND_NAME, - EnhancerConstants.TRACKER_FIELD_NAME , - DIRTY_TRACKER_IMPL - ); - - MethodWriter.write( - managedCtClass, - "public %s %s() { return %s; }", - CollectionTracker.class.getName(), - EnhancerConstants.TRACKER_COLLECTION_GET_NAME, - EnhancerConstants.TRACKER_COLLECTION_NAME - ); - } - catch (CannotCompileException cce) { - throw new RuntimeException( "createDirtyTrackerMethodsWithCollections failed", cce ); - } - } - - private List collectCollectionFields(CtClass managedCtClass) { - List collectionList = new ArrayList<>(); - - for ( CtField ctField : managedCtClass.getDeclaredFields() ) { - // skip static fields and skip fields added by enhancement - if ( Modifier.isStatic( ctField.getModifiers() ) || ctField.getName().startsWith( "$$_hibernate_" ) ) { - continue; - } - if ( enhancementContext.isPersistentField( ctField ) && enhancementContext.isMappedCollection( ctField ) ) { - if ( PersistentAttributesHelper.isAssignable( ctField, Collection.class.getName() ) || - PersistentAttributesHelper.isAssignable( ctField, Map.class.getName() ) ) { - collectionList.add( ctField ); - } - } - } - - // HHH-10646 Add fields inherited from @MappedSuperclass - // HHH-10981 There is no need to do it for @MappedSuperclass - if ( !enhancementContext.isMappedSuperclassClass( managedCtClass ) ) { - collectionList.addAll( collectInheritCollectionFields( managedCtClass ) ); - } - - return collectionList; - } - - private Collection collectInheritCollectionFields(CtClass managedCtClass) { - if ( managedCtClass == null || Object.class.getName().equals( managedCtClass.getName() ) ) { - return Collections.emptyList(); - } - try { - CtClass managedCtSuperclass = managedCtClass.getSuperclass(); - - if ( !enhancementContext.isMappedSuperclassClass( managedCtSuperclass ) ) { - return collectInheritCollectionFields( managedCtSuperclass ); - } - List collectionList = new ArrayList(); - - for ( CtField ctField : managedCtSuperclass.getDeclaredFields() ) { - if ( !Modifier.isStatic( ctField.getModifiers() ) ) { - if ( enhancementContext.isPersistentField( ctField ) && enhancementContext.isMappedCollection( ctField ) ) { - if ( PersistentAttributesHelper.isAssignable( ctField, Collection.class.getName() ) || - PersistentAttributesHelper.isAssignable( ctField, Map.class.getName() ) ) { - collectionList.add( ctField ); - } - } - } - } - collectionList.addAll( collectInheritCollectionFields( managedCtSuperclass ) ); - return collectionList; - } - catch ( NotFoundException nfe ) { - return Collections.emptyList(); - } - } - - private void createCollectionDirtyCheckMethod(CtClass managedCtClass) { - try { - final StringBuilder body = new StringBuilder(); - - body.append( - String.format( - "private boolean %1$s() {%n" + - " if (%2$s == null) { return false; }%n%n", - EnhancerConstants.TRACKER_COLLECTION_CHANGED_NAME, - EnhancerConstants.TRACKER_COLLECTION_NAME - ) - ); - - for ( CtField ctField : collectCollectionFields( managedCtClass ) ) { - body.append( - String.format( - " // collection field [%1$s]%n" + - " if (%1$s == null && %2$s.getSize(\"%1$s\") != -1) { return true; }%n" + - " if (%1$s != null && %2$s.getSize(\"%1$s\") != %1$s.size()) { return true; }%n%n", - ctField.getName(), - EnhancerConstants.TRACKER_COLLECTION_NAME - ) - ); - } - body.append( " return false;%n}" ); - - MethodWriter.write( managedCtClass, body.toString() ); - } - catch (CannotCompileException cce) { - throw new RuntimeException( "createCollectionDirtyCheckMethod failed", cce ); - } - } - - private void createCollectionDirtyCheckGetFieldsMethod(CtClass managedCtClass) { - try { - final StringBuilder body = new StringBuilder(); - - body.append( - String.format( - "private void %1$s(%3$s tracker) {%n" + - " if (%2$s == null) { return; }%n%n", - EnhancerConstants.TRACKER_COLLECTION_CHANGED_FIELD_NAME, - EnhancerConstants.TRACKER_COLLECTION_NAME, - DirtyTracker.class.getName() - ) - ); - - for ( CtField ctField : collectCollectionFields( managedCtClass ) ) { - body.append( - String.format( - " // Collection field [%1$s]%n" + - " if (%1$s == null && %2$s.getSize(\"%1$s\") != -1) { tracker.add(\"%1$s\"); }%n" + - " if (%1$s != null && %2$s.getSize(\"%1$s\") != %1$s.size()) { tracker.add(\"%1$s\"); }%n%n", - ctField.getName(), - EnhancerConstants.TRACKER_COLLECTION_NAME - ) - ); - } - body.append( "}" ); - - MethodWriter.write( managedCtClass, body.toString() ); - } - catch (CannotCompileException cce) { - throw new RuntimeException( "createCollectionDirtyCheckGetFieldsMethod failed", cce ); - } - } - - private void createClearDirtyCollectionMethod(CtClass managedCtClass) throws CannotCompileException { - try { - final StringBuilder body = new StringBuilder(); - - body.append( - String.format( - "private void %1$s() {%n" + - " if (%2$s == null) { %2$s = new %3$s(); }%n" + - " %4$s lazyInterceptor = null;%n", - EnhancerConstants.TRACKER_COLLECTION_CLEAR_NAME, - EnhancerConstants.TRACKER_COLLECTION_NAME, - COLLECTION_TRACKER_IMPL, - LazyAttributeLoadingInterceptor.class.getName() - ) - ); - - if ( PersistentAttributesHelper.isAssignable( managedCtClass, PersistentAttributeInterceptable.class.getName() ) ) { - body.append( - String.format( - " if(%1$s != null && %1$s instanceof %2$s) lazyInterceptor = (%2$s) %1$s;%n%n", - EnhancerConstants.INTERCEPTOR_FIELD_NAME, - LazyAttributeLoadingInterceptor.class.getName() - ) - ); - } - - for ( CtField ctField : collectCollectionFields( managedCtClass ) ) { - body.append( - String.format( - " // collection field [%1$s]%n" + - " if (lazyInterceptor == null || lazyInterceptor.isAttributeLoaded(\"%1$s\")) {%n" + - " if (%1$s == null) { %2$s.add(\"%1$s\", -1); }%n" + - " else { %2$s.add(\"%1$s\", %1$s.size()); }%n" + - " }%n%n", - ctField.getName(), - EnhancerConstants.TRACKER_COLLECTION_NAME - ) - ); - } - body.append( "}" ); - - MethodWriter.write( managedCtClass, body.toString() ); - } - catch (CannotCompileException cce) { - throw cce; - } - } - -} diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/FieldWriter.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/FieldWriter.java deleted file mode 100644 index a0492d869dca..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/FieldWriter.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.bytecode.enhance.internal.javassist; - -import javax.persistence.Transient; - -import javassist.CannotCompileException; -import javassist.CtClass; -import javassist.CtField; -import javassist.Modifier; -import javassist.bytecode.AnnotationsAttribute; -import javassist.bytecode.FieldInfo; -import javassist.bytecode.annotation.Annotation; - -import org.hibernate.bytecode.enhance.spi.EnhancementException; -import org.hibernate.internal.CoreLogging; -import org.hibernate.internal.CoreMessageLogger; - -/** - * @author Luis Barreiro - */ -public class FieldWriter { - - private static final CoreMessageLogger log = CoreLogging.messageLogger( FieldWriter.class ); - - private FieldWriter() { } - - /* --- */ - - /** - * Add enhancement field - */ - public static void addField(CtClass target, CtClass type, String field) { - addPrivateTransient( target, type, field ); - } - - /** - * Add enhancement field with getter and setter - */ - public static void addFieldWithGetterAndSetter(CtClass target, CtClass type, String field, String getter, String setter) { - addPrivateTransient( target, type, field ); - MethodWriter.addGetter( target, field, getter ); - MethodWriter.addSetter( target, field, setter ); - } - - /* --- */ - - private static void addPrivateTransient(CtClass target, CtClass type, String name) { - addWithModifiers( target, type, name, Modifier.PRIVATE | Modifier.TRANSIENT, Transient.class ); - log.debugf( "Wrote field into [%s]: @Transient private transient %s %s;", target.getName(), type.getName(), name ); - } - - private static void addWithModifiers(CtClass target, CtClass type, String name, int modifiers, Class ... annotations ) { - try { - final CtField f = new CtField( type, name, target ); - f.setModifiers( f.getModifiers() | modifiers ); - addAnnotations( f.getFieldInfo(), annotations ); - target.addField( f ); - } - catch (CannotCompileException cce) { - final String msg = String.format( "Could not enhance class [%s] to add field [%s]", target.getName(), name ); - throw new EnhancementException( msg, cce ); - } - } - - /* --- */ - - private static void addAnnotations(FieldInfo fieldInfo, Class[] annotations) { - AnnotationsAttribute annotationsAttribute = (AnnotationsAttribute) fieldInfo.getAttribute( AnnotationsAttribute.visibleTag ); - if ( annotationsAttribute == null ) { - annotationsAttribute = new AnnotationsAttribute( fieldInfo.getConstPool(), AnnotationsAttribute.visibleTag ); - fieldInfo.addAttribute( annotationsAttribute ); - } - for (Class annotation : annotations) { - annotationsAttribute.addAnnotation( new Annotation( annotation.getName(), fieldInfo.getConstPool() ) ); - } - } - -} diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/JavassistEnhancementContext.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/JavassistEnhancementContext.java deleted file mode 100644 index 9efa704fbf38..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/JavassistEnhancementContext.java +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.bytecode.enhance.internal.javassist; - -import javassist.CtClass; -import javassist.CtField; - -import org.hibernate.bytecode.enhance.spi.EnhancementContext; -import org.hibernate.bytecode.enhance.spi.UnloadedField; - -public class JavassistEnhancementContext { - - private final EnhancementContext enhancementContext; - - public JavassistEnhancementContext(EnhancementContext enhancementContext) { - this.enhancementContext = enhancementContext; - } - - public ClassLoader getLoadingClassLoader() { - return enhancementContext.getLoadingClassLoader(); - } - - public boolean isEntityClass(CtClass classDescriptor) { - return enhancementContext.isEntityClass( new UnloadedCtClass( classDescriptor ) ); - } - - public boolean isCompositeClass(CtClass classDescriptor) { - return enhancementContext.isCompositeClass( new UnloadedCtClass( classDescriptor ) ); - } - - public boolean isMappedSuperclassClass(CtClass classDescriptor) { - return enhancementContext.isMappedSuperclassClass( new UnloadedCtClass( classDescriptor ) ); - } - - public boolean doBiDirectionalAssociationManagement(CtField field) { - return enhancementContext.doBiDirectionalAssociationManagement( new UnloadedCtField( field ) ); - } - - public boolean doDirtyCheckingInline(CtClass classDescriptor) { - return enhancementContext.doDirtyCheckingInline( new UnloadedCtClass( classDescriptor ) ); - } - - public boolean doExtendedEnhancement(CtClass classDescriptor) { - return enhancementContext.doExtendedEnhancement( new UnloadedCtClass( classDescriptor ) ); - } - - public boolean hasLazyLoadableAttributes(CtClass classDescriptor) { - return enhancementContext.hasLazyLoadableAttributes( new UnloadedCtClass( classDescriptor ) ); - } - - public boolean isPersistentField(CtField ctField) { - return enhancementContext.isPersistentField( new UnloadedCtField( ctField ) ); - } - - public CtField[] order(CtField[] persistentFields) { - UnloadedField[] unloadedFields = new UnloadedField[persistentFields.length]; - for ( int i = 0; i < unloadedFields.length; i++ ) { - unloadedFields[i] = new UnloadedCtField( persistentFields[i] ); - } - UnloadedField[] ordered = enhancementContext.order( unloadedFields ); - CtField[] orderedFields = new CtField[persistentFields.length]; - for ( int i = 0; i < orderedFields.length; i++ ) { - orderedFields[i] = ( (UnloadedCtField) ordered[i] ).ctField; - } - return orderedFields; - } - - public boolean isLazyLoadable(CtField field) { - return enhancementContext.isLazyLoadable( new UnloadedCtField( field ) ); - } - - public boolean isMappedCollection(CtField field) { - return enhancementContext.isMappedCollection( new UnloadedCtField( field ) ); - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/MappedSuperclassEnhancer.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/MappedSuperclassEnhancer.java deleted file mode 100644 index 4f0a7802061a..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/MappedSuperclassEnhancer.java +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.bytecode.enhance.internal.javassist; - -import javassist.CtClass; -import javassist.CtField; -import javassist.CtMethod; - -import org.hibernate.bytecode.enhance.spi.EnhancementContext; -import org.hibernate.bytecode.enhance.spi.EnhancerConstants; -import org.hibernate.engine.spi.ManagedMappedSuperclass; - -/** - * enhancer for mapped superclass - * - * @author Luis Barreiro - */ -public class MappedSuperclassEnhancer extends PersistentAttributesEnhancer { - - public MappedSuperclassEnhancer(JavassistEnhancementContext context) { - super( context ); - } - - public void enhance(CtClass managedCtClass) { - // Add the Managed interface - managedCtClass.addInterface( loadCtClassFromClass( ManagedMappedSuperclass.class ) ); - - super.enhance( managedCtClass ); - } - - // Generate 'template' methods for each attribute. This will be overridden by the actual entities - - @Override - protected CtMethod generateFieldReader( - CtClass managedCtClass, - CtField persistentField, - AttributeTypeDescriptor typeDescriptor) { - - String fieldName = persistentField.getName(); - String readerName = EnhancerConstants.PERSISTENT_FIELD_READER_PREFIX + fieldName; - - return MethodWriter.addGetter( managedCtClass, fieldName, readerName ); - } - - @Override - protected CtMethod generateFieldWriter( - CtClass managedCtClass, - CtField persistentField, - AttributeTypeDescriptor typeDescriptor) { - - String fieldName = persistentField.getName(); - String writerName = EnhancerConstants.PERSISTENT_FIELD_WRITER_PREFIX + fieldName; - - return MethodWriter.addSetter( managedCtClass, fieldName, writerName ); - } - -} diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/MethodWriter.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/MethodWriter.java deleted file mode 100644 index 6b1453e3de12..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/MethodWriter.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.bytecode.enhance.internal.javassist; - -import javassist.CannotCompileException; -import javassist.CtClass; -import javassist.CtField; -import javassist.CtMethod; -import javassist.CtNewMethod; -import javassist.NotFoundException; -import javassist.bytecode.ConstPool; -import org.hibernate.bytecode.enhance.spi.EnhancementException; -import org.hibernate.internal.CoreLogging; -import org.hibernate.internal.CoreMessageLogger; - -/** - * utility class to compile methods and add the to class files - * - * @author Luis Barreiro - */ -public class MethodWriter { - - private static final CoreMessageLogger log = CoreLogging.messageLogger( MethodWriter.class ); - - private MethodWriter() { } - - /* --- */ - - /** - * convenience method that builds a method from a format string. {@see String.format} for more details - * - * @throws CannotCompileException - */ - public static CtMethod write(CtClass target, String format, Object ... args) throws CannotCompileException { - String body = String.format( format, args ); - // System.out.printf( "writing method into [%s]:%n%s%n", target.getName(), body ); - log.debugf( "writing method into [%s]:%n%s", target.getName(), body ); - CtMethod method = CtNewMethod.make( body, target ); - target.addMethod( method ); - return method; - } - - /* --- */ - - public static CtMethod addGetter(CtClass target, String field, String name) { - CtField actualField = null; - try { - actualField = target.getField( field ); - log.debugf( "Writing getter method [%s] into [%s] for field [%s]", name, target.getName(), field ); - CtMethod method = CtNewMethod.getter( name, target.getField( field ) ); - target.addMethod( method ); - return method; - } - catch (CannotCompileException cce) { - try { - // Fall back to create a getter from delegation. - CtMethod method = CtNewMethod.delegator( CtNewMethod.getter( name, actualField ), target ); - target.addMethod( method ); - return method; - } - catch (CannotCompileException ignored) { - String msg = String.format( "Could not enhance class [%s] to add method [%s] for field [%s]", target.getName(), name, field ); - throw new EnhancementException( msg, cce ); - } - } - catch (NotFoundException nfe) { - String msg = String.format( "Could not enhance class [%s] to add method [%s] for field [%s]", target.getName(), name, field ); - throw new EnhancementException( msg, nfe ); - } - } - - public static CtMethod addSetter(CtClass target, String field, String name) { - CtField actualField = null; - try { - actualField = target.getField( field ); - log.debugf( "Writing setter method [%s] into [%s] for field [%s]", name, target.getName(), field ); - CtMethod method = CtNewMethod.setter( name, actualField ); - target.addMethod( method ); - return method; - } - catch (CannotCompileException cce) { - try { - // Fall back to create a getter from delegation. - CtMethod method = CtNewMethod.delegator( CtNewMethod.setter( name, actualField ), target ); - target.addMethod( method ); - return method; - } - catch (CannotCompileException ignored) { - String msg = String.format( "Could not enhance class [%s] to add method [%s] for field [%s]", target.getName(), name, field ); - throw new EnhancementException( msg, cce ); - } - } - catch (NotFoundException nfe) { - String msg = String.format( "Could not enhance class [%s] to add method [%s] for field [%s]", target.getName(), name, field ); - throw new EnhancementException( msg, nfe ); - } - } - - /* --- */ - - public static int addMethod(ConstPool cPool, CtMethod method) { - return cPool.addMethodrefInfo( cPool.getThisClassInfo(), method.getName(), method.getSignature() ); - } - -} diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/PersistentAttributesEnhancer.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/PersistentAttributesEnhancer.java deleted file mode 100644 index c28aec49360f..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/PersistentAttributesEnhancer.java +++ /dev/null @@ -1,745 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.bytecode.enhance.internal.javassist; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.IdentityHashMap; -import java.util.List; -import java.util.Map; -import javax.persistence.Embedded; -import javax.persistence.Id; -import javax.persistence.ManyToMany; -import javax.persistence.ManyToOne; -import javax.persistence.OneToMany; -import javax.persistence.OneToOne; - -import javassist.CannotCompileException; -import javassist.ClassPool; -import javassist.CtClass; -import javassist.CtField; -import javassist.CtMethod; -import javassist.Modifier; -import javassist.NotFoundException; -import javassist.bytecode.BadBytecode; -import javassist.bytecode.CodeIterator; -import javassist.bytecode.ConstPool; -import javassist.bytecode.MethodInfo; -import javassist.bytecode.Opcode; -import javassist.bytecode.stackmap.MapMaker; - -import org.hibernate.Hibernate; -import org.hibernate.bytecode.enhance.spi.EnhancementException; -import org.hibernate.bytecode.enhance.spi.EnhancerConstants; -import org.hibernate.engine.spi.CompositeOwner; -import org.hibernate.engine.spi.CompositeTracker; -import org.hibernate.internal.CoreLogging; -import org.hibernate.internal.CoreMessageLogger; - -/** - * enhancer for persistent attributes of any type of entity - * - * @author Luis Barreiro - */ -public class PersistentAttributesEnhancer extends EnhancerImpl { - - private static final CoreMessageLogger log = CoreLogging.messageLogger( PersistentAttributesEnhancer.class ); - - public PersistentAttributesEnhancer(JavassistEnhancementContext context) { - super( context ); - } - - public void enhance(CtClass managedCtClass) { - final IdentityHashMap attrDescriptorMap = new IdentityHashMap(); - - for ( CtField persistentField : collectPersistentFields( managedCtClass ) ) { - attrDescriptorMap.put( - persistentField.getName(), enhancePersistentAttribute( - managedCtClass, - persistentField - ) - ); - } - - // find all references to the transformed fields and replace with calls to the added reader/writer methods - enhanceAttributesAccess( managedCtClass, attrDescriptorMap ); - - // same thing for direct access to fields of other entities - if ( this.enhancementContext.doExtendedEnhancement( managedCtClass ) ) { - extendedEnhancement( managedCtClass ); - } - } - - private CtField[] collectPersistentFields(CtClass managedCtClass) { - List persistentFieldList = new ArrayList(); - for ( CtField ctField : managedCtClass.getDeclaredFields() ) { - // skip static fields and skip fields added by enhancement and outer reference in inner classes - if ( ctField.getName().startsWith( "$$_hibernate_" ) || "this$0".equals( ctField.getName() ) ) { - continue; - } - if ( !Modifier.isStatic( ctField.getModifiers() ) && enhancementContext.isPersistentField( ctField ) ) { - persistentFieldList.add( ctField ); - } - } - // HHH-10646 Add fields inherited from @MappedSuperclass - // HHH-10981 There is no need to do it for @MappedSuperclass - if ( !enhancementContext.isMappedSuperclassClass( managedCtClass ) ) { - persistentFieldList.addAll( collectInheritPersistentFields( managedCtClass ) ); - } - - CtField[] orderedFields = enhancementContext.order( persistentFieldList.toArray( new CtField[0] ) ); - log.debugf( "Persistent fields for entity %s: %s", managedCtClass.getName(), Arrays.toString( orderedFields ) ); - return orderedFields; - } - - private Collection collectInheritPersistentFields(CtClass managedCtClass) { - if ( managedCtClass == null || Object.class.getName().equals( managedCtClass.getName() ) ) { - return Collections.emptyList(); - } - try { - CtClass managedCtSuperclass = managedCtClass.getSuperclass(); - - if ( enhancementContext.isEntityClass( managedCtSuperclass ) ) { - return Collections.emptyList(); - } - else if ( !enhancementContext.isMappedSuperclassClass( managedCtSuperclass ) ) { - return collectInheritPersistentFields( managedCtSuperclass ); - } - log.debugf( "Found @MappedSuperclass %s to collectPersistenceFields", managedCtSuperclass.getName() ); - List persistentFieldList = new ArrayList(); - - for ( CtField ctField : managedCtSuperclass.getDeclaredFields() ) { - if ( ctField.getName().startsWith( "$$_hibernate_" ) || "this$0".equals( ctField.getName() ) ) { - continue; - } - if ( !Modifier.isStatic( ctField.getModifiers() ) && enhancementContext.isPersistentField( ctField ) ) { - persistentFieldList.add( ctField ); - } - } - persistentFieldList.addAll( collectInheritPersistentFields( managedCtSuperclass ) ); - return persistentFieldList; - } - catch ( NotFoundException nfe ) { - log.warnf( "Could not find the superclass of %s", managedCtClass ); - return Collections.emptyList(); - } - } - - private PersistentAttributeAccessMethods enhancePersistentAttribute(CtClass managedCtClass, CtField persistentField) { - try { - AttributeTypeDescriptor typeDescriptor = AttributeTypeDescriptor.resolve( managedCtClass, persistentField ); - return new PersistentAttributeAccessMethods( - generateFieldReader( managedCtClass, persistentField, typeDescriptor ), - generateFieldWriter( managedCtClass, persistentField, typeDescriptor ) - ); - } - catch (Exception e) { - final String msg = String.format( - "Unable to enhance persistent attribute [%s:%s]", - managedCtClass.getName(), - persistentField.getName() - ); - throw new EnhancementException( msg, e ); - } - } - - protected CtMethod generateFieldReader( - CtClass managedCtClass, - CtField persistentField, - AttributeTypeDescriptor typeDescriptor) { - String fieldName = persistentField.getName(); - String readerName = EnhancerConstants.PERSISTENT_FIELD_READER_PREFIX + fieldName; - String writerName = EnhancerConstants.PERSISTENT_FIELD_WRITER_PREFIX + fieldName; - CtMethod tmpSuperReader = null; - CtMethod tmpSuperWriter = null; - CtMethod reader = null; - - try { - boolean declared = persistentField.getDeclaringClass().equals( managedCtClass ); - String declaredReadFragment = "this." + fieldName; - String superReadFragment = "super." + readerName + "()"; - - if ( !declared ) { - // create a temporary getter on the supper entity to be able to compile our code - try { - persistentField.getDeclaringClass().getDeclaredMethod( readerName ); - persistentField.getDeclaringClass().getDeclaredMethod( writerName ); - } - catch ( NotFoundException nfe ) { - tmpSuperReader = MethodWriter.addGetter( persistentField.getDeclaringClass(), persistentField.getName(), readerName ); - tmpSuperWriter = MethodWriter.addSetter( persistentField.getDeclaringClass(), persistentField.getName(), writerName ); - } - } - - // read attempts only have to deal lazy-loading support, not dirty checking; - // so if the field is not enabled as lazy-loadable return a plain simple getter as the reader - if ( !enhancementContext.hasLazyLoadableAttributes( managedCtClass ) || !enhancementContext.isLazyLoadable( persistentField ) ) { - reader = MethodWriter.write( - managedCtClass, "public %s %s() { return %s;%n}", - persistentField.getType().getName(), - readerName, - declared ? declaredReadFragment : superReadFragment - ); - } - else { - reader = MethodWriter.write( - managedCtClass, "public %s %s() {%n%s%n return %s;%n}", - persistentField.getType().getName(), - readerName, - typeDescriptor.buildReadInterceptionBodyFragment( fieldName ), - declared ? declaredReadFragment : superReadFragment - ); - } - if ( tmpSuperReader != null ) { - persistentField.getDeclaringClass().removeMethod( tmpSuperReader ); - } - if ( tmpSuperWriter != null ) { - persistentField.getDeclaringClass().removeMethod( tmpSuperWriter ); - } - return reader; - } - catch (CannotCompileException cce) { - final String msg = String.format( - "Could not enhance entity class [%s] to add field reader method [%s]", - managedCtClass.getName(), - readerName - ); - throw new EnhancementException( msg, cce ); - } - catch (NotFoundException nfe) { - final String msg = String.format( - "Could not enhance entity class [%s] to add field reader method [%s]", - managedCtClass.getName(), - readerName - ); - throw new EnhancementException( msg, nfe ); - } - } - - protected CtMethod generateFieldWriter( - CtClass managedCtClass, - CtField persistentField, - AttributeTypeDescriptor typeDescriptor) { - String fieldName = persistentField.getName(); - String readerName = EnhancerConstants.PERSISTENT_FIELD_READER_PREFIX + fieldName; - String writerName = EnhancerConstants.PERSISTENT_FIELD_WRITER_PREFIX + fieldName; - CtMethod tmpSuperReader = null; - CtMethod tmpSuperWriter = null; - CtMethod writer; - - try { - boolean declared = persistentField.getDeclaringClass().equals( managedCtClass ); - String declaredWriteFragment = "this." + fieldName + "=" + fieldName + ";"; - String superWriteFragment = "super." + writerName + "(" + fieldName + ");"; - - if ( !declared ) { - // create a temporary setter on the supper entity to be able to compile our code - try { - persistentField.getDeclaringClass().getDeclaredMethod( readerName ); - persistentField.getDeclaringClass().getDeclaredMethod( writerName ); - } - catch ( NotFoundException nfe ) { - tmpSuperReader = MethodWriter.addGetter( persistentField.getDeclaringClass(), persistentField.getName(), readerName ); - tmpSuperWriter = MethodWriter.addSetter( persistentField.getDeclaringClass(), persistentField.getName(), writerName ); - } - } - - if ( !enhancementContext.hasLazyLoadableAttributes( managedCtClass ) || !enhancementContext.isLazyLoadable( persistentField ) ) { - writer = MethodWriter.write( - managedCtClass, - "public void %s(%s %s) {%n %s%n}", - writerName, - persistentField.getType().getName(), - fieldName, - declared ? declaredWriteFragment : superWriteFragment - ); - } - else { - writer = MethodWriter.write( - managedCtClass, - "public void %s(%s %s) {%n%s%n}", - writerName, - persistentField.getType().getName(), - fieldName, - typeDescriptor.buildWriteInterceptionBodyFragment( fieldName ) - ); - } - - if ( enhancementContext.doDirtyCheckingInline( managedCtClass ) ) { - if ( enhancementContext.isCompositeClass( managedCtClass ) ) { - writer.insertBefore( - String.format( - " if (%1$s != null) { %1$s.callOwner(\"\"); }%n", - EnhancerConstants.TRACKER_COMPOSITE_FIELD_NAME - ) - ); - } - else { - writer.insertBefore( typeDescriptor.buildInLineDirtyCheckingBodyFragment( enhancementContext, persistentField ) ); - } - - handleCompositeField( managedCtClass, persistentField, writer ); - } - - if ( enhancementContext.doBiDirectionalAssociationManagement( persistentField ) ) { - handleBiDirectionalAssociation( managedCtClass, persistentField, writer ); - } - - if ( tmpSuperReader != null ) { - persistentField.getDeclaringClass().removeMethod( tmpSuperReader ); - } - if ( tmpSuperWriter != null ) { - persistentField.getDeclaringClass().removeMethod( tmpSuperWriter ); - } - return writer; - } - catch (CannotCompileException cce) { - final String msg = String.format( - "Could not enhance entity class [%s] to add field writer method [%s]", - managedCtClass.getName(), - writerName - ); - throw new EnhancementException( msg, cce ); - } - catch (NotFoundException nfe) { - final String msg = String.format( - "Could not enhance entity class [%s] to add field writer method [%s]", - managedCtClass.getName(), - writerName - ); - throw new EnhancementException( msg, nfe ); - } - } - - private void handleBiDirectionalAssociation(CtClass managedCtClass, CtField persistentField, CtMethod fieldWriter) - throws NotFoundException, CannotCompileException { - if ( !PersistentAttributesHelper.isPossibleBiDirectionalAssociation( persistentField ) ) { - return; - } - final CtClass targetEntity = PersistentAttributesHelper.getTargetEntityClass( managedCtClass, persistentField ); - if ( targetEntity == null ) { - log.infof( - "Bi-directional association not managed for field [%s#%s]: Could not find target type", - managedCtClass.getName(), - persistentField.getName() - ); - return; - } - final String mappedBy = PersistentAttributesHelper.getMappedBy( persistentField, targetEntity, enhancementContext ); - if ( mappedBy == null || mappedBy.isEmpty() ) { - log.infof( - "Bi-directional association not managed for field [%s#%s]: Could not find target field in [%s]", - managedCtClass.getName(), - persistentField.getName(), - targetEntity.getName() - ); - return; - } - - // create a temporary getter and setter on the target entity to be able to compile our code - final String mappedByGetterName = EnhancerConstants.PERSISTENT_FIELD_READER_PREFIX + mappedBy; - final String mappedBySetterName = EnhancerConstants.PERSISTENT_FIELD_WRITER_PREFIX + mappedBy; - CtMethod getter; - CtMethod setter; - boolean tmpTargetMethods = false; - try { - getter = targetEntity.getDeclaredMethod( mappedByGetterName ); - setter = targetEntity.getDeclaredMethod( mappedByGetterName ); - } - catch ( NotFoundException nfe ) { - getter = MethodWriter.addGetter( targetEntity, mappedBy, mappedByGetterName ); - setter = MethodWriter.addSetter( targetEntity, mappedBy, mappedBySetterName ); - tmpTargetMethods = true; - } - - // code fragments to check loaded state. We don't want to trigger lazy loading in association management code - String currentAssociationLoaded = String.format( - "%s.isPropertyInitialized(this.%s, \"%s\")", - Hibernate.class.getName(), - persistentField.getName(), - mappedBy - ); - String targetElementLoaded = String.format( - "%s.isPropertyInitialized(target, \"%s\")", - Hibernate.class.getName(), - mappedBy - ); - String newAssociationLoaded = String.format( - "%s.isPropertyInitialized($1, \"%s\")", - Hibernate.class.getName(), - mappedBy - ); - - if ( PersistentAttributesHelper.hasAnnotation( persistentField, OneToOne.class ) ) { - // only unset when $1 != null to avoid recursion - fieldWriter.insertBefore( - String.format( - " if (this.%1$s != null && %2$s && $1 != null) { this.%1$s.%3$s(null); }%n", - persistentField.getName(), - currentAssociationLoaded, - mappedBySetterName - ) - ); - fieldWriter.insertAfter( - String.format( - " if ($1 != null && %s && $1.%s() != this) { $1.%s(this); }%n", - newAssociationLoaded, - mappedByGetterName, - mappedBySetterName - ) - ); - } - if ( PersistentAttributesHelper.hasAnnotation( persistentField, OneToMany.class ) ) { - boolean isMap = PersistentAttributesHelper.isAssignable( persistentField.getType(), Map.class.getName() ); - String toArrayMethod = isMap ? "values().toArray()" : "toArray()"; - - // only remove elements not in the new collection or else we would loose those elements - // don't use iterator to avoid ConcurrentModificationException - fieldWriter.insertBefore( - String.format( - " if (this.%3$s != null && %1$s) {%n" + - " Object[] array = this.%3$s.%2$s;%n" + - " for (int i = 0; i < array.length; i++) {%n" + - " %4$s target = (%4$s) array[i];%n" + - " if ($1 == null || !$1.contains(target)) { target.%5$s(null); }%n" + - " }%n" + - " }%n", - currentAssociationLoaded, - toArrayMethod, - persistentField.getName(), - targetEntity.getName(), - mappedBySetterName - ) - ); - fieldWriter.insertAfter( - String.format( - " if ($1 != null && %1$s) {%n" + - " Object[] array = $1.%2$s;%n" + - " for (int i = 0; i < array.length; i++) {%n" + - " %4$s target = (%4$s) array[i];%n" + - " if (%3$s && target.%5$s() != this) { target.%6$s(this); }%n" + - " }%n" + - " }%n", - newAssociationLoaded, - toArrayMethod, - targetElementLoaded, - targetEntity.getName(), - mappedByGetterName, - mappedBySetterName - ) - ); - } - if ( PersistentAttributesHelper.hasAnnotation( persistentField, ManyToOne.class ) ) { - fieldWriter.insertBefore( - String.format( - " if (this.%2$s != null && %1$s && this.%2$s.%3$s() != null) { this.%2$s.%3$s().remove(this); }%n", - currentAssociationLoaded, - persistentField.getName(), - mappedByGetterName - ) - ); - // check .contains(this) to avoid double inserts (but preventing duplicates) - fieldWriter.insertAfter( - String.format( - " if ($1 != null && %s) {%n" + - " java.util.Collection c = $1.%s();%n" + - " if (c != null && !c.contains(this)) { c.add(this); }%n" + - " }%n", - newAssociationLoaded, - mappedByGetterName - ) - ); - } - if ( PersistentAttributesHelper.hasAnnotation( persistentField, ManyToMany.class ) ) { - if ( PersistentAttributesHelper.isAssignable( persistentField.getType(), Map.class.getName() ) || - PersistentAttributesHelper.isAssignable( targetEntity.getField( mappedBy ).getType(), Map.class.getName() ) ) { - log.infof( - "Bi-directional association not managed for field [%s#%s]: @ManyToMany in java.util.Map attribute not supported ", - managedCtClass.getName(), - persistentField.getName() - ); - return; - } - fieldWriter.insertBefore( - String.format( - " if (this.%2$s != null && %1$s) {%n" + - " Object[] array = this.%2$s.toArray();%n" + - " for (int i = 0; i < array.length; i++) {%n" + - " %3$s target = (%3$s) array[i];%n" + - " if ($1 == null || !$1.contains(target)) { target.%4$s().remove(this); }%n" + - " }%n" + - " }%n", - currentAssociationLoaded, - persistentField.getName(), - targetEntity.getName(), - mappedByGetterName - ) - ); - fieldWriter.insertAfter( - String.format( - " if ($1 != null && %s) {%n" + - " Object[] array = $1.toArray();%n" + - " for (int i = 0; i < array.length; i++) {%n" + - " %s target = (%s) array[i];%n" + - " if (%s) {%n" + - " java.util.Collection c = target.%s();%n" + - " if (c != this && c != null) { c.add(this); }%n" + - " }%n" + - " }%n" + - " }%n", - newAssociationLoaded, - targetEntity.getName(), - targetEntity.getName(), - targetElementLoaded, - mappedByGetterName - ) - ); - } - // implementation note: association management @OneToMany and @ManyToMay works for add() operations but for remove() a snapshot of the collection is needed so we know what associations to break. - // another approach that could force that behavior would be to return Collections.unmodifiableCollection() ... - - if ( tmpTargetMethods ) { - targetEntity.removeMethod( getter ); - targetEntity.removeMethod( setter ); - } - } - - private void handleCompositeField(CtClass managedCtClass, CtField persistentField, CtMethod fieldWriter) - throws NotFoundException, CannotCompileException { - if ( !enhancementContext.isCompositeClass( persistentField.getType() ) || - !PersistentAttributesHelper.hasAnnotation( persistentField, Embedded.class ) ) { - return; - } - - // make sure to add the CompositeOwner interface - addCompositeOwnerInterface( managedCtClass ); - - String readFragment = persistentField.visibleFrom( managedCtClass ) ? persistentField.getName() : "super." + EnhancerConstants.PERSISTENT_FIELD_READER_PREFIX + persistentField.getName() + "()"; - - // cleanup previous owner - fieldWriter.insertBefore( - String.format( - "if (%1$s != null) { ((%2$s) %1$s).%3$s(\"%4$s\"); }%n", - readFragment, - CompositeTracker.class.getName(), - EnhancerConstants.TRACKER_COMPOSITE_CLEAR_OWNER, - persistentField.getName() - ) - ); - - // trigger track changes - fieldWriter.insertAfter( - String.format( - "if (%1$s != null) { ((%2$s) %1$s).%4$s(\"%6$s\", (%3$s) this); }%n" + - "%5$s(\"%6$s\");", - readFragment, - CompositeTracker.class.getName(), - CompositeOwner.class.getName(), - EnhancerConstants.TRACKER_COMPOSITE_SET_OWNER, - EnhancerConstants.TRACKER_CHANGER_NAME, - persistentField.getName() - ) - ); - } - - private void addCompositeOwnerInterface(CtClass managedCtClass) throws NotFoundException, CannotCompileException { - CtClass compositeOwnerCtClass = managedCtClass.getClassPool().get( CompositeOwner.class.getName() ); - - // HHH-10540 only add the interface once - for ( CtClass i : managedCtClass.getInterfaces() ) { - if ( i.subclassOf( compositeOwnerCtClass ) ) { - return; - } - } - - managedCtClass.addInterface( compositeOwnerCtClass ); - - if ( enhancementContext.isCompositeClass( managedCtClass ) ) { - // if a composite has an embedded field we need to implement the TRACKER_CHANGER_NAME method as well - MethodWriter.write( - managedCtClass, - "public void %1$s(String name) {%n" + - " if (%2$s != null) { %2$s.callOwner(\".\" + name); }%n}", - EnhancerConstants.TRACKER_CHANGER_NAME, - EnhancerConstants.TRACKER_COMPOSITE_FIELD_NAME - ); - } - } - - protected void enhanceAttributesAccess( - CtClass managedCtClass, - IdentityHashMap attributeDescriptorMap) { - final ConstPool constPool = managedCtClass.getClassFile().getConstPool(); - final ClassPool classPool = managedCtClass.getClassPool(); - - for ( Object oMethod : managedCtClass.getClassFile().getMethods() ) { - final MethodInfo methodInfo = (MethodInfo) oMethod; - final String methodName = methodInfo.getName(); - - // skip methods added by enhancement and abstract methods (methods without any code) - if ( methodName.startsWith( "$$_hibernate_" ) || methodInfo.getCodeAttribute() == null ) { - continue; - } - - try { - final CodeIterator itr = methodInfo.getCodeAttribute().iterator(); - while ( itr.hasNext() ) { - final int index = itr.next(); - final int op = itr.byteAt( index ); - if ( op != Opcode.PUTFIELD && op != Opcode.GETFIELD ) { - continue; - } - - // only transform access to fields of the entity being enhanced - if ( !managedCtClass.getName().equals( constPool.getFieldrefClassName( itr.u16bitAt( index + 1 ) ) ) ) { - continue; - } - - final String fieldName = constPool.getFieldrefName( itr.u16bitAt( index + 1 ) ); - final PersistentAttributeAccessMethods attributeMethods = attributeDescriptorMap.get( fieldName ); - - // its not a field we have enhanced for interception, so skip it - if ( attributeMethods == null ) { - continue; - } - //System.out.printf( "Transforming access to field [%s] from method [%s]%n", fieldName, methodName ); - log.debugf( "Transforming access to field [%s] from method [%s]", fieldName, methodName ); - - if ( op == Opcode.GETFIELD ) { - final int methodIndex = MethodWriter.addMethod( constPool, attributeMethods.getReader() ); - itr.writeByte( Opcode.INVOKEVIRTUAL, index ); - itr.write16bit( methodIndex, index + 1 ); - } - else { - final int methodIndex = MethodWriter.addMethod( constPool, attributeMethods.getWriter() ); - itr.writeByte( Opcode.INVOKEVIRTUAL, index ); - itr.write16bit( methodIndex, index + 1 ); - } - } - methodInfo.getCodeAttribute().setAttribute( MapMaker.make( classPool, methodInfo ) ); - } - catch (BadBytecode bb) { - final String msg = String.format( - "Unable to perform field access transformation in method [%s]", - methodName - ); - throw new EnhancementException( msg, bb ); - } - } - } - - private static class PersistentAttributeAccessMethods { - private final CtMethod reader; - private final CtMethod writer; - - private PersistentAttributeAccessMethods(CtMethod reader, CtMethod writer) { - this.reader = reader; - this.writer = writer; - } - - private CtMethod getReader() { - return reader; - } - - private CtMethod getWriter() { - return writer; - } - } - - // --- // - - /** - * Replace access to fields of entities (for example, entity.field) with a call to the enhanced getter / setter - * (in this example, entity.$$_hibernate_read_field()). It's assumed that the target entity is enhanced as well. - * - * @param aCtClass Class to enhance (not an entity class). - */ - public void extendedEnhancement(CtClass aCtClass) { - final ConstPool constPool = aCtClass.getClassFile().getConstPool(); - final ClassPool classPool = aCtClass.getClassPool(); - - for ( Object oMethod : aCtClass.getClassFile().getMethods() ) { - final MethodInfo methodInfo = (MethodInfo) oMethod; - final String methodName = methodInfo.getName(); - - // skip methods added by enhancement and abstract methods (methods without any code) - if ( methodName.startsWith( "$$_hibernate_" ) || methodInfo.getCodeAttribute() == null ) { - continue; - } - - try { - final CodeIterator itr = methodInfo.getCodeAttribute().iterator(); - while ( itr.hasNext() ) { - int index = itr.next(); - int op = itr.byteAt( index ); - if ( op != Opcode.PUTFIELD && op != Opcode.GETFIELD ) { - continue; - } - String fieldName = constPool.getFieldrefName( itr.u16bitAt( index + 1 ) ); - String fieldClassName = constPool.getClassInfo( constPool.getFieldrefClass( itr.u16bitAt( index + 1 ) ) ); - CtClass targetCtClass = classPool.getCtClass( fieldClassName ); - - if ( !enhancementContext.isEntityClass( targetCtClass ) && !enhancementContext.isCompositeClass( targetCtClass ) ) { - continue; - } - if ( targetCtClass == aCtClass - || !enhancementContext.isPersistentField( targetCtClass.getField( fieldName ) ) - || PersistentAttributesHelper.hasAnnotation( targetCtClass, fieldName, Id.class ) - || "this$0".equals( fieldName ) ) { - continue; - } - - log.debugf( - "Extended enhancement: Transforming access to field [%s.%s] from method [%s#%s]", - fieldClassName, - fieldName, - aCtClass.getName(), - methodName - ); - - if ( op == Opcode.GETFIELD ) { - int fieldReaderMethodIndex = constPool.addMethodrefInfo( - constPool.addClassInfo( fieldClassName ), - EnhancerConstants.PERSISTENT_FIELD_READER_PREFIX + fieldName, - "()" + constPool.getFieldrefType( itr.u16bitAt( index + 1 ) ) - ); - itr.writeByte( Opcode.INVOKEVIRTUAL, index ); - itr.write16bit( fieldReaderMethodIndex, index + 1 ); - } - else { - int fieldWriterMethodIndex = constPool.addMethodrefInfo( - constPool.addClassInfo( fieldClassName ), - EnhancerConstants.PERSISTENT_FIELD_WRITER_PREFIX + fieldName, - "(" + constPool.getFieldrefType( itr.u16bitAt( index + 1 ) ) + ")V" - ); - itr.writeByte( Opcode.INVOKEVIRTUAL, index ); - itr.write16bit( fieldWriterMethodIndex, index + 1 ); - } - - } - methodInfo.getCodeAttribute().setAttribute( MapMaker.make( classPool, methodInfo ) ); - } - catch (BadBytecode bb) { - final String msg = String.format( - "Unable to perform extended enhancement in method [%s]", - methodName - ); - throw new EnhancementException( msg, bb ); - } - catch (NotFoundException nfe) { - final String msg = String.format( - "Unable to perform extended enhancement in method [%s]", - methodName - ); - throw new EnhancementException( msg, nfe ); - } - } - } - -} diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/PersistentAttributesHelper.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/PersistentAttributesHelper.java deleted file mode 100644 index 26e113c0f16a..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/PersistentAttributesHelper.java +++ /dev/null @@ -1,412 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.bytecode.enhance.internal.javassist; - -import java.beans.Introspector; -import java.lang.annotation.Annotation; -import java.util.Collection; -import java.util.Map; -import javax.persistence.Access; -import javax.persistence.AccessType; -import javax.persistence.ManyToMany; -import javax.persistence.ManyToOne; -import javax.persistence.OneToMany; -import javax.persistence.OneToOne; - -import javassist.CtClass; -import javassist.CtField; -import javassist.CtMember; -import javassist.CtMethod; -import javassist.NotFoundException; -import javassist.bytecode.BadBytecode; -import javassist.bytecode.SignatureAttribute; - -import org.hibernate.bytecode.enhance.spi.EnhancementContext; -import org.hibernate.internal.CoreLogging; -import org.hibernate.internal.CoreMessageLogger; - -/** - * util methods to fetch attribute metadata. consistent for both field and property access types. - * - * @author Luis Barreiro - * @see org.hibernate.internal.util.ReflectHelper - */ -public class PersistentAttributesHelper { - - private PersistentAttributesHelper() { - } - - private static final CoreMessageLogger log = CoreLogging.messageLogger( PersistentAttributesHelper.class ); - - public static boolean hasAnnotation(CtField attribute, Class annotation) { - return getAnnotation( attribute, annotation ) != null; - } - - public static boolean hasAnnotation(CtClass ctClass, String attributeName, Class annotation) { - return getAnnotation( ctClass, attributeName, annotation ) != null; - } - - public static T getAnnotation(CtField attribute, Class annotation) { - return getAnnotation( attribute.getDeclaringClass(), attribute.getName(), annotation ); - } - - public static T getAnnotation(CtClass ctClass, String attributeName, Class annotation) { - AccessType classAccessType = getAccessTypeOrNull( ctClass ); - CtField field = findFieldOrNull( ctClass, attributeName ); - CtMethod getter = findGetterOrNull( ctClass, attributeName ); - - if ( classAccessType == AccessType.FIELD || ( field != null && getAccessTypeOrNull( field ) == AccessType.FIELD ) ) { - return field == null ? null : getAnnotationOrNull( field, annotation ); - } - if ( classAccessType == AccessType.PROPERTY || ( getter != null && getAccessTypeOrNull( getter ) == AccessType.PROPERTY ) ) { - return getter == null ? null : getAnnotationOrNull( getter, annotation ); - } - - T found = ( getter == null ? null : getAnnotationOrNull( getter, annotation ) ); - if ( found == null && field != null ) { - return getAnnotationOrNull( field, annotation ); - } - return found; - } - - private static T getAnnotationOrNull(CtMember ctMember, Class annotation) { - try { - if ( ctMember.hasAnnotation( annotation ) ) { - return annotation.cast( ctMember.getAnnotation( annotation ) ); - } - } - catch (ClassNotFoundException cnfe) { - // should never happen - } - return null; - } - - private static AccessType getAccessTypeOrNull(CtMember ctMember) { - Access access = getAnnotationOrNull( ctMember, Access.class ); - return access == null ? null : access.value(); - } - - private static AccessType getAccessTypeOrNull(CtClass ctClass) { - try { - if ( ctClass.hasAnnotation( Access.class ) ) { - return ( (Access) ctClass.getAnnotation( Access.class ) ).value(); - } - else { - CtClass extendsClass = ctClass.getSuperclass(); - return extendsClass == null ? null : getAccessTypeOrNull( extendsClass ); - } - } - catch (ClassNotFoundException e) { - return null; - } - catch (NotFoundException e) { - return null; - } - } - - // - - /** - * duplicated here to take CtClass instead of Class - * @see org.hibernate.internal.util.ReflectHelper#locateField - */ - private static CtField findFieldOrNull(CtClass ctClass, String propertyName) { - if ( ctClass == null ) { - return null; - } - try { - return ctClass.getField( propertyName ); - } - catch ( NotFoundException nsfe ) { - try { - return findFieldOrNull( ctClass.getSuperclass(), propertyName ); - } - catch (NotFoundException e) { - return null; - } - } - } - - /** - * duplicated here to take CtClass instead of Class - * @see org.hibernate.internal.util.ReflectHelper#findGetterMethod - */ - private static CtMethod findGetterOrNull(CtClass ctClass, String propertyName) { - if ( ctClass == null ) { - return null; - } - CtMethod method = getterOrNull( ctClass, propertyName ); - if ( method != null ) { - return method; - } - try { - // check if extends - method = findGetterOrNull( ctClass.getSuperclass(), propertyName ); - if ( method != null ) { - return method; - } - // check if implements - for ( CtClass interfaceCtClass : ctClass.getInterfaces() ) { - method = getterOrNull( interfaceCtClass, propertyName ); - if ( method != null ) { - return method; - } - } - } - catch (NotFoundException nfe) { - // give up - } - return null; - } - - private static CtMethod getterOrNull(CtClass containerClass, String propertyName) { - for ( CtMethod method : containerClass.getDeclaredMethods() ) { - try { - // if the method has parameters, skip it - if ( method.isEmpty() || method.getParameterTypes().length != 0 ) { - continue; - } - } - catch (NotFoundException e) { - continue; - } - - final String methodName = method.getName(); - - // try "get" - if ( methodName.startsWith( "get" ) ) { - String testStdMethod = Introspector.decapitalize( methodName.substring( 3 ) ); - String testOldMethod = methodName.substring( 3 ); - if ( testStdMethod.equals( propertyName ) || testOldMethod.equals( propertyName ) ) { - return method; - } - } - - // if not "get", then try "is" - if ( methodName.startsWith( "is" ) ) { - String testStdMethod = Introspector.decapitalize( methodName.substring( 2 ) ); - String testOldMethod = methodName.substring( 2 ); - if ( testStdMethod.equals( propertyName ) || testOldMethod.equals( propertyName ) ) { - return method; - } - } - } - return null; - } - - // - - public static boolean isPossibleBiDirectionalAssociation(CtField persistentField) { - return PersistentAttributesHelper.hasAnnotation( persistentField, OneToOne.class ) || - PersistentAttributesHelper.hasAnnotation( persistentField, OneToMany.class ) || - PersistentAttributesHelper.hasAnnotation( persistentField, ManyToOne.class ) || - PersistentAttributesHelper.hasAnnotation( persistentField, ManyToMany.class ); - } - - public static String getMappedBy(CtField persistentField, CtClass targetEntity, JavassistEnhancementContext context) throws NotFoundException { - final String local = getMappedByFromAnnotation( persistentField ); - if ( local == null || local.isEmpty() ) { - return getMappedByFromTargetEntity( persistentField, targetEntity, context ); - } - else { - // HHH-13446 - mappedBy from annotation may not be a valid bi-directional association, verify by calling isValidMappedBy() - return isValidMappedBy( persistentField, targetEntity, local, context ) ? local : ""; - } - } - - private static boolean isValidMappedBy(CtField persistentField, CtClass targetEntity, String mappedBy, JavassistEnhancementContext context) { - try { - CtField f = targetEntity.getField( mappedBy ); - return context.isPersistentField( f ) && isAssignable( persistentField.getDeclaringClass(), inferFieldTypeName( f ) ); - } - catch ( NotFoundException e ) { - return false; - } - } - - private static String getMappedByFromAnnotation(CtField persistentField) { - - OneToOne oto = PersistentAttributesHelper.getAnnotation( persistentField, OneToOne.class ); - if ( oto != null ) { - return oto.mappedBy(); - } - - OneToMany otm = PersistentAttributesHelper.getAnnotation( persistentField, OneToMany.class ); - if ( otm != null ) { - return otm.mappedBy(); - } - - // For @ManyToOne associations, mappedBy must come from the @OneToMany side of the association - - ManyToMany mtm = PersistentAttributesHelper.getAnnotation( persistentField, ManyToMany.class ); - return mtm == null ? "" : mtm.mappedBy(); - } - - private static String getMappedByFromTargetEntity( - CtField persistentField, - CtClass targetEntity, - JavassistEnhancementContext context) throws NotFoundException { - // get mappedBy value by searching in the fields of the target entity class - for ( CtField f : targetEntity.getDeclaredFields() ) { - if ( context.isPersistentField( f ) - && getMappedByFromAnnotation( f ).equals( persistentField.getName() ) - && isAssignable( persistentField.getDeclaringClass(), inferFieldTypeName( f ) ) ) { - log.debugf( - "mappedBy association for field [%s#%s] is [%s#%s]", - persistentField.getDeclaringClass().getName(), - persistentField.getName(), - targetEntity.getName(), - f.getName() - ); - return f.getName(); - } - } - return ""; - } - - public static CtClass getTargetEntityClass(CtClass managedCtClass, CtField persistentField) throws NotFoundException { - // get targetEntity defined in the annotation - try { - OneToOne oto = PersistentAttributesHelper.getAnnotation( persistentField, OneToOne.class ); - OneToMany otm = PersistentAttributesHelper.getAnnotation( persistentField, OneToMany.class ); - ManyToOne mto = PersistentAttributesHelper.getAnnotation( persistentField, ManyToOne.class ); - ManyToMany mtm = PersistentAttributesHelper.getAnnotation( persistentField, ManyToMany.class ); - - Class targetClass = null; - if ( oto != null ) { - targetClass = oto.targetEntity(); - } - if ( otm != null ) { - targetClass = otm.targetEntity(); - } - if ( mto != null ) { - targetClass = mto.targetEntity(); - } - if ( mtm != null ) { - targetClass = mtm.targetEntity(); - } - - if ( targetClass != null && targetClass != void.class ) { - return managedCtClass.getClassPool().get( targetClass.getName() ); - } - } - catch (NotFoundException ignore) { - } - - // infer targetEntity from generic type signature - String inferredTypeName = inferTypeName( managedCtClass, persistentField.getName() ); - return inferredTypeName == null ? null : managedCtClass.getClassPool().get( inferredTypeName ); - } - - /** - * Consistent with hasAnnotation() - */ - private static String inferTypeName(CtClass ctClass, String attributeName ) { - AccessType classAccessType = getAccessTypeOrNull( ctClass ); - CtField field = findFieldOrNull( ctClass, attributeName ); - CtMethod getter = findGetterOrNull( ctClass, attributeName ); - - if ( classAccessType == AccessType.FIELD || ( field != null && getAccessTypeOrNull( field ) == AccessType.FIELD ) ) { - return field == null ? null : inferFieldTypeName( field ); - } - if ( classAccessType == AccessType.PROPERTY || ( getter != null && getAccessTypeOrNull( getter ) == AccessType.PROPERTY ) ) { - return getter == null ? null : inferMethodTypeName( getter ); - } - - String found = ( getter == null ? null : inferMethodTypeName( getter ) ); - if ( found == null && field != null ) { - return inferFieldTypeName( field ); - } - return found; - } - - private static String inferFieldTypeName(CtField field) { - try { - if ( field.getFieldInfo2().getAttribute( SignatureAttribute.tag ) == null ) { - return field.getType().getName(); - } - return inferGenericTypeName( - field.getType(), - SignatureAttribute.toTypeSignature( field.getGenericSignature() ) - ); - } - catch (BadBytecode ignore) { - return null; - } - catch (NotFoundException e) { - return null; - } - } - - private static String inferMethodTypeName(CtMethod method) { - try { - if ( method.getMethodInfo2().getAttribute( SignatureAttribute.tag ) == null ) { - return method.getReturnType().getName(); - } - return inferGenericTypeName( - method.getReturnType(), - SignatureAttribute.toMethodSignature( method.getGenericSignature() ).getReturnType() - ); - } - catch (BadBytecode ignore) { - return null; - } - catch (NotFoundException e) { - return null; - } - } - - private static String inferGenericTypeName(CtClass ctClass, SignatureAttribute.Type genericSignature) { - // infer targetEntity from generic type signature - if ( isAssignable( ctClass, Collection.class.getName() ) ) { - return ( (SignatureAttribute.ClassType) genericSignature ).getTypeArguments()[0].getType().jvmTypeName(); - } - if ( isAssignable( ctClass, Map.class.getName() ) ) { - return ( (SignatureAttribute.ClassType) genericSignature ).getTypeArguments()[1].getType().jvmTypeName(); - } - return ctClass.getName(); - } - - // - - public static boolean isAssignable(CtClass thisCtClass, String targetClassName) { - if ( thisCtClass == null ) { - return false; - } - if ( thisCtClass.getName().equals( targetClassName ) ) { - return true; - } - - try { - // check if extends - if ( isAssignable( thisCtClass.getSuperclass(), targetClassName ) ) { - return true; - } - // check if implements - for ( CtClass interfaceCtClass : thisCtClass.getInterfaces() ) { - if ( isAssignable( interfaceCtClass, targetClassName ) ) { - return true; - } - } - } - catch (NotFoundException e) { - // keep going - } - return false; - } - - public static boolean isAssignable(CtField thisCtField, String targetClassName) { - try { - return isAssignable( thisCtField.getType(), targetClassName ); - } - catch (NotFoundException e) { - // keep going - } - return false; - } - -} diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/UnloadedCtClass.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/UnloadedCtClass.java deleted file mode 100644 index e0d2bc391275..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/UnloadedCtClass.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.bytecode.enhance.internal.javassist; - -import java.lang.annotation.Annotation; - -import javassist.CtClass; - -import org.hibernate.bytecode.enhance.spi.UnloadedClass; - -public class UnloadedCtClass implements UnloadedClass { - - private final CtClass ctClass; - - public UnloadedCtClass(CtClass ctClass) { - this.ctClass = ctClass; - } - - @Override - public boolean hasAnnotation(Class annotationType) { - return ctClass.hasAnnotation( annotationType ); - } - - @Override - public String getName() { - return ctClass.getName(); - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/UnloadedCtField.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/UnloadedCtField.java deleted file mode 100644 index 1c04d176de4f..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/UnloadedCtField.java +++ /dev/null @@ -1,32 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.bytecode.enhance.internal.javassist; - -import java.lang.annotation.Annotation; - -import javassist.CtField; - -import org.hibernate.bytecode.enhance.spi.UnloadedField; - -public class UnloadedCtField implements UnloadedField { - - final CtField ctField; - - public UnloadedCtField(CtField ctField) { - this.ctField = ctField; - } - - @Override - public boolean hasAnnotation(Class annotationType) { - return ctField.hasAnnotation( annotationType ); - } - - @Override - public String toString() { - return this.ctField.toString(); - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/package-info.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/package-info.java deleted file mode 100644 index f44c3174dfc3..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/javassist/package-info.java +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ - -/** - * package containing bytecode enhancement code (internals) - */ -package org.hibernate.bytecode.enhance.internal.javassist; diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/AccessOptimizerAdapter.java b/hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/AccessOptimizerAdapter.java deleted file mode 100644 index a48ec1402d8c..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/AccessOptimizerAdapter.java +++ /dev/null @@ -1,101 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.bytecode.internal.javassist; - -import java.io.Serializable; - -import org.hibernate.PropertyAccessException; -import org.hibernate.bytecode.spi.ReflectionOptimizer; -import org.hibernate.cfg.AvailableSettings; - -/** - * The {@link org.hibernate.bytecode.spi.ReflectionOptimizer.AccessOptimizer} implementation for Javassist - * which simply acts as an adapter to the {@link BulkAccessor} class. - * - * @author Steve Ebersole - */ -public class AccessOptimizerAdapter implements ReflectionOptimizer.AccessOptimizer, Serializable { - - private static final String PROPERTY_GET_EXCEPTION = String.format( - "exception getting property value with Javassist (set %s to false for more info)", - AvailableSettings.USE_REFLECTION_OPTIMIZER - ); - - private static final String PROPERTY_SET_EXCEPTION = String.format( - "exception setting property value with Javassist (set %s to false for more info)", - AvailableSettings.USE_REFLECTION_OPTIMIZER - ); - - private final BulkAccessor bulkAccessor; - private final Class mappedClass; - - /** - * Constructs an AccessOptimizerAdapter - * - * @param bulkAccessor The bulk accessor to use - * @param mappedClass The mapped class - */ - public AccessOptimizerAdapter(BulkAccessor bulkAccessor, Class mappedClass) { - this.bulkAccessor = bulkAccessor; - this.mappedClass = mappedClass; - } - - @Override - public String[] getPropertyNames() { - return bulkAccessor.getGetters(); - } - - @Override - public Object[] getPropertyValues(Object object) { - try { - return bulkAccessor.getPropertyValues( object ); - } - catch ( Throwable t ) { - throw new PropertyAccessException( - t, - PROPERTY_GET_EXCEPTION, - false, - mappedClass, - getterName( t, bulkAccessor ) - ); - } - } - - @Override - public void setPropertyValues(Object object, Object[] values) { - try { - bulkAccessor.setPropertyValues( object, values ); - } - catch ( Throwable t ) { - throw new PropertyAccessException( - t, - PROPERTY_SET_EXCEPTION, - true, - mappedClass, - setterName( t, bulkAccessor ) - ); - } - } - - private static String setterName(Throwable t, BulkAccessor accessor) { - if (t instanceof BulkAccessorException ) { - return accessor.getSetters()[ ( (BulkAccessorException) t ).getIndex() ]; - } - else { - return "?"; - } - } - - private static String getterName(Throwable t, BulkAccessor accessor) { - if (t instanceof BulkAccessorException ) { - return accessor.getGetters()[ ( (BulkAccessorException) t ).getIndex() ]; - } - else { - return "?"; - } - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/BulkAccessor.java b/hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/BulkAccessor.java deleted file mode 100644 index c29016f6f50f..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/BulkAccessor.java +++ /dev/null @@ -1,109 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.bytecode.internal.javassist; - -import java.io.Serializable; - -/** - * A JavaBean bulk accessor, which provides methods capable of getting/setting multiple properties - * of a JavaBean at once. - * - * IMPORTANT NOTE!!! Apparently the order of the methods here is important as I think BulkAccessorFactory - * makes use of that information in terms of accessing the constructor. Anyway, when I tried to re-arrange them - * the BulkAccessor creation failed and tests started to fail. - * - * @author Muga Nishizawa - * @author Shigeru Chiba - */ -public abstract class BulkAccessor implements Serializable { - protected Class target; - protected String[] getters, setters; - protected Class[] types; - - /** - * Protected access constructor so the generated class has access to it. - */ - protected BulkAccessor() { - } - - /** - * Obtains the values of properties of a given bean. - * - * @param bean JavaBean. - * @param values the obtained values are stored in this array. - */ - public abstract void getPropertyValues(Object bean, Object[] values); - - /** - * Sets properties of a given bean to specified values. - * - * @param bean JavaBean. - * @param values the values assinged to properties. - */ - public abstract void setPropertyValues(Object bean, Object[] values); - - /** - * Returns the values of properties of a given bean. - * - * @param bean JavaBean. - * - * @return The property values - */ - public Object[] getPropertyValues(Object bean) { - final Object[] values = new Object[getters.length]; - getPropertyValues( bean, values ); - return values; - } - - /** - * Returns the types of properties. - * - * @return The property types - */ - public Class[] getPropertyTypes() { - return types.clone(); - } - - /** - * Returns the setter names of properties. - * - * @return The getter names - */ - public String[] getGetters() { - return getters.clone(); - } - - /** - * Returns the getter names of the properties. - * - * @return The setter names - */ - public String[] getSetters() { - return setters.clone(); - } - - /** - * Creates a new instance of BulkAccessor. - * The created instance provides methods for setting/getting - * specified properties at once. - * - * @param beanClass the class of the JavaBeans accessed - * through the created object. - * @param getters the names of setter methods for specified properties. - * @param setters the names of getter methods for specified properties. - * @param types the types of specified properties. - * - * @return The created BulkAccessor - */ - public static BulkAccessor create( - Class beanClass, - String[] getters, - String[] setters, - Class[] types) { - return new BulkAccessorFactory( beanClass, getters, setters, types ).create(); - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/BulkAccessorException.java b/hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/BulkAccessorException.java deleted file mode 100644 index f61617291f75..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/BulkAccessorException.java +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.bytecode.internal.javassist; - -import org.hibernate.HibernateException; - -/** - * An exception thrown while generating a bulk accessor. - * - * @author Muga Nishizawa - * @author modified by Shigeru Chiba - */ -public class BulkAccessorException extends HibernateException { - private final int index; - - /** - * Constructs an exception. - * - * @param message Message explaining the exception condition - */ - public BulkAccessorException(String message) { - this( message, -1 ); - } - - /** - * Constructs an exception. - * - * @param message Message explaining the exception condition - * @param index The index of the property that causes an exception. - */ - public BulkAccessorException(String message, int index) { - this( message, index, null ); - } - - /** - * Constructs an exception. - * - * @param message Message explaining the exception condition - * @param cause The underlying cause - */ - public BulkAccessorException(String message, Exception cause) { - this( message, -1, cause ); - } - - /** - * Constructs an exception. - * - * @param message Message explaining the exception condition - * @param index The index of the property that causes an exception. - * @param cause The underlying cause - */ - public BulkAccessorException(String message, int index, Exception cause) { - super( message + " : @" + index, cause ); - this.index = index; - } - - /** - * Returns the index of the property that causes this exception. - * - * @return -1 if the index is not specified. - */ - public int getIndex() { - return this.index; - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/BulkAccessorFactory.java b/hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/BulkAccessorFactory.java deleted file mode 100644 index 12d19bcb64f6..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/BulkAccessorFactory.java +++ /dev/null @@ -1,423 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.bytecode.internal.javassist; - -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.security.ProtectionDomain; - -import javassist.CannotCompileException; -import javassist.bytecode.AccessFlag; -import javassist.bytecode.Bytecode; -import javassist.bytecode.ClassFile; -import javassist.bytecode.CodeAttribute; -import javassist.bytecode.ConstPool; -import javassist.bytecode.MethodInfo; -import javassist.bytecode.Opcode; -import javassist.bytecode.StackMapTable; -import javassist.util.proxy.FactoryHelper; -import javassist.util.proxy.RuntimeSupport; - -/** - * A factory of bulk accessors. - * - * @author Muga Nishizawa - * @author modified by Shigeru Chiba - */ -class BulkAccessorFactory { - private static final String PACKAGE_NAME_PREFIX = "org.javassist.tmp."; - private static final String BULKACESSOR_CLASS_NAME = BulkAccessor.class.getName(); - private static final String OBJECT_CLASS_NAME = Object.class.getName(); - private static final String GENERATED_GETTER_NAME = "getPropertyValues"; - private static final String GENERATED_SETTER_NAME = "setPropertyValues"; - private static final String GET_SETTER_DESC = "(Ljava/lang/Object;[Ljava/lang/Object;)V"; - private static final String THROWABLE_CLASS_NAME = Throwable.class.getName(); - private static final String BULKEXCEPTION_CLASS_NAME = BulkAccessorException.class.getName(); - - private static int counter; - - private Class targetBean; - private String[] getterNames; - private String[] setterNames; - private Class[] types; - public String writeDirectory; - - BulkAccessorFactory( - Class target, - String[] getterNames, - String[] setterNames, - Class[] types) { - this.targetBean = target; - this.getterNames = getterNames; - this.setterNames = setterNames; - this.types = types; - this.writeDirectory = null; - } - - BulkAccessor create() { - final Method[] getters = new Method[getterNames.length]; - final Method[] setters = new Method[setterNames.length]; - findAccessors( targetBean, getterNames, setterNames, types, getters, setters ); - - final Class beanClass; - try { - final ClassFile classfile = make( getters, setters ); - final ClassLoader loader = this.getClassLoader(); - if ( writeDirectory != null ) { - FactoryHelper.writeFile( classfile, writeDirectory ); - } - - beanClass = FactoryHelper.toClass( classfile, null, loader, getDomain() ); - return (BulkAccessor) this.newInstance( beanClass ); - } - catch ( Exception e ) { - throw new BulkAccessorException( e.getMessage(), e ); - } - } - - private ProtectionDomain getDomain() { - final Class cl; - if ( this.targetBean != null ) { - cl = this.targetBean; - } - else { - cl = this.getClass(); - } - return cl.getProtectionDomain(); - } - - private ClassFile make(Method[] getters, Method[] setters) throws CannotCompileException { - String className = targetBean.getName(); - // set the name of bulk accessor. - className = className + "_$$_bulkaccess_" + counter++; - if ( className.startsWith( "java." ) ) { - className = PACKAGE_NAME_PREFIX + className; - } - - final ClassFile classfile = new ClassFile( false, className, BULKACESSOR_CLASS_NAME ); - classfile.setAccessFlags( AccessFlag.PUBLIC ); - addDefaultConstructor( classfile ); - addGetter( classfile, getters ); - addSetter( classfile, setters ); - return classfile; - } - - private ClassLoader getClassLoader() { - if ( targetBean != null && targetBean.getName().equals( OBJECT_CLASS_NAME ) ) { - return targetBean.getClassLoader(); - } - else { - return getClass().getClassLoader(); - } - } - - private Object newInstance(Class type) throws Exception { - final BulkAccessor instance = (BulkAccessor) type.newInstance(); - instance.target = targetBean; - final int len = getterNames.length; - instance.getters = new String[len]; - instance.setters = new String[len]; - instance.types = new Class[len]; - for ( int i = 0; i < len; i++ ) { - instance.getters[i] = getterNames[i]; - instance.setters[i] = setterNames[i]; - instance.types[i] = types[i]; - } - - return instance; - } - - /** - * Declares a constructor that takes no parameter. - * - * @param classfile The class descriptor - * - * @throws CannotCompileException Indicates trouble with the underlying Javassist calls - */ - private void addDefaultConstructor(ClassFile classfile) throws CannotCompileException { - final ConstPool constPool = classfile.getConstPool(); - final String constructorSignature = "()V"; - final MethodInfo constructorMethodInfo = new MethodInfo( constPool, MethodInfo.nameInit, constructorSignature ); - - final Bytecode code = new Bytecode( constPool, 0, 1 ); - // aload_0 - code.addAload( 0 ); - // invokespecial - code.addInvokespecial( BulkAccessor.class.getName(), MethodInfo.nameInit, constructorSignature ); - // return - code.addOpcode( Opcode.RETURN ); - - constructorMethodInfo.setCodeAttribute( code.toCodeAttribute() ); - constructorMethodInfo.setAccessFlags( AccessFlag.PUBLIC ); - classfile.addMethod( constructorMethodInfo ); - } - - private void addGetter(ClassFile classfile, final Method[] getters) throws CannotCompileException { - final ConstPool constPool = classfile.getConstPool(); - final int targetBeanConstPoolIndex = constPool.addClassInfo( this.targetBean.getName() ); - final String desc = GET_SETTER_DESC; - final MethodInfo getterMethodInfo = new MethodInfo( constPool, GENERATED_GETTER_NAME, desc ); - - final Bytecode code = new Bytecode( constPool, 6, 4 ); - /* | this | bean | args | raw bean | */ - if ( getters.length >= 0 ) { - // aload_1 // load bean - code.addAload( 1 ); - // checkcast // cast bean - code.addCheckcast( this.targetBean.getName() ); - // astore_3 // store bean - code.addAstore( 3 ); - for ( int i = 0; i < getters.length; ++i ) { - if ( getters[i] != null ) { - final Method getter = getters[i]; - // aload_2 // args - code.addAload( 2 ); - // iconst_i // continue to aastore - // growing stack is 1 - code.addIconst( i ); - final Class returnType = getter.getReturnType(); - int typeIndex = -1; - if ( returnType.isPrimitive() ) { - typeIndex = FactoryHelper.typeIndex( returnType ); - // new - code.addNew( FactoryHelper.wrapperTypes[typeIndex] ); - // dup - code.addOpcode( Opcode.DUP ); - } - - // aload_3 // load the raw bean - code.addAload( 3 ); - final String getterSignature = RuntimeSupport.makeDescriptor( getter ); - final String getterName = getter.getName(); - if ( this.targetBean.isInterface() ) { - // invokeinterface - code.addInvokeinterface( targetBeanConstPoolIndex, getterName, getterSignature, 1 ); - } - else { - // invokevirtual - code.addInvokevirtual( targetBeanConstPoolIndex, getterName, getterSignature ); - } - - if ( typeIndex >= 0 ) { - // is a primitive type - // invokespecial - code.addInvokespecial( - FactoryHelper.wrapperTypes[typeIndex], - MethodInfo.nameInit, - FactoryHelper.wrapperDesc[typeIndex] - ); - } - - // aastore // args - code.add( Opcode.AASTORE ); - code.growStack( -3 ); - } - } - } - // return - code.addOpcode( Opcode.RETURN ); - - getterMethodInfo.setCodeAttribute( code.toCodeAttribute() ); - getterMethodInfo.setAccessFlags( AccessFlag.PUBLIC ); - classfile.addMethod( getterMethodInfo ); - } - - private void addSetter(ClassFile classfile, final Method[] setters) throws CannotCompileException { - final ConstPool constPool = classfile.getConstPool(); - final int targetTypeConstPoolIndex = constPool.addClassInfo( this.targetBean.getName() ); - final String desc = GET_SETTER_DESC; - final MethodInfo setterMethodInfo = new MethodInfo( constPool, GENERATED_SETTER_NAME, desc ); - - final Bytecode code = new Bytecode( constPool, 4, 6 ); - StackMapTable stackmap = null; - /* | this | bean | args | i | raw bean | exception | */ - if ( setters.length > 0 ) { - // required to exception table - int start; - int end; - // iconst_0 // i - code.addIconst( 0 ); - // istore_3 // store i - code.addIstore( 3 ); - // aload_1 // load the bean - code.addAload( 1 ); - // checkcast // cast the bean into a raw bean - code.addCheckcast( this.targetBean.getName() ); - // astore 4 // store the raw bean - code.addAstore( 4 ); - /* current stack len = 0 */ - // start region to handling exception (BulkAccessorException) - start = code.currentPc(); - int lastIndex = 0; - for ( int i = 0; i < setters.length; ++i ) { - if ( setters[i] != null ) { - final int diff = i - lastIndex; - if ( diff > 0 ) { - // iinc 3, 1 - code.addOpcode( Opcode.IINC ); - code.add( 3 ); - code.add( diff ); - lastIndex = i; - } - } - /* current stack len = 0 */ - // aload 4 // load the raw bean - code.addAload( 4 ); - // aload_2 // load the args - code.addAload( 2 ); - // iconst_i - code.addIconst( i ); - // aaload - code.addOpcode( Opcode.AALOAD ); - // checkcast - final Class[] setterParamTypes = setters[i].getParameterTypes(); - final Class setterParamType = setterParamTypes[0]; - if ( setterParamType.isPrimitive() ) { - // checkcast (case of primitive type) - // invokevirtual (case of primitive type) - this.addUnwrapper( code, setterParamType ); - } - else { - // checkcast (case of reference type) - code.addCheckcast( setterParamType.getName() ); - } - /* current stack len = 2 */ - final String rawSetterMethodDesc = RuntimeSupport.makeDescriptor( setters[i] ); - if ( !this.targetBean.isInterface() ) { - // invokevirtual - code.addInvokevirtual( targetTypeConstPoolIndex, setters[i].getName(), rawSetterMethodDesc ); - } - else { - // invokeinterface - final Class[] params = setters[i].getParameterTypes(); - int size; - if ( params[0].equals( Double.TYPE ) || params[0].equals( Long.TYPE ) ) { - size = 3; - } - else { - size = 2; - } - - code.addInvokeinterface( targetTypeConstPoolIndex, setters[i].getName(), rawSetterMethodDesc, size ); - } - } - - // end region to handling exception (BulkAccessorException) - end = code.currentPc(); - // return - code.addOpcode( Opcode.RETURN ); - /* current stack len = 0 */ - // register in exception table - final int throwableTypeIndex = constPool.addClassInfo( THROWABLE_CLASS_NAME ); - final int handlerPc = code.currentPc(); - code.addExceptionHandler( start, end, handlerPc, throwableTypeIndex ); - // astore 5 // store exception - code.addAstore( 5 ); - // new // BulkAccessorException - code.addNew( BULKEXCEPTION_CLASS_NAME ); - // dup - code.addOpcode( Opcode.DUP ); - // aload 5 // load exception - code.addAload( 5 ); - // iload_3 // i - code.addIload( 3 ); - // invokespecial // BulkAccessorException. - final String consDesc = "(Ljava/lang/Throwable;I)V"; - code.addInvokespecial( BULKEXCEPTION_CLASS_NAME, MethodInfo.nameInit, consDesc ); - // athrow - code.addOpcode( Opcode.ATHROW ); - final StackMapTable.Writer writer = new StackMapTable.Writer(32); - final int[] localTags = { - StackMapTable.OBJECT, - StackMapTable.OBJECT, - StackMapTable.OBJECT, - StackMapTable.INTEGER - }; - final int[] localData = { - constPool.getThisClassInfo(), - constPool.addClassInfo( "java/lang/Object" ), - constPool.addClassInfo( "[Ljava/lang/Object;" ), - 0 - }; - final int[] stackTags = { - StackMapTable.OBJECT - }; - final int[] stackData = { - throwableTypeIndex - }; - writer.fullFrame( handlerPc, localTags, localData, stackTags, stackData ); - stackmap = writer.toStackMapTable( constPool ); - } - else { - // return - code.addOpcode( Opcode.RETURN ); - } - final CodeAttribute ca = code.toCodeAttribute(); - if ( stackmap != null ) { - ca.setAttribute( stackmap ); - } - setterMethodInfo.setCodeAttribute( ca ); - setterMethodInfo.setAccessFlags( AccessFlag.PUBLIC ); - classfile.addMethod( setterMethodInfo ); - } - - private void addUnwrapper(Bytecode code, Class type) { - final int index = FactoryHelper.typeIndex( type ); - final String wrapperType = FactoryHelper.wrapperTypes[index]; - // checkcast - code.addCheckcast( wrapperType ); - // invokevirtual - code.addInvokevirtual( wrapperType, FactoryHelper.unwarpMethods[index], FactoryHelper.unwrapDesc[index] ); - } - - private static void findAccessors( - Class clazz, - String[] getterNames, - String[] setterNames, - Class[] types, - Method[] getters, - Method[] setters) { - final int length = types.length; - if ( setterNames.length != length || getterNames.length != length ) { - throw new BulkAccessorException( "bad number of accessors" ); - } - - final Class[] getParam = new Class[0]; - final Class[] setParam = new Class[1]; - for ( int i = 0; i < length; i++ ) { - if ( getterNames[i] != null ) { - final Method getter = findAccessor( clazz, getterNames[i], getParam, i ); - if ( getter.getReturnType() != types[i] ) { - throw new BulkAccessorException( "wrong return type: " + getterNames[i], i ); - } - - getters[i] = getter; - } - - if ( setterNames[i] != null ) { - setParam[0] = types[i]; - setters[i] = findAccessor( clazz, setterNames[i], setParam, i ); - } - } - } - - @SuppressWarnings("unchecked") - private static Method findAccessor(Class clazz, String name, Class[] params, int index) - throws BulkAccessorException { - try { - final Method method = clazz.getDeclaredMethod( name, params ); - if ( Modifier.isPrivate( method.getModifiers() ) ) { - throw new BulkAccessorException( "private property", index ); - } - - return method; - } - catch ( NoSuchMethodException e ) { - throw new BulkAccessorException( "cannot find an accessor", index ); - } - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/BytecodeProviderImpl.java b/hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/BytecodeProviderImpl.java deleted file mode 100644 index ca588e25199b..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/BytecodeProviderImpl.java +++ /dev/null @@ -1,106 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.bytecode.internal.javassist; - -import java.lang.reflect.Modifier; - -import org.hibernate.bytecode.enhance.internal.javassist.EnhancerImpl; -import org.hibernate.bytecode.enhance.spi.EnhancementContext; -import org.hibernate.bytecode.enhance.spi.Enhancer; -import org.hibernate.bytecode.spi.BytecodeProvider; -import org.hibernate.bytecode.spi.ProxyFactoryFactory; -import org.hibernate.bytecode.spi.ReflectionOptimizer; -import org.hibernate.internal.CoreMessageLogger; -import org.hibernate.internal.util.StringHelper; - -import org.jboss.logging.Logger; - -/** - * Bytecode provider implementation for Javassist. - * @deprecated The Javassist based enhancer will be removed soon, - * please use the one based on ByteBuddy (which is the default since - * version 5.3 of Hibernate ORM) - * - * @author Steve Ebersole - */ -@Deprecated -public class BytecodeProviderImpl implements BytecodeProvider { - private static final CoreMessageLogger LOG = Logger.getMessageLogger( - CoreMessageLogger.class, - BytecodeProviderImpl.class.getName() - ); - - @Override - public ProxyFactoryFactory getProxyFactoryFactory() { - return new ProxyFactoryFactoryImpl(); - } - - @Override - public ReflectionOptimizer getReflectionOptimizer( - Class clazz, - String[] getterNames, - String[] setterNames, - Class[] types) { - FastClass fastClass; - BulkAccessor bulkAccessor; - try { - fastClass = FastClass.create( clazz ); - bulkAccessor = BulkAccessor.create( clazz, getterNames, setterNames, types ); - if ( !clazz.isInterface() && !Modifier.isAbstract( clazz.getModifiers() ) ) { - if ( fastClass == null ) { - bulkAccessor = null; - } - else { - //test out the optimizer: - final Object instance = fastClass.newInstance(); - bulkAccessor.setPropertyValues( instance, bulkAccessor.getPropertyValues( instance ) ); - } - } - } - catch ( Throwable t ) { - fastClass = null; - bulkAccessor = null; - if ( LOG.isDebugEnabled() ) { - int index = 0; - if (t instanceof BulkAccessorException) { - index = ( (BulkAccessorException) t ).getIndex(); - } - if ( index >= 0 ) { - LOG.debugf( - "Reflection optimizer disabled for %s [%s: %s (property %s)]", - clazz.getName(), - StringHelper.unqualify( t.getClass().getName() ), - t.getMessage(), - setterNames[index] - ); - } - else { - LOG.debugf( - "Reflection optimizer disabled for %s [%s: %s]", - clazz.getName(), - StringHelper.unqualify( t.getClass().getName() ), - t.getMessage() - ); - } - } - } - - if ( fastClass != null && bulkAccessor != null ) { - return new ReflectionOptimizerImpl( - new InstantiationOptimizerAdapter( fastClass ), - new AccessOptimizerAdapter( bulkAccessor, clazz ) - ); - } - - return null; - } - - @Override - public Enhancer getEnhancer(EnhancementContext enhancementContext) { - return new EnhancerImpl( enhancementContext ); - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/FastClass.java b/hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/FastClass.java deleted file mode 100644 index 40c172e988f9..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/FastClass.java +++ /dev/null @@ -1,247 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.bytecode.internal.javassist; - -import java.io.Serializable; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; - -/** - * Fast access to class information - * - * @author Muga Nishizawa - */ -public class FastClass implements Serializable { - private static final Class[] EMPTY_CLASS_ARRAY = new Class[0]; - - private final Class type; - - /** - * Constructs a FastClass - * - * @param type The class to optimize - * - * @return The fast class access to the given class - */ - public static FastClass create(Class type) { - return new FastClass( type ); - } - - private FastClass(Class type) { - this.type = type; - } - - /** - * Access to invoke a method on the class that this fast class handles - * - * @param name The name of the method to invoke, - * @param parameterTypes The method parameter types - * @param obj The instance on which to invoke the method - * @param args The parameter arguments - * - * @return The method result - * - * @throws InvocationTargetException Indicates a problem performing invocation - */ - public Object invoke( - String name, - Class[] parameterTypes, - Object obj, - Object[] args) throws InvocationTargetException { - return this.invoke( this.getIndex( name, parameterTypes ), obj, args ); - } - - /** - * Access to invoke a method on the class that this fast class handles by its index - * - * @param index The method index - * @param obj The instance on which to invoke the method - * @param args The parameter arguments - * - * @return The method result - * - * @throws InvocationTargetException Indicates a problem performing invocation - */ - public Object invoke( - int index, - Object obj, - Object[] args) throws InvocationTargetException { - final Method[] methods = this.type.getMethods(); - try { - return methods[index].invoke( obj, args ); - } - catch ( ArrayIndexOutOfBoundsException e ) { - throw new IllegalArgumentException( - "Cannot find matching method/constructor" - ); - } - catch ( IllegalAccessException e ) { - throw new InvocationTargetException( e ); - } - } - - /** - * Invoke the default constructor - * - * @return The constructed instance - * - * @throws InvocationTargetException Indicates a problem performing invocation - */ - public Object newInstance() throws InvocationTargetException { - return this.newInstance( this.getIndex( EMPTY_CLASS_ARRAY ), null ); - } - - /** - * Invoke a parameterized constructor - * - * @param parameterTypes The parameter types - * @param args The parameter arguments to pass along - * - * @return The constructed instance - * - * @throws InvocationTargetException Indicates a problem performing invocation - */ - public Object newInstance( - Class[] parameterTypes, - Object[] args) throws InvocationTargetException { - return this.newInstance( this.getIndex( parameterTypes ), args ); - } - - /** - * Invoke a constructor by its index - * - * @param index The constructor index - * @param args The parameter arguments to pass along - * - * @return The constructed instance - * - * @throws InvocationTargetException Indicates a problem performing invocation - */ - public Object newInstance( - int index, - Object[] args) throws InvocationTargetException { - final Constructor[] constructors = this.type.getConstructors(); - try { - return constructors[index].newInstance( args ); - } - catch ( ArrayIndexOutOfBoundsException e ) { - throw new IllegalArgumentException( "Cannot find matching method/constructor" ); - } - catch ( InstantiationException e ) { - throw new InvocationTargetException( e ); - } - catch ( IllegalAccessException e ) { - throw new InvocationTargetException( e ); - } - } - - /** - * Locate the index of a method - * - * @param name The method name - * @param parameterTypes The method parameter types - * - * @return The index - */ - public int getIndex(String name, Class[] parameterTypes) { - final Method[] methods = this.type.getMethods(); - boolean eq; - - for ( int i = 0; i < methods.length; ++i ) { - if ( !Modifier.isPublic( methods[i].getModifiers() ) ) { - continue; - } - if ( !methods[i].getName().equals( name ) ) { - continue; - } - final Class[] params = methods[i].getParameterTypes(); - if ( params.length != parameterTypes.length ) { - continue; - } - eq = true; - for ( int j = 0; j < params.length; ++j ) { - if ( !params[j].equals( parameterTypes[j] ) ) { - eq = false; - break; - } - } - if ( eq ) { - return i; - } - } - return -1; - } - - /** - * Locate the index of a constructor - * - * @param parameterTypes The constructor parameter types - * - * @return The index - */ - public int getIndex(Class[] parameterTypes) { - final Constructor[] constructors = this.type.getConstructors(); - boolean eq; - - for ( int i = 0; i < constructors.length; ++i ) { - if ( !Modifier.isPublic( constructors[i].getModifiers() ) ) { - continue; - } - final Class[] params = constructors[i].getParameterTypes(); - if ( params.length != parameterTypes.length ) { - continue; - } - eq = true; - for ( int j = 0; j < params.length; ++j ) { - if ( !params[j].equals( parameterTypes[j] ) ) { - eq = false; - break; - } - } - if ( eq ) { - return i; - } - } - return -1; - } - - /** - * Get the wrapped class name - * - * @return The class name - */ - public String getName() { - return this.type.getName(); - } - - /** - * Get the wrapped java class reference - * - * @return The class reference - */ - public Class getJavaClass() { - return this.type; - } - - @Override - public String toString() { - return this.type.toString(); - } - - @Override - public int hashCode() { - return this.type.hashCode(); - } - - @Override - public boolean equals(Object o) { - return o instanceof FastClass - && this.type.equals( ((FastClass) o).type ); - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/InstantiationOptimizerAdapter.java b/hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/InstantiationOptimizerAdapter.java deleted file mode 100644 index 9b62fa196687..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/InstantiationOptimizerAdapter.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.bytecode.internal.javassist; - -import java.io.Serializable; - -import org.hibernate.InstantiationException; -import org.hibernate.bytecode.spi.ReflectionOptimizer; - -/** - * The {@link org.hibernate.bytecode.spi.ReflectionOptimizer.InstantiationOptimizer} implementation for Javassist - * which simply acts as an adapter to the {@link FastClass} class. - * - * @author Steve Ebersole - */ -public class InstantiationOptimizerAdapter implements ReflectionOptimizer.InstantiationOptimizer, Serializable { - private final FastClass fastClass; - - /** - * Constructs the InstantiationOptimizerAdapter - * - * @param fastClass The fast class for the class to be instantiated here. - */ - public InstantiationOptimizerAdapter(FastClass fastClass) { - this.fastClass = fastClass; - } - - @Override - public Object newInstance() { - try { - return fastClass.newInstance(); - } - catch ( Exception e ) { - throw new InstantiationException( - "Could not instantiate entity with Javassist optimizer: ", - fastClass.getJavaClass(), - e - ); - } - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/ProxyFactoryFactoryImpl.java b/hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/ProxyFactoryFactoryImpl.java deleted file mode 100644 index 01bd7d107cdd..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/ProxyFactoryFactoryImpl.java +++ /dev/null @@ -1,160 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.bytecode.internal.javassist; - -import java.lang.reflect.Method; -import java.util.HashMap; - -import javassist.util.proxy.MethodFilter; -import javassist.util.proxy.MethodHandler; -import javassist.util.proxy.Proxy; - -import org.hibernate.AssertionFailure; -import org.hibernate.HibernateException; -import org.hibernate.bytecode.internal.bytebuddy.BasicProxyFactoryImpl; -import org.hibernate.bytecode.spi.BasicProxyFactory; -import org.hibernate.bytecode.spi.ProxyFactoryFactory; -import org.hibernate.engine.spi.SessionFactoryImplementor; -import org.hibernate.proxy.ProxyFactory; -import org.hibernate.proxy.pojo.javassist.JavassistProxyFactory; - -/** - * A factory for Javassist-based {@link ProxyFactory} instances. - * - * @author Steve Ebersole - */ -public class ProxyFactoryFactoryImpl implements ProxyFactoryFactory { - - /** - * Builds a Javassist-based proxy factory. - * - * @return a new Javassist-based proxy factory. - */ - @Override - public ProxyFactory buildProxyFactory(SessionFactoryImplementor sessionFactory) { - return new JavassistProxyFactory(); - } - - /** - * Constructs a BasicProxyFactoryImpl - * - * @param superClass The abstract super class (or null if none). - * @param interfaces Interfaces to be proxied (or null if none). - * @deprecated use {@link #buildBasicProxyFactory(Class)} - * - * @return The constructed BasicProxyFactoryImpl - */ - @Override - @Deprecated - public BasicProxyFactory buildBasicProxyFactory(Class superClass, Class[] interfaces) { - return new BasicProxyFactoryImpl( superClass, interfaces ); - } - - @Override - public BasicProxyFactory buildBasicProxyFactory(Class superClassOrInterface) { - if ( superClassOrInterface.isInterface() ) { - return new BasicProxyFactoryImpl( null, new Class[]{ superClassOrInterface } ); - } - else { - return new BasicProxyFactoryImpl( superClassOrInterface, null ); - } - } - - private static class BasicProxyFactoryImpl implements BasicProxyFactory { - private final Class proxyClass; - - public BasicProxyFactoryImpl(Class superClass, Class[] interfaces) { - if ( superClass == null && ( interfaces == null || interfaces.length < 1 ) ) { - throw new AssertionFailure( "attempting to build proxy without any superclass or interfaces" ); - } - - final javassist.util.proxy.ProxyFactory factory = new javassist.util.proxy.ProxyFactory(); - factory.setFilter( FINALIZE_FILTER ); - if ( superClass != null ) { - factory.setSuperclass( superClass ); - } - if ( interfaces != null && interfaces.length > 0 ) { - factory.setInterfaces( interfaces ); - } - proxyClass = factory.createClass(); - } - - public Object getProxy() { - try { - final Proxy proxy = (Proxy) proxyClass.newInstance(); - proxy.setHandler( new PassThroughHandler( proxy, proxyClass.getName() ) ); - return proxy; - } - catch ( Throwable t ) { - throw new HibernateException( "Unable to instantiated proxy instance" ); - } - } - - public boolean isInstance(Object object) { - return proxyClass.isInstance( object ); - } - } - - private static final MethodFilter FINALIZE_FILTER = new MethodFilter() { - public boolean isHandled(Method m) { - // skip finalize methods - return !( m.getParameterCount() == 0 && m.getName().equals( "finalize" ) ); - } - }; - - private static class PassThroughHandler implements MethodHandler { - private HashMap data = new HashMap(); - private final Object proxiedObject; - private final String proxiedClassName; - - public PassThroughHandler(Object proxiedObject, String proxiedClassName) { - this.proxiedObject = proxiedObject; - this.proxiedClassName = proxiedClassName; - } - - @SuppressWarnings("unchecked") - public Object invoke( - Object object, - Method method, - Method method1, - Object[] args) throws Exception { - final String name = method.getName(); - if ( "toString".equals( name ) ) { - return proxiedClassName + "@" + System.identityHashCode( object ); - } - else if ( "equals".equals( name ) ) { - return proxiedObject == object; - } - else if ( "hashCode".equals( name ) ) { - return System.identityHashCode( object ); - } - - final boolean hasGetterSignature = method.getParameterCount() == 0 - && method.getReturnType() != null; - final boolean hasSetterSignature = method.getParameterCount() == 1 - && ( method.getReturnType() == null || method.getReturnType() == void.class ); - - if ( name.startsWith( "get" ) && hasGetterSignature ) { - final String propName = name.substring( 3 ); - return data.get( propName ); - } - else if ( name.startsWith( "is" ) && hasGetterSignature ) { - final String propName = name.substring( 2 ); - return data.get( propName ); - } - else if ( name.startsWith( "set" ) && hasSetterSignature) { - final String propName = name.substring( 3 ); - data.put( propName, args[0] ); - return null; - } - else { - // todo : what else to do here? - return null; - } - } - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/ReflectionOptimizerImpl.java b/hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/ReflectionOptimizerImpl.java deleted file mode 100644 index 17372dcee9fb..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/ReflectionOptimizerImpl.java +++ /dev/null @@ -1,45 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.bytecode.internal.javassist; - -import java.io.Serializable; - -import org.hibernate.bytecode.spi.ReflectionOptimizer; - -/** - * ReflectionOptimizer implementation for Javassist. - * - * @author Steve Ebersole - */ -public class ReflectionOptimizerImpl implements ReflectionOptimizer, Serializable { - private final InstantiationOptimizer instantiationOptimizer; - private final AccessOptimizer accessOptimizer; - - /** - * Constructs a ReflectionOptimizerImpl - * - * @param instantiationOptimizer The instantiation optimizer to use - * @param accessOptimizer The property access optimizer to use. - */ - public ReflectionOptimizerImpl( - InstantiationOptimizer instantiationOptimizer, - AccessOptimizer accessOptimizer) { - this.instantiationOptimizer = instantiationOptimizer; - this.accessOptimizer = accessOptimizer; - } - - @Override - public InstantiationOptimizer getInstantiationOptimizer() { - return instantiationOptimizer; - } - - @Override - public AccessOptimizer getAccessOptimizer() { - return accessOptimizer; - } - -} diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/package-info.java b/hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/package-info.java deleted file mode 100644 index 87073b5d461c..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/internal/javassist/package-info.java +++ /dev/null @@ -1,11 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ - -/** - * Javassist support internals - */ -package org.hibernate.bytecode.internal.javassist; diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/spi/ProxyFactoryFactory.java b/hibernate-core/src/main/java/org/hibernate/bytecode/spi/ProxyFactoryFactory.java index 75907cdab814..1fbc5a1a7fad 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/spi/ProxyFactoryFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/spi/ProxyFactoryFactory.java @@ -14,7 +14,7 @@ * An interface for factories of {@link ProxyFactory proxy factory} instances. *

    * Currently used to abstract from the tuplizer whether we are using Byte Buddy or - * Javassist for lazy proxy generation. + * possibly another implementation (in the future?) for lazy proxy generation. * * @author Steve Ebersole */ diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java index 13cb5b8a6f2a..37704d3f5180 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java @@ -1375,9 +1375,8 @@ public interface AvailableSettings extends org.hibernate.jpa.AvailableSettings { */ String CHECK_NULLABILITY = "hibernate.check_nullability"; - /** - * Pick which bytecode enhancing library to use. Currently supports javassist and bytebuddy, bytebuddy being the default since version 5.3. + * Pick which bytecode enhancing library to use. Currently supports only bytebuddy, bytebuddy being the default since version 5.3. */ String BYTECODE_PROVIDER = "hibernate.bytecode.provider"; diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/Environment.java b/hibernate-core/src/main/java/org/hibernate/cfg/Environment.java index 892a07f350ae..8783e4412da5 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/Environment.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/Environment.java @@ -346,8 +346,7 @@ private static BytecodeProvider buildBytecodeProvider(String providerName) { } if ( BYTECODE_PROVIDER_NAME_JAVASSIST.equals( providerName ) ) { - LOG.warnUsingJavassistBytecodeProviderIsDeprecated(); - return new org.hibernate.bytecode.internal.javassist.BytecodeProviderImpl(); + throw LOG.usingRemovedJavassistBytecodeProvider(); } LOG.bytecodeProvider( providerName ); diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/PropertyContainer.java b/hibernate-core/src/main/java/org/hibernate/cfg/PropertyContainer.java index 02e3e50b34ea..2beaeda86c4c 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/PropertyContainer.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/PropertyContainer.java @@ -416,7 +416,6 @@ else if ( p.isAnnotationPresent( Target.class ) ) { private static boolean mustBeSkipped(XProperty property) { //TODO make those hardcoded tests more portable (through the bytecode provider?) return property.isAnnotationPresent( Transient.class ) - || "net.sf.cglib.transform.impl.InterceptFieldCallback".equals( property.getType().getName() ) - || "org.hibernate.bytecode.internal.javassist.FieldHandler".equals( property.getType().getName() ); + || "net.sf.cglib.transform.impl.InterceptFieldCallback".equals( property.getType().getName() ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java b/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java index 3028bbb1805e..b6a5cef95b41 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/CoreMessageLogger.java @@ -1860,9 +1860,7 @@ void attemptToAssociateProxyWithTwoOpenSessions( @Message(value = "Detaching an uninitialized collection with enabled filters from a session: %s", id = 506) void enabledFiltersWhenDetachFromSession(String collectionInfoString); - @LogMessage(level = WARN) - @Message(value = "The Javassist based BytecodeProvider is deprecated. Please switch to using the ByteBuddy based BytecodeProvider, " + - "which is the default since Hibernate ORM 5.3. The Javassist one will be removed soon.", id = 507) - void warnUsingJavassistBytecodeProviderIsDeprecated(); + @Message(value = "The Javassist based BytecodeProvider has been removed: remove the `hibernate.bytecode.provider` configuration property to switch to the default provider", id = 508) + HibernateException usingRemovedJavassistBytecodeProvider(); } diff --git a/hibernate-core/src/main/java/org/hibernate/proxy/pojo/javassist/JavassistLazyInitializer.java b/hibernate-core/src/main/java/org/hibernate/proxy/pojo/javassist/JavassistLazyInitializer.java deleted file mode 100644 index 61b15f09a3e6..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/proxy/pojo/javassist/JavassistLazyInitializer.java +++ /dev/null @@ -1,135 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.proxy.pojo.javassist; - -import java.io.Serializable; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; - -import javassist.util.proxy.MethodHandler; - -import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.internal.CoreMessageLogger; -import org.hibernate.internal.util.ReflectHelper; -import org.hibernate.proxy.pojo.BasicLazyInitializer; -import org.hibernate.type.CompositeType; - -import static org.hibernate.internal.CoreLogging.messageLogger; - -/** - * A Javassist-based lazy initializer proxy. - * - * @author Muga Nishizawa - */ -public class JavassistLazyInitializer extends BasicLazyInitializer implements MethodHandler { - private static final CoreMessageLogger LOG = messageLogger( JavassistLazyInitializer.class ); - - private final Class[] interfaces; - - private boolean constructed; - - public JavassistLazyInitializer( - String entityName, - Class persistentClass, - Class[] interfaces, - Serializable id, - Method getIdentifierMethod, - Method setIdentifierMethod, - CompositeType componentIdType, - SharedSessionContractImplementor session, - boolean overridesEquals) { - super( entityName, persistentClass, id, getIdentifierMethod, setIdentifierMethod, componentIdType, session, overridesEquals ); - this.interfaces = interfaces; - } - - protected void constructed() { - constructed = true; - } - - @Override - public Object invoke( - final Object proxy, - final Method thisMethod, - final Method proceed, - final Object[] args) throws Throwable { - if ( this.constructed ) { - // HHH-10922 - Internal calls to bytecode enhanced methods cause proxy to be initialized - if ( thisMethod.getName().startsWith( "$$_hibernate_" ) ) { - return proceed.invoke( proxy, args ); - } - - Object result; - try { - result = this.invoke( thisMethod, args, proxy ); - } - catch ( Throwable t ) { - throw t instanceof RuntimeException ? t : new Exception( t.getCause() ); - } - if ( result == INVOKE_IMPLEMENTATION ) { - Object target = getImplementation(); - final Object returnValue; - try { - if ( ReflectHelper.isPublic( persistentClass, thisMethod ) ) { - if ( !thisMethod.getDeclaringClass().isInstance( target ) ) { - throw new ClassCastException( - target.getClass().getName() - + " incompatible with " - + thisMethod.getDeclaringClass().getName() - ); - } - returnValue = thisMethod.invoke( target, args ); - } - else { - thisMethod.setAccessible( true ); - returnValue = thisMethod.invoke( target, args ); - } - - if ( returnValue == target ) { - if ( returnValue.getClass().isInstance( proxy ) ) { - return proxy; - } - else { - LOG.narrowingProxy( returnValue.getClass() ); - } - } - return returnValue; - } - catch ( InvocationTargetException ite ) { - throw ite.getTargetException(); - } - } - else { - return result; - } - } - else { - // while constructor is running - if ( thisMethod.getName().equals( "getHibernateLazyInitializer" ) ) { - return this; - } - else { - return proceed.invoke( proxy, args ); - } - } - } - - @Override - protected Object serializableProxy() { - return new SerializableProxy( - getEntityName(), - persistentClass, - interfaces, - getInternalIdentifier(), - ( isReadOnlySettingAvailable() ? Boolean.valueOf( isReadOnly() ) : isReadOnlyBeforeAttachedToSession() ), - getSessionFactoryUuid(), - isAllowLoadOutsideTransaction(), - getIdentifierMethod, - setIdentifierMethod, - componentIdType - ); - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/proxy/pojo/javassist/JavassistProxyFactory.java b/hibernate-core/src/main/java/org/hibernate/proxy/pojo/javassist/JavassistProxyFactory.java deleted file mode 100644 index ce288312585c..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/proxy/pojo/javassist/JavassistProxyFactory.java +++ /dev/null @@ -1,224 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.proxy.pojo.javassist; - -import java.io.Serializable; -import java.lang.reflect.Method; -import java.util.Locale; -import java.util.Set; - -import javassist.util.proxy.MethodFilter; -import javassist.util.proxy.Proxy; - -import org.hibernate.HibernateException; -import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.internal.CoreMessageLogger; -import org.hibernate.internal.util.ReflectHelper; -import org.hibernate.internal.util.collections.ArrayHelper; -import org.hibernate.proxy.HibernateProxy; -import org.hibernate.proxy.ProxyFactory; -import org.hibernate.type.CompositeType; - -import static org.hibernate.internal.CoreLogging.messageLogger; - -/** - * A {@link ProxyFactory} implementation for producing Javassist-based proxies. - * - * @author Muga Nishizawa - */ -public class JavassistProxyFactory implements ProxyFactory, Serializable { - private static final CoreMessageLogger LOG = messageLogger( JavassistProxyFactory.class ); - - private static final MethodFilter EXCLUDE_FILTER = m -> { - // skip finalize methods and Groovy getMetaClass - return !( - m.getParameterCount() == 0 && m.getName().equals( "finalize" ) || ( - m.getName().equals( "getMetaClass" ) && - m.getReturnType().getName().equals( "groovy.lang.MetaClass" ) - ) - ); - }; - - private Class persistentClass; - private String entityName; - private Class[] interfaces; - private Method getIdentifierMethod; - private Method setIdentifierMethod; - private CompositeType componentIdType; - private boolean overridesEquals; - - private Class proxyClass; - - public JavassistProxyFactory() { - } - - @Override - public void postInstantiate( - final String entityName, - final Class persistentClass, - final Set interfaces, - final Method getIdentifierMethod, - final Method setIdentifierMethod, - CompositeType componentIdType) throws HibernateException { - this.entityName = entityName; - this.persistentClass = persistentClass; - this.interfaces = toArray( interfaces ); - this.getIdentifierMethod = getIdentifierMethod; - this.setIdentifierMethod = setIdentifierMethod; - this.componentIdType = componentIdType; - this.overridesEquals = ReflectHelper.overridesEquals( persistentClass ); - - this.proxyClass = buildJavassistProxyFactory().createClass(); - } - - private Class[] toArray(Set interfaces) { - if ( interfaces == null ) { - return ArrayHelper.EMPTY_CLASS_ARRAY; - } - - return interfaces.toArray( new Class[interfaces.size()] ); - } - - private javassist.util.proxy.ProxyFactory buildJavassistProxyFactory() { - return buildJavassistProxyFactory( - persistentClass, - interfaces - ); - } - - public static javassist.util.proxy.ProxyFactory buildJavassistProxyFactory( - final Class persistentClass, - final Class[] interfaces) { - javassist.util.proxy.ProxyFactory factory = new javassist.util.proxy.ProxyFactory() { - @Override - protected ClassLoader getClassLoader() { - return persistentClass.getClassLoader(); - } - }; - factory.setSuperclass( interfaces.length == 1 ? persistentClass : null ); - factory.setInterfaces( interfaces ); - factory.setFilter( EXCLUDE_FILTER ); - return factory; - } - - @Override - public HibernateProxy getProxy( - Serializable id, - SharedSessionContractImplementor session) throws HibernateException { - final JavassistLazyInitializer initializer = new JavassistLazyInitializer( - entityName, - persistentClass, - interfaces, - id, - getIdentifierMethod, - setIdentifierMethod, - componentIdType, - session, - overridesEquals - ); - - try { - final HibernateProxy proxy = (HibernateProxy) proxyClass.getConstructor().newInstance(); - ( (Proxy) proxy ).setHandler( initializer ); - initializer.constructed(); - - return proxy; - } - catch (NoSuchMethodException e) { - String logMessage = LOG.bytecodeEnhancementFailedBecauseOfDefaultConstructor( entityName ); - LOG.error( logMessage, e ); - throw new HibernateException( logMessage, e ); - } - catch (Throwable t) { - String logMessage = LOG.bytecodeEnhancementFailed( entityName ); - LOG.error( logMessage, t ); - throw new HibernateException( logMessage, t ); - } - } - - public static HibernateProxy deserializeProxy(SerializableProxy serializableProxy) { - final JavassistLazyInitializer initializer = new JavassistLazyInitializer( - serializableProxy.getEntityName(), - serializableProxy.getPersistentClass(), - serializableProxy.getInterfaces(), - serializableProxy.getId(), - resolveIdGetterMethod( serializableProxy ), - resolveIdSetterMethod( serializableProxy ), - serializableProxy.getComponentIdType(), - null, - ReflectHelper.overridesEquals( serializableProxy.getPersistentClass() ) - ); - - final javassist.util.proxy.ProxyFactory factory = buildJavassistProxyFactory( - serializableProxy.getPersistentClass(), - serializableProxy.getInterfaces() - ); - - // note: interface is assumed to already contain HibernateProxy.class - try { - final Class proxyClass = factory.createClass(); - final HibernateProxy proxy = ( HibernateProxy ) proxyClass.newInstance(); - ( (Proxy) proxy ).setHandler( initializer ); - initializer.constructed(); - return proxy; - } - catch ( Throwable t ) { - final String message = LOG.bytecodeEnhancementFailed( serializableProxy.getEntityName() ); - LOG.error( message, t ); - throw new HibernateException( message, t ); - } - } - - @SuppressWarnings("unchecked") - private static Method resolveIdGetterMethod(SerializableProxy serializableProxy) { - if ( serializableProxy.getIdentifierGetterMethodName() == null ) { - return null; - } - - try { - return serializableProxy.getIdentifierGetterMethodClass().getDeclaredMethod( serializableProxy.getIdentifierGetterMethodName() ); - } - catch (NoSuchMethodException e) { - throw new HibernateException( - String.format( - Locale.ENGLISH, - "Unable to deserialize proxy [%s, %s]; could not locate id getter method [%s] on entity class [%s]", - serializableProxy.getEntityName(), - serializableProxy.getId(), - serializableProxy.getIdentifierGetterMethodName(), - serializableProxy.getIdentifierGetterMethodClass() - ) - ); - } - } - - @SuppressWarnings("unchecked") - private static Method resolveIdSetterMethod(SerializableProxy serializableProxy) { - if ( serializableProxy.getIdentifierSetterMethodName() == null ) { - return null; - } - - try { - return serializableProxy.getIdentifierSetterMethodClass().getDeclaredMethod( - serializableProxy.getIdentifierSetterMethodName(), - serializableProxy.getIdentifierSetterMethodParams() - ); - } - catch (NoSuchMethodException e) { - throw new HibernateException( - String.format( - Locale.ENGLISH, - "Unable to deserialize proxy [%s, %s]; could not locate id setter method [%s] on entity class [%s]", - serializableProxy.getEntityName(), - serializableProxy.getId(), - serializableProxy.getIdentifierSetterMethodName(), - serializableProxy.getIdentifierSetterMethodClass() - ) - ); - } - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/proxy/pojo/javassist/SerializableProxy.java b/hibernate-core/src/main/java/org/hibernate/proxy/pojo/javassist/SerializableProxy.java deleted file mode 100644 index 3ec55b8182e3..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/proxy/pojo/javassist/SerializableProxy.java +++ /dev/null @@ -1,141 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.proxy.pojo.javassist; - -import java.io.Serializable; -import java.lang.reflect.Method; - -import org.hibernate.proxy.AbstractSerializableProxy; -import org.hibernate.proxy.HibernateProxy; -import org.hibernate.type.CompositeType; - -/** - * Serializable placeholder for Javassist proxies - */ -public final class SerializableProxy extends AbstractSerializableProxy { - private final Class persistentClass; - private final Class[] interfaces; - - private final String identifierGetterMethodName; - private final Class identifierGetterMethodClass; - - private final String identifierSetterMethodName; - private final Class identifierSetterMethodClass; - private final Class[] identifierSetterMethodParams; - - private final CompositeType componentIdType; - - /** - * @deprecated use {@link #SerializableProxy(String, Class, Class[], Serializable, Boolean, String, boolean, Method, Method, CompositeType)} instead. - */ - @Deprecated - public SerializableProxy( - String entityName, - Class persistentClass, - Class[] interfaces, - Serializable id, - Boolean readOnly, - Method getIdentifierMethod, - Method setIdentifierMethod, - CompositeType componentIdType) { - this( - entityName, persistentClass, interfaces, id, readOnly, null, false, - getIdentifierMethod, setIdentifierMethod, componentIdType - ); - } - - public SerializableProxy( - String entityName, - Class persistentClass, - Class[] interfaces, - Serializable id, - Boolean readOnly, - String sessionFactoryUuid, - boolean allowLoadOutsideTransaction, - Method getIdentifierMethod, - Method setIdentifierMethod, - CompositeType componentIdType) { - super( entityName, id, readOnly, sessionFactoryUuid, allowLoadOutsideTransaction ); - this.persistentClass = persistentClass; - this.interfaces = interfaces; - if ( getIdentifierMethod != null ) { - identifierGetterMethodName = getIdentifierMethod.getName(); - identifierGetterMethodClass = getIdentifierMethod.getDeclaringClass(); - } - else { - identifierGetterMethodName = null; - identifierGetterMethodClass = null; - } - - if ( setIdentifierMethod != null ) { - identifierSetterMethodName = setIdentifierMethod.getName(); - identifierSetterMethodClass = setIdentifierMethod.getDeclaringClass(); - identifierSetterMethodParams = setIdentifierMethod.getParameterTypes(); - } - else { - identifierSetterMethodName = null; - identifierSetterMethodClass = null; - identifierSetterMethodParams = null; - } - - this.componentIdType = componentIdType; - } - - @Override - protected String getEntityName() { - return super.getEntityName(); - } - - @Override - protected Serializable getId() { - return super.getId(); - } - - protected Class getPersistentClass() { - return persistentClass; - } - - protected Class[] getInterfaces() { - return interfaces; - } - - protected String getIdentifierGetterMethodName() { - return identifierGetterMethodName; - } - - protected Class getIdentifierGetterMethodClass() { - return identifierGetterMethodClass; - } - - protected String getIdentifierSetterMethodName() { - return identifierSetterMethodName; - } - - protected Class getIdentifierSetterMethodClass() { - return identifierSetterMethodClass; - } - - protected Class[] getIdentifierSetterMethodParams() { - return identifierSetterMethodParams; - } - - protected CompositeType getComponentIdType() { - return componentIdType; - } - - /** - * Deserialization hook. This method is called by JDK deserialization. We use this hook - * to replace the serial form with a live form. - * - * @return The live form. - */ - private Object readResolve() { - HibernateProxy proxy = JavassistProxyFactory.deserializeProxy( this ); - afterDeserialization( ( JavassistLazyInitializer ) proxy.getHibernateLazyInitializer() ); - return proxy; - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/tool/instrument/javassist/InstrumentTask.java b/hibernate-core/src/main/java/org/hibernate/tool/instrument/javassist/InstrumentTask.java deleted file mode 100644 index 45ca9ca98230..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/tool/instrument/javassist/InstrumentTask.java +++ /dev/null @@ -1,34 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.tool.instrument.javassist; - -import org.hibernate.internal.log.DeprecationLogger; -import org.hibernate.tool.enhance.EnhancementTask; - -/** - * This is the legacy Ant-task Hibernate provided historically to - * perform its old-school bytecode instrumentation. That has been replaced wholesale - * with a new approach to bytecode manipulation offering 3 build-time variations for Ant, - * Maven and Gradle. - * - * @author Muga Nishizawa - * @author Steve Ebersole - * - * @deprecated This is the legacy Ant-task Hibernate provided historically to - * perform its old-school bytecode instrumentation. That has been replaced wholesale - * with a new approach to bytecode manipulation offering 3 build-time variations for Ant, - * Maven and Gradle. - * - * @see EnhancementTask - */ -@Deprecated -@SuppressWarnings("unused") -public class InstrumentTask extends EnhancementTask { - public InstrumentTask() { - DeprecationLogger.DEPRECATION_LOGGER.logDeprecatedInstrumentTask( InstrumentTask.class, EnhancementTask.class ); - } -} diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/callbacks/PrivateConstructorTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/callbacks/PrivateConstructorTest.java index c07da949c4c9..6d997d370e5b 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/callbacks/PrivateConstructorTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/callbacks/PrivateConstructorTest.java @@ -23,7 +23,6 @@ import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; import org.hibernate.proxy.ProxyFactory; import org.hibernate.proxy.pojo.bytebuddy.ByteBuddyProxyFactory; -import org.hibernate.proxy.pojo.javassist.JavassistProxyFactory; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.logger.LoggerInspectionRule; @@ -104,9 +103,6 @@ private static Class proxyFactoryClass() { if ( byteCodeProvider == null || Environment.BYTECODE_PROVIDER_NAME_BYTEBUDDY.equals( byteCodeProvider ) ) { return ByteBuddyProxyFactory.class; } - else if ( Environment.BYTECODE_PROVIDER_NAME_JAVASSIST.equals( byteCodeProvider ) ) { - return JavassistProxyFactory.class; - } else { throw new UnsupportedOperationException( "Unknown bytecode provider:" + byteCodeProvider ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/classloader/ProxyInterfaceClassLoaderTest.java b/hibernate-core/src/test/java/org/hibernate/test/classloader/ProxyInterfaceClassLoaderTest.java index 8c3c391ea382..7769040a5363 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/classloader/ProxyInterfaceClassLoaderTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/classloader/ProxyInterfaceClassLoaderTest.java @@ -19,7 +19,7 @@ import org.junit.Test; /** - * Tests if javassist instrumentation is done with the proper classloader for entities with proxy class. The classloader + * Tests if instrumentation is done with the proper classloader for entities with proxy class. The classloader * of {@link HibernateProxy} will not see {@link IPerson}, since it is only accessible from this package. But: the * classloader of {@link IPerson} will see {@link HibernateProxy}, so instrumentation will only work if this classloader * is chosen for creating the instrumented proxy class. We need to check the class of a loaded object though, since diff --git a/hibernate-core/src/testJavassist/java/org/hibernate/test/bytecode/enhancement/javassist/EnhancerFileNotFoundTest.java b/hibernate-core/src/testJavassist/java/org/hibernate/test/bytecode/enhancement/javassist/EnhancerFileNotFoundTest.java deleted file mode 100644 index 38647d1a6f4d..000000000000 --- a/hibernate-core/src/testJavassist/java/org/hibernate/test/bytecode/enhancement/javassist/EnhancerFileNotFoundTest.java +++ /dev/null @@ -1,67 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.bytecode.enhancement.javassist; - -import java.io.FileNotFoundException; -import java.net.URL; -import java.nio.file.Files; -import java.nio.file.Paths; - -import javassist.CtClass; - -import org.hibernate.bytecode.enhance.internal.javassist.EnhancerImpl; -import org.hibernate.bytecode.enhance.spi.DefaultEnhancementContext; -import org.hibernate.bytecode.enhance.spi.EnhancementContext; - -import org.hibernate.testing.TestForIssue; -import org.junit.Test; - -import static org.junit.Assert.assertSame; -import static org.junit.Assert.fail; - -/** - * @author Vlad Mihalcea - */ -public class EnhancerFileNotFoundTest { - - @Test - @TestForIssue( jiraKey = "HHH-11307" ) - public void test() throws Exception { - Enhancer enhancer = new Enhancer( new DefaultEnhancementContext() ); - try { - String resourceName = Hidden.class.getName().replace( '.', '/' ) + ".class"; - URL url = getClass().getClassLoader().getResource( resourceName ); - if ( url != null ) { - Files.delete( Paths.get( url.toURI() ) ); - enhancer.loadCtClassFromClass( Hidden.class ); - } - fail( "Should throw FileNotFoundException!" ); - } catch ( Exception expected ) { - assertSame( FileNotFoundException.class, expected.getCause().getClass() ); - } - } - - // --- // - - private static class Enhancer extends EnhancerImpl { - - public Enhancer(EnhancementContext enhancementContext) { - super( enhancementContext ); - } - - @Override - // change visibility protected -> public - public CtClass loadCtClassFromClass(Class aClass) { - return super.loadCtClassFromClass( aClass ); - } - } - - // --- // - - private static class Hidden { - } -} diff --git a/hibernate-core/src/testJavassist/java/org/hibernate/test/bytecode/javassist/Bean.java b/hibernate-core/src/testJavassist/java/org/hibernate/test/bytecode/javassist/Bean.java deleted file mode 100644 index 5049283aa7ef..000000000000 --- a/hibernate-core/src/testJavassist/java/org/hibernate/test/bytecode/javassist/Bean.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.bytecode.javassist; -import java.text.ParseException; -import java.util.Date; - -/** - * @author Steve Ebersole - */ -public class Bean { - private String someString; - private Long someLong; - private Integer someInteger; - private Date someDate; - private long somelong; - private int someint; - private Object someObject; - - - public String getSomeString() { - return someString; - } - - public void setSomeString(String someString) { - this.someString = someString; - } - - public Long getSomeLong() { - return someLong; - } - - public void setSomeLong(Long someLong) { - this.someLong = someLong; - } - - public Integer getSomeInteger() { - return someInteger; - } - - public void setSomeInteger(Integer someInteger) { - this.someInteger = someInteger; - } - - public Date getSomeDate() { - return someDate; - } - - public void setSomeDate(Date someDate) { - this.someDate = someDate; - } - - public long getSomelong() { - return somelong; - } - - public void setSomelong(long somelong) { - this.somelong = somelong; - } - - public int getSomeint() { - return someint; - } - - public void setSomeint(int someint) { - this.someint = someint; - } - - public Object getSomeObject() { - return someObject; - } - - public void setSomeObject(Object someObject) { - this.someObject = someObject; - } - - public void throwException() throws ParseException { - throw new ParseException( "you asked for it...", 0 ); - } -} diff --git a/hibernate-core/src/testJavassist/java/org/hibernate/test/bytecode/javassist/BeanReflectionHelper.java b/hibernate-core/src/testJavassist/java/org/hibernate/test/bytecode/javassist/BeanReflectionHelper.java deleted file mode 100644 index a7711524095c..000000000000 --- a/hibernate-core/src/testJavassist/java/org/hibernate/test/bytecode/javassist/BeanReflectionHelper.java +++ /dev/null @@ -1,92 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.bytecode.javassist; -import java.util.Date; - -import org.hibernate.property.access.internal.PropertyAccessStrategyBasicImpl; -import org.hibernate.property.access.spi.Getter; -import org.hibernate.property.access.spi.PropertyAccess; -import org.hibernate.property.access.spi.Setter; - -/** - * @author Steve Ebersole - */ -public class BeanReflectionHelper { - - public static final Object[] TEST_VALUES = new Object[] { - "hello", new Long(1), new Integer(1), new Date(), new Long(1), new Integer(1), new Object() - }; - - private static final String[] getterNames = new String[7]; - private static final String[] setterNames = new String[7]; - private static final Class[] types = new Class[7]; - - static { - final PropertyAccessStrategyBasicImpl propertyAccessStrategy = new PropertyAccessStrategyBasicImpl(); - - PropertyAccess propertyAccess = propertyAccessStrategy.buildPropertyAccess( Bean.class, "someString" ); - Getter getter = propertyAccess.getGetter(); - Setter setter = propertyAccess.getSetter(); - getterNames[0] = getter.getMethodName(); - types[0] = getter.getReturnType(); - setterNames[0] = setter.getMethodName(); - - propertyAccess = propertyAccessStrategy.buildPropertyAccess( Bean.class, "someLong" ); - getter = propertyAccess.getGetter(); - setter = propertyAccess.getSetter(); - getterNames[1] = getter.getMethodName(); - types[1] = getter.getReturnType(); - setterNames[1] = setter.getMethodName(); - - propertyAccess = propertyAccessStrategy.buildPropertyAccess( Bean.class, "someInteger" ); - getter = propertyAccess.getGetter(); - setter = propertyAccess.getSetter(); - getterNames[2] = getter.getMethodName(); - types[2] = getter.getReturnType(); - setterNames[2] = setter.getMethodName(); - - propertyAccess = propertyAccessStrategy.buildPropertyAccess( Bean.class, "someDate" ); - getter = propertyAccess.getGetter(); - setter = propertyAccess.getSetter(); - getterNames[3] = getter.getMethodName(); - types[3] = getter.getReturnType(); - setterNames[3] = setter.getMethodName(); - - propertyAccess = propertyAccessStrategy.buildPropertyAccess( Bean.class, "somelong" ); - getter = propertyAccess.getGetter(); - setter = propertyAccess.getSetter(); - getterNames[4] = getter.getMethodName(); - types[4] = getter.getReturnType(); - setterNames[4] = setter.getMethodName(); - - propertyAccess = propertyAccessStrategy.buildPropertyAccess( Bean.class, "someint" ); - getter = propertyAccess.getGetter(); - setter = propertyAccess.getSetter(); - getterNames[5] = getter.getMethodName(); - types[5] = getter.getReturnType(); - setterNames[5] = setter.getMethodName(); - - propertyAccess = propertyAccessStrategy.buildPropertyAccess( Bean.class, "someObject" ); - getter = propertyAccess.getGetter(); - setter = propertyAccess.getSetter(); - getterNames[6] = getter.getMethodName(); - types[6] = getter.getReturnType(); - setterNames[6] = setter.getMethodName(); - } - - public static String[] getGetterNames() { - return getterNames; - } - - public static String[] getSetterNames() { - return setterNames; - } - - public static Class[] getTypes() { - return types; - } -} diff --git a/hibernate-core/src/testJavassist/java/org/hibernate/test/bytecode/javassist/BulkAccessorTest.java b/hibernate-core/src/testJavassist/java/org/hibernate/test/bytecode/javassist/BulkAccessorTest.java deleted file mode 100644 index a513e6d925a9..000000000000 --- a/hibernate-core/src/testJavassist/java/org/hibernate/test/bytecode/javassist/BulkAccessorTest.java +++ /dev/null @@ -1,30 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ -package org.hibernate.test.bytecode.javassist; - -import org.hibernate.bytecode.internal.javassist.BulkAccessor; - -import org.hibernate.testing.junit4.BaseUnitTestCase; -import org.junit.Test; - -/** - * @author Steve Ebersole - */ -// Extracted from org.hibernate.test.bytecode.ReflectionOptimizerTest. -// I (Yoann) don't know what this tests does, but it's definitely specific to javassist. -public class BulkAccessorTest extends BaseUnitTestCase { - - @Test - public void testBulkAccessorDirectly() { - BulkAccessor bulkAccessor = BulkAccessor.create( - Bean.class, - BeanReflectionHelper.getGetterNames(), - BeanReflectionHelper.getSetterNames(), - BeanReflectionHelper.getTypes() - ); - } -} diff --git a/hibernate-envers-jakarta/hibernate-envers-jakarta.gradle b/hibernate-envers-jakarta/hibernate-envers-jakarta.gradle index 9e1e109c9f40..0a72f9ef9d08 100644 --- a/hibernate-envers-jakarta/hibernate-envers-jakarta.gradle +++ b/hibernate-envers-jakarta/hibernate-envers-jakarta.gradle @@ -16,10 +16,7 @@ configurations { } dependencies { - compile( project( ':hibernate-core-jakarta' ) ) { - // Exclude access to this to avoid future use. - exclude group: "org.javassist", module: "javassist" - } + compile( project( ':hibernate-core-jakarta' ) ) jakartaeeTransformJars 'biz.aQute.bnd:biz.aQute.bnd.transform:5.1.1', 'commons-cli:commons-cli:1.4', @@ -100,4 +97,4 @@ test { jvmArgs( ['--add-opens', 'java.base/java.security=ALL-UNNAMED'] ) jvmArgs( ['--add-opens', 'java.base/java.lang=ALL-UNNAMED'] ) } -} \ No newline at end of file +} diff --git a/hibernate-envers/hibernate-envers.gradle b/hibernate-envers/hibernate-envers.gradle index 005453e9183a..f168ec015af4 100644 --- a/hibernate-envers/hibernate-envers.gradle +++ b/hibernate-envers/hibernate-envers.gradle @@ -11,10 +11,7 @@ apply from: rootProject.file( 'gradle/published-java-module.gradle' ) apply plugin: 'hibernate-matrix-testing' dependencies { - compile( project( ':hibernate-core' ) ) { - // Exclude access to this to avoid future use. - exclude group: "org.javassist", module: "javassist" - } + compile( project( ':hibernate-core' ) ) // TODO HHH-13703: get rid of this dependency compile( libraries.dom4j ) diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/internal/tools/EntityTools.java b/hibernate-envers/src/main/java/org/hibernate/envers/internal/tools/EntityTools.java index 5a287c17577b..a21a7fa8033a 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/internal/tools/EntityTools.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/internal/tools/EntityTools.java @@ -77,7 +77,7 @@ public static Class getTargetClassIfProxied(Class clazz) { return null; } else if ( HibernateProxy.class.isAssignableFrom( clazz ) ) { - // Get the source class of Javassist proxy instance. + // Get the source class of the proxy instance. return (Class) clazz.getSuperclass(); } return clazz; diff --git a/hibernate-integrationtest-java-modules/src/test/java/module-info.java b/hibernate-integrationtest-java-modules/src/test/java/module-info.java index d6fdab1efd00..f4108d62393e 100644 --- a/hibernate-integrationtest-java-modules/src/test/java/module-info.java +++ b/hibernate-integrationtest-java-modules/src/test/java/module-info.java @@ -10,9 +10,7 @@ * Main configuration, necessary for real client applications. */ - opens org.hibernate.orm.integrationtest.java.module.test.entity to - org.hibernate.orm.core, - javassist; // Necessary for javassist, but not for bytebuddy (the default) + opens org.hibernate.orm.integrationtest.java.module.test.entity to org.hibernate.orm.core; requires java.persistence; // IDEA will not find the modules below because it apparently doesn't support automatic module names @@ -31,4 +29,5 @@ opens org.hibernate.orm.integrationtest.java.module.test to junit; requires junit; -} \ No newline at end of file +} + diff --git a/hibernate-micrometer/hibernate-micrometer.gradle b/hibernate-micrometer/hibernate-micrometer.gradle index dccd513b6834..10f92073a831 100644 --- a/hibernate-micrometer/hibernate-micrometer.gradle +++ b/hibernate-micrometer/hibernate-micrometer.gradle @@ -21,11 +21,4 @@ sourceSets { setSrcDirs( ['src/test/java','src/test/resources'] ) } } - - testJavassist { - java { - compileClasspath += main.output + test.output - runtimeClasspath += main.output + test.output - } - } } diff --git a/hibernate-osgi/src/test/java/org/hibernate/osgi/test/OsgiIntegrationTest.java b/hibernate-osgi/src/test/java/org/hibernate/osgi/test/OsgiIntegrationTest.java index 644fd33134c8..0aa15cfa6c19 100644 --- a/hibernate-osgi/src/test/java/org/hibernate/osgi/test/OsgiIntegrationTest.java +++ b/hibernate-osgi/src/test/java/org/hibernate/osgi/test/OsgiIntegrationTest.java @@ -168,7 +168,6 @@ public TestProbeBuilder probeConfiguration(TestProbeBuilder probe) { // // and use defined imports instead // probe.setHeader( // Constants.IMPORT_PACKAGE, -// "javassist.util.proxy" // + ",javax.persistence" // + ",javax.persistence.spi" // + ",org.h2" diff --git a/release/release.gradle b/release/release.gradle index ee6ae330fb56..7c95227d6879 100644 --- a/release/release.gradle +++ b/release/release.gradle @@ -144,8 +144,6 @@ distributions { from parent.project( 'hibernate-core' ).configurations.provided.files { dep -> dep.name == 'jta' } from parent.project( 'hibernate-core' ).configurations.runtime from parent.project( 'hibernate-core' ).configurations.archives.allArtifacts.files.filter{ file -> !file.name.endsWith('-sources.jar') } - // for now, - from parent.project( 'hibernate-core' ).configurations.provided.files { dep -> dep.name == 'javassist' } } // into( 'lib/jpa' ) { diff --git a/tooling/hibernate-enhance-maven-plugin/hibernate-enhance-maven-plugin.gradle b/tooling/hibernate-enhance-maven-plugin/hibernate-enhance-maven-plugin.gradle index 7b5f2e0180ad..50853ae0a25e 100644 --- a/tooling/hibernate-enhance-maven-plugin/hibernate-enhance-maven-plugin.gradle +++ b/tooling/hibernate-enhance-maven-plugin/hibernate-enhance-maven-plugin.gradle @@ -27,7 +27,6 @@ dependencies { compile( libraries.maven_plugin_tools ) { transitive = false } compile( project(':hibernate-core') ) { transitive = false } compile( libraries.jpa ) { transitive = false } - compile( libraries.javassist ) { transitive = false } compile( libraries.byteBuddy ) { transitive = false } compile 'org.codehaus.plexus:plexus-utils:3.0.24' compile 'org.sonatype.plexus:plexus-build-api:0.0.7' @@ -38,7 +37,6 @@ dependencies { runtime( project(':hibernate-core') ) runtime( libraries.jpa ) runtime( libraries.jta ) - runtime( libraries.javassist ) runtime( libraries.byteBuddy ) runtime 'org.codehaus.plexus:plexus-utils:3.0.24' } @@ -57,7 +55,6 @@ task processPluginXml(type: Copy) { + generateMavenDependency(libraries.antlr)\ + generateMavenDependency(libraries.jta)\ + generateMavenDependency(libraries.commons_annotations)\ - + generateMavenDependency(libraries.javassist)\ + generateMavenDependency(libraries.byteBuddy)\ + generateMavenDependency(libraries.logging)\ + generateMavenDependency("org.hibernate:hibernate-core:" + project.version)]) diff --git a/tooling/hibernate-gradle-plugin/hibernate-gradle-plugin.gradle b/tooling/hibernate-gradle-plugin/hibernate-gradle-plugin.gradle index 2d10c66dc582..98a470d1c89b 100644 --- a/tooling/hibernate-gradle-plugin/hibernate-gradle-plugin.gradle +++ b/tooling/hibernate-gradle-plugin/hibernate-gradle-plugin.gradle @@ -16,7 +16,6 @@ apply plugin: 'maven' dependencies { compile( project( ':hibernate-core' ) ) compile( libraries.jpa ) - compile( libraries.javassist ) compile( libraries.byteBuddy ) compile gradleApi() compile localGroovy() From 8f3cd7476d667f32c435de08c98029c187a22fa3 Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Fri, 27 Aug 2021 09:34:52 +0000 Subject: [PATCH 295/644] 5.6.0.Beta1 --- changelog.txt | 10 ++++++++++ gradle/version.properties | 2 +- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 2eff0cc75cfc..3b5e99fe0bfc 100644 --- a/changelog.txt +++ b/changelog.txt @@ -3,6 +3,16 @@ Hibernate 5 Changelog Note: Please refer to JIRA to learn more about each issue. +Changes in 5.6.0.Beta1 (August 27, 2021) +------------------------------------------------------------------------------------------------------------------------ + +https://hibernate.atlassian.net/projects/HHH/versions/31974 + +** Task + * [HHH-14792] - Remove support for bytecode enhancement via Javassist + * [HHH-14744] - Refactor contextual information for SchemaManagementTool to be more easily extended by Hibernate Reactive + + Changes in 5.5.7.Final (August 25, 2021) ------------------------------------------------------------------------------------------------------------------------ diff --git a/gradle/version.properties b/gradle/version.properties index b6875391f169..5407ba1b4a18 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -hibernateVersion=5.6.0-SNAPSHOT \ No newline at end of file +hibernateVersion=5.6.0.Beta1 \ No newline at end of file From 5e4b3bd32173b685c3a6c57daf18f5ddcfef3793 Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Fri, 27 Aug 2021 09:39:27 +0000 Subject: [PATCH 296/644] 5.6.0-SNAPSHOT --- gradle/version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/version.properties b/gradle/version.properties index 5407ba1b4a18..b6875391f169 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -hibernateVersion=5.6.0.Beta1 \ No newline at end of file +hibernateVersion=5.6.0-SNAPSHOT \ No newline at end of file From ae80deb63c4150552b255ec15bb679db95aec0b6 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Fri, 27 Aug 2021 15:22:59 +0100 Subject: [PATCH 297/644] Upgrade the Migration Guide for 5.6 --- migration-guide.adoc | 28 ++++++++++------------------ 1 file changed, 10 insertions(+), 18 deletions(-) diff --git a/migration-guide.adoc b/migration-guide.adoc index e2700b165ed2..6e038bba594c 100644 --- a/migration-guide.adoc +++ b/migration-guide.adoc @@ -1,29 +1,21 @@ -= 5.5 Migration Guide += 5.6 Migration Guide :toc: -This guide discusses migration from Hibernate ORM version 5.4 to version 5.5. For migration from -earlier versions, see any other pertinent migration guides as well. - -== Background +This guide discusses migration from Hibernate ORM version 5.5 to version 5.5. +For migration from other versions, see https://github.com/hibernate/hibernate-orm/wiki/Migration-Guides . == Known changes -This version is very similar to Hibernate ORM 5.4; essentially it includes all bugfixes that have been -applied to the 5.4 maintenance releases, and on top of this it introduces support for the Jakarta Persistence -API (in addition the the JPA APIs we already support). - +This version is very similar to Hibernate ORM 5.5, with the exception of having removed some long standing deprecated features. -=== Dom4J based XML mapping +=== Javassist removed -The implementation of Hibernate's parsing of XML mapping definitions has been entirely reimplemented based on -JAXB rather than DOM4J, making progress to remove this ancient dependency. -No specific issues are known at this time. +It is no longer an option to choose Javassist as implementation used for the bytecode enhancement of entities. +Byte Buddy has been the default for some time, and Javassist has been deprecated for some time and now has been removed. -=== Removed the ability to disable "enhanced proxies" +This should have no functional impact on applications; the only exception being that it's not longer valid to +configure `hibernate.bytecode.provider=javassist`: remove the property if you're using this. -The "enhanced proxies" feature has been introduced as a performance improving feature in 5.3 initially, at -which time it was optional. +A side effect is that Hibenate ORM no longer lists javassist among its dependencies. -Since then, many more corner cases have been fixed and this feature is now always enabled. Enjoy the improvements! -No changes are expected to be needed in user code to benefit from this. From fe1f89d75453f0e3f80328013735894537050276 Mon Sep 17 00:00:00 2001 From: Karel Maesen Date: Sat, 28 Aug 2021 13:58:39 +0200 Subject: [PATCH 298/644] HHH-14633 Upgrade geolatte-geom to 1.8.2 --- gradle/libraries.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libraries.gradle b/gradle/libraries.gradle index 7923d39e2cab..7af725942f6a 100644 --- a/gradle/libraries.gradle +++ b/gradle/libraries.gradle @@ -30,7 +30,7 @@ ext { assertjVersion = '3.14.0' - geolatteVersion = '1.8.0' + geolatteVersion = '1.8.2' shrinkwrapVersion = '1.2.6' shrinkwrapDescriptorsVersion = '2.0.0' From 3edad14c181dada98606119a9e635a2ba88b1159 Mon Sep 17 00:00:00 2001 From: Karel Maesen Date: Sat, 28 Aug 2021 14:16:56 +0200 Subject: [PATCH 299/644] HHH-14757 Use geolatte's JTSUtils --- .../JTSGeometryJavaTypeDescriptor.java | 2 +- .../org/hibernate/spatial/jts/JTSUtils.java | 132 ------------------ .../spatial/geometry/JTSUtilsTest.java | 35 +++++ 3 files changed, 36 insertions(+), 133 deletions(-) delete mode 100644 hibernate-spatial/src/main/java/org/hibernate/spatial/jts/JTSUtils.java create mode 100644 hibernate-spatial/src/test/java/org/hibernate/spatial/geometry/JTSUtilsTest.java diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/JTSGeometryJavaTypeDescriptor.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/JTSGeometryJavaTypeDescriptor.java index 535c6fc8e2d4..26804e24c8c9 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/JTSGeometryJavaTypeDescriptor.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/JTSGeometryJavaTypeDescriptor.java @@ -9,11 +9,11 @@ import java.util.Locale; -import org.hibernate.spatial.jts.JTSUtils; import org.hibernate.type.descriptor.WrapperOptions; import org.hibernate.type.descriptor.java.AbstractTypeDescriptor; import org.hibernate.type.descriptor.java.JavaTypeDescriptor; +import org.geolatte.geom.jts.JTSUtils; import org.locationtech.jts.geom.Geometry; import org.locationtech.jts.io.ParseException; import org.locationtech.jts.io.WKTReader; diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/jts/JTSUtils.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/jts/JTSUtils.java deleted file mode 100644 index 8a4507b456e7..000000000000 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/jts/JTSUtils.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later. - * See the lgpl.txt file in the root directory or . - */ - -package org.hibernate.spatial.jts; - - -//Note that this Utility class will be available directly from -// geolatte-geom 1.9 - - -import org.locationtech.jts.geom.Coordinate; -import org.locationtech.jts.geom.Geometry; -import org.locationtech.jts.geom.LineString; -import org.locationtech.jts.geom.Point; -import org.locationtech.jts.geom.Polygon; - -/** - * Some utility functions for working with JTS geometries - */ -public class JTSUtils { - - private JTSUtils() { - } - - /** - * Determines equality between geometries taking into - * account all coordinates, and the SRID. - *

    - * This is used e.g. for Dirty-checking of geometry values - * in Hibernate - * - * @param g1 - * @param g2 - * - * @return - */ - public static boolean equalsExact3D(Geometry g1, Geometry g2) { - if ( g1 == g2 ) { - return true; - } - if ( g1 == null || g2 == null ) { - return false; - } - if ( !g1.getGeometryType().equals( g2.getGeometryType() ) ) { - return false; - } - if ( g1.getSRID() != g2.getSRID() ) { - return false; - } - - //empty geometries of the same type are the same - if ( g1.isEmpty() && g2.isEmpty() ) { - return true; - } - - int ng1 = g1.getNumGeometries(); - int ng2 = g2.getNumGeometries(); - if ( ng1 != ng2 ) { - return false; - } - - if ( ng1 == 1 ) { - return equals3DPrimitiveGeometries( g1, g2 ); - } - - return equalComponentGeometries( g1, g2, ng1 ); - } - - private static boolean equalComponentGeometries(Geometry g1, Geometry g2, int ng1) { - for ( int gIdx = 0; gIdx < ng1; gIdx++ ) { - if ( !equalsExact3D( g1.getGeometryN( gIdx ), g2.getGeometryN( gIdx ) ) ) { - return false; - } - } - return true; - } - - public static boolean equals3D(Coordinate c1, Coordinate c2) { - return c1.x == c2.x && c1.y == c2.y && - ( ( Double.isNaN( c1.z ) && Double.isNaN( c2.z ) ) || c1.z == c2.z ) && - ( ( Double.isNaN( c1.getM() ) && Double.isNaN( c2.getM() ) ) || c1.getM() == c2.getM() ); - } - - private static boolean equalLineStringCoordinates(LineString g1, LineString g2) { - int np1 = g1.getNumPoints(); - int np2 = g2.getNumPoints(); - if ( np1 != np2 ) { - return false; - } - for ( int i = 0; i < np1; i++ ) { - if ( !equalsExact3D( g1.getPointN( i ), g2.getPointN( i ) ) ) { - return false; - } - } - return true; - } - - private static boolean equalPolygonCoordinates(Polygon g1, Polygon g2) { - int nr1 = g1.getNumInteriorRing(); - int nr2 = g2.getNumInteriorRing(); - if ( nr1 != nr2 ) { - return false; - } - for ( int i = 0; i < nr1; i++ ) { - if ( !equalLineStringCoordinates( g1.getInteriorRingN( i ), g2.getInteriorRingN( i ) ) ) { - return false; - } - } - return equalLineStringCoordinates( g1.getExteriorRing(), g2.getExteriorRing() ); - } - - private static boolean equals3DPrimitiveGeometries(Geometry g1, Geometry g2) { - //this method assumes that g1 and g2 are of the same type - assert ( g1.getClass().equals( g2.getClass() ) ); - if ( g1 instanceof Point ) { - return equals3D( g1.getCoordinate(), g2.getCoordinate() ); - } - - if ( g1 instanceof LineString ) { - return equalLineStringCoordinates( (LineString) g1, (LineString) g2 ); - } - - if ( g1 instanceof Polygon ) { - return equalPolygonCoordinates( (Polygon) g1, (Polygon) g2 ); - } - throw new IllegalStateException( "Only simple geometries should be used" ); - } -} diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/geometry/JTSUtilsTest.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/geometry/JTSUtilsTest.java new file mode 100644 index 000000000000..300aae732bcd --- /dev/null +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/geometry/JTSUtilsTest.java @@ -0,0 +1,35 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ + +package org.hibernate.spatial.geometry; + +import org.hibernate.testing.TestForIssue; +import org.junit.Ignore; +import org.junit.Test; + +import org.geolatte.geom.codec.Wkt; +import org.geolatte.geom.jts.JTS; +import org.locationtech.jts.geom.Geometry; +import org.geolatte.geom.jts.JTSUtils; + +import static org.junit.Assert.assertTrue; + +public class JTSUtilsTest { + + @Test + @TestForIssue(jiraKey = "HHH-14757") + public void testGeometryCollection() { + Geometry elem2a = JTS.to( Wkt.fromWkt( "GEOMETRYCOLLECTION(POINT(2 3),LINESTRING(2 3,3 4))" ) ); + Geometry elem2b = JTS.to( Wkt.fromWkt( "GEOMETRYCOLLECTION(POINT(2 3),LINESTRING(2 3,3 4))" ) ); + Geometry elem1a = JTS.to( Wkt.fromWkt( "GEOMETRYCOLLECTION(POINT(2 3))" ) ); + Geometry elem1b = JTS.to( Wkt.fromWkt( "GEOMETRYCOLLECTION(POINT(2 3))" ) ); + + assertTrue( JTSUtils.equalsExact3D( elem2a, elem2b ) ); + assertTrue( JTSUtils.equalsExact3D( elem1a, elem1b ) ); + } + +} From 2cbcf152df8a9ed28091ca74674961ee0f9fb0c3 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Mon, 6 Sep 2021 10:28:27 +0100 Subject: [PATCH 300/644] HHH-14812 Upgrade integration tests to use Oracle JDBC driver v 21.3.0.0 --- gradle/libraries.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libraries.gradle b/gradle/libraries.gradle index 7af725942f6a..b3f6ccdc05d1 100644 --- a/gradle/libraries.gradle +++ b/gradle/libraries.gradle @@ -129,7 +129,7 @@ ext { mariadb: 'org.mariadb.jdbc:mariadb-java-client:2.2.3', cockroachdb: 'org.postgresql:postgresql:42.2.8', - oracle: 'com.oracle.database.jdbc:ojdbc8:21.1.0.0', + oracle: 'com.oracle.database.jdbc:ojdbc8:21.3.0.0', mssql: 'com.microsoft.sqlserver:mssql-jdbc:7.2.1.jre8', db2: 'com.ibm.db2:jcc:11.5.4.0', hana: 'com.sap.cloud.db.jdbc:ngdbc:2.4.59', From 30a5acf74115aabeb9470094a9734ee565787807 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Mon, 6 Sep 2021 11:30:09 +0200 Subject: [PATCH 301/644] HHH-14811 Test loading a lazy association on a deleted entity with bytecode enhancement --- ...nhancedLazyLoadingOnDeletedEntityTest.java | 149 ++++++++++++++++++ 1 file changed, 149 insertions(+) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/BytecodeEnhancedLazyLoadingOnDeletedEntityTest.java diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/BytecodeEnhancedLazyLoadingOnDeletedEntityTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/BytecodeEnhancedLazyLoadingOnDeletedEntityTest.java new file mode 100644 index 000000000000..16e086b47786 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/BytecodeEnhancedLazyLoadingOnDeletedEntityTest.java @@ -0,0 +1,149 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.test.bytecode.enhancement.lazy.proxy; + +import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; + +import java.util.ArrayList; +import java.util.List; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.ManyToMany; +import javax.persistence.Table; + +import org.hibernate.LazyInitializationException; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; +import org.hibernate.testing.bytecode.enhancement.EnhancementOptions; +import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; +import org.junit.After; +import org.junit.Test; +import org.junit.runner.RunWith; + +@TestForIssue(jiraKey = "HHH-14811") +@RunWith(BytecodeEnhancerRunner.class) +@EnhancementOptions(lazyLoading = true) +public class BytecodeEnhancedLazyLoadingOnDeletedEntityTest + extends BaseNonConfigCoreFunctionalTestCase { + + @Override + public Class[] getAnnotatedClasses() { + return new Class[] { AssociationOwner.class, AssociationNonOwner.class }; + } + + @After + public void tearDown() { + doInHibernate( this::sessionFactory, s -> { + s.createQuery( "delete from AOwner" ).executeUpdate(); + s.createQuery( "delete from ANonOwner" ).executeUpdate(); + } ); + } + + @Test + public void accessUnloadedLazyAssociationOnDeletedOwner() { + inTransaction( s -> { + AssociationOwner owner = new AssociationOwner(); + owner.setId( 1 ); + for ( int i = 0; i < 2; i++ ) { + AssociationNonOwner nonOwner = new AssociationNonOwner(); + nonOwner.setId( i ); + s.persist( nonOwner ); + nonOwner.getOwners().add( owner ); + owner.getNonOwners().add( nonOwner ); + } + s.persist( owner ); + } ); + assertThatThrownBy( () -> inTransaction( session -> { + AssociationOwner owner = session.load( AssociationOwner.class, 1 ); + session.delete( owner ); + session.flush(); + owner.getNonOwners().size(); + } ) ) + .isInstanceOf( LazyInitializationException.class ) + .hasMessageContaining( + "Could not locate EntityEntry for the collection owner in the PersistenceContext" ); + } + + @Test + public void accessUnloadedLazyAssociationOnDeletedNonOwner() { + inTransaction( s -> { + AssociationNonOwner nonOwner = new AssociationNonOwner(); + nonOwner.setId( 1 ); + s.persist( nonOwner ); + } ); + assertThatThrownBy( () -> inTransaction( session -> { + AssociationNonOwner nonOwner = session.load( AssociationNonOwner.class, 1 ); + session.delete( nonOwner ); + session.flush(); + nonOwner.getOwners().size(); + } ) ) + .isInstanceOf( LazyInitializationException.class ) + .hasMessageContaining( + "Could not locate EntityEntry for the collection owner in the PersistenceContext" ); + } + + @Entity(name = "AOwner") + @Table + private static class AssociationOwner { + + @Id + Integer id; + + @ManyToMany(fetch = FetchType.LAZY) + List nonOwners = new ArrayList<>(); + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public List getNonOwners() { + return nonOwners; + } + + public void setNonOwners( + List nonOwners) { + this.nonOwners = nonOwners; + } + } + + @Entity(name = "ANonOwner") + @Table + private static class AssociationNonOwner { + + @Id + Integer id; + + @ManyToMany(mappedBy = "nonOwners", fetch = FetchType.LAZY) + List owners = new ArrayList<>(); + + AssociationNonOwner() { + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public List getOwners() { + return owners; + } + + public void setOwners(List owners) { + this.owners = owners; + } + } +} \ No newline at end of file From 3810727f5d4dbd6c0f4e8b8c84a1ef2dc1377ce2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Mon, 6 Sep 2021 11:30:34 +0200 Subject: [PATCH 302/644] HHH-14811 Throw LazyInitializationException on lazy-loading an association on a deleted entity with bytecode enhancement --- .../hibernate/persister/entity/AbstractEntityPersister.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index 61a2b609ce63..fbd6be954474 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -29,6 +29,7 @@ import org.hibernate.FetchMode; import org.hibernate.HibernateException; import org.hibernate.JDBCException; +import org.hibernate.LazyInitializationException; import org.hibernate.LockMode; import org.hibernate.LockOptions; import org.hibernate.MappingException; @@ -1149,8 +1150,9 @@ public Object initializeLazyProperty(String fieldName, Object entity, SharedSess // for the collection to the just loaded collection final EntityEntry ownerEntry = persistenceContext.getEntry( entity ); if ( ownerEntry == null ) { - // not good - throw new AssertionFailure( + // the entity is not in the session; it was probably deleted, + // so we cannot load the collection anymore. + throw new LazyInitializationException( "Could not locate EntityEntry for the collection owner in the PersistenceContext" ); } From 971a47d15d8ab23064de0689d7707b4b3b288a0a Mon Sep 17 00:00:00 2001 From: Gavin King Date: Sun, 5 Sep 2021 14:08:23 +0200 Subject: [PATCH 303/644] expose two operations on EntityType for use by Hibernate Reactive see https://github.com/hibernate/hibernate-reactive/pull/954 --- .../java/org/hibernate/type/EntityType.java | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/type/EntityType.java b/hibernate-core/src/main/java/org/hibernate/type/EntityType.java index 577134dc7851..e9f4583a696a 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/EntityType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/EntityType.java @@ -488,7 +488,7 @@ public Type getSemiResolvedType(SessionFactoryImplementor factory) { return getAssociatedEntityPersister( factory ).getIdentifierType(); } - protected EntityPersister getAssociatedEntityPersister(final SessionFactoryImplementor factory) { + public EntityPersister getAssociatedEntityPersister(final SessionFactoryImplementor factory) { final EntityPersister persister = associatedEntityPersister; //The following branch implements a simple lazy-initialization, but rather than the canonical //form it returns the local variable to avoid a second volatile read: associatedEntityPersister @@ -503,7 +503,7 @@ protected EntityPersister getAssociatedEntityPersister(final SessionFactoryImple } protected final Object getIdentifier(Object value, SharedSessionContractImplementor session) throws HibernateException { - if ( isReferenceToPrimaryKey() || uniqueKeyPropertyName == null ) { + if ( isReferenceToIdentifierProperty() ) { return ForeignKeys.getEntityIdentifierIfNotUnsaved( getAssociatedEntityName(), value, @@ -639,7 +639,7 @@ Type getIdentifierType(final SharedSessionContractImplementor session) { * or unique key property name. */ public final Type getIdentifierOrUniqueKeyType(Mapping factory) throws MappingException { - if ( isReferenceToPrimaryKey() || uniqueKeyPropertyName == null ) { + if ( isReferenceToIdentifierProperty() ) { return getIdentifierType( factory ); } else { @@ -663,12 +663,14 @@ public final Type getIdentifierOrUniqueKeyType(Mapping factory) throws MappingEx */ public final String getIdentifierOrUniqueKeyPropertyName(Mapping factory) throws MappingException { - if ( isReferenceToPrimaryKey() || uniqueKeyPropertyName == null ) { - return factory.getIdentifierPropertyName( getAssociatedEntityName() ); - } - else { - return uniqueKeyPropertyName; - } + return isReferenceToIdentifierProperty() + ? factory.getIdentifierPropertyName( getAssociatedEntityName() ) + : uniqueKeyPropertyName; + } + + public boolean isReferenceToIdentifierProperty() { + return isReferenceToPrimaryKey() + || uniqueKeyPropertyName == null; } /** From a666ac0dac9450c4f0c99bcad549edf9b996a94a Mon Sep 17 00:00:00 2001 From: rmartinc Date: Thu, 2 Sep 2021 10:55:40 +0200 Subject: [PATCH 304/644] HHH-14796 Cannot replace an existing JPQL NamedQuery with a native NamedQuery --- .../query/spi/NamedQueryRepository.java | 18 ++++++++++ .../jpa/test/query/AddNamedQueryTest.java | 35 +++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/hibernate-core/src/main/java/org/hibernate/query/spi/NamedQueryRepository.java b/hibernate-core/src/main/java/org/hibernate/query/spi/NamedQueryRepository.java index 72e1f70aaefb..c25cb5243d84 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/spi/NamedQueryRepository.java +++ b/hibernate-core/src/main/java/org/hibernate/query/spi/NamedQueryRepository.java @@ -92,6 +92,14 @@ public ResultSetMappingDefinition getResultSetMappingDefinition(String mappingNa return namedSqlResultSetMappingMap.get( mappingName ); } + private synchronized void removeNamedQueryDefinition(String name) { + if ( this.namedQueryDefinitionMap.containsKey( name ) ) { + final Map copy = CollectionHelper.makeCopy( namedQueryDefinitionMap ); + copy.remove( name ); + this.namedQueryDefinitionMap = toSmallMap( copy ); + } + } + public synchronized void registerNamedQueryDefinition(String name, NamedQueryDefinition definition) { if ( NamedSQLQueryDefinition.class.isInstance( definition ) ) { throw new IllegalArgumentException( "NamedSQLQueryDefinition instance incorrectly passed to registerNamedQueryDefinition" ); @@ -112,6 +120,15 @@ public synchronized void registerNamedQueryDefinition(String name, NamedQueryDef } this.namedQueryDefinitionMap = toSmallMap( copy ); + removeNamedSQLQueryDefinition( name ); + } + + private synchronized void removeNamedSQLQueryDefinition(String name) { + if ( this.namedSqlQueryDefinitionMap.containsKey( name ) ) { + final Map copy = CollectionHelper.makeCopy( namedSqlQueryDefinitionMap ); + copy.remove( name ); + this.namedSqlQueryDefinitionMap = toSmallMap( copy ); + } } public synchronized void registerNamedSQLQueryDefinition(String name, NamedSQLQueryDefinition definition) { @@ -130,6 +147,7 @@ public synchronized void registerNamedSQLQueryDefinition(String name, NamedSQLQu } this.namedSqlQueryDefinitionMap = toSmallMap( copy ); + removeNamedQueryDefinition( name ); } public synchronized void registerNamedProcedureCallMemento(String name, ProcedureCallMemento memento) { diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/query/AddNamedQueryTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/query/AddNamedQueryTest.java index 5921fa508cd7..8fa7aa71ef4f 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/query/AddNamedQueryTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/query/AddNamedQueryTest.java @@ -54,6 +54,41 @@ public void basicTest() { em.close(); } + @Test + public void replaceTest() { + EntityManager em = getOrCreateEntityManager(); + final String name = "myReplaceItemQuery"; + + // create a jpql query + String sql = "from Item"; + Query query = em.createQuery( sql ); + query.setHint( "org.hibernate.comment", sql ); + em.getEntityManagerFactory().addNamedQuery( name, query ); + query = em.createNamedQuery( name ); + assertEquals( sql, query.getHints().get( "org.hibernate.comment" ) ); + assertEquals( 0, query.getResultList().size() ); + + // create a native query and replace the previous jpql + sql = "select * from Item"; + query = em.createNativeQuery( sql, Item.class ); + query.setHint( "org.hibernate.comment", sql ); + em.getEntityManagerFactory().addNamedQuery( name, query ); + query = em.createNamedQuery( name ); + assertEquals( sql, query.getHints().get( "org.hibernate.comment" ) ); + assertEquals( 0, query.getResultList().size() ); + + // define back a named query + sql = "from Item"; + query = em.createQuery( sql ); + query.setHint( "org.hibernate.comment", sql ); + em.getEntityManagerFactory().addNamedQuery( name, query ); + query = em.createNamedQuery( name ); + assertEquals( sql, query.getHints().get( "org.hibernate.comment" ) ); + assertEquals( 0, query.getResultList().size() ); + + em.close(); + } + @Test public void testLockModeHandling() { final String name = "lock-mode-handling"; From e0d262cc3fbdea8507f834c09f408d1bade189af Mon Sep 17 00:00:00 2001 From: Arkadiusz Biczewski Date: Mon, 6 Sep 2021 15:59:47 +0200 Subject: [PATCH 305/644] HHH-14813 Update DB2 dialect with bind parameters limit Provide allowed parameters limit for DB2 queries based on official documentation: https://www.ibm.com/docs/en/db2/11.5?topic=sql-xml-limits --- .../src/main/java/org/hibernate/dialect/DB2Dialect.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/DB2Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/DB2Dialect.java index 38fe222790db..dbdce61ed039 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/DB2Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/DB2Dialect.java @@ -51,6 +51,8 @@ */ public class DB2Dialect extends Dialect { + private static final int BIND_PARAMETERS_NUMBER_LIMIT = 32_767; + private static final AbstractLimitHandler LIMIT_HANDLER = new AbstractLimitHandler() { @Override public String processSql(String sql, RowSelection selection) { @@ -596,4 +598,9 @@ public IdentityColumnSupport getIdentityColumnSupport() { public boolean supportsPartitionBy() { return true; } + + @Override + public int getInExpressionCountLimit() { + return BIND_PARAMETERS_NUMBER_LIMIT; + } } From 0af8755949c52348ba25a1f8763c34652bbeaa18 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Thu, 9 Sep 2021 15:53:14 +0200 Subject: [PATCH 306/644] Backport of changes from 6314395edf05117f374a8de5e5e506840a337ebb on wip/6.0 (Fix connection leaks by properly closing service registries) --- .../java/org/hibernate/cfg/Configuration.java | 9 +- .../EntityManagerFactoryBuilderImpl.java | 125 +++--- .../CacheKeyImplementationHashCodeTest.java | 29 +- .../dialect/resolver/DialectFactoryTest.java | 8 + .../enhanced/SequenceStyleConfigUnitTest.java | 78 +--- .../test/cdi/NoCdiAvailableTestDelegate.java | 2 +- .../ConfigurationObjectSettingTest.java | 60 +-- ...DropUtf8WithoutHbm2DdlCharsetNameTest.java | 10 +- ...hemaDatabaseFileGenerationFailureTest.java | 12 +- ...SchemaScriptFileGenerationFailureTest.java | 13 +- .../SchemaScriptFileGenerationTest.java | 9 +- .../SessionFactorySerializationTest.java | 78 ++-- .../service/ServiceRegistryTest.java | 21 +- .../ServiceRegistryClosingCascadeTest.java | 4 +- .../SubclassProxyInterfaceTest.java | 6 +- .../test/annotations/ConfigurationTest.java | 162 ++++---- .../test/annotations/SafeMappingTest.java | 1 + .../test/annotations/SecuredBindingTest.java | 1 + .../annotations/backquotes/BackquoteTest.java | 39 +- .../configuration/ConfigurationTest.java | 6 +- .../embeddables/EmbeddableIntegratorTest.java | 23 +- ...beddableWithManyToMany_HHH_11302_Test.java | 3 - ...mbeddableWithOneToMany_HHH_11302_Test.java | 3 - ...EmbeddableWithOneToMany_HHH_8564_Test.java | 3 - ...EmbeddableWithOneToMany_HHH_8860_Test.java | 3 - .../fetchprofile/FetchProfileTest.java | 62 +-- .../MappedByFetchProfileUnitTest.java | 44 +- .../formula/JoinColumnOrFormulaTest.java | 20 +- ...ntityInheritanceAttributeOverrideTest.java | 15 +- .../JPAXMLOverriddenAnnotationReaderTest.java | 81 ++-- .../reflection/XMLContextTest.java | 17 +- .../annotations/xml/ejb3/Ejb3XmlTestCase.java | 19 +- .../xml/ejb3/NonExistentOrmVersionTest.java | 6 +- .../jaxb/hbm/internal/XmlBindingChecker.java | 5 +- .../NonRootEntityWithCacheAnnotationTest.java | 21 +- ...RootEntityWithCacheableAnnotationTest.java | 23 +- .../cache/SingleRegisteredProviderTest.java | 90 ++-- .../general/mixed/DelayedMixedAccessTest.java | 7 +- .../mixed/ExtendedMixedAccessTest.java | 53 +-- .../mixed/ImmediateMixedAccessTests.java | 4 +- .../test/cfg/AnnotationBinderTest.java | 19 +- .../collection/bag/MultipleBagFetchTest.java | 14 +- .../converter/AttributeConverterTest.java | 103 ++--- .../AttributeConverterOnSuperclassTest.java | 8 + .../hibernate/test/foreignkeys/HHH14230.java | 23 +- .../disabled/DefaultConstraintModeTest.java | 9 +- .../OneToManyBidirectionalForeignKeyTest.java | 13 +- .../test/hbm/comment/ClassCommentTest.java | 19 +- .../UserDefinedGeneratorsTests.java | 71 ++-- .../tck2_2/GeneratedValueTests.java | 392 +++++++++--------- .../CachingWithSecondaryTablesTests.java | 24 +- .../test/mapping/ValueVisitorTest.java | 32 +- .../DiscriminatorMultiTenancyTest.java | 90 ++-- .../SchemaUpdateSchemaNameTest.java | 12 +- .../hhh_x/InheritanceSchemaUpdateTest.java | 12 +- .../StoredProcedureResultSetMappingTest.java | 6 +- .../org/hibernate/test/stats/StatsTest.java | 160 +++---- .../schema/DropSchemaDuringJtaTxnTest.java | 15 +- ...reparedStatementSpyConnectionProvider.java | 6 +- .../dynamic/AuditedDynamicComponentTest.java | 2 +- .../org/hibernate/jcache/test/TestHelper.java | 9 +- .../testing/boot/BootstrapContextImpl.java | 10 +- .../MetadataBuildingContextTestingImpl.java | 4 - .../junit4/BaseCoreFunctionalTestCase.java | 60 ++- .../ViburDBCPConnectionProviderTest.java | 4 +- 65 files changed, 1226 insertions(+), 1066 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/Configuration.java b/hibernate-core/src/main/java/org/hibernate/cfg/Configuration.java index d6c4715f1ab0..f91ff17c1cf0 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/Configuration.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/Configuration.java @@ -741,7 +741,14 @@ public SessionFactory buildSessionFactory(ServiceRegistry serviceRegistry) throw public SessionFactory buildSessionFactory() throws HibernateException { log.debug( "Building session factory using internal StandardServiceRegistryBuilder" ); standardServiceRegistryBuilder.applySettings( properties ); - return buildSessionFactory( standardServiceRegistryBuilder.build() ); + StandardServiceRegistry serviceRegistry = standardServiceRegistryBuilder.build(); + try { + return buildSessionFactory( serviceRegistry ); + } + catch (Throwable t) { + serviceRegistry.close(); + throw t; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java b/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java index 8d0adeea1c80..ac2cc7bc303c 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java @@ -33,6 +33,7 @@ import org.hibernate.boot.cfgxml.spi.CfgXmlAccessService; import org.hibernate.boot.cfgxml.spi.LoadedConfig; import org.hibernate.boot.cfgxml.spi.MappingReference; +import org.hibernate.boot.model.convert.spi.ConverterDescriptor; import org.hibernate.boot.model.process.spi.ManagedResources; import org.hibernate.boot.model.process.spi.MetadataBuildingProcess; import org.hibernate.boot.registry.BootstrapServiceRegistry; @@ -222,80 +223,87 @@ private EntityManagerFactoryBuilderImpl( providedClassLoader, providedClassLoaderService ); + try { + // merge configuration sources and build the "standard" service registry + final StandardServiceRegistryBuilder ssrBuilder = getStandardServiceRegistryBuilder( bsr ); - // merge configuration sources and build the "standard" service registry - final StandardServiceRegistryBuilder ssrBuilder = getStandardServiceRegistryBuilder( bsr ); - - final MergedSettings mergedSettings = mergeSettings( persistenceUnit, integrationSettings, ssrBuilder ); + final MergedSettings mergedSettings = mergeSettings( persistenceUnit, integrationSettings, ssrBuilder ); - // flush before completion validation - if ( "true".equals( mergedSettings.configurationValues.get( Environment.FLUSH_BEFORE_COMPLETION ) ) ) { - LOG.definingFlushBeforeCompletionIgnoredInHem( Environment.FLUSH_BEFORE_COMPLETION ); - mergedSettings.configurationValues.put( Environment.FLUSH_BEFORE_COMPLETION, "false" ); - } + // flush before completion validation + if ( "true".equals( mergedSettings.configurationValues.get( Environment.FLUSH_BEFORE_COMPLETION ) ) ) { + LOG.definingFlushBeforeCompletionIgnoredInHem( Environment.FLUSH_BEFORE_COMPLETION ); + mergedSettings.configurationValues.put( Environment.FLUSH_BEFORE_COMPLETION, "false" ); + } - // keep the merged config values for phase-2 - this.configurationValues = mergedSettings.getConfigurationValues(); + // keep the merged config values for phase-2 + this.configurationValues = mergedSettings.getConfigurationValues(); - // Build the "standard" service registry - ssrBuilder.applySettings( configurationValues ); + // Build the "standard" service registry + ssrBuilder.applySettings( configurationValues ); - this.standardServiceRegistry = ssrBuilder.build(); + this.standardServiceRegistry = ssrBuilder.build(); - configureIdentifierGenerators( standardServiceRegistry ); + configureIdentifierGenerators( standardServiceRegistry ); - final MetadataSources metadataSources = new MetadataSources( bsr ); - List attributeConverterDefinitions = applyMappingResources( metadataSources ); + final MetadataSources metadataSources = new MetadataSources( bsr ); + this.metamodelBuilder = (MetadataBuilderImplementor) metadataSources.getMetadataBuilder( standardServiceRegistry ); + List attributeConverterDefinitions = applyMappingResources( metadataSources ); - this.metamodelBuilder = (MetadataBuilderImplementor) metadataSources.getMetadataBuilder( standardServiceRegistry ); - applyMetamodelBuilderSettings( mergedSettings, attributeConverterDefinitions ); + applyMetamodelBuilderSettings( mergedSettings, attributeConverterDefinitions ); - applyMetadataBuilderContributor(); + applyMetadataBuilderContributor(); - // todo : would be nice to have MetadataBuilder still do the handling of CfgXmlAccessService here - // another option is to immediately handle them here (probably in mergeSettings?) as we encounter them... - final CfgXmlAccessService cfgXmlAccessService = standardServiceRegistry.getService( CfgXmlAccessService.class ); - if ( cfgXmlAccessService.getAggregatedConfig() != null ) { - if ( cfgXmlAccessService.getAggregatedConfig().getMappingReferences() != null ) { - for ( MappingReference mappingReference : cfgXmlAccessService.getAggregatedConfig().getMappingReferences() ) { - mappingReference.apply( metadataSources ); + // todo : would be nice to have MetadataBuilder still do the handling of CfgXmlAccessService here + // another option is to immediately handle them here (probably in mergeSettings?) as we encounter them... + final CfgXmlAccessService cfgXmlAccessService = standardServiceRegistry.getService( CfgXmlAccessService.class ); + if ( cfgXmlAccessService.getAggregatedConfig() != null ) { + if ( cfgXmlAccessService.getAggregatedConfig().getMappingReferences() != null ) { + for ( MappingReference mappingReference : cfgXmlAccessService.getAggregatedConfig() + .getMappingReferences() ) { + mappingReference.apply( metadataSources ); + } } } - } - this.managedResources = MetadataBuildingProcess.prepare( - metadataSources, - metamodelBuilder.getBootstrapContext() - ); + this.managedResources = MetadataBuildingProcess.prepare( + metadataSources, + metamodelBuilder.getBootstrapContext() + ); - final Object validatorFactory = configurationValues.get( org.hibernate.cfg.AvailableSettings.JPA_VALIDATION_FACTORY ); - if ( validatorFactory == null ) { - withValidatorFactory( configurationValues.get( org.hibernate.cfg.AvailableSettings.JAKARTA_JPA_VALIDATION_FACTORY ) ); - } - else { - withValidatorFactory( validatorFactory ); - } + final Object validatorFactory = configurationValues.get( org.hibernate.cfg.AvailableSettings.JPA_VALIDATION_FACTORY ); + if ( validatorFactory == null ) { + withValidatorFactory( configurationValues.get( org.hibernate.cfg.AvailableSettings.JAKARTA_JPA_VALIDATION_FACTORY ) ); + } + else { + withValidatorFactory( validatorFactory ); + } - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - // push back class transformation to the environment; for the time being this only has any effect in EE - // container situations, calling back into PersistenceUnitInfo#addClassTransformer + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // push back class transformation to the environment; for the time being this only has any effect in EE + // container situations, calling back into PersistenceUnitInfo#addClassTransformer - final boolean dirtyTrackingEnabled = readBooleanConfigurationValue( AvailableSettings.ENHANCER_ENABLE_DIRTY_TRACKING ); - final boolean lazyInitializationEnabled = readBooleanConfigurationValue( AvailableSettings.ENHANCER_ENABLE_LAZY_INITIALIZATION ); - final boolean associationManagementEnabled = readBooleanConfigurationValue( AvailableSettings.ENHANCER_ENABLE_ASSOCIATION_MANAGEMENT ); + final boolean dirtyTrackingEnabled = readBooleanConfigurationValue( AvailableSettings.ENHANCER_ENABLE_DIRTY_TRACKING ); + final boolean lazyInitializationEnabled = readBooleanConfigurationValue( AvailableSettings.ENHANCER_ENABLE_LAZY_INITIALIZATION ); + final boolean associationManagementEnabled = readBooleanConfigurationValue( AvailableSettings.ENHANCER_ENABLE_ASSOCIATION_MANAGEMENT ); - if ( dirtyTrackingEnabled || lazyInitializationEnabled || associationManagementEnabled ) { - EnhancementContext enhancementContext = getEnhancementContext( - dirtyTrackingEnabled, - lazyInitializationEnabled, - associationManagementEnabled - ); + if ( dirtyTrackingEnabled || lazyInitializationEnabled || associationManagementEnabled ) { + EnhancementContext enhancementContext = getEnhancementContext( + dirtyTrackingEnabled, + lazyInitializationEnabled, + associationManagementEnabled + ); - persistenceUnit.pushClassTransformer( enhancementContext ); - } + persistenceUnit.pushClassTransformer( enhancementContext ); + } - // for the time being we want to revoke access to the temp ClassLoader if one was passed - metamodelBuilder.applyTempClassLoader( null ); + // for the time being we want to revoke access to the temp ClassLoader if one was passed + metamodelBuilder.applyTempClassLoader( null ); + } + catch (Throwable t) { + bsr.close(); + cleanup(); + throw t; + } } /** @@ -532,8 +540,9 @@ private MergedSettings mergeSettings( if ( keyString.startsWith( JACC_PREFIX ) ) { if( !JACC_CONTEXT_ID.equals( keyString ) && !JACC_ENABLED.equals( keyString )) { if ( jaccContextId == null ) { - LOG.debug( - "Found JACC permission grant [%s] in properties, but no JACC context id was specified; ignoring" + LOG.debugf( + "Found JACC permission grant [%s] in properties, but no JACC context id was specified; ignoring", + keyString ); } else { @@ -716,7 +725,7 @@ else if ( persistenceUnit.getTransactionType() != null ) { if ( txnType == null ) { // is it more appropriate to have this be based on bootstrap entry point (EE vs SE)? - LOG.debugf( "PersistenceUnitTransactionType not specified - falling back to RESOURCE_LOCAL" ); + LOG.debug( "PersistenceUnitTransactionType not specified - falling back to RESOURCE_LOCAL" ); txnType = PersistenceUnitTransactionType.RESOURCE_LOCAL; } diff --git a/hibernate-core/src/test/java/org/hibernate/cache/internal/CacheKeyImplementationHashCodeTest.java b/hibernate-core/src/test/java/org/hibernate/cache/internal/CacheKeyImplementationHashCodeTest.java index 89160be926bb..a9652bb499db 100644 --- a/hibernate-core/src/test/java/org/hibernate/cache/internal/CacheKeyImplementationHashCodeTest.java +++ b/hibernate-core/src/test/java/org/hibernate/cache/internal/CacheKeyImplementationHashCodeTest.java @@ -34,22 +34,23 @@ public class CacheKeyImplementationHashCodeTest { @Test @TestForIssue( jiraKey = "HHH-12746") public void test() { - ServiceRegistryImplementor serviceRegistry = ( - ServiceRegistryImplementor) new StandardServiceRegistryBuilder().build(); - MetadataSources ms = new MetadataSources( serviceRegistry ); - ms.addAnnotatedClass( AnEntity.class ).addAnnotatedClass( AnotherEntity.class ); - Metadata metadata = ms.buildMetadata(); - final SessionFactoryBuilder sfb = metadata.getSessionFactoryBuilder(); - SessionFactoryImplementor sessionFactory = (SessionFactoryImplementor) sfb.build(); + try (ServiceRegistryImplementor serviceRegistry = ( + ServiceRegistryImplementor) new StandardServiceRegistryBuilder().build()) { + MetadataSources ms = new MetadataSources( serviceRegistry ); + ms.addAnnotatedClass( AnEntity.class ).addAnnotatedClass( AnotherEntity.class ); + Metadata metadata = ms.buildMetadata(); + final SessionFactoryBuilder sfb = metadata.getSessionFactoryBuilder(); + SessionFactoryImplementor sessionFactory = (SessionFactoryImplementor) sfb.build(); - CacheKeyImplementation anEntityCacheKey = createCacheKeyImplementation( - 1, sessionFactory.getMetamodel().entityPersister( AnEntity.class ), sessionFactory - ); - CacheKeyImplementation anotherEntityCacheKey = createCacheKeyImplementation( - 1, sessionFactory.getMetamodel().entityPersister( AnotherEntity.class ), sessionFactory - ); - assertFalse( anEntityCacheKey.equals( anotherEntityCacheKey ) ); + CacheKeyImplementation anEntityCacheKey = createCacheKeyImplementation( + 1, sessionFactory.getMetamodel().entityPersister( AnEntity.class ), sessionFactory + ); + CacheKeyImplementation anotherEntityCacheKey = createCacheKeyImplementation( + 1, sessionFactory.getMetamodel().entityPersister( AnotherEntity.class ), sessionFactory + ); + assertFalse( anEntityCacheKey.equals( anotherEntityCacheKey ) ); + } } private CacheKeyImplementation createCacheKeyImplementation( diff --git a/hibernate-core/src/test/java/org/hibernate/dialect/resolver/DialectFactoryTest.java b/hibernate-core/src/test/java/org/hibernate/dialect/resolver/DialectFactoryTest.java index 7eaf8d840617..0d9ba376beb9 100644 --- a/hibernate-core/src/test/java/org/hibernate/dialect/resolver/DialectFactoryTest.java +++ b/hibernate-core/src/test/java/org/hibernate/dialect/resolver/DialectFactoryTest.java @@ -22,6 +22,7 @@ import org.hibernate.engine.jdbc.dialect.spi.DialectResolver; import org.hibernate.service.spi.ServiceRegistryImplementor; import org.hibernate.testing.junit4.BaseUnitTestCase; +import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -50,6 +51,13 @@ public void setUp() { dialectFactory.injectServices( (ServiceRegistryImplementor) registry ); } + @After + public void destroy() { + if ( registry != null ) { + registry.close(); + } + } + @Test public void testExplicitShortNameUse() { final Map configValues = new HashMap(); diff --git a/hibernate-core/src/test/java/org/hibernate/id/enhanced/SequenceStyleConfigUnitTest.java b/hibernate-core/src/test/java/org/hibernate/id/enhanced/SequenceStyleConfigUnitTest.java index d706441082ae..c3eaf912a74f 100644 --- a/hibernate-core/src/test/java/org/hibernate/id/enhanced/SequenceStyleConfigUnitTest.java +++ b/hibernate-core/src/test/java/org/hibernate/id/enhanced/SequenceStyleConfigUnitTest.java @@ -34,15 +34,13 @@ public class SequenceStyleConfigUnitTest extends BaseUnitTestCase { /** - * Test all params defaulted with a dialect supporting sequences + * Test all params defaulted with a dialect supporting pooled sequences */ @Test public void testDefaultedSequenceBackedConfiguration() { - StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder() - .applySetting( AvailableSettings.DIALECT, SequenceDialect.class.getName() ) - .build(); - - try { + try (StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder() + .applySetting( AvailableSettings.DIALECT, PooledSequenceDialect.class.getName() ) + .build()) { Properties props = buildGeneratorPropertiesBase( serviceRegistry ); SequenceStyleGenerator generator = new SequenceStyleGenerator(); generator.configure( StandardBasicTypes.LONG, props, serviceRegistry ); @@ -55,9 +53,6 @@ public void testDefaultedSequenceBackedConfiguration() { assertClassAssignability( NoopOptimizer.class, generator.getOptimizer().getClass() ); assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME, generator.getDatabaseStructure().getName() ); } - finally { - StandardServiceRegistryBuilder.destroy( serviceRegistry ); - } } private Properties buildGeneratorPropertiesBase(StandardServiceRegistry serviceRegistry) { @@ -74,11 +69,9 @@ private Properties buildGeneratorPropertiesBase(StandardServiceRegistry serviceR */ @Test public void testDefaultedTableBackedConfiguration() { - StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder() + try (StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder() .applySetting( AvailableSettings.DIALECT, TableDialect.class.getName() ) - .build(); - - try { + .build()) { Properties props = buildGeneratorPropertiesBase( serviceRegistry ); SequenceStyleGenerator generator = new SequenceStyleGenerator(); generator.configure( StandardBasicTypes.LONG, props, serviceRegistry ); @@ -91,9 +84,6 @@ public void testDefaultedTableBackedConfiguration() { assertClassAssignability( NoopOptimizer.class, generator.getOptimizer().getClass() ); assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME, generator.getDatabaseStructure().getName() ); } - finally { - StandardServiceRegistryBuilder.destroy( serviceRegistry ); - } } /** @@ -104,11 +94,9 @@ public void testDefaultedTableBackedConfiguration() { @Test public void testDefaultOptimizerBasedOnIncrementBackedBySequence() { // for dialects which do not support pooled sequences, we default to pooled+table - StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder() + try (StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder() .applySetting( AvailableSettings.DIALECT, SequenceDialect.class.getName() ) - .build(); - - try { + .build()) { Properties props = buildGeneratorPropertiesBase( serviceRegistry ); props.setProperty( SequenceStyleGenerator.INCREMENT_PARAM, "10" ); @@ -123,16 +111,11 @@ public void testDefaultOptimizerBasedOnIncrementBackedBySequence() { assertClassAssignability( PooledOptimizer.class, generator.getOptimizer().getClass() ); assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME, generator.getDatabaseStructure().getName() ); } - finally { - StandardServiceRegistryBuilder.destroy( serviceRegistry ); - } // for dialects which do support pooled sequences, we default to pooled+sequence - serviceRegistry = new StandardServiceRegistryBuilder() + try (StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder() .applySetting( AvailableSettings.DIALECT, PooledSequenceDialect.class.getName() ) - .build(); - - try { + .build()) { Properties props = buildGeneratorPropertiesBase( serviceRegistry ); props.setProperty( SequenceStyleGenerator.INCREMENT_PARAM, "10" ); @@ -146,9 +129,6 @@ public void testDefaultOptimizerBasedOnIncrementBackedBySequence() { assertClassAssignability( PooledOptimizer.class, generator.getOptimizer().getClass() ); assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME, generator.getDatabaseStructure().getName() ); } - finally { - StandardServiceRegistryBuilder.destroy( serviceRegistry ); - } } /** @@ -158,11 +138,9 @@ public void testDefaultOptimizerBasedOnIncrementBackedBySequence() { */ @Test public void testDefaultOptimizerBasedOnIncrementBackedByTable() { - StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder() + try (StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder() .applySetting( AvailableSettings.DIALECT, TableDialect.class.getName() ) - .build(); - - try { + .build()) { Properties props = buildGeneratorPropertiesBase( serviceRegistry ); props.setProperty( SequenceStyleGenerator.INCREMENT_PARAM, "10" ); @@ -176,9 +154,6 @@ public void testDefaultOptimizerBasedOnIncrementBackedByTable() { assertClassAssignability( PooledOptimizer.class, generator.getOptimizer().getClass() ); assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME, generator.getDatabaseStructure().getName() ); } - finally { - StandardServiceRegistryBuilder.destroy( serviceRegistry ); - } } /** @@ -186,11 +161,9 @@ public void testDefaultOptimizerBasedOnIncrementBackedByTable() { */ @Test public void testForceTableUse() { - StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder() + try (StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder() .applySetting( AvailableSettings.DIALECT, SequenceDialect.class.getName() ) - .build(); - - try { + .build()) { Properties props = buildGeneratorPropertiesBase( serviceRegistry ); props.setProperty( SequenceStyleGenerator.FORCE_TBL_PARAM, "true" ); @@ -204,9 +177,6 @@ public void testForceTableUse() { assertClassAssignability( NoopOptimizer.class, generator.getOptimizer().getClass() ); assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME, generator.getDatabaseStructure().getName() ); } - finally { - StandardServiceRegistryBuilder.destroy( serviceRegistry ); - } } /** @@ -214,12 +184,10 @@ public void testForceTableUse() { */ @Test public void testExplicitOptimizerWithExplicitIncrementSize() { - StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder() - .applySetting( AvailableSettings.DIALECT, SequenceDialect.class.getName() ) - .build(); - // optimizer=none w/ increment > 1 => should honor optimizer - try { + try (StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder() + .applySetting( AvailableSettings.DIALECT, SequenceDialect.class.getName() ) + .build()) { Properties props = buildGeneratorPropertiesBase( serviceRegistry ); props.setProperty( SequenceStyleGenerator.OPT_PARAM, StandardOptimizerDescriptor.NONE.getExternalName() ); props.setProperty( SequenceStyleGenerator.INCREMENT_PARAM, "20" ); @@ -264,18 +232,13 @@ public void testExplicitOptimizerWithExplicitIncrementSize() { assertEquals( 20, generator.getOptimizer().getIncrementSize() ); assertEquals( 20, generator.getDatabaseStructure().getIncrementSize() ); } - finally { - StandardServiceRegistryBuilder.destroy( serviceRegistry ); - } } @Test public void testPreferredPooledOptimizerSetting() { - StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder() + try (StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder() .applySetting( AvailableSettings.DIALECT, PooledSequenceDialect.class.getName() ) - .build(); - - try { + .build()) { Properties props = buildGeneratorPropertiesBase( serviceRegistry ); props.setProperty( SequenceStyleGenerator.INCREMENT_PARAM, "20" ); SequenceStyleGenerator generator = new SequenceStyleGenerator(); @@ -304,9 +267,6 @@ public void testPreferredPooledOptimizerSetting() { assertClassAssignability( SequenceStructure.class, generator.getDatabaseStructure().getClass() ); assertClassAssignability( PooledLoThreadLocalOptimizer.class, generator.getOptimizer().getClass() ); } - finally { - StandardServiceRegistryBuilder.destroy( serviceRegistry ); - } } public static class TableDialect extends Dialect { diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/cdi/NoCdiAvailableTestDelegate.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/cdi/NoCdiAvailableTestDelegate.java index e320feecd190..f683442f06a8 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/cdi/NoCdiAvailableTestDelegate.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/cdi/NoCdiAvailableTestDelegate.java @@ -29,6 +29,6 @@ public static void passingBeanManager() { new HibernatePersistenceProvider().createContainerEntityManagerFactory( new PersistenceUnitInfoAdapter(), Collections.singletonMap( AvailableSettings.CDI_BEAN_MANAGER, new Object() ) - ); + ).close(); } } diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/ejb3configuration/ConfigurationObjectSettingTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/ejb3configuration/ConfigurationObjectSettingTest.java index b1078c148bf2..543b994654d0 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/ejb3configuration/ConfigurationObjectSettingTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/ejb3configuration/ConfigurationObjectSettingTest.java @@ -11,7 +11,7 @@ import javax.persistence.ValidationMode; import org.hibernate.HibernateException; -import org.hibernate.jpa.AvailableSettings; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl; import org.hibernate.jpa.boot.spi.Bootstrap; import org.hibernate.jpa.test.PersistenceUnitInfoAdapter; @@ -32,22 +32,25 @@ public class ConfigurationObjectSettingTest extends BaseUnitTestCase { public void testContainerBootstrapSharedCacheMode() { // first, via the integration vars PersistenceUnitInfoAdapter empty = new PersistenceUnitInfoAdapter(); + EntityManagerFactoryBuilderImpl builder = null; { // as object - EntityManagerFactoryBuilderImpl builder = (EntityManagerFactoryBuilderImpl) Bootstrap.getEntityManagerFactoryBuilder( + builder = (EntityManagerFactoryBuilderImpl) Bootstrap.getEntityManagerFactoryBuilder( empty, - Collections.singletonMap( AvailableSettings.SHARED_CACHE_MODE, SharedCacheMode.DISABLE_SELECTIVE ) + Collections.singletonMap( AvailableSettings.JPA_SHARED_CACHE_MODE, SharedCacheMode.DISABLE_SELECTIVE ) ); - assertEquals( SharedCacheMode.DISABLE_SELECTIVE, builder.getConfigurationValues().get( AvailableSettings.SHARED_CACHE_MODE ) ); + assertEquals( SharedCacheMode.DISABLE_SELECTIVE, builder.getConfigurationValues().get( AvailableSettings.JPA_SHARED_CACHE_MODE ) ); } + builder.cancel(); { // as string - EntityManagerFactoryBuilderImpl builder = (EntityManagerFactoryBuilderImpl) Bootstrap.getEntityManagerFactoryBuilder( + builder = (EntityManagerFactoryBuilderImpl) Bootstrap.getEntityManagerFactoryBuilder( empty, - Collections.singletonMap( AvailableSettings.SHARED_CACHE_MODE, SharedCacheMode.DISABLE_SELECTIVE.name() ) + Collections.singletonMap( AvailableSettings.JPA_SHARED_CACHE_MODE, SharedCacheMode.DISABLE_SELECTIVE.name() ) ); - assertEquals( SharedCacheMode.DISABLE_SELECTIVE.name(), builder.getConfigurationValues().get( AvailableSettings.SHARED_CACHE_MODE ) ); + assertEquals( SharedCacheMode.DISABLE_SELECTIVE.name(), builder.getConfigurationValues().get( AvailableSettings.JPA_SHARED_CACHE_MODE ) ); } + builder.cancel(); // next, via the PUI PersistenceUnitInfoAdapter adapter = new PersistenceUnitInfoAdapter() { @@ -57,43 +60,48 @@ public SharedCacheMode getSharedCacheMode() { } }; { - EntityManagerFactoryBuilderImpl builder = (EntityManagerFactoryBuilderImpl) Bootstrap.getEntityManagerFactoryBuilder( + builder = (EntityManagerFactoryBuilderImpl) Bootstrap.getEntityManagerFactoryBuilder( adapter, null ); - assertEquals( SharedCacheMode.ENABLE_SELECTIVE, builder.getConfigurationValues().get( AvailableSettings.SHARED_CACHE_MODE ) ); + assertEquals( SharedCacheMode.ENABLE_SELECTIVE, builder.getConfigurationValues().get( AvailableSettings.JPA_SHARED_CACHE_MODE ) ); } + builder.cancel(); // via both, integration vars should take precedence { - EntityManagerFactoryBuilderImpl builder = (EntityManagerFactoryBuilderImpl) Bootstrap.getEntityManagerFactoryBuilder( + builder = (EntityManagerFactoryBuilderImpl) Bootstrap.getEntityManagerFactoryBuilder( adapter, - Collections.singletonMap( AvailableSettings.SHARED_CACHE_MODE, SharedCacheMode.DISABLE_SELECTIVE ) + Collections.singletonMap( AvailableSettings.JPA_SHARED_CACHE_MODE, SharedCacheMode.DISABLE_SELECTIVE ) ); - assertEquals( SharedCacheMode.DISABLE_SELECTIVE, builder.getConfigurationValues().get( AvailableSettings.SHARED_CACHE_MODE ) ); + assertEquals( SharedCacheMode.DISABLE_SELECTIVE, builder.getConfigurationValues().get( AvailableSettings.JPA_SHARED_CACHE_MODE ) ); } + builder.cancel(); } @Test public void testContainerBootstrapValidationMode() { // first, via the integration vars PersistenceUnitInfoAdapter empty = new PersistenceUnitInfoAdapter(); + EntityManagerFactoryBuilderImpl builder = null; { // as object - EntityManagerFactoryBuilderImpl builder = (EntityManagerFactoryBuilderImpl) Bootstrap.getEntityManagerFactoryBuilder( + builder = (EntityManagerFactoryBuilderImpl) Bootstrap.getEntityManagerFactoryBuilder( empty, - Collections.singletonMap( AvailableSettings.VALIDATION_MODE, ValidationMode.CALLBACK ) + Collections.singletonMap( AvailableSettings.JPA_VALIDATION_MODE, ValidationMode.CALLBACK ) ); - assertEquals( ValidationMode.CALLBACK, builder.getConfigurationValues().get( AvailableSettings.VALIDATION_MODE ) ); + assertEquals( ValidationMode.CALLBACK, builder.getConfigurationValues().get( AvailableSettings.JPA_VALIDATION_MODE ) ); } + builder.cancel(); { // as string - EntityManagerFactoryBuilderImpl builder = (EntityManagerFactoryBuilderImpl) Bootstrap.getEntityManagerFactoryBuilder( + builder = (EntityManagerFactoryBuilderImpl) Bootstrap.getEntityManagerFactoryBuilder( empty, - Collections.singletonMap( AvailableSettings.VALIDATION_MODE, ValidationMode.CALLBACK.name() ) + Collections.singletonMap( AvailableSettings.JPA_VALIDATION_MODE, ValidationMode.CALLBACK.name() ) ); - assertEquals( ValidationMode.CALLBACK.name(), builder.getConfigurationValues().get( AvailableSettings.VALIDATION_MODE ) ); + assertEquals( ValidationMode.CALLBACK.name(), builder.getConfigurationValues().get( AvailableSettings.JPA_VALIDATION_MODE ) ); } + builder.cancel(); // next, via the PUI PersistenceUnitInfoAdapter adapter = new PersistenceUnitInfoAdapter() { @@ -103,21 +111,23 @@ public ValidationMode getValidationMode() { } }; { - EntityManagerFactoryBuilderImpl builder = (EntityManagerFactoryBuilderImpl) Bootstrap.getEntityManagerFactoryBuilder( + builder = (EntityManagerFactoryBuilderImpl) Bootstrap.getEntityManagerFactoryBuilder( adapter, null ); - assertEquals( ValidationMode.CALLBACK, builder.getConfigurationValues().get( AvailableSettings.VALIDATION_MODE ) ); + assertEquals( ValidationMode.CALLBACK, builder.getConfigurationValues().get( AvailableSettings.JPA_VALIDATION_MODE ) ); } + builder.cancel(); // via both, integration vars should take precedence { - EntityManagerFactoryBuilderImpl builder = (EntityManagerFactoryBuilderImpl) Bootstrap.getEntityManagerFactoryBuilder( + builder = (EntityManagerFactoryBuilderImpl) Bootstrap.getEntityManagerFactoryBuilder( adapter, - Collections.singletonMap( AvailableSettings.VALIDATION_MODE, ValidationMode.NONE ) + Collections.singletonMap( AvailableSettings.JPA_VALIDATION_MODE, ValidationMode.NONE ) ); - assertEquals( ValidationMode.NONE, builder.getConfigurationValues().get( AvailableSettings.VALIDATION_MODE ) ); + assertEquals( ValidationMode.NONE, builder.getConfigurationValues().get( AvailableSettings.JPA_VALIDATION_MODE ) ); } + builder.cancel(); } @Test @@ -127,8 +137,8 @@ public void testContainerBootstrapValidationFactory() { try { Bootstrap.getEntityManagerFactoryBuilder( adapter, - Collections.singletonMap( AvailableSettings.VALIDATION_FACTORY, token ) - ); + Collections.singletonMap( AvailableSettings.JPA_VALIDATION_FACTORY, token ) + ).cancel(); fail( "Was expecting error as token did not implement ValidatorFactory" ); } catch ( HibernateException e ) { diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/schemagen/SchemaCreateDropUtf8WithoutHbm2DdlCharsetNameTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/schemagen/SchemaCreateDropUtf8WithoutHbm2DdlCharsetNameTest.java index e3d91076b88d..167370990cb0 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/schemagen/SchemaCreateDropUtf8WithoutHbm2DdlCharsetNameTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/schemagen/SchemaCreateDropUtf8WithoutHbm2DdlCharsetNameTest.java @@ -21,8 +21,9 @@ import org.hibernate.jpa.boot.spi.Bootstrap; import org.hibernate.jpa.boot.spi.EntityManagerFactoryBuilder; import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; - import org.hibernate.testing.TestForIssue; + +import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -63,6 +64,13 @@ public void setUp() throws IOException { ); } + @After + public void destroy() { + if ( entityManagerFactoryBuilder != null ) { + entityManagerFactoryBuilder.cancel(); + } + } + @Test @TestForIssue(jiraKey = "HHH-10972") public void testEncoding() throws Exception { diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/schemagen/SchemaDatabaseFileGenerationFailureTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/schemagen/SchemaDatabaseFileGenerationFailureTest.java index 037d87a9135c..84491e51f19a 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/schemagen/SchemaDatabaseFileGenerationFailureTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/schemagen/SchemaDatabaseFileGenerationFailureTest.java @@ -27,8 +27,9 @@ import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; import org.hibernate.tool.schema.spi.CommandAcceptanceException; import org.hibernate.tool.schema.spi.SchemaManagementException; - import org.hibernate.testing.TestForIssue; + +import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -60,6 +61,13 @@ public void setUp() throws IOException, SQLException { ); } + @After + public void destroy() { + if ( entityManagerFactoryBuilder != null ) { + entityManagerFactoryBuilder.cancel(); + } + } + @Test @TestForIssue(jiraKey = "HHH-12192") public void testErrorMessageContainsTheFailingDDLCommand() { @@ -83,7 +91,6 @@ public void testErrorMessageContainsTheFailingDDLCommand() { SQLException root = (SQLException) e.getCause().getCause().getCause(); assertEquals( "Expected", root.getMessage() ); - } } @@ -119,5 +126,4 @@ private Map getConfig() { config.put( org.hibernate.jpa.AvailableSettings.LOADED_CLASSES, classes ); return config; } - } diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/schemagen/SchemaScriptFileGenerationFailureTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/schemagen/SchemaScriptFileGenerationFailureTest.java index e08c873dab6a..3fb7307a8b7e 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/schemagen/SchemaScriptFileGenerationFailureTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/schemagen/SchemaScriptFileGenerationFailureTest.java @@ -25,8 +25,9 @@ import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; import org.hibernate.tool.schema.spi.CommandAcceptanceException; import org.hibernate.tool.schema.spi.SchemaManagementException; - import org.hibernate.testing.TestForIssue; + +import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -52,12 +53,19 @@ public void setUp() { ); } + @After + public void destroy() { + if ( entityManagerFactoryBuilder != null ) { + entityManagerFactoryBuilder.cancel(); + } + } + @Test @TestForIssue(jiraKey = "HHH-12192") public void testErrorMessageContainsTheFailingDDLCommand() { try { entityManagerFactoryBuilder.generateSchema(); - fail( "Should haave thrown IOException" ); + fail( "Should have thrown IOException" ); } catch (Exception e) { assertTrue( e instanceof PersistenceException ); @@ -126,7 +134,6 @@ public void flush() throws IOException { @Override public void close() throws IOException { - } } } diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/schemagen/SchemaScriptFileGenerationTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/schemagen/SchemaScriptFileGenerationTest.java index c70aca3fbe5b..02ca66ac7241 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/schemagen/SchemaScriptFileGenerationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/schemagen/SchemaScriptFileGenerationTest.java @@ -24,6 +24,7 @@ import org.hibernate.jpa.boot.spi.PersistenceUnitDescriptor; import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; +import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -53,6 +54,13 @@ public void setUp() throws IOException { ); } + @After + public void destroy() { + if ( entityManagerFactoryBuilder != null ) { + entityManagerFactoryBuilder.cancel(); + } + } + @Test @TestForIssue(jiraKey = "10601") public void testGenerateSchemaDoesNotProduceTheSameStatementTwice() throws Exception { @@ -109,5 +117,4 @@ private Map getConfig() { config.put( org.hibernate.jpa.AvailableSettings.LOADED_CLASSES, classes ); return config; } - } diff --git a/hibernate-core/src/test/java/org/hibernate/serialization/SessionFactorySerializationTest.java b/hibernate-core/src/test/java/org/hibernate/serialization/SessionFactorySerializationTest.java index 4dd68095e338..cc9a71dea171 100644 --- a/hibernate-core/src/test/java/org/hibernate/serialization/SessionFactorySerializationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/serialization/SessionFactorySerializationTest.java @@ -36,21 +36,27 @@ public void testNamedSessionFactorySerialization() throws Exception { Configuration cfg = new Configuration() .setProperty( AvailableSettings.SESSION_FACTORY_NAME, NAME ) .setProperty( AvailableSettings.SESSION_FACTORY_NAME_IS_JNDI, "false" ); // default is true - SessionFactory factory = cfg.buildSessionFactory(); - - // we need to do some tricking here so that Hibernate thinks the deserialization happens in a - // different VM - String uuid = ( (SessionFactoryImplementor) factory ).getUuid(); - // deregister under this uuid... - SessionFactoryRegistry.INSTANCE.removeSessionFactory( uuid, NAME, false, null ); - // and then register under a different uuid... - SessionFactoryRegistry.INSTANCE.addSessionFactory( "some-other-uuid", NAME, false, factory, null ); - - SessionFactory factory2 = (SessionFactory) SerializationHelper.clone( factory ); - assertSame( factory, factory2 ); - - SessionFactoryRegistry.INSTANCE.removeSessionFactory( "some-other-uuid", NAME, false, null ); - factory.close(); + try (SessionFactory factory = cfg.buildSessionFactory()) { + + // we need to do some tricking here so that Hibernate thinks the deserialization happens in a + // different VM + String uuid = ( (SessionFactoryImplementor) factory ).getUuid(); + // deregister under this uuid... + SessionFactoryRegistry.INSTANCE.removeSessionFactory( uuid, NAME, false, null ); + // and then register under a different uuid... + SessionFactoryRegistry.INSTANCE.addSessionFactory( + "some-other-uuid", + NAME, + false, + factory, + null + ); + + SessionFactory factory2 = (SessionFactory) SerializationHelper.clone( factory ); + assertSame( factory, factory2 ); + + SessionFactoryRegistry.INSTANCE.removeSessionFactory( "some-other-uuid", NAME, false, null ); + } assertFalse( SessionFactoryRegistry.INSTANCE.hasRegistrations() ); } @@ -61,26 +67,32 @@ public void testUnNamedSessionFactorySerialization() throws Exception { // here, the test should fail based just on attempted uuid resolution Configuration cfg = new Configuration() .setProperty( AvailableSettings.SESSION_FACTORY_NAME_IS_JNDI, "false" ); // default is true - SessionFactory factory = cfg.buildSessionFactory(); - - // we need to do some tricking here so that Hibernate thinks the deserialization happens in a - // different VM - String uuid = ( (SessionFactoryImplementor) factory ).getUuid(); - // deregister under this uuid... - SessionFactoryRegistry.INSTANCE.removeSessionFactory( uuid, null, false, null ); - // and then register under a different uuid... - SessionFactoryRegistry.INSTANCE.addSessionFactory( "some-other-uuid", null, false, factory, null ); - - try { - SerializationHelper.clone( factory ); - fail( "Expecting an error" ); - } - catch ( SerializationException expected ) { + try (SessionFactory factory = cfg.buildSessionFactory()) { + + // we need to do some tricking here so that Hibernate thinks the deserialization happens in a + // different VM + String uuid = ( (SessionFactoryImplementor) factory ).getUuid(); + // deregister under this uuid... + SessionFactoryRegistry.INSTANCE.removeSessionFactory( uuid, null, false, null ); + // and then register under a different uuid... + SessionFactoryRegistry.INSTANCE.addSessionFactory( + "some-other-uuid", + null, + false, + factory, + null + ); + + try { + SerializationHelper.clone( factory ); + fail( "Expecting an error" ); + } + catch (SerializationException expected) { + } + + SessionFactoryRegistry.INSTANCE.removeSessionFactory( "some-other-uuid", null, false, null ); } - SessionFactoryRegistry.INSTANCE.removeSessionFactory( "some-other-uuid", null, false, null ); - factory.close(); - assertFalse( SessionFactoryRegistry.INSTANCE.hasRegistrations() ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/service/ServiceRegistryTest.java b/hibernate-core/src/test/java/org/hibernate/service/ServiceRegistryTest.java index 710d3efd0f5a..3adc6e276912 100644 --- a/hibernate-core/src/test/java/org/hibernate/service/ServiceRegistryTest.java +++ b/hibernate-core/src/test/java/org/hibernate/service/ServiceRegistryTest.java @@ -15,6 +15,8 @@ import org.hibernate.service.spi.ServiceRegistryImplementor; import org.hibernate.service.spi.Startable; +import org.junit.After; +import org.junit.Before; import org.junit.Test; import org.hibernate.testing.TestForIssue; @@ -25,9 +27,18 @@ import static org.junit.Assert.assertTrue; public class ServiceRegistryTest { - private final ServiceRegistry registry = buildRegistry(); + private ServiceRegistry registry; private final static int NUMBER_OF_THREADS = 100; - private StandardServiceRegistryBuilder standardServiceRegistryBuilder; + + @Before + public void init() { + registry = buildRegistry(); + } + + @After + public void destroy() { + registry.close(); + } @Test @TestForIssue(jiraKey = "HHH-10427") @@ -46,9 +57,6 @@ public void testOnlyOneInstanceOfTheServiceShouldBeCreated() throws InterruptedE } } - - standardServiceRegistryBuilder.destroy( registry ); - } @Test @@ -82,8 +90,7 @@ public void testRequireServiceThrowsAnExceptionWhenTheServiceInitiatorInitiateSe } private ServiceRegistry buildRegistry() { - standardServiceRegistryBuilder = new StandardServiceRegistryBuilder(); - return standardServiceRegistryBuilder.addInitiator( new SlowServiceInitiator() ) + return new StandardServiceRegistryBuilder().addInitiator( new SlowServiceInitiator() ) .addInitiator( new NullServiceInitiator() ) .build(); } diff --git a/hibernate-core/src/test/java/org/hibernate/service/internal/ServiceRegistryClosingCascadeTest.java b/hibernate-core/src/test/java/org/hibernate/service/internal/ServiceRegistryClosingCascadeTest.java index b39d43171c67..71726675f455 100644 --- a/hibernate-core/src/test/java/org/hibernate/service/internal/ServiceRegistryClosingCascadeTest.java +++ b/hibernate-core/src/test/java/org/hibernate/service/internal/ServiceRegistryClosingCascadeTest.java @@ -30,9 +30,9 @@ public void testSessionFactoryClosing() { StandardServiceRegistry sr = new StandardServiceRegistryBuilder(bsr).build(); assertTrue( ( (BootstrapServiceRegistryImpl) bsr ).isActive() ); Configuration config = new Configuration(); - SessionFactory sf = config.buildSessionFactory( sr ); + try (SessionFactory sf = config.buildSessionFactory( sr )) { - sf.close(); + } assertFalse( ( (BootstrapServiceRegistryImpl) bsr ).isActive() ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/subclassProxyInterface/SubclassProxyInterfaceTest.java b/hibernate-core/src/test/java/org/hibernate/subclassProxyInterface/SubclassProxyInterfaceTest.java index 7307370a5a32..31a830f20d54 100644 --- a/hibernate-core/src/test/java/org/hibernate/subclassProxyInterface/SubclassProxyInterfaceTest.java +++ b/hibernate-core/src/test/java/org/hibernate/subclassProxyInterface/SubclassProxyInterfaceTest.java @@ -24,8 +24,8 @@ public void testSubclassProxyInterfaces() { final Configuration cfg = new Configuration() .setProperty( Environment.DIALECT, H2Dialect.class.getName() ) .addClass( Person.class ); - ServiceRegistry serviceRegistry = ServiceRegistryBuilder.buildServiceRegistry( cfg.getProperties() ); - cfg.buildSessionFactory( serviceRegistry ).close(); - ServiceRegistryBuilder.destroy( serviceRegistry ); + try (ServiceRegistry serviceRegistry = ServiceRegistryBuilder.buildServiceRegistry( cfg.getProperties() )) { + cfg.buildSessionFactory( serviceRegistry ).close(); + } } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/ConfigurationTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/ConfigurationTest.java index 8b0c4376f749..dff877cdff65 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/ConfigurationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/ConfigurationTest.java @@ -31,24 +31,25 @@ */ public class ConfigurationTest { @Test - public void testDeclarativeMix() throws Exception { + public void testDeclarativeMix() { Configuration cfg = new Configuration(); cfg.configure( "org/hibernate/test/annotations/hibernate.cfg.xml" ); cfg.setProperty( Environment.HBM2DDL_AUTO, "create-drop" ); - SessionFactory sf = cfg.buildSessionFactory(); - assertNotNull( sf ); - Session s = sf.openSession(); - Transaction tx = s.beginTransaction(); - Query q = s.createQuery( "from Boat" ); - assertEquals( 0, q.list().size() ); - q = s.createQuery( "from Plane" ); - assertEquals( 0, q.list().size() ); - tx.commit(); - s.close(); - sf.close(); + try (SessionFactory sf = cfg.buildSessionFactory()) { + assertNotNull( sf ); + Session s = sf.openSession(); + Transaction tx = s.beginTransaction(); + Query q = s.createQuery( "from Boat" ); + assertEquals( 0, q.list().size() ); + q = s.createQuery( "from Plane" ); + assertEquals( 0, q.list().size() ); + tx.commit(); + s.close(); + } } - @Test - public void testIgnoringHbm() throws Exception { + + @Test + public void testIgnoringHbm() { Configuration cfg = new Configuration(); cfg.configure( "org/hibernate/test/annotations/hibernate.cfg.xml" ); cfg.setProperty( Environment.HBM2DDL_AUTO, "create-drop" ); @@ -84,90 +85,93 @@ public void testIgnoringHbm() throws Exception { } } - @Test - public void testPrecedenceHbm() throws Exception { + @Test + public void testPrecedenceHbm() { Configuration cfg = new Configuration(); cfg.configure( "org/hibernate/test/annotations/hibernate.cfg.xml" ); cfg.setProperty( Environment.HBM2DDL_AUTO, "create-drop" ); cfg.addAnnotatedClass( Boat.class ); - SessionFactory sf = cfg.buildSessionFactory(); - assertNotNull( sf ); - Session s = sf.openSession(); - s.getTransaction().begin(); - Boat boat = new Boat(); - boat.setSize( 12 ); - boat.setWeight( 34 ); - s.persist( boat ); - s.getTransaction().commit(); - s.clear(); - Transaction tx = s.beginTransaction(); - boat = (Boat) s.get( Boat.class, boat.getId() ); - assertTrue( "Annotation has precedence", 34 != boat.getWeight() ); - s.delete( boat ); - //s.getTransaction().commit(); - tx.commit(); - s.close(); - sf.close(); + try (SessionFactory sf = cfg.buildSessionFactory()) { + assertNotNull( sf ); + Session s = sf.openSession(); + s.getTransaction().begin(); + Boat boat = new Boat(); + boat.setSize( 12 ); + boat.setWeight( 34 ); + s.persist( boat ); + s.getTransaction().commit(); + s.clear(); + Transaction tx = s.beginTransaction(); + boat = (Boat) s.get( Boat.class, boat.getId() ); + assertTrue( "Annotation has precedence", 34 != boat.getWeight() ); + s.delete( boat ); + //s.getTransaction().commit(); + tx.commit(); + s.close(); + } } - @Test - public void testPrecedenceAnnotation() throws Exception { + + @Test + public void testPrecedenceAnnotation() { Configuration cfg = new Configuration(); cfg.configure( "org/hibernate/test/annotations/hibernate.cfg.xml" ); cfg.setProperty( Environment.HBM2DDL_AUTO, "create-drop" ); cfg.setProperty( Configuration.ARTEFACT_PROCESSING_ORDER, "class, hbm" ); cfg.addAnnotatedClass( Boat.class ); - SessionFactory sf = cfg.buildSessionFactory(); - assertNotNull( sf ); - Session s = sf.openSession(); - s.getTransaction().begin(); - Boat boat = new Boat(); - boat.setSize( 12 ); - boat.setWeight( 34 ); - s.persist( boat ); - s.getTransaction().commit(); - s.clear(); - Transaction tx = s.beginTransaction(); - boat = (Boat) s.get( Boat.class, boat.getId() ); - assertTrue( "Annotation has precedence", 34 == boat.getWeight() ); - s.delete( boat ); - tx.commit(); - s.close(); - sf.close(); + try (SessionFactory sf = cfg.buildSessionFactory()) { + assertNotNull( sf ); + Session s = sf.openSession(); + s.getTransaction().begin(); + Boat boat = new Boat(); + boat.setSize( 12 ); + boat.setWeight( 34 ); + s.persist( boat ); + s.getTransaction().commit(); + s.clear(); + Transaction tx = s.beginTransaction(); + boat = (Boat) s.get( Boat.class, boat.getId() ); + assertTrue( "Annotation has precedence", 34 == boat.getWeight() ); + s.delete( boat ); + tx.commit(); + s.close(); + } } - @Test - public void testHbmWithSubclassExtends() throws Exception { + + @Test + public void testHbmWithSubclassExtends() { Configuration cfg = new Configuration(); cfg.configure( "org/hibernate/test/annotations/hibernate.cfg.xml" ); cfg.addClass( Ferry.class ); cfg.setProperty( Environment.HBM2DDL_AUTO, "create-drop" ); - SessionFactory sf = cfg.buildSessionFactory(); - assertNotNull( sf ); - Session s = sf.openSession(); - Transaction tx = s.beginTransaction(); - Query q = s.createQuery( "from Ferry" ); - assertEquals( 0, q.list().size() ); - q = s.createQuery( "from Plane" ); - assertEquals( 0, q.list().size() ); - tx.commit(); - s.close(); - sf.close(); + try (SessionFactory sf = cfg.buildSessionFactory()) { + assertNotNull( sf ); + Session s = sf.openSession(); + Transaction tx = s.beginTransaction(); + Query q = s.createQuery( "from Ferry" ); + assertEquals( 0, q.list().size() ); + q = s.createQuery( "from Plane" ); + assertEquals( 0, q.list().size() ); + tx.commit(); + s.close(); + } } - @Test - public void testAnnReferencesHbm() throws Exception { + + @Test + public void testAnnReferencesHbm() { Configuration cfg = new Configuration(); cfg.configure( "org/hibernate/test/annotations/hibernate.cfg.xml" ); cfg.addAnnotatedClass( Port.class ); cfg.setProperty( Environment.HBM2DDL_AUTO, "create-drop" ); - SessionFactory sf = cfg.buildSessionFactory(); - assertNotNull( sf ); - Session s = sf.openSession(); - Transaction tx = s.beginTransaction(); - Query q = s.createQuery( "from Boat" ); - assertEquals( 0, q.list().size() ); - q = s.createQuery( "from Port" ); - assertEquals( 0, q.list().size() ); - tx.commit(); - s.close(); - sf.close(); + try (SessionFactory sf = cfg.buildSessionFactory()) { + assertNotNull( sf ); + Session s = sf.openSession(); + Transaction tx = s.beginTransaction(); + Query q = s.createQuery( "from Boat" ); + assertEquals( 0, q.list().size() ); + q = s.createQuery( "from Port" ); + assertEquals( 0, q.list().size() ); + tx.commit(); + s.close(); + } } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/SafeMappingTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/SafeMappingTest.java index 19e1db4e870c..445d4c02b41b 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/SafeMappingTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/SafeMappingTest.java @@ -44,6 +44,7 @@ public void testDeclarativeMix() throws Exception { if ( serviceRegistry != null ) { ServiceRegistryBuilder.destroy( serviceRegistry ); } + cfg.getStandardServiceRegistryBuilder().getBootstrapServiceRegistry().close(); } } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/SecuredBindingTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/SecuredBindingTest.java index 5ad40ede7038..316f1f5034d7 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/SecuredBindingTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/SecuredBindingTest.java @@ -60,6 +60,7 @@ public void testConfigurationMethods() throws Exception { if ( serviceRegistry != null ) { ServiceRegistryBuilder.destroy( serviceRegistry ); } + ac.getStandardServiceRegistryBuilder().getBootstrapServiceRegistry().close(); } } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/backquotes/BackquoteTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/backquotes/BackquoteTest.java index 0583b1bfd224..bc2f1bccd7df 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/backquotes/BackquoteTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/backquotes/BackquoteTest.java @@ -11,13 +11,14 @@ import java.io.PrintWriter; import java.io.StringWriter; -import org.jboss.logging.Logger; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.hibernate.MappingException; import org.hibernate.SessionFactory; +import org.hibernate.boot.registry.BootstrapServiceRegistry; +import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder; import org.hibernate.cfg.Configuration; import org.hibernate.cfg.Environment; import org.hibernate.service.ServiceRegistry; @@ -46,8 +47,12 @@ public void setUp() { @After public void tearDown() { - if(sessionFactory !=null) sessionFactory.close(); - if (serviceRegistry != null) ServiceRegistryBuilder.destroy(serviceRegistry); + if(sessionFactory !=null) { + sessionFactory.close(); + } + if (serviceRegistry != null) { + ServiceRegistryBuilder.destroy(serviceRegistry); + } } @Test @@ -55,15 +60,15 @@ public void tearDown() { public void testBackquotes() { try { Configuration config = new Configuration(); - config.addAnnotatedClass(Bug.class); - config.addAnnotatedClass(Category.class); + config.addAnnotatedClass( Bug.class ); + config.addAnnotatedClass( Category.class ); sessionFactory = config.buildSessionFactory( serviceRegistry ); } catch( Exception e ) { StringWriter writer = new StringWriter(); - e.printStackTrace(new PrintWriter(writer)); - log.debug(writer.toString()); - fail(e.getMessage()); + e.printStackTrace( new PrintWriter(writer) ); + log.debug( writer.toString() ); + fail( e.getMessage() ); } finally { if ( sessionFactory != null ) { @@ -83,12 +88,12 @@ public void testBackquotes() { @Test @TestForIssue( jiraKey = "HHH-4647" ) public void testInvalidReferenceToQuotedTableName() { - try { - Configuration config = new Configuration(); - config.addAnnotatedClass(Printer.class); - config.addAnnotatedClass(PrinterCable.class); - sessionFactory = config.buildSessionFactory( serviceRegistry ); - fail("expected MappingException to be thrown"); + try (BootstrapServiceRegistry serviceRegistry = new BootstrapServiceRegistryBuilder().build()) { + Configuration config = new Configuration( serviceRegistry ); + config.addAnnotatedClass( Printer.class ); + config.addAnnotatedClass( PrinterCable.class ); + sessionFactory = config.buildSessionFactory( this.serviceRegistry ); + fail( "expected MappingException to be thrown" ); } //we WANT MappingException to be thrown catch( MappingException e ) { @@ -96,9 +101,9 @@ public void testInvalidReferenceToQuotedTableName() { } catch(Exception e) { StringWriter writer = new StringWriter(); - e.printStackTrace(new PrintWriter(writer)); - log.debug(writer.toString()); - fail(e.getMessage()); + e.printStackTrace( new PrintWriter(writer) ); + log.debug( writer.toString() ); + fail( e.getMessage() ); } finally { if(sessionFactory!=null){ sessionFactory.close(); diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/configuration/ConfigurationTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/configuration/ConfigurationTest.java index dc7c68199690..2ebc58d30101 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/configuration/ConfigurationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/configuration/ConfigurationTest.java @@ -8,6 +8,8 @@ //$Id$ package org.hibernate.test.annotations.configuration; +import org.hibernate.boot.registry.BootstrapServiceRegistry; +import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder; import org.hibernate.cfg.Configuration; import org.junit.Assert; @@ -19,8 +21,8 @@ public class ConfigurationTest { @Test public void testMixPackageAndResourceOrdering() throws Exception { - try { - Configuration config = new Configuration(); + try (BootstrapServiceRegistry serviceRegistry = new BootstrapServiceRegistryBuilder().build()) { + Configuration config = new Configuration( serviceRegistry ); config.addResource( "org/hibernate/test/annotations/configuration/orm.xml" ); config.addPackage( "org.hibernate.test.annotations.configuration" ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/embeddables/EmbeddableIntegratorTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/embeddables/EmbeddableIntegratorTest.java index fb8b8e6cd5c4..50a41f1ae028 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/embeddables/EmbeddableIntegratorTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/embeddables/EmbeddableIntegratorTest.java @@ -37,11 +37,9 @@ public class EmbeddableIntegratorTest extends BaseUnitTestCase { */ @Test public void testWithoutIntegrator() { - SessionFactory sf = new Configuration().addAnnotatedClass( Investor.class ) + try (SessionFactory sf = new Configuration().addAnnotatedClass( Investor.class ) .setProperty( "hibernate.hbm2ddl.auto", "create-drop" ) - .buildSessionFactory(); - - try { + .buildSessionFactory()) { Session sess = sf.openSession(); try { sess.getTransaction().begin(); @@ -62,20 +60,14 @@ public void testWithoutIntegrator() { } sess.close(); } - finally { - sf.close(); - } } @Test public void testWithTypeContributor() { - SessionFactory sf = new Configuration().addAnnotatedClass( Investor.class ) + try (SessionFactory sf = new Configuration().addAnnotatedClass( Investor.class ) .registerTypeContributor( new InvestorTypeContributor() ) .setProperty( "hibernate.hbm2ddl.auto", "create-drop" ) - .buildSessionFactory(); - - Session sess = sf.openSession(); - try { + .buildSessionFactory(); Session sess = sf.openSession()) { sess.getTransaction().begin(); Investor myInv = getInvestor(); myInv.setId( 2L ); @@ -86,13 +78,6 @@ public void testWithTypeContributor() { Investor inv = (Investor) sess.get( Investor.class, 2L ); assertEquals( new BigDecimal( "100" ), inv.getInvestments().get( 0 ).getAmount().getAmount() ); - }catch (Exception e){ - sess.getTransaction().rollback(); - throw e; - } - finally { - sess.close(); - sf.close(); } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/embeddables/collection/EmbeddableWithManyToMany_HHH_11302_Test.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/embeddables/collection/EmbeddableWithManyToMany_HHH_11302_Test.java index 6b1ecb2b70eb..734b430a0357 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/embeddables/collection/EmbeddableWithManyToMany_HHH_11302_Test.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/embeddables/collection/EmbeddableWithManyToMany_HHH_11302_Test.java @@ -61,9 +61,6 @@ protected void buildSessionFactory() { "@OneToMany, @ManyToMany or @ElementCollection cannot be used inside an @Embeddable that is also contained within an @ElementCollection" ) ); } - finally { - serviceRegistry().destroy(); - } } @Test diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/embeddables/collection/EmbeddableWithOneToMany_HHH_11302_Test.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/embeddables/collection/EmbeddableWithOneToMany_HHH_11302_Test.java index 0ec874fca4a7..5034d75f0ea6 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/embeddables/collection/EmbeddableWithOneToMany_HHH_11302_Test.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/embeddables/collection/EmbeddableWithOneToMany_HHH_11302_Test.java @@ -61,9 +61,6 @@ protected void buildSessionFactory() { "@OneToMany, @ManyToMany or @ElementCollection cannot be used inside an @Embeddable that is also contained within an @ElementCollection" ) ); } - finally { - serviceRegistry().destroy(); - } } @Test diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/embeddables/collection/EmbeddableWithOneToMany_HHH_8564_Test.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/embeddables/collection/EmbeddableWithOneToMany_HHH_8564_Test.java index f69c38aaf7a1..13c575f43c29 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/embeddables/collection/EmbeddableWithOneToMany_HHH_8564_Test.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/embeddables/collection/EmbeddableWithOneToMany_HHH_8564_Test.java @@ -55,9 +55,6 @@ protected void buildSessionFactory() { "@OneToMany, @ManyToMany or @ElementCollection cannot be used inside an @Embeddable that is also contained within an @ElementCollection" ) ); } - finally { - serviceRegistry().destroy(); - } } @Test diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/embeddables/collection/EmbeddableWithOneToMany_HHH_8860_Test.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/embeddables/collection/EmbeddableWithOneToMany_HHH_8860_Test.java index 85212876f8e5..994b4e02a362 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/embeddables/collection/EmbeddableWithOneToMany_HHH_8860_Test.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/embeddables/collection/EmbeddableWithOneToMany_HHH_8860_Test.java @@ -53,9 +53,6 @@ protected void buildSessionFactory() { "@OneToMany, @ManyToMany or @ElementCollection cannot be used inside an @Embeddable that is also contained within an @ElementCollection" ) ); } - finally { - serviceRegistry().destroy(); - } } @Test diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/fetchprofile/FetchProfileTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/fetchprofile/FetchProfileTest.java index 5b507892d7a4..d2456aff283e 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/fetchprofile/FetchProfileTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/fetchprofile/FetchProfileTest.java @@ -57,19 +57,19 @@ public void testFetchProfileConfigured() { config.addAnnotatedClass( Order.class ); config.addAnnotatedClass( SupportTickets.class ); config.addAnnotatedClass( Country.class ); - SessionFactoryImplementor sessionImpl = ( SessionFactoryImplementor ) config.buildSessionFactory( + try (SessionFactoryImplementor sessionImpl = ( SessionFactoryImplementor ) config.buildSessionFactory( serviceRegistry - ); - - assertTrue( - "fetch profile not parsed properly", - sessionImpl.containsFetchProfileDefinition( "customer-with-orders" ) - ); - assertFalse( - "package info should not be parsed", - sessionImpl.containsFetchProfileDefinition( "package-profile-1" ) - ); - sessionImpl.close(); + )) { + + assertTrue( + "fetch profile not parsed properly", + sessionImpl.containsFetchProfileDefinition( "customer-with-orders" ) + ); + assertFalse( + "package info should not be parsed", + sessionImpl.containsFetchProfileDefinition( "package-profile-1" ) + ); + } } @Test @@ -148,15 +148,15 @@ public void testXmlOverride() { .getContextClassLoader() .getResourceAsStream( "org/hibernate/test/annotations/fetchprofile/mappings.hbm.xml" ); config.addInputStream( is ); - SessionFactoryImplementor sessionImpl = ( SessionFactoryImplementor ) config.buildSessionFactory( + try (SessionFactoryImplementor sessionImpl = ( SessionFactoryImplementor ) config.buildSessionFactory( serviceRegistry - ); + )) { - assertTrue( - "fetch profile not parsed properly", - sessionImpl.containsFetchProfileDefinition( "orders-profile" ) - ); - sessionImpl.close(); + assertTrue( + "fetch profile not parsed properly", + sessionImpl.containsFetchProfileDefinition( "orders-profile" ) + ); + } // now the same with no xml final MetadataSources metadataSources = new MetadataSources() @@ -187,18 +187,18 @@ public void testPackageConfiguredFetchProfile() { config.addAnnotatedClass( SupportTickets.class ); config.addAnnotatedClass( Country.class ); config.addPackage( Customer.class.getPackage().getName() ); - SessionFactoryImplementor sessionImpl = ( SessionFactoryImplementor ) config.buildSessionFactory( + try (SessionFactoryImplementor sessionImpl = ( SessionFactoryImplementor ) config.buildSessionFactory( serviceRegistry - ); - - assertTrue( - "fetch profile not parsed properly", - sessionImpl.containsFetchProfileDefinition( "package-profile-1" ) - ); - assertTrue( - "fetch profile not parsed properly", - sessionImpl.containsFetchProfileDefinition( "package-profile-2" ) - ); - sessionImpl.close(); + )) { + + assertTrue( + "fetch profile not parsed properly", + sessionImpl.containsFetchProfileDefinition( "package-profile-1" ) + ); + assertTrue( + "fetch profile not parsed properly", + sessionImpl.containsFetchProfileDefinition( "package-profile-2" ) + ); + } } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/fetchprofile/MappedByFetchProfileUnitTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/fetchprofile/MappedByFetchProfileUnitTest.java index c3955ecca3a8..91e498672de7 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/fetchprofile/MappedByFetchProfileUnitTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/fetchprofile/MappedByFetchProfileUnitTest.java @@ -34,19 +34,19 @@ public void testFetchProfileConfigured() { Configuration config = new Configuration(); config.addAnnotatedClass( Customer6.class ); config.addAnnotatedClass( Address.class ); - SessionFactoryImplementor sessionImpl = ( SessionFactoryImplementor ) config.buildSessionFactory( + try (SessionFactoryImplementor sessionImpl = ( SessionFactoryImplementor ) config.buildSessionFactory( serviceRegistry - ); + )) { - assertTrue( - "fetch profile not parsed properly", - sessionImpl.containsFetchProfileDefinition( "address-with-customer" ) - ); - assertTrue( - "fetch profile not parsed properly", - sessionImpl.containsFetchProfileDefinition( "customer-with-address" ) - ); - sessionImpl.close(); + assertTrue( + "fetch profile not parsed properly", + sessionImpl.containsFetchProfileDefinition( "address-with-customer" ) + ); + assertTrue( + "fetch profile not parsed properly", + sessionImpl.containsFetchProfileDefinition( "customer-with-address" ) + ); + } } @Test @@ -55,19 +55,19 @@ public void testPackageConfiguredFetchProfile() { config.addAnnotatedClass( Customer6.class ); config.addAnnotatedClass( Address.class ); config.addPackage( Address.class.getPackage().getName() ); - SessionFactoryImplementor sessionImpl = ( SessionFactoryImplementor ) config.buildSessionFactory( + try (SessionFactoryImplementor sessionImpl = ( SessionFactoryImplementor ) config.buildSessionFactory( serviceRegistry - ); + )) { - assertTrue( - "fetch profile not parsed properly", - sessionImpl.containsFetchProfileDefinition( "mappedBy-package-profile-1" ) - ); - assertTrue( - "fetch profile not parsed properly", - sessionImpl.containsFetchProfileDefinition( "mappedBy-package-profile-2" ) - ); - sessionImpl.close(); + assertTrue( + "fetch profile not parsed properly", + sessionImpl.containsFetchProfileDefinition( "mappedBy-package-profile-1" ) + ); + assertTrue( + "fetch profile not parsed properly", + sessionImpl.containsFetchProfileDefinition( "mappedBy-package-profile-2" ) + ); + } } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/formula/JoinColumnOrFormulaTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/formula/JoinColumnOrFormulaTest.java index 375c5e46479d..9b0f9d6c4110 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/formula/JoinColumnOrFormulaTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/formula/JoinColumnOrFormulaTest.java @@ -18,6 +18,8 @@ import org.hibernate.annotations.JoinFormula; import org.hibernate.boot.Metadata; import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.BootstrapServiceRegistry; +import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; @@ -50,15 +52,17 @@ public void after() { @TestForIssue( jiraKey = "HHH-9897" ) @FailureExpected( jiraKey = "HHH-9897" ) public void testUseOfJoinColumnOrFormula() { - Metadata metadata = new MetadataSources() - .addAnnotatedClass( A.class ) - .addAnnotatedClass( D.class ) - .buildMetadata(); + try (BootstrapServiceRegistry serviceRegistry = new BootstrapServiceRegistryBuilder().build()) { + Metadata metadata = new MetadataSources( serviceRegistry ) + .addAnnotatedClass( A.class ) + .addAnnotatedClass( D.class ) + .buildMetadata(); - // Binding to the mapping model works after the simple change for HHH-9897 - // But building the SessionFactory fails in the collection persister trying to - // use the formula (it expects Columns too) - metadata.buildSessionFactory().close(); + // Binding to the mapping model works after the simple change for HHH-9897 + // But building the SessionFactory fails in the collection persister trying to + // use the formula (it expects Columns too) + metadata.buildSessionFactory().close(); + } } @Entity( name = "A" ) diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/override/inheritance/EntityInheritanceAttributeOverrideTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/override/inheritance/EntityInheritanceAttributeOverrideTest.java index 7ed667757d8f..e1dcf07d2610 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/override/inheritance/EntityInheritanceAttributeOverrideTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/override/inheritance/EntityInheritanceAttributeOverrideTest.java @@ -11,6 +11,7 @@ import javax.persistence.AttributeOverride; import javax.persistence.Column; import javax.persistence.Entity; +import javax.persistence.EntityManagerFactory; import javax.persistence.Id; import javax.persistence.Inheritance; import javax.persistence.InheritanceType; @@ -39,24 +40,26 @@ public class EntityInheritanceAttributeOverrideTest extends BaseEntityManagerFun @Override public Class[] getAnnotatedClasses() { - return new Class[]{ - CategoryEntity.class, - TaxonEntity.class, - AbstractEntity.class + return new Class[] { + CategoryEntity.class, + TaxonEntity.class, + AbstractEntity.class }; } - @Override - public void buildEntityManagerFactory() { + public EntityManagerFactory produceEntityManagerFactory() { Triggerable warningLogged = logInspection.watchForLogMessages( "HHH000499:" ); super.buildEntityManagerFactory(); + EntityManagerFactory entityManagerFactory = entityManagerFactory(); assertTrue("A warning should have been logged for this unsupported configuration", warningLogged.wasTriggered()); + return entityManagerFactory; } @Test public void test() { + produceEntityManagerFactory().close(); } @Entity(name = "AbstractEntity") diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/JPAXMLOverriddenAnnotationReaderTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/JPAXMLOverriddenAnnotationReaderTest.java index 8eaec9352f65..1c12a7a146cd 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/JPAXMLOverriddenAnnotationReaderTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/JPAXMLOverriddenAnnotationReaderTest.java @@ -15,6 +15,8 @@ import org.hibernate.testing.boot.BootstrapContextImpl; import org.hibernate.testing.junit4.BaseUnitTestCase; import org.hibernate.testing.TestForIssue; +import org.junit.After; +import org.junit.Before; import org.junit.Test; import javax.persistence.*; @@ -29,19 +31,32 @@ */ @TestForIssue(jiraKey = "HHH-14529") public class JPAXMLOverriddenAnnotationReaderTest extends BaseUnitTestCase { + + private BootstrapContextImpl bootstrapContext; + + @Before + public void init() { + bootstrapContext = new BootstrapContextImpl(); + } + + @After + public void destroy() { + bootstrapContext.close(); + } + @Test public void testMappedSuperclassAnnotations() throws Exception { XMLContext context = buildContext( "org/hibernate/test/annotations/reflection/metadata-complete.xml" ); - JPAXMLOverriddenAnnotationReader reader = new JPAXMLOverriddenAnnotationReader( Organization.class, context, BootstrapContextImpl.INSTANCE ); + JPAXMLOverriddenAnnotationReader reader = new JPAXMLOverriddenAnnotationReader( Organization.class, context, bootstrapContext ); assertTrue( reader.isAnnotationPresent( MappedSuperclass.class ) ); } @Test public void testEntityRelatedAnnotations() throws Exception { XMLContext context = buildContext( "org/hibernate/test/annotations/reflection/orm.xml" ); - JPAXMLOverriddenAnnotationReader reader = new JPAXMLOverriddenAnnotationReader( Administration.class, context, BootstrapContextImpl.INSTANCE ); + JPAXMLOverriddenAnnotationReader reader = new JPAXMLOverriddenAnnotationReader( Administration.class, context, bootstrapContext ); assertNotNull( reader.getAnnotation( Entity.class ) ); assertEquals( "Default value in xml entity should not override @Entity.name", "JavaAdministration", @@ -75,7 +90,7 @@ public void testEntityRelatedAnnotations() throws Exception { assertEquals( "wrong tble name", "tablehilo", reader.getAnnotation( TableGenerator.class ).table() ); assertEquals( "no schema overriding", "myschema", reader.getAnnotation( TableGenerator.class ).schema() ); - reader = new JPAXMLOverriddenAnnotationReader( Match.class, context, BootstrapContextImpl.INSTANCE ); + reader = new JPAXMLOverriddenAnnotationReader( Match.class, context, bootstrapContext ); assertNotNull( reader.getAnnotation( Table.class ) ); assertEquals( "Java annotation not taken into account", "matchtable", reader.getAnnotation( Table.class ).name() @@ -123,10 +138,10 @@ public void testEntityRelatedAnnotations() throws Exception { assertNotNull( reader.getAnnotation( ExcludeSuperclassListeners.class ) ); assertNotNull( reader.getAnnotation( ExcludeDefaultListeners.class ) ); - reader = new JPAXMLOverriddenAnnotationReader( Competition.class, context, BootstrapContextImpl.INSTANCE ); + reader = new JPAXMLOverriddenAnnotationReader( Competition.class, context, bootstrapContext ); assertNotNull( reader.getAnnotation( MappedSuperclass.class ) ); - reader = new JPAXMLOverriddenAnnotationReader( TennisMatch.class, context, BootstrapContextImpl.INSTANCE ); + reader = new JPAXMLOverriddenAnnotationReader( TennisMatch.class, context, bootstrapContext ); assertNull( "Mutualize PKJC into PKJCs", reader.getAnnotation( PrimaryKeyJoinColumn.class ) ); assertNotNull( reader.getAnnotation( PrimaryKeyJoinColumns.class ) ); assertEquals( @@ -153,7 +168,7 @@ public void testEntityRelatedAnnotations() throws Exception { ); - reader = new JPAXMLOverriddenAnnotationReader( SocialSecurityPhysicalAccount.class, context, BootstrapContextImpl.INSTANCE ); + reader = new JPAXMLOverriddenAnnotationReader( SocialSecurityPhysicalAccount.class, context, bootstrapContext ); assertNotNull( reader.getAnnotation( IdClass.class ) ); assertEquals( "id-class not used", SocialSecurityNumber.class, reader.getAnnotation( IdClass.class ).value() ); assertEquals( @@ -174,7 +189,7 @@ public void testEntityRelatedAnnotationsMetadataComplete() throws Exception { XMLContext context = buildContext( "org/hibernate/test/annotations/reflection/metadata-complete.xml" ); - JPAXMLOverriddenAnnotationReader reader = new JPAXMLOverriddenAnnotationReader( Administration.class, context, BootstrapContextImpl.INSTANCE ); + JPAXMLOverriddenAnnotationReader reader = new JPAXMLOverriddenAnnotationReader( Administration.class, context, bootstrapContext ); assertNotNull( reader.getAnnotation( Entity.class ) ); assertEquals( "Metadata complete should ignore java annotations", "", reader.getAnnotation( Entity.class ).name() @@ -183,7 +198,7 @@ public void testEntityRelatedAnnotationsMetadataComplete() throws Exception { assertEquals( "@Table should not be used", "", reader.getAnnotation( Table.class ).name() ); assertEquals( "Default schema not overriden", "myschema", reader.getAnnotation( Table.class ).schema() ); - reader = new JPAXMLOverriddenAnnotationReader( Match.class, context, BootstrapContextImpl.INSTANCE ); + 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() ); @@ -194,14 +209,14 @@ public void testEntityRelatedAnnotationsMetadataComplete() throws Exception { assertNull( reader.getAnnotation( NamedQueries.class ) ); assertNull( reader.getAnnotation( NamedNativeQueries.class ) ); - reader = new JPAXMLOverriddenAnnotationReader( TennisMatch.class, context, BootstrapContextImpl.INSTANCE ); + reader = new JPAXMLOverriddenAnnotationReader( TennisMatch.class, context, bootstrapContext ); assertNull( reader.getAnnotation( PrimaryKeyJoinColumn.class ) ); assertNull( reader.getAnnotation( PrimaryKeyJoinColumns.class ) ); - reader = new JPAXMLOverriddenAnnotationReader( Competition.class, context, BootstrapContextImpl.INSTANCE ); + reader = new JPAXMLOverriddenAnnotationReader( Competition.class, context, bootstrapContext ); assertNull( reader.getAnnotation( MappedSuperclass.class ) ); - reader = new JPAXMLOverriddenAnnotationReader( SocialSecurityMoralAccount.class, context, BootstrapContextImpl.INSTANCE ); + reader = new JPAXMLOverriddenAnnotationReader( SocialSecurityMoralAccount.class, context, bootstrapContext ); assertNull( reader.getAnnotation( IdClass.class ) ); assertNull( reader.getAnnotation( DiscriminatorValue.class ) ); assertNull( reader.getAnnotation( DiscriminatorColumn.class ) ); @@ -213,11 +228,11 @@ public void testEntityRelatedAnnotationsMetadataComplete() throws Exception { public void testIdRelatedAnnotations() throws Exception { XMLContext context = buildContext( "org/hibernate/test/annotations/reflection/orm.xml" ); Method method = Administration.class.getDeclaredMethod( "getId" ); - JPAXMLOverriddenAnnotationReader reader = new JPAXMLOverriddenAnnotationReader( method, context, BootstrapContextImpl.INSTANCE ); + JPAXMLOverriddenAnnotationReader reader = new JPAXMLOverriddenAnnotationReader( method, context, bootstrapContext ); assertNull( reader.getAnnotation( Id.class ) ); assertNull( reader.getAnnotation( Column.class ) ); Field field = Administration.class.getDeclaredField( "id" ); - reader = new JPAXMLOverriddenAnnotationReader( field, context, BootstrapContextImpl.INSTANCE ); + reader = new JPAXMLOverriddenAnnotationReader( field, context, bootstrapContext ); assertNotNull( reader.getAnnotation( Id.class ) ); assertNotNull( reader.getAnnotation( GeneratedValue.class ) ); assertEquals( GenerationType.SEQUENCE, reader.getAnnotation( GeneratedValue.class ).strategy() ); @@ -234,23 +249,23 @@ public void testIdRelatedAnnotations() throws Exception { "org/hibernate/test/annotations/reflection/metadata-complete.xml" ); method = Administration.class.getDeclaredMethod( "getId" ); - reader = new JPAXMLOverriddenAnnotationReader( method, context, BootstrapContextImpl.INSTANCE ); + reader = new JPAXMLOverriddenAnnotationReader( method, context, bootstrapContext ); assertNotNull( "Default access type when not defined in metadata complete should be property", reader.getAnnotation( Id.class ) ); field = Administration.class.getDeclaredField( "id" ); - reader = new JPAXMLOverriddenAnnotationReader( field, context, BootstrapContextImpl.INSTANCE ); + reader = new JPAXMLOverriddenAnnotationReader( field, context, bootstrapContext ); assertNull( "Default access type when not defined in metadata complete should be property", reader.getAnnotation( Id.class ) ); method = BusTrip.class.getDeclaredMethod( "getId" ); - reader = new JPAXMLOverriddenAnnotationReader( method, context, BootstrapContextImpl.INSTANCE ); + reader = new JPAXMLOverriddenAnnotationReader( method, context, bootstrapContext ); assertNull( reader.getAnnotation( EmbeddedId.class ) ); field = BusTrip.class.getDeclaredField( "id" ); - reader = new JPAXMLOverriddenAnnotationReader( field, context, BootstrapContextImpl.INSTANCE ); + reader = new JPAXMLOverriddenAnnotationReader( field, context, bootstrapContext ); assertNotNull( reader.getAnnotation( EmbeddedId.class ) ); assertNotNull( reader.getAnnotation( AttributeOverrides.class ) ); assertEquals( 1, reader.getAnnotation( AttributeOverrides.class ).value().length ); @@ -262,22 +277,22 @@ public void testBasicRelatedAnnotations() throws Exception { "org/hibernate/test/annotations/reflection/metadata-complete.xml" ); Field field = BusTrip.class.getDeclaredField( "status" ); - JPAXMLOverriddenAnnotationReader reader = new JPAXMLOverriddenAnnotationReader( field, context, BootstrapContextImpl.INSTANCE ); + JPAXMLOverriddenAnnotationReader reader = new JPAXMLOverriddenAnnotationReader( field, context, bootstrapContext ); assertNotNull( reader.getAnnotation( Enumerated.class ) ); assertEquals( EnumType.STRING, reader.getAnnotation( Enumerated.class ).value() ); assertEquals( false, reader.getAnnotation( Basic.class ).optional() ); field = BusTrip.class.getDeclaredField( "serial" ); - reader = new JPAXMLOverriddenAnnotationReader( field, context, BootstrapContextImpl.INSTANCE ); + reader = new JPAXMLOverriddenAnnotationReader( field, context, bootstrapContext ); assertNotNull( reader.getAnnotation( Lob.class ) ); assertEquals( "serialbytes", reader.getAnnotation( Columns.class ).columns()[0].name() ); field = BusTrip.class.getDeclaredField( "terminusTime" ); - reader = new JPAXMLOverriddenAnnotationReader( field, context, BootstrapContextImpl.INSTANCE ); + reader = new JPAXMLOverriddenAnnotationReader( field, context, bootstrapContext ); assertNotNull( reader.getAnnotation( Temporal.class ) ); assertEquals( TemporalType.TIMESTAMP, reader.getAnnotation( Temporal.class ).value() ); assertEquals( FetchType.LAZY, reader.getAnnotation( Basic.class ).fetch() ); field = BusTripPk.class.getDeclaredField( "busDriver" ); - reader = new JPAXMLOverriddenAnnotationReader( field, context, BootstrapContextImpl.INSTANCE ); + reader = new JPAXMLOverriddenAnnotationReader( field, context, bootstrapContext ); assertNotNull( reader.isAnnotationPresent( Basic.class ) ); } @@ -285,7 +300,7 @@ public void testBasicRelatedAnnotations() throws Exception { public void testVersionRelatedAnnotations() throws Exception { XMLContext context = buildContext( "org/hibernate/test/annotations/reflection/orm.xml" ); Method method = Administration.class.getDeclaredMethod( "getVersion" ); - JPAXMLOverriddenAnnotationReader reader = new JPAXMLOverriddenAnnotationReader( method, context, BootstrapContextImpl.INSTANCE ); + JPAXMLOverriddenAnnotationReader reader = new JPAXMLOverriddenAnnotationReader( method, context, bootstrapContext ); assertNotNull( reader.getAnnotation( Version.class ) ); Field field = Match.class.getDeclaredField( "version" ); @@ -297,12 +312,12 @@ public void testTransientAndEmbeddedRelatedAnnotations() throws Exception { XMLContext context = buildContext( "org/hibernate/test/annotations/reflection/orm.xml" ); Field field = Administration.class.getDeclaredField( "transientField" ); - JPAXMLOverriddenAnnotationReader reader = new JPAXMLOverriddenAnnotationReader( field, context, BootstrapContextImpl.INSTANCE ); + JPAXMLOverriddenAnnotationReader reader = new JPAXMLOverriddenAnnotationReader( field, context, bootstrapContext ); assertNotNull( reader.getAnnotation( Transient.class ) ); assertNull( reader.getAnnotation( Basic.class ) ); field = Match.class.getDeclaredField( "playerASSN" ); - reader = new JPAXMLOverriddenAnnotationReader( field, context, BootstrapContextImpl.INSTANCE ); + reader = new JPAXMLOverriddenAnnotationReader( field, context, bootstrapContext ); assertNotNull( reader.getAnnotation( Embedded.class ) ); } @@ -311,7 +326,7 @@ public void testAssociationRelatedAnnotations() throws Exception { XMLContext context = buildContext( "org/hibernate/test/annotations/reflection/orm.xml" ); Field field = Administration.class.getDeclaredField( "defaultBusTrip" ); - JPAXMLOverriddenAnnotationReader reader = new JPAXMLOverriddenAnnotationReader( field, context, BootstrapContextImpl.INSTANCE ); + JPAXMLOverriddenAnnotationReader reader = new JPAXMLOverriddenAnnotationReader( field, context, bootstrapContext ); assertNotNull( reader.getAnnotation( OneToOne.class ) ); assertNull( reader.getAnnotation( JoinColumns.class ) ); assertNotNull( reader.getAnnotation( PrimaryKeyJoinColumns.class ) ); @@ -324,7 +339,7 @@ public void testAssociationRelatedAnnotations() throws Exception { "org/hibernate/test/annotations/reflection/metadata-complete.xml" ); field = BusTrip.class.getDeclaredField( "players" ); - reader = new JPAXMLOverriddenAnnotationReader( field, context, BootstrapContextImpl.INSTANCE ); + reader = new JPAXMLOverriddenAnnotationReader( field, context, bootstrapContext ); assertNotNull( reader.getAnnotation( OneToMany.class ) ); assertNotNull( reader.getAnnotation( JoinColumns.class ) ); assertEquals( 2, reader.getAnnotation( JoinColumns.class ).value().length ); @@ -333,7 +348,7 @@ public void testAssociationRelatedAnnotations() throws Exception { assertEquals( "name", reader.getAnnotation( MapKey.class ).name() ); field = BusTrip.class.getDeclaredField( "roads" ); - reader = new JPAXMLOverriddenAnnotationReader( field, context, BootstrapContextImpl.INSTANCE ); + reader = new JPAXMLOverriddenAnnotationReader( field, context, bootstrapContext ); assertNotNull( reader.getAnnotation( ManyToMany.class ) ); assertNotNull( reader.getAnnotation( JoinTable.class ) ); assertEquals( "bus_road", reader.getAnnotation( JoinTable.class ).name() ); @@ -350,7 +365,7 @@ public void testElementCollectionConverter() throws Exception { XMLContext context = buildContext( "org/hibernate/test/annotations/reflection/orm.xml" ); Field field = Company.class.getDeclaredField( "organizations" ); - JPAXMLOverriddenAnnotationReader reader = new JPAXMLOverriddenAnnotationReader( field, context, BootstrapContextImpl.INSTANCE ); + JPAXMLOverriddenAnnotationReader reader = new JPAXMLOverriddenAnnotationReader( field, context, bootstrapContext ); assertNotNull( reader.getAnnotation( ElementCollection.class ) ); assertNotNull( reader.getAnnotation( Converts.class ) ); assertNotNull( reader.getAnnotation( Converts.class ).value() ); @@ -363,20 +378,20 @@ public void testEntityListeners() throws Exception { XMLContext context = buildContext( "org/hibernate/test/annotations/reflection/orm.xml" ); Method method = Administration.class.getDeclaredMethod( "calculate" ); - JPAXMLOverriddenAnnotationReader reader = new JPAXMLOverriddenAnnotationReader( method, context, BootstrapContextImpl.INSTANCE ); + JPAXMLOverriddenAnnotationReader reader = new JPAXMLOverriddenAnnotationReader( method, context, bootstrapContext ); assertTrue( reader.isAnnotationPresent( PrePersist.class ) ); - reader = new JPAXMLOverriddenAnnotationReader( Administration.class, context, BootstrapContextImpl.INSTANCE ); + reader = new JPAXMLOverriddenAnnotationReader( Administration.class, context, bootstrapContext ); assertTrue( reader.isAnnotationPresent( EntityListeners.class ) ); assertEquals( 1, reader.getAnnotation( EntityListeners.class ).value().length ); assertEquals( LogListener.class, reader.getAnnotation( EntityListeners.class ).value()[0] ); method = LogListener.class.getDeclaredMethod( "noLog", Object.class ); - reader = new JPAXMLOverriddenAnnotationReader( method, context, BootstrapContextImpl.INSTANCE ); + reader = new JPAXMLOverriddenAnnotationReader( method, context, bootstrapContext ); assertTrue( reader.isAnnotationPresent( PostLoad.class ) ); method = LogListener.class.getDeclaredMethod( "log", Object.class ); - reader = new JPAXMLOverriddenAnnotationReader( method, context, BootstrapContextImpl.INSTANCE ); + reader = new JPAXMLOverriddenAnnotationReader( method, context, bootstrapContext ); assertTrue( reader.isAnnotationPresent( PrePersist.class ) ); assertFalse( reader.isAnnotationPresent( PostPersist.class ) ); @@ -387,7 +402,7 @@ public void testEntityListeners() throws Exception { private XMLContext buildContext(String ormfile) throws IOException { XMLMappingHelper xmlHelper = new XMLMappingHelper(); JaxbEntityMappings mappings = xmlHelper.readOrmXmlMappings( ormfile ); - XMLContext context = new XMLContext( BootstrapContextImpl.INSTANCE ); + XMLContext context = new XMLContext( bootstrapContext ); context.addDocument( mappings ); return context; } diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/XMLContextTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/XMLContextTest.java index 22f6e4dbb6f4..4608b7eb40fb 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/XMLContextTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/XMLContextTest.java @@ -12,6 +12,8 @@ import org.hibernate.testing.TestForIssue; import org.hibernate.testing.boot.BootstrapContextImpl; +import org.junit.After; +import org.junit.Before; import org.junit.Test; /** @@ -19,10 +21,23 @@ */ @TestForIssue(jiraKey = "HHH-14529") public class XMLContextTest { + + private BootstrapContextImpl bootstrapContext; + + @Before + public void init() { + bootstrapContext = new BootstrapContextImpl(); + } + + @After + public void destroy() { + bootstrapContext.close(); + } + @Test public void testAll() throws Exception { XMLMappingHelper xmlHelper = new XMLMappingHelper(); - final XMLContext context = new XMLContext( BootstrapContextImpl.INSTANCE ); + final XMLContext context = new XMLContext( bootstrapContext ); JaxbEntityMappings mappings = xmlHelper.readOrmXmlMappings( "org/hibernate/test/annotations/reflection/orm.xml" ); context.addDocument( mappings ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlTestCase.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlTestCase.java index b5b18a78150c..540b461dc94f 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlTestCase.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/Ejb3XmlTestCase.java @@ -18,6 +18,9 @@ import org.hibernate.testing.boot.BootstrapContextImpl; import org.hibernate.testing.junit4.BaseUnitTestCase; +import org.junit.After; +import org.junit.Before; + import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertTrue; @@ -31,9 +34,21 @@ public abstract class Ejb3XmlTestCase extends BaseUnitTestCase { protected JPAXMLOverriddenAnnotationReader reader; + private BootstrapContextImpl bootstrapContext; + protected Ejb3XmlTestCase() { } + @Before + public void init() { + bootstrapContext = new BootstrapContextImpl(); + } + + @After + public void destroy() { + bootstrapContext.close(); + } + protected void assertAnnotationPresent(Class annotationType) { assertTrue( "Expected annotation " + annotationType.getSimpleName() + " was not present", @@ -52,7 +67,7 @@ protected JPAXMLOverriddenAnnotationReader getReader(Class entityClass, Strin throws Exception { AnnotatedElement el = getAnnotatedElement( entityClass, fieldName ); XMLContext xmlContext = getContext( ormResourceName ); - return new JPAXMLOverriddenAnnotationReader( el, xmlContext, BootstrapContextImpl.INSTANCE ); + return new JPAXMLOverriddenAnnotationReader( el, xmlContext, bootstrapContext ); } protected AnnotatedElement getAnnotatedElement(Class entityClass, String fieldName) throws Exception { @@ -68,7 +83,7 @@ protected XMLContext getContext(String resourceName) throws Exception { protected XMLContext getContext(InputStream is, String resourceName) throws Exception { XMLMappingHelper xmlHelper = new XMLMappingHelper(); JaxbEntityMappings mappings = xmlHelper.readOrmXmlMappings( is, resourceName ); - XMLContext context = new XMLContext( BootstrapContextImpl.INSTANCE ); + XMLContext context = new XMLContext( bootstrapContext ); context.addDocument( mappings ); return context; } diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/NonExistentOrmVersionTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/NonExistentOrmVersionTest.java index adc2b3d6fbe2..bb6988d48b31 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/NonExistentOrmVersionTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/xml/ejb3/NonExistentOrmVersionTest.java @@ -8,6 +8,7 @@ import org.hibernate.InvalidMappingException; import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.BootstrapServiceRegistry; import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder; import org.hibernate.internal.util.xml.UnsupportedOrmXsdVersionException; @@ -21,9 +22,8 @@ public class NonExistentOrmVersionTest extends BaseUnitTestCase { @Test public void testNonExistentOrmVersion() { - try { - BootstrapServiceRegistryBuilder builder = new BootstrapServiceRegistryBuilder(); - new MetadataSources( builder.build() ) + try (BootstrapServiceRegistry serviceRegistry = new BootstrapServiceRegistryBuilder().build()) { + new MetadataSources( serviceRegistry ) .addResource( "org/hibernate/test/annotations/xml/ejb3/orm5.xml" ) .buildMetadata(); fail( "Expecting failure due to unsupported xsd version" ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/boot/jaxb/hbm/internal/XmlBindingChecker.java b/hibernate-core/src/test/java/org/hibernate/test/boot/jaxb/hbm/internal/XmlBindingChecker.java index 21d9c30aac6a..b2cab5c18c3e 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/boot/jaxb/hbm/internal/XmlBindingChecker.java +++ b/hibernate-core/src/test/java/org/hibernate/test/boot/jaxb/hbm/internal/XmlBindingChecker.java @@ -32,7 +32,8 @@ public static void checkValidGeneration(JaxbHbmHibernateMapping hbmMapping) ByteArrayOutputStream bos = new ByteArrayOutputStream(); jaxbMarshaller.marshal( hbmMapping, bos ); ByteArrayInputStream is = new ByteArrayInputStream( bos.toByteArray() ); - ServiceRegistry sr = new StandardServiceRegistryBuilder().build(); - new XmlMappingBinderAccess( sr ).bind( is ); + try (ServiceRegistry sr = new StandardServiceRegistryBuilder().build()) { + new XmlMappingBinderAccess( sr ).bind( is ); + } } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/cache/NonRootEntityWithCacheAnnotationTest.java b/hibernate-core/src/test/java/org/hibernate/test/cache/NonRootEntityWithCacheAnnotationTest.java index 8af2f60ee44e..f4721274b607 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/cache/NonRootEntityWithCacheAnnotationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/cache/NonRootEntityWithCacheAnnotationTest.java @@ -54,21 +54,20 @@ public void testCacheOnNonRootEntity() { settings.put( Environment.CACHE_REGION_FACTORY, CachingRegionFactory.class.getName() ); settings.put( AvailableSettings.JPA_SHARED_CACHE_MODE, SharedCacheMode.ENABLE_SELECTIVE ); - ServiceRegistryImplementor serviceRegistry = (ServiceRegistryImplementor) new StandardServiceRegistryBuilder() + try (ServiceRegistryImplementor serviceRegistry = (ServiceRegistryImplementor) new StandardServiceRegistryBuilder() .applySettings( settings ) - .build(); + .build()) { - Triggerable triggerable = logInspection.watchForLogMessages( "HHH000482" ); + Triggerable triggerable = logInspection.watchForLogMessages( "HHH000482" ); - Metadata metadata = new MetadataSources( serviceRegistry ) - .addAnnotatedClass( ABase.class ) - .addAnnotatedClass( AEntity.class ) - .buildMetadata(); + Metadata metadata = new MetadataSources( serviceRegistry ) + .addAnnotatedClass( ABase.class ) + .addAnnotatedClass( AEntity.class ) + .buildMetadata(); - assertTrue( triggerable.wasTriggered() ); - assertFalse( metadata.getEntityBinding( AEntity.class.getName() ).isCached() ); - - serviceRegistry.destroy(); + assertTrue( triggerable.wasTriggered() ); + assertFalse( metadata.getEntityBinding( AEntity.class.getName() ).isCached() ); + } } @Entity diff --git a/hibernate-core/src/test/java/org/hibernate/test/cache/NonRootEntityWithCacheableAnnotationTest.java b/hibernate-core/src/test/java/org/hibernate/test/cache/NonRootEntityWithCacheableAnnotationTest.java index f613fdd51149..538fe5cfd9b5 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/cache/NonRootEntityWithCacheableAnnotationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/cache/NonRootEntityWithCacheableAnnotationTest.java @@ -53,23 +53,22 @@ public void testCacheableOnNonRootEntity() { settings.put( AvailableSettings.DEFAULT_CACHE_CONCURRENCY_STRATEGY, "read-write" ); settings.put( AvailableSettings.JPA_SHARED_CACHE_MODE, SharedCacheMode.ENABLE_SELECTIVE ); - ServiceRegistryImplementor serviceRegistry = (ServiceRegistryImplementor) new StandardServiceRegistryBuilder() + try (ServiceRegistryImplementor serviceRegistry = (ServiceRegistryImplementor) new StandardServiceRegistryBuilder() .applySettings( settings ) - .build(); + .build()) { - Triggerable triggerable = logInspection.watchForLogMessages( "HHH000482" ); + Triggerable triggerable = logInspection.watchForLogMessages( "HHH000482" ); - Metadata metadata = new MetadataSources( serviceRegistry ) - .addAnnotatedClass( ABase.class ) - .addAnnotatedClass( AEntity.class ) - .buildMetadata(); + Metadata metadata = new MetadataSources( serviceRegistry ) + .addAnnotatedClass( ABase.class ) + .addAnnotatedClass( AEntity.class ) + .buildMetadata(); - assertFalse( metadata.getEntityBinding( ABase.class.getName() ).isCached() ); - assertTrue( metadata.getEntityBinding( AEntity.class.getName() ).isCached() ); + assertFalse( metadata.getEntityBinding( ABase.class.getName() ).isCached() ); + assertTrue( metadata.getEntityBinding( AEntity.class.getName() ).isCached() ); - assertFalse( triggerable.wasTriggered() ); - - serviceRegistry.destroy(); + assertFalse( triggerable.wasTriggered() ); + } } @Entity diff --git a/hibernate-core/src/test/java/org/hibernate/test/cache/SingleRegisteredProviderTest.java b/hibernate-core/src/test/java/org/hibernate/test/cache/SingleRegisteredProviderTest.java index 6525a21ecf00..df4d097d25d5 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/cache/SingleRegisteredProviderTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/cache/SingleRegisteredProviderTest.java @@ -32,75 +32,75 @@ public class SingleRegisteredProviderTest extends BaseUnitTestCase { @Test public void testCachingExplicitlyDisabled() { - final StandardServiceRegistry registry = new StandardServiceRegistryBuilder() + try (final StandardServiceRegistry registry = new StandardServiceRegistryBuilder() .applySetting( AvailableSettings.USE_SECOND_LEVEL_CACHE, "false" ) - .build(); - - assertThat( registry.getService( RegionFactory.class ), instanceOf( NoCachingRegionFactory.class ) ); + .build()) { + assertThat( registry.getService( RegionFactory.class ), instanceOf( NoCachingRegionFactory.class ) ); + } } @Test public void testCachingImplicitlyEnabledRegistered() { - final BootstrapServiceRegistry bsr = new BootstrapServiceRegistryBuilder() - .build(); - - final Collection> implementors = bsr - .getService( StrategySelector.class ) - .getRegisteredStrategyImplementors( RegionFactory.class ); + try (final BootstrapServiceRegistry bsr = new BootstrapServiceRegistryBuilder() + .build()) { + final Collection> implementors = bsr + .getService( StrategySelector.class ) + .getRegisteredStrategyImplementors( RegionFactory.class ); - assertThat( implementors.size(), equalTo( 1 ) ); + assertThat( implementors.size(), equalTo( 1 ) ); - final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder( bsr ) - .applySetting( AvailableSettings.USE_SECOND_LEVEL_CACHE, "" ) - .build(); + final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder( bsr ) + .applySetting( AvailableSettings.USE_SECOND_LEVEL_CACHE, "" ) + .build(); - assertThat( ssr.getService( RegionFactory.class ), instanceOf( NoCachingRegionFactory.class ) ); + assertThat( ssr.getService( RegionFactory.class ), instanceOf( NoCachingRegionFactory.class ) ); + } } @Test public void testCachingImplicitlyEnabledNoRegistered() { - final BootstrapServiceRegistry bsr = new BootstrapServiceRegistryBuilder() - .build(); + try (final BootstrapServiceRegistry bsr = new BootstrapServiceRegistryBuilder() + .build()) { + final Collection> implementors = bsr + .getService( StrategySelector.class ) + .getRegisteredStrategyImplementors( RegionFactory.class ); - final Collection> implementors = bsr - .getService( StrategySelector.class ) - .getRegisteredStrategyImplementors( RegionFactory.class ); + assertThat( implementors.size(), equalTo( 1 ) ); - assertThat( implementors.size(), equalTo( 1 ) ); + bsr.getService( StrategySelector.class ).unRegisterStrategyImplementor( + RegionFactory.class, + implementors.iterator().next() + ); - bsr.getService( StrategySelector.class ).unRegisterStrategyImplementor( - RegionFactory.class, - implementors.iterator().next() - ); + final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder( bsr ) + .applySetting( AvailableSettings.USE_SECOND_LEVEL_CACHE, "" ) + .build(); - final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder( bsr ) - .applySetting( AvailableSettings.USE_SECOND_LEVEL_CACHE, "" ) - .build(); - - assertThat( ssr.getService( RegionFactory.class ), instanceOf( NoCachingRegionFactory.class ) ); + assertThat( ssr.getService( RegionFactory.class ), instanceOf( NoCachingRegionFactory.class ) ); + } } @Test public void testConnectionsRegistered() { - final BootstrapServiceRegistry bsr = new BootstrapServiceRegistryBuilder() - .build(); - - final Collection> implementors = bsr - .getService( StrategySelector.class ) - .getRegisteredStrategyImplementors( ConnectionProvider.class ); + try (final BootstrapServiceRegistry bsr = new BootstrapServiceRegistryBuilder() + .build()) { + final Collection> implementors = bsr + .getService( StrategySelector.class ) + .getRegisteredStrategyImplementors( ConnectionProvider.class ); - assertThat( implementors.size(), equalTo( 0 ) ); + assertThat( implementors.size(), equalTo( 0 ) ); - bsr.getService( StrategySelector.class ).registerStrategyImplementor( - ConnectionProvider.class, - "testing", - DriverManagerConnectionProviderImpl.class - ); + bsr.getService( StrategySelector.class ).registerStrategyImplementor( + ConnectionProvider.class, + "testing", + DriverManagerConnectionProviderImpl.class + ); - final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder( bsr ).build(); + final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder( bsr ).build(); - final ConnectionProvider configuredProvider = ssr.getService( ConnectionProvider.class ); + final ConnectionProvider configuredProvider = ssr.getService( ConnectionProvider.class ); - assertThat( configuredProvider, instanceOf( DriverManagerConnectionProviderImpl.class ) ); + assertThat( configuredProvider, instanceOf( DriverManagerConnectionProviderImpl.class ) ); + } } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/cdi/general/mixed/DelayedMixedAccessTest.java b/hibernate-core/src/test/java/org/hibernate/test/cdi/general/mixed/DelayedMixedAccessTest.java index 78e03ee78c97..7b4ab809e0fa 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/cdi/general/mixed/DelayedMixedAccessTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/cdi/general/mixed/DelayedMixedAccessTest.java @@ -42,14 +42,13 @@ public boolean useJpaCompliantCreation() { @Test public void testDelayedMixedAccess() { - try ( final SeContainer cdiContainer = Helper.createSeContainer() ) { - BootstrapServiceRegistry bsr = new BootstrapServiceRegistryBuilder().build(); - + try ( final SeContainer cdiContainer = Helper.createSeContainer(); + final BootstrapServiceRegistry bsr = new BootstrapServiceRegistryBuilder().build(); final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder( bsr ) .applySetting( AvailableSettings.HBM2DDL_AUTO, Action.CREATE_DROP ) .applySetting( AvailableSettings.CDI_BEAN_MANAGER, cdiContainer.getBeanManager() ) .applySetting( AvailableSettings.DELAY_CDI_ACCESS, "true" ) - .build(); + .build() ) { final BeanContainer beanContainer = CdiBeanContainerBuilder.fromBeanManagerReference( cdiContainer.getBeanManager(), diff --git a/hibernate-core/src/test/java/org/hibernate/test/cdi/general/mixed/ExtendedMixedAccessTest.java b/hibernate-core/src/test/java/org/hibernate/test/cdi/general/mixed/ExtendedMixedAccessTest.java index 00aab0638e83..350d59407d23 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/cdi/general/mixed/ExtendedMixedAccessTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/cdi/general/mixed/ExtendedMixedAccessTest.java @@ -46,42 +46,45 @@ public void testLegacyExtendedMixedAccess() { } private void doTest(TestingExtendedBeanManager extendedBeanManager) { - final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder() + try (final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder() .applySetting( AvailableSettings.HBM2DDL_AUTO, Action.CREATE_DROP ) .applySetting( AvailableSettings.CDI_BEAN_MANAGER, extendedBeanManager ) - .build(); + .build()) { + final BeanContainer beanContainer = ssr.getService( ManagedBeanRegistry.class ).getBeanContainer(); - final BeanContainer beanContainer = ssr.getService( ManagedBeanRegistry.class ).getBeanContainer(); + assertThat( beanContainer, instanceOf( CdiBeanContainerExtendedAccessImpl.class ) ); - assertThat( beanContainer, instanceOf( CdiBeanContainerExtendedAccessImpl.class ) ); + try (final SeContainer cdiContainer = Helper.createSeContainer()) { + final BeanManager beanManager = cdiContainer.getBeanManager(); + extendedBeanManager.notifyListenerReady( beanManager ); - try ( final SeContainer cdiContainer = Helper.createSeContainer() ) { - final BeanManager beanManager = cdiContainer.getBeanManager(); - extendedBeanManager.notifyListenerReady( beanManager ); + assertThat( + beanManager, + sameInstance( ( (CdiBeanContainerExtendedAccessImpl) beanContainer ).getUsableBeanManager() ) + ); - assertThat( beanManager, sameInstance( ( (CdiBeanContainerExtendedAccessImpl) beanContainer ).getUsableBeanManager() ) ); + final ContainedBean hostedBean = beanContainer.getBean( + HostedBean.class, + this, + FallbackBeanInstanceProducer.INSTANCE + ); - final ContainedBean hostedBean = beanContainer.getBean( - HostedBean.class, - this, - FallbackBeanInstanceProducer.INSTANCE - ); + assertThat( hostedBean, notNullValue() ); + assertThat( hostedBean.getBeanInstance(), notNullValue() ); - assertThat( hostedBean, notNullValue() ); - assertThat( hostedBean.getBeanInstance(), notNullValue() ); + assertThat( hostedBean.getBeanInstance().getInjectedHostedBean(), notNullValue() ); - assertThat( hostedBean.getBeanInstance().getInjectedHostedBean(), notNullValue() ); + final ContainedBean nonHostedBean = beanContainer.getBean( + NonHostedBean.class, + this, + FallbackBeanInstanceProducer.INSTANCE + ); - final ContainedBean nonHostedBean = beanContainer.getBean( - NonHostedBean.class, - this, - FallbackBeanInstanceProducer.INSTANCE - ); + assertThat( nonHostedBean, notNullValue() ); + assertThat( nonHostedBean.getBeanInstance(), notNullValue() ); - assertThat( nonHostedBean, notNullValue() ); - assertThat( nonHostedBean.getBeanInstance(), notNullValue() ); - - extendedBeanManager.notifyListenerShuttingDown( beanManager ); + extendedBeanManager.notifyListenerShuttingDown( beanManager ); + } } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/cdi/general/mixed/ImmediateMixedAccessTests.java b/hibernate-core/src/test/java/org/hibernate/test/cdi/general/mixed/ImmediateMixedAccessTests.java index def3cd6b8ffe..a694708956bb 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/cdi/general/mixed/ImmediateMixedAccessTests.java +++ b/hibernate-core/src/test/java/org/hibernate/test/cdi/general/mixed/ImmediateMixedAccessTests.java @@ -44,8 +44,8 @@ public boolean useJpaCompliantCreation() { @Test public void testImmediateMixedAccess() { - try ( final SeContainer cdiContainer = Helper.createSeContainer() ) { - BootstrapServiceRegistry bsr = new BootstrapServiceRegistryBuilder().build(); + try ( final SeContainer cdiContainer = Helper.createSeContainer(); + BootstrapServiceRegistry bsr = new BootstrapServiceRegistryBuilder().build() ) { final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder( bsr ) .applySetting( AvailableSettings.HBM2DDL_AUTO, Action.CREATE_DROP ) diff --git a/hibernate-core/src/test/java/org/hibernate/test/cfg/AnnotationBinderTest.java b/hibernate-core/src/test/java/org/hibernate/test/cfg/AnnotationBinderTest.java index 471ba21026c6..8927bb7d623d 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/cfg/AnnotationBinderTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/cfg/AnnotationBinderTest.java @@ -13,6 +13,7 @@ import javax.persistence.PrimaryKeyJoinColumn; import org.hibernate.boot.Metadata; import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cfg.AnnotationBinder; import org.hibernate.internal.CoreMessageLogger; @@ -38,15 +39,19 @@ public void testInvalidPrimaryKeyJoinColumnAnnotationMessageContainsClassName() Triggerable triggerable = logInspection.watchForLogMessages( "HHH000137" ); - StandardServiceRegistryBuilder srb = new StandardServiceRegistryBuilder(); + try (StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().build()) { - Metadata metadata = new MetadataSources( srb.build() ) - .addAnnotatedClass( InvalidPrimaryKeyJoinColumnAnnotationEntity.class ) - .buildMetadata(); + Metadata metadata = new MetadataSources( serviceRegistry ) + .addAnnotatedClass( InvalidPrimaryKeyJoinColumnAnnotationEntity.class ) + .buildMetadata(); - assertTrue( "Expected warning HHH00137 but it wasn't triggered", triggerable.wasTriggered() ); - assertTrue( "Expected invalid class name in warning HHH00137 message but it does not apper to be present; got " + triggerable.triggerMessage(), - triggerable.triggerMessage().matches( ".*\\b\\Q" + InvalidPrimaryKeyJoinColumnAnnotationEntity.class.getName() + "\\E\\b.*" ) ); + assertTrue( "Expected warning HHH00137 but it wasn't triggered", triggerable.wasTriggered() ); + assertTrue( + "Expected invalid class name in warning HHH00137 message but it does not apper to be present; got " + triggerable.triggerMessage(), + triggerable.triggerMessage() + .matches( ".*\\b\\Q" + InvalidPrimaryKeyJoinColumnAnnotationEntity.class.getName() + "\\E\\b.*" ) + ); + } } @Entity diff --git a/hibernate-core/src/test/java/org/hibernate/test/collection/bag/MultipleBagFetchTest.java b/hibernate-core/src/test/java/org/hibernate/test/collection/bag/MultipleBagFetchTest.java index bf4128fe7344..b32e04e37e89 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/collection/bag/MultipleBagFetchTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/collection/bag/MultipleBagFetchTest.java @@ -21,7 +21,6 @@ import org.hibernate.boot.MetadataSources; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; - import org.hibernate.loader.MultipleBagFetchException; import org.junit.Test; @@ -32,7 +31,7 @@ public class MultipleBagFetchTest { @Test public void testEntityWithMultipleJoinFetchedBags() { - StandardServiceRegistry standardRegistry = new StandardServiceRegistryBuilder().build(); + try (StandardServiceRegistry standardRegistry = new StandardServiceRegistryBuilder().build()) { Metadata metadata = new MetadataSources( standardRegistry ) .addAnnotatedClass( Post.class ) @@ -40,11 +39,12 @@ public void testEntityWithMultipleJoinFetchedBags() { .addAnnotatedClass( Tag.class ) .getMetadataBuilder() .build(); - try { - metadata.buildSessionFactory(); - fail( "MultipleBagFetchException should have been thrown." ); - } - catch (MultipleBagFetchException expected) { + try { + metadata.buildSessionFactory(); + fail( "MultipleBagFetchException should have been thrown." ); + } + catch (MultipleBagFetchException expected) { + } } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/converter/AttributeConverterTest.java b/hibernate-core/src/test/java/org/hibernate/test/converter/AttributeConverterTest.java index a8d46871d832..2d71536d6e3c 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/converter/AttributeConverterTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/converter/AttributeConverterTest.java @@ -99,25 +99,29 @@ public String convertToEntityAttribute(String dbData) { @Test public void testBasicOperation() { - - SimpleValue simpleValue = new SimpleValue( new MetadataBuildingContextTestingImpl() ); - simpleValue.setJpaAttributeConverterDescriptor( - new InstanceBasedConverterDescriptor( - new StringClobConverter(), - new ClassmateContext() - ) - ); - simpleValue.setTypeUsingReflection( IrrelevantEntity.class.getName(), "name" ); - - Type type = simpleValue.getType(); - assertNotNull( type ); - if ( !AttributeConverterTypeAdapter.class.isInstance( type ) ) { - fail( "AttributeConverter not applied" ); - } - AbstractStandardBasicType basicType = assertTyping( AbstractStandardBasicType.class, type ); - assertSame( StringTypeDescriptor.INSTANCE, basicType.getJavaTypeDescriptor() ); - SqlTypeDescriptor sqlTypeDescriptor = basicType.getSqlTypeDescriptor(); - assertEquals( Dialect.getDialect().remapSqlTypeDescriptor(ClobTypeDescriptor.CLOB_BINDING).getSqlType(), sqlTypeDescriptor.getSqlType() ); + try (StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().build()) { + SimpleValue simpleValue = new SimpleValue( new MetadataBuildingContextTestingImpl( serviceRegistry ) ); + simpleValue.setJpaAttributeConverterDescriptor( + new InstanceBasedConverterDescriptor( + new StringClobConverter(), + new ClassmateContext() + ) + ); + simpleValue.setTypeUsingReflection( IrrelevantEntity.class.getName(), "name" ); + + Type type = simpleValue.getType(); + assertNotNull( type ); + if ( !AttributeConverterTypeAdapter.class.isInstance( type ) ) { + fail( "AttributeConverter not applied" ); + } + AbstractStandardBasicType basicType = assertTyping( AbstractStandardBasicType.class, type ); + assertSame( StringTypeDescriptor.INSTANCE, basicType.getJavaTypeDescriptor() ); + SqlTypeDescriptor sqlTypeDescriptor = basicType.getSqlTypeDescriptor(); + assertEquals( + Dialect.getDialect().remapSqlTypeDescriptor( ClobTypeDescriptor.CLOB_BINDING ).getSqlType(), + sqlTypeDescriptor.getSqlType() + ); + } } @Test @@ -151,24 +155,24 @@ public void testBasicConverterApplication() { final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder().build(); try { - MetadataImplementor metadata = (MetadataImplementor) new MetadataSources( ssr ) + final MetadataImplementor metadata = (MetadataImplementor) new MetadataSources( ssr ) .addAnnotatedClass( Tester.class ) .getMetadataBuilder() .applyAttributeConverter( StringClobConverter.class, true ) .build(); - PersistentClass tester = metadata.getEntityBinding( Tester.class.getName() ); - Property nameProp = tester.getProperty( "name" ); - SimpleValue nameValue = (SimpleValue) nameProp.getValue(); - Type type = nameValue.getType(); + final PersistentClass tester = metadata.getEntityBinding( Tester.class.getName() ); + final Property nameProp = tester.getProperty( "name" ); + final SimpleValue nameValue = (SimpleValue) nameProp.getValue(); + final Type type = nameValue.getType(); assertNotNull( type ); assertTyping( BasicType.class, type ); if ( !AttributeConverterTypeAdapter.class.isInstance( type ) ) { fail( "AttributeConverter not applied" ); } - AbstractStandardBasicType basicType = assertTyping( AbstractStandardBasicType.class, type ); + final AbstractStandardBasicType basicType = assertTyping( AbstractStandardBasicType.class, type ); assertSame( StringTypeDescriptor.INSTANCE, basicType.getJavaTypeDescriptor() ); - SqlTypeDescriptor sqlTypeDescriptor = basicType.getSqlTypeDescriptor(); + final SqlTypeDescriptor sqlTypeDescriptor = basicType.getSqlTypeDescriptor(); assertEquals( Dialect.getDialect().remapSqlTypeDescriptor(ClobTypeDescriptor.CLOB_BINDING).getSqlType(), sqlTypeDescriptor.getSqlType() ); } finally { @@ -196,9 +200,9 @@ public void testBasicOrmXmlConverterApplication() { if ( !AttributeConverterTypeAdapter.class.isInstance( type ) ) { fail( "AttributeConverter not applied" ); } - AttributeConverterTypeAdapter basicType = assertTyping( AttributeConverterTypeAdapter.class, type ); + final AttributeConverterTypeAdapter basicType = assertTyping( AttributeConverterTypeAdapter.class, type ); assertSame( StringTypeDescriptor.INSTANCE, basicType.getJavaTypeDescriptor() ); - SqlTypeDescriptor sqlTypeDescriptor = basicType.getSqlTypeDescriptor(); + final SqlTypeDescriptor sqlTypeDescriptor = basicType.getSqlTypeDescriptor(); assertEquals( Dialect.getDialect().remapSqlTypeDescriptor(ClobTypeDescriptor.CLOB_BINDING).getSqlType(), sqlTypeDescriptor.getSqlType() ); } finally { @@ -242,9 +246,7 @@ public void testBasicUsage() { cfg.setProperty( AvailableSettings.HBM2DDL_AUTO, "create-drop" ); cfg.setProperty( AvailableSettings.GENERATE_STATISTICS, "true" ); - SessionFactory sf = cfg.buildSessionFactory(); - - try { + try (SessionFactory sf = cfg.buildSessionFactory()) { Session session = sf.openSession(); session.beginTransaction(); session.save( new Tester4( 1L, "steve", 200 ) ); @@ -274,9 +276,6 @@ public void testBasicUsage() { session.getTransaction().commit(); session.close(); } - finally { - sf.close(); - } } @Test @@ -285,23 +284,23 @@ public void testPrimitiveTypeConverterAutoApplied() { final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder().build(); try { - MetadataImplementor metadata = (MetadataImplementor) new MetadataSources( ssr ) + final MetadataImplementor metadata = (MetadataImplementor) new MetadataSources( ssr ) .addAnnotatedClass( Tester5.class ) .getMetadataBuilder() .applyAttributeConverter( IntegerToVarcharConverter.class, true ) .build(); - PersistentClass tester = metadata.getEntityBinding( Tester5.class.getName() ); - Property codeProp = tester.getProperty( "code" ); - SimpleValue nameValue = (SimpleValue) codeProp.getValue(); + final PersistentClass tester = metadata.getEntityBinding( Tester5.class.getName() ); + final Property codeProp = tester.getProperty( "code" ); + final SimpleValue nameValue = (SimpleValue) codeProp.getValue(); Type type = nameValue.getType(); assertNotNull( type ); if ( !AttributeConverterTypeAdapter.class.isInstance( type ) ) { fail( "AttributeConverter not applied to primitive type field: code(int)" ); } - AttributeConverterTypeAdapter basicType = assertTyping( AttributeConverterTypeAdapter.class, type ); + final AttributeConverterTypeAdapter basicType = assertTyping( AttributeConverterTypeAdapter.class, type ); assertSame( IntegerTypeDescriptor.INSTANCE, basicType.getJavaTypeDescriptor() ); - SqlTypeDescriptor sqlTypeDescriptor = basicType.getSqlTypeDescriptor(); + final SqlTypeDescriptor sqlTypeDescriptor = basicType.getSqlTypeDescriptor(); assertEquals( VarcharTypeDescriptor.INSTANCE.getSqlType(), sqlTypeDescriptor.getSqlType() ); } finally { @@ -317,9 +316,7 @@ public void testBasicTimestampUsage() { cfg.setProperty( AvailableSettings.HBM2DDL_AUTO, "create-drop" ); cfg.setProperty( AvailableSettings.GENERATE_STATISTICS, "true" ); - SessionFactory sf = cfg.buildSessionFactory(); - - try { + try (SessionFactory sf = cfg.buildSessionFactory()) { Session session = sf.openSession(); session.beginTransaction(); session.save( new IrrelevantInstantEntity( 1L ) ); @@ -340,9 +337,6 @@ public void testBasicTimestampUsage() { session.getTransaction().commit(); session.close(); } - finally { - sf.close(); - } } @Test @@ -354,9 +348,7 @@ public void testBasicByteUsage() { cfg.setProperty( AvailableSettings.HBM2DDL_AUTO, "create-drop" ); cfg.setProperty( AvailableSettings.GENERATE_STATISTICS, "true" ); - SessionFactory sf = cfg.buildSessionFactory(); - - try { + try (SessionFactory sf = cfg.buildSessionFactory()) { Session session = sf.openSession(); session.beginTransaction(); session.save( new Tester4( 1L, "George", 150, ConvertibleEnum.DEFAULT ) ); @@ -386,9 +378,6 @@ public void testBasicByteUsage() { session.getTransaction().commit(); session.close(); } - finally { - sf.close(); - } } @Test @@ -406,16 +395,16 @@ public void testEnumConverter() { .build(); // first lets validate that the converter was applied... - PersistentClass tester = metadata.getEntityBinding( EntityWithConvertibleField.class.getName() ); - Property nameProp = tester.getProperty( "convertibleEnum" ); - SimpleValue nameValue = (SimpleValue) nameProp.getValue(); - Type type = nameValue.getType(); + final PersistentClass tester = metadata.getEntityBinding( EntityWithConvertibleField.class.getName() ); + final Property nameProp = tester.getProperty( "convertibleEnum" ); + final SimpleValue nameValue = (SimpleValue) nameProp.getValue(); + final Type type = nameValue.getType(); assertNotNull( type ); assertTyping( BasicType.class, type ); if ( !AttributeConverterTypeAdapter.class.isInstance( type ) ) { fail( "AttributeConverter not applied" ); } - AbstractStandardBasicType basicType = assertTyping( AbstractStandardBasicType.class, type ); + final AbstractStandardBasicType basicType = assertTyping( AbstractStandardBasicType.class, type ); assertTyping( EnumJavaTypeDescriptor.class, basicType.getJavaTypeDescriptor() ); if (metadata.getDatabase().getDialect() instanceof HANACloudColumnStoreDialect) { assertEquals( Types.NVARCHAR, basicType.getSqlTypeDescriptor().getSqlType() ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/converter/inheritence/AttributeConverterOnSuperclassTest.java b/hibernate-core/src/test/java/org/hibernate/test/converter/inheritence/AttributeConverterOnSuperclassTest.java index 979dc5156275..25267d601949 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/converter/inheritence/AttributeConverterOnSuperclassTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/converter/inheritence/AttributeConverterOnSuperclassTest.java @@ -1,11 +1,19 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ package org.hibernate.test.converter.inheritence; import java.util.List; import javax.persistence.AttributeConverter; +import org.hibernate.boot.model.convert.internal.ClassBasedConverterDescriptor; import org.hibernate.cfg.AttributeConverterDefinition; import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.boot.BootstrapContextImpl; import org.hibernate.testing.junit4.BaseUnitTestCase; import org.junit.Test; diff --git a/hibernate-core/src/test/java/org/hibernate/test/foreignkeys/HHH14230.java b/hibernate-core/src/test/java/org/hibernate/test/foreignkeys/HHH14230.java index 09e1bcf378f5..02895b078631 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/foreignkeys/HHH14230.java +++ b/hibernate-core/src/test/java/org/hibernate/test/foreignkeys/HHH14230.java @@ -19,6 +19,7 @@ import org.hibernate.boot.Metadata; import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.mapping.Table; import org.hibernate.testing.TestForIssue; @@ -35,16 +36,18 @@ public class HHH14230 { @Test public void test() { - Metadata metadata = new MetadataSources(new StandardServiceRegistryBuilder().build()) - .addAnnotatedClass(TestEntity.class).buildMetadata(); - Table table = StreamSupport.stream(metadata.getDatabase().getNamespaces().spliterator(), false) - .flatMap(namespace -> namespace.getTables().stream()) - .filter(t -> t.getName().equals(TABLE_NAME)).findFirst().orElse(null); - assertNotNull(table); - assertEquals(1, table.getForeignKeys().size()); - - // ClassCastException before HHH-14230 - assertTrue(table.getForeignKeys().keySet().iterator().next().toString().contains(JOIN_COLUMN_NAME)); + try (StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().build()) { + Metadata metadata = new MetadataSources( serviceRegistry ) + .addAnnotatedClass( TestEntity.class ).buildMetadata(); + Table table = StreamSupport.stream( metadata.getDatabase().getNamespaces().spliterator(), false ) + .flatMap( namespace -> namespace.getTables().stream() ) + .filter( t -> t.getName().equals( TABLE_NAME ) ).findFirst().orElse( null ); + assertNotNull( table ); + assertEquals( 1, table.getForeignKeys().size() ); + + // ClassCastException before HHH-14230 + assertTrue( table.getForeignKeys().keySet().iterator().next().toString().contains( JOIN_COLUMN_NAME ) ); + } } @Entity diff --git a/hibernate-core/src/test/java/org/hibernate/test/foreignkeys/disabled/DefaultConstraintModeTest.java b/hibernate-core/src/test/java/org/hibernate/test/foreignkeys/disabled/DefaultConstraintModeTest.java index 86ab995be14b..ea2bcc983394 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/foreignkeys/disabled/DefaultConstraintModeTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/foreignkeys/disabled/DefaultConstraintModeTest.java @@ -46,10 +46,11 @@ public void testForeignKeyShouldBeCreated() { } private void testForeignKeyCreation(boolean created) { - StandardServiceRegistry ssr = new StandardServiceRegistryBuilder() - .applySetting(Environment.HBM2DDL_DEFAULT_CONSTRAINT_MODE, created ? "CONSTRAINT" : "NO_CONSTRAINT").build(); - Metadata metadata = new MetadataSources(ssr).addAnnotatedClass(TestEntity.class).buildMetadata(); - assertThat(findTable(metadata, TABLE_NAME).getForeignKeys().isEmpty(), is(!created)); + try (StandardServiceRegistry ssr = new StandardServiceRegistryBuilder() + .applySetting(Environment.HBM2DDL_DEFAULT_CONSTRAINT_MODE, created ? "CONSTRAINT" : "NO_CONSTRAINT").build()) { + Metadata metadata = new MetadataSources( ssr ).addAnnotatedClass( TestEntity.class ).buildMetadata(); + assertThat( findTable( metadata, TABLE_NAME ).getForeignKeys().isEmpty(), is( !created ) ); + } } private static Table findTable(Metadata metadata, String tableName) { diff --git a/hibernate-core/src/test/java/org/hibernate/test/foreignkeys/disabled/OneToManyBidirectionalForeignKeyTest.java b/hibernate-core/src/test/java/org/hibernate/test/foreignkeys/disabled/OneToManyBidirectionalForeignKeyTest.java index 38cd379156ee..37bf045191b9 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/foreignkeys/disabled/OneToManyBidirectionalForeignKeyTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/foreignkeys/disabled/OneToManyBidirectionalForeignKeyTest.java @@ -26,6 +26,7 @@ import org.hibernate.annotations.OnDeleteAction; import org.hibernate.boot.Metadata; import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.mapping.Table; import org.hibernate.testing.TestForIssue; @@ -44,11 +45,13 @@ public class OneToManyBidirectionalForeignKeyTest { @Test public void testForeignKeyShouldNotBeCreated() { - Metadata metadata = new MetadataSources(new StandardServiceRegistryBuilder().build()) - .addAnnotatedClass(PlainTreeEntity.class).addAnnotatedClass(TreeEntityWithOnDelete.class) - .buildMetadata(); - assertTrue(findTable(metadata, TABLE_NAME_PLAIN).getForeignKeys().isEmpty()); - assertFalse(findTable(metadata, TABLE_NAME_WITH_ON_DELETE).getForeignKeys().isEmpty()); + try (StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().build()) { + Metadata metadata = new MetadataSources( serviceRegistry ) + .addAnnotatedClass( PlainTreeEntity.class ).addAnnotatedClass( TreeEntityWithOnDelete.class ) + .buildMetadata(); + assertTrue( findTable( metadata, TABLE_NAME_PLAIN ).getForeignKeys().isEmpty() ); + assertFalse( findTable( metadata, TABLE_NAME_WITH_ON_DELETE ).getForeignKeys().isEmpty() ); + } } private static Table findTable(Metadata metadata, String tableName) { diff --git a/hibernate-core/src/test/java/org/hibernate/test/hbm/comment/ClassCommentTest.java b/hibernate-core/src/test/java/org/hibernate/test/hbm/comment/ClassCommentTest.java index ff8f01fdb702..da7b5e1bdebc 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/hbm/comment/ClassCommentTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/hbm/comment/ClassCommentTest.java @@ -4,6 +4,7 @@ import org.hibernate.boot.Metadata; import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.engine.jdbc.ReaderInputStream; import org.hibernate.mapping.PersistentClass; @@ -28,14 +29,16 @@ public class ClassCommentTest { public void testClassComment() { StandardServiceRegistryBuilder serviceRegistryBuilder = new StandardServiceRegistryBuilder() .applySetting("hibernate.dialect", "org.hibernate.dialect.HSQLDialect"); - MetadataSources metadataSources = new MetadataSources(serviceRegistryBuilder.build()); - metadataSources.addInputStream(new ReaderInputStream(new StringReader(CLASS_COMMENT_HBM_XML))); - Metadata metadata = metadataSources.buildMetadata(); - PersistentClass pc = metadata.getEntityBinding("org.hibernate.test.hbm.Foo"); - Assert.assertNotNull(pc); - Table table = pc.getTable(); - Assert.assertNotNull(table); - Assert.assertEquals("This is class 'Foo' with property 'bar'.", table.getComment()); + try (StandardServiceRegistry serviceRegistry = serviceRegistryBuilder.build()) { + MetadataSources metadataSources = new MetadataSources( serviceRegistry ); + metadataSources.addInputStream( new ReaderInputStream( new StringReader( CLASS_COMMENT_HBM_XML ) ) ); + Metadata metadata = metadataSources.buildMetadata(); + PersistentClass pc = metadata.getEntityBinding( "org.hibernate.test.hbm.Foo" ); + Assert.assertNotNull( pc ); + Table table = pc.getTable(); + Assert.assertNotNull( table ); + Assert.assertEquals( "This is class 'Foo' with property 'bar'.", table.getComment() ); + } } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/idgen/userdefined/UserDefinedGeneratorsTests.java b/hibernate-core/src/test/java/org/hibernate/test/idgen/userdefined/UserDefinedGeneratorsTests.java index e84c5681bf0c..352004381533 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/idgen/userdefined/UserDefinedGeneratorsTests.java +++ b/hibernate-core/src/test/java/org/hibernate/test/idgen/userdefined/UserDefinedGeneratorsTests.java @@ -64,38 +64,45 @@ public void testCreateGeneratorsByBeanContainer() { final StandardServiceRegistryBuilder ssrb = new StandardServiceRegistryBuilder(); ssrb.applySetting( AvailableSettings.BEAN_CONTAINER, beanContainer ); - final StandardServiceRegistry ssr = ssrb.build(); - final Metadata metadata = new MetadataSources( ssr ) - .addAnnotatedClass( Entity1.class ) - .addAnnotatedClass( Entity2.class ) - .buildMetadata(); - - final DefaultIdentifierGeneratorFactory generatorFactory = new DefaultIdentifierGeneratorFactory(); - generatorFactory.injectServices( (ServiceRegistryImplementor) ssr ); - - final PersistentClass entityBinding1 = metadata.getEntityBinding( Entity1.class.getName() ); - final PersistentClass entityBinding2 = metadata.getEntityBinding( Entity2.class.getName() ); - final IdentifierGenerator generator1 = entityBinding1.getRootClass().getIdentifier().createIdentifierGenerator( - generatorFactory, - new H2Dialect(), - "", - "", - entityBinding1.getRootClass() - ); - final IdentifierGenerator generator2 = entityBinding2.getRootClass().getIdentifier().createIdentifierGenerator( - generatorFactory, - new H2Dialect(), - "", - "", - entityBinding2.getRootClass() - ); - - then( beanContainer ).should( times( 2 ) ).getBean( same( TestIdentifierGenerator.class ), any( LifecycleOptions.class ), - same( FallbackBeanInstanceProducer.INSTANCE ) ); - - assertThat( generator1, is( instanceOf( TestIdentifierGenerator.class ) ) ); - assertThat( generator2, is( instanceOf( TestIdentifierGenerator.class ) ) ); - assertThat( generator1 == generator2, is( false ) ); // should not be same instance + try (final StandardServiceRegistry ssr = ssrb.build()) { + final Metadata metadata = new MetadataSources( ssr ) + .addAnnotatedClass( Entity1.class ) + .addAnnotatedClass( Entity2.class ) + .buildMetadata(); + + final DefaultIdentifierGeneratorFactory generatorFactory = new DefaultIdentifierGeneratorFactory(); + generatorFactory.injectServices( (ServiceRegistryImplementor) ssr ); + + final PersistentClass entityBinding1 = metadata.getEntityBinding( Entity1.class.getName() ); + final PersistentClass entityBinding2 = metadata.getEntityBinding( Entity2.class.getName() ); + final IdentifierGenerator generator1 = entityBinding1.getRootClass() + .getIdentifier() + .createIdentifierGenerator( + generatorFactory, + new H2Dialect(), + "", + "", + entityBinding1.getRootClass() + ); + final IdentifierGenerator generator2 = entityBinding2.getRootClass() + .getIdentifier() + .createIdentifierGenerator( + generatorFactory, + new H2Dialect(), + "", + "", + entityBinding2.getRootClass() + ); + + then( beanContainer ).should( times( 2 ) ).getBean( same( TestIdentifierGenerator.class ), + any( LifecycleOptions.class ), + same( FallbackBeanInstanceProducer.INSTANCE ) + ); + + assertThat( generator1, is( instanceOf( TestIdentifierGenerator.class ) ) ); + assertThat( generator2, is( instanceOf( TestIdentifierGenerator.class ) ) ); + assertThat( generator1 == generator2, is( false ) ); // should not be same instance + } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/jpa/compliance/tck2_2/GeneratedValueTests.java b/hibernate-core/src/test/java/org/hibernate/test/jpa/compliance/tck2_2/GeneratedValueTests.java index d642f20c4937..3fd7d89eb86b 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/jpa/compliance/tck2_2/GeneratedValueTests.java +++ b/hibernate-core/src/test/java/org/hibernate/test/jpa/compliance/tck2_2/GeneratedValueTests.java @@ -49,80 +49,92 @@ public class GeneratedValueTests extends BaseUnitTestCase { @Test public void baseline() { - final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder().build(); - final Metadata bootModel = new MetadataSources( ssr ) - .addAnnotatedClass( ExplicitGeneratorEntity.class ) - .buildMetadata(); - final PersistentClass entityMapping = bootModel.getEntityBinding( ExplicitGeneratorEntity.class.getName() ); - final IdentifierGenerator generator = entityMapping.getIdentifier().createIdentifierGenerator( - bootModel.getIdentifierGeneratorFactory(), - ssr.getService( JdbcEnvironment.class ).getDialect(), - null, - null, - (RootClass) entityMapping - ); - - final SequenceStyleGenerator sequenceStyleGenerator = assertTyping( SequenceStyleGenerator.class, generator ); - - assertThat( sequenceStyleGenerator.getDatabaseStructure().getName(), is( "my_real_db_sequence" ) ); - - // all the JPA defaults since they were not defined - assertThat( sequenceStyleGenerator.getDatabaseStructure().getInitialValue(), is( 100 ) ); - assertThat( sequenceStyleGenerator.getDatabaseStructure().getIncrementSize(), is( 500 ) ); + try (final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder().build()) { + final Metadata bootModel = new MetadataSources( ssr ) + .addAnnotatedClass( ExplicitGeneratorEntity.class ) + .buildMetadata(); + final PersistentClass entityMapping = bootModel.getEntityBinding( ExplicitGeneratorEntity.class.getName() ); + final IdentifierGenerator generator = entityMapping.getIdentifier().createIdentifierGenerator( + bootModel.getIdentifierGeneratorFactory(), + ssr.getService( JdbcEnvironment.class ).getDialect(), + null, + null, + (RootClass) entityMapping + ); + + final SequenceStyleGenerator sequenceStyleGenerator = assertTyping( + SequenceStyleGenerator.class, + generator + ); + + assertThat( sequenceStyleGenerator.getDatabaseStructure().getName(), is( "my_real_db_sequence" ) ); + + // all the JPA defaults since they were not defined + assertThat( sequenceStyleGenerator.getDatabaseStructure().getInitialValue(), is( 100 ) ); + assertThat( sequenceStyleGenerator.getDatabaseStructure().getIncrementSize(), is( 500 ) ); + } } @Test public void testImplicitSequenceGenerator() { - final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder() + try (final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder() .applySetting( AvailableSettings.PREFER_GENERATOR_NAME_AS_DEFAULT_SEQUENCE_NAME, "false" ) - .build(); - final Metadata bootModel = new MetadataSources( ssr ) - .addAnnotatedClass( ImplicitSequenceGeneratorEntity.class ) - .buildMetadata(); - final PersistentClass entityMapping = bootModel.getEntityBinding( ImplicitSequenceGeneratorEntity.class.getName() ); - final IdentifierGenerator generator = entityMapping.getIdentifier().createIdentifierGenerator( - bootModel.getIdentifierGeneratorFactory(), - ssr.getService( JdbcEnvironment.class ).getDialect(), - null, - null, - (RootClass) entityMapping - ); - - final SequenceStyleGenerator sequenceStyleGenerator = assertTyping( SequenceStyleGenerator.class, generator ); - - // PREFER_GENERATOR_NAME_AS_DEFAULT_SEQUENCE_NAME == false indicates that the legacy - // default (hibernate_sequence) should be used - assertThat( sequenceStyleGenerator.getDatabaseStructure().getName(), is( "hibernate_sequence" ) ); - - // the JPA defaults since they were not defined - assertThat( sequenceStyleGenerator.getDatabaseStructure().getInitialValue(), is( 1 ) ); - assertThat( sequenceStyleGenerator.getDatabaseStructure().getIncrementSize(), is( 50 ) ); + .build()) { + final Metadata bootModel = new MetadataSources( ssr ) + .addAnnotatedClass( ImplicitSequenceGeneratorEntity.class ) + .buildMetadata(); + final PersistentClass entityMapping = bootModel.getEntityBinding( ImplicitSequenceGeneratorEntity.class.getName() ); + final IdentifierGenerator generator = entityMapping.getIdentifier().createIdentifierGenerator( + bootModel.getIdentifierGeneratorFactory(), + ssr.getService( JdbcEnvironment.class ).getDialect(), + null, + null, + (RootClass) entityMapping + ); + + final SequenceStyleGenerator sequenceStyleGenerator = assertTyping( + SequenceStyleGenerator.class, + generator + ); + + // PREFER_GENERATOR_NAME_AS_DEFAULT_SEQUENCE_NAME == false indicates that the legacy + // default (hibernate_sequence) should be used + assertThat( sequenceStyleGenerator.getDatabaseStructure().getName(), is( "hibernate_sequence" ) ); + + // the JPA defaults since they were not defined + assertThat( sequenceStyleGenerator.getDatabaseStructure().getInitialValue(), is( 1 ) ); + assertThat( sequenceStyleGenerator.getDatabaseStructure().getIncrementSize(), is( 50 ) ); + } } @Test public void testImplicitSequenceGeneratorGeneratorName() { - final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder().build(); - final Metadata bootModel = new MetadataSources( ssr ) - .addAnnotatedClass( ImplicitSequenceGeneratorEntity.class ) - .buildMetadata(); - final PersistentClass entityMapping = bootModel.getEntityBinding( ImplicitSequenceGeneratorEntity.class.getName() ); - final IdentifierGenerator generator = entityMapping.getIdentifier().createIdentifierGenerator( - bootModel.getIdentifierGeneratorFactory(), - ssr.getService( JdbcEnvironment.class ).getDialect(), - null, - null, - (RootClass) entityMapping - ); - - final SequenceStyleGenerator sequenceStyleGenerator = assertTyping( SequenceStyleGenerator.class, generator ); - - // PREFER_GENERATOR_NAME_AS_DEFAULT_SEQUENCE_NAME == true (the default) indicates that the generator-name - // should be used as the default instead. - assertThat( sequenceStyleGenerator.getDatabaseStructure().getName(), is( "my_db_sequence" ) ); - - // the JPA defaults since they were not defined - assertThat( sequenceStyleGenerator.getDatabaseStructure().getInitialValue(), is( 1 ) ); - assertThat( sequenceStyleGenerator.getDatabaseStructure().getIncrementSize(), is( 50 ) ); + try (final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder().build()) { + final Metadata bootModel = new MetadataSources( ssr ) + .addAnnotatedClass( ImplicitSequenceGeneratorEntity.class ) + .buildMetadata(); + final PersistentClass entityMapping = bootModel.getEntityBinding( ImplicitSequenceGeneratorEntity.class.getName() ); + final IdentifierGenerator generator = entityMapping.getIdentifier().createIdentifierGenerator( + bootModel.getIdentifierGeneratorFactory(), + ssr.getService( JdbcEnvironment.class ).getDialect(), + null, + null, + (RootClass) entityMapping + ); + + final SequenceStyleGenerator sequenceStyleGenerator = assertTyping( + SequenceStyleGenerator.class, + generator + ); + + // PREFER_GENERATOR_NAME_AS_DEFAULT_SEQUENCE_NAME == true (the default) indicates that the generator-name + // should be used as the default instead. + assertThat( sequenceStyleGenerator.getDatabaseStructure().getName(), is( "my_db_sequence" ) ); + + // the JPA defaults since they were not defined + assertThat( sequenceStyleGenerator.getDatabaseStructure().getInitialValue(), is( 1 ) ); + assertThat( sequenceStyleGenerator.getDatabaseStructure().getIncrementSize(), is( 50 ) ); + } } @Test @@ -152,146 +164,156 @@ public void testExplicitSequenceGeneratorImplicitName() { @Test public void testExplicitSequenceGeneratorImplicitNamePreferGeneratorName() { // this should be the default behavior - final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder().build(); - final Metadata bootModel = new MetadataSources( ssr ) - .addAnnotatedClass( ExplicitSequenceGeneratorImplicitNameEntity.class ) - .buildMetadata(); - final PersistentClass entityMapping = bootModel.getEntityBinding( ExplicitSequenceGeneratorImplicitNameEntity.class.getName() ); - final IdentifierGenerator generator = entityMapping.getIdentifier().createIdentifierGenerator( - bootModel.getIdentifierGeneratorFactory(), - ssr.getService( JdbcEnvironment.class ).getDialect(), - null, - null, - (RootClass) entityMapping - ); - - final SequenceStyleGenerator sequenceStyleGenerator = assertTyping( SequenceStyleGenerator.class, generator ); - // all the JPA defaults since they were not defined - assertThat( sequenceStyleGenerator.getDatabaseStructure().getName(), is( "my_db_sequence" ) ); - assertThat( sequenceStyleGenerator.getDatabaseStructure().getInitialValue(), is( 100 ) ); - assertThat( sequenceStyleGenerator.getDatabaseStructure().getIncrementSize(), is( 500 ) ); - - final Sequence sequence = bootModel.getDatabase() - .getDefaultNamespace() - .locateSequence( Identifier.toIdentifier( "my_db_sequence" ) ); - assertThat( sequence, notNullValue() ); - final String[] sqlCreateStrings = new H2Dialect().getSequenceExporter().getSqlCreateStrings( - sequence, - bootModel - ); - assertThat( sqlCreateStrings.length, is(1) ); - final String cmd = sqlCreateStrings[0].toLowerCase(); - assertTrue( cmd.startsWith( "create sequence my_db_sequence start with 100 increment by 500" ) ); + try (final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder().build()) { + final Metadata bootModel = new MetadataSources( ssr ) + .addAnnotatedClass( ExplicitSequenceGeneratorImplicitNameEntity.class ) + .buildMetadata(); + final PersistentClass entityMapping = bootModel.getEntityBinding( + ExplicitSequenceGeneratorImplicitNameEntity.class.getName() ); + final IdentifierGenerator generator = entityMapping.getIdentifier().createIdentifierGenerator( + bootModel.getIdentifierGeneratorFactory(), + ssr.getService( JdbcEnvironment.class ).getDialect(), + null, + null, + (RootClass) entityMapping + ); + + final SequenceStyleGenerator sequenceStyleGenerator = assertTyping( + SequenceStyleGenerator.class, + generator + ); + // all the JPA defaults since they were not defined + assertThat( sequenceStyleGenerator.getDatabaseStructure().getName(), is( "my_db_sequence" ) ); + assertThat( sequenceStyleGenerator.getDatabaseStructure().getInitialValue(), is( 100 ) ); + assertThat( sequenceStyleGenerator.getDatabaseStructure().getIncrementSize(), is( 500 ) ); + + final Sequence sequence = bootModel.getDatabase() + .getDefaultNamespace() + .locateSequence( Identifier.toIdentifier( "my_db_sequence" ) ); + assertThat( sequence, notNullValue() ); + final String[] sqlCreateStrings = new H2Dialect().getSequenceExporter().getSqlCreateStrings( + sequence, + bootModel + ); + assertThat( sqlCreateStrings.length, is( 1 ) ); + final String cmd = sqlCreateStrings[0].toLowerCase(); + assertTrue( cmd.startsWith( "create sequence my_db_sequence start with 100 increment by 500" ) ); + } } @Test public void testImplicitTableGenerator() { - final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder().build(); - final Metadata bootModel = new MetadataSources( ssr ) - .addAnnotatedClass( ImplicitTableGeneratorEntity.class ) - .buildMetadata(); - final PersistentClass entityMapping = bootModel.getEntityBinding( ImplicitTableGeneratorEntity.class.getName() ); - final IdentifierGenerator generator = entityMapping.getIdentifier().createIdentifierGenerator( - bootModel.getIdentifierGeneratorFactory(), - ssr.getService( JdbcEnvironment.class ).getDialect(), - null, - null, - (RootClass) entityMapping - ); - - final TableGenerator tableGenerator = assertTyping( TableGenerator.class, generator ); - - assertThat( tableGenerator.getTableName(), is( "my_id_table" ) ); - - // all the JPA defaults since they were not defined - assertThat( tableGenerator.getInitialValue(), is( 1 ) ); - assertThat( tableGenerator.getIncrementSize(), is( 50 ) ); + try (final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder().build()) { + final Metadata bootModel = new MetadataSources( ssr ) + .addAnnotatedClass( ImplicitTableGeneratorEntity.class ) + .buildMetadata(); + final PersistentClass entityMapping = bootModel.getEntityBinding( ImplicitTableGeneratorEntity.class.getName() ); + final IdentifierGenerator generator = entityMapping.getIdentifier().createIdentifierGenerator( + bootModel.getIdentifierGeneratorFactory(), + ssr.getService( JdbcEnvironment.class ).getDialect(), + null, + null, + (RootClass) entityMapping + ); + + final TableGenerator tableGenerator = assertTyping( TableGenerator.class, generator ); + + assertThat( tableGenerator.getTableName(), is( "my_id_table" ) ); + + // all the JPA defaults since they were not defined + assertThat( tableGenerator.getInitialValue(), is( 1 ) ); + assertThat( tableGenerator.getIncrementSize(), is( 50 ) ); + } } @Test public void testExplicitTableGeneratorImplicitName() { - final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder().build(); - final Metadata bootModel = new MetadataSources( ssr ) - .addAnnotatedClass( ExplicitTableGeneratorImplicitNameEntity.class ) - .buildMetadata(); - final PersistentClass entityMapping = bootModel.getEntityBinding( ExplicitTableGeneratorImplicitNameEntity.class.getName() ); - final IdentifierGenerator generator = entityMapping.getIdentifier().createIdentifierGenerator( - bootModel.getIdentifierGeneratorFactory(), - ssr.getService( JdbcEnvironment.class ).getDialect(), - null, - null, - (RootClass) entityMapping - ); - - final TableGenerator tableGenerator = assertTyping( TableGenerator.class, generator ); - - assertThat( tableGenerator.getTableName(), is( "my_id_table" ) ); - - // - note : currently initialValue=1 in mapping is shows up here as 2 - assertThat( tableGenerator.getInitialValue(), is( 1 ) ); - assertThat( tableGenerator.getIncrementSize(), is( 25 ) ); + try (final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder().build()) { + final Metadata bootModel = new MetadataSources( ssr ) + .addAnnotatedClass( ExplicitTableGeneratorImplicitNameEntity.class ) + .buildMetadata(); + final PersistentClass entityMapping = bootModel.getEntityBinding( ExplicitTableGeneratorImplicitNameEntity.class.getName() ); + final IdentifierGenerator generator = entityMapping.getIdentifier().createIdentifierGenerator( + bootModel.getIdentifierGeneratorFactory(), + ssr.getService( JdbcEnvironment.class ).getDialect(), + null, + null, + (RootClass) entityMapping + ); + + final TableGenerator tableGenerator = assertTyping( TableGenerator.class, generator ); + + assertThat( tableGenerator.getTableName(), is( "my_id_table" ) ); + + // - note : currently initialValue=1 in mapping is shows up here as 2 + assertThat( tableGenerator.getInitialValue(), is( 1 ) ); + assertThat( tableGenerator.getIncrementSize(), is( 25 ) ); + } } @Test public void testExplicitTableGenerator() { - final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder().build(); - final Metadata bootModel = new MetadataSources( ssr ) - .addAnnotatedClass( ExplicitTableGeneratorEntity.class ) - .buildMetadata(); - final PersistentClass entityMapping = bootModel.getEntityBinding( ExplicitTableGeneratorEntity.class.getName() ); - final IdentifierGenerator generator = entityMapping.getIdentifier().createIdentifierGenerator( - bootModel.getIdentifierGeneratorFactory(), - ssr.getService( JdbcEnvironment.class ).getDialect(), - null, - null, - (RootClass) entityMapping - ); - - final TableGenerator tableGenerator = assertTyping( TableGenerator.class, generator ); - - assertThat( tableGenerator.getTableName(), is( "my_real_id_table" ) ); - - // all the JPA defaults since they were not defined - // - note : currently initialValue=1 in mapping is shows up here - // as 2 + try (final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder().build()) { + final Metadata bootModel = new MetadataSources( ssr ) + .addAnnotatedClass( ExplicitTableGeneratorEntity.class ) + .buildMetadata(); + final PersistentClass entityMapping = bootModel.getEntityBinding( ExplicitTableGeneratorEntity.class.getName() ); + final IdentifierGenerator generator = entityMapping.getIdentifier().createIdentifierGenerator( + bootModel.getIdentifierGeneratorFactory(), + ssr.getService( JdbcEnvironment.class ).getDialect(), + null, + null, + (RootClass) entityMapping + ); + + final TableGenerator tableGenerator = assertTyping( TableGenerator.class, generator ); + + assertThat( tableGenerator.getTableName(), is( "my_real_id_table" ) ); + + // all the JPA defaults since they were not defined + // - note : currently initialValue=1 in mapping is shows up here + // as 2 // assertThat( tableGenerator.getInitialValue(), is( 1 ) ); - assertThat( tableGenerator.getIncrementSize(), is( 25 ) ); + assertThat( tableGenerator.getIncrementSize(), is( 25 ) ); + } } @Test public void testExplicitIncrementGenerator() { - final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder().build(); - final Metadata bootModel = new MetadataSources( ssr ) - .addAnnotatedClass( ExplicitIncrementGeneratorEntity.class ) - .buildMetadata(); - final PersistentClass entityMapping = bootModel.getEntityBinding( ExplicitIncrementGeneratorEntity.class.getName() ); - final IdentifierGenerator generator = entityMapping.getIdentifier().createIdentifierGenerator( - bootModel.getIdentifierGeneratorFactory(), - ssr.getService( JdbcEnvironment.class ).getDialect(), - null, - null, - (RootClass) entityMapping - ); - - assertTyping( IncrementGenerator.class, generator ); + try (final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder().build()) { + final Metadata bootModel = new MetadataSources( ssr ) + .addAnnotatedClass( ExplicitIncrementGeneratorEntity.class ) + .buildMetadata(); + final PersistentClass entityMapping = bootModel.getEntityBinding( ExplicitIncrementGeneratorEntity.class.getName() ); + final IdentifierGenerator generator = entityMapping.getIdentifier().createIdentifierGenerator( + bootModel.getIdentifierGeneratorFactory(), + ssr.getService( JdbcEnvironment.class ).getDialect(), + null, + null, + (RootClass) entityMapping + ); + + assertTyping( IncrementGenerator.class, generator ); + } } @Test public void testImplicitIncrementGenerator() { - final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder().build(); - final Metadata bootModel = new MetadataSources( ssr ) - .addAnnotatedClass( ImplicitIncrementGeneratorEntity.class ) - .buildMetadata(); - final PersistentClass entityMapping = bootModel.getEntityBinding( ImplicitIncrementGeneratorEntity.class.getName() ); - final IdentifierGenerator generator = entityMapping.getIdentifier().createIdentifierGenerator( - bootModel.getIdentifierGeneratorFactory(), - ssr.getService( JdbcEnvironment.class ).getDialect(), - null, - null, - (RootClass) entityMapping - ); - - assertTyping( IncrementGenerator.class, generator ); + try (final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder().build()) { + final Metadata bootModel = new MetadataSources( ssr ) + .addAnnotatedClass( ImplicitIncrementGeneratorEntity.class ) + .buildMetadata(); + final PersistentClass entityMapping = bootModel.getEntityBinding( ImplicitIncrementGeneratorEntity.class.getName() ); + final IdentifierGenerator generator = entityMapping.getIdentifier().createIdentifierGenerator( + bootModel.getIdentifierGeneratorFactory(), + ssr.getService( JdbcEnvironment.class ).getDialect(), + null, + null, + (RootClass) entityMapping + ); + + assertTyping( IncrementGenerator.class, generator ); + } } @Entity @@ -320,7 +342,7 @@ public static class ImplicitSequenceGeneratorEntity { @Entity public static class ExplicitSequenceGeneratorImplicitNameEntity { /** - * This entity does not have explicit {@link SequenceGenerator} defined + * This entity does have explicit {@link SequenceGenerator} defined */ @Id @GeneratedValue( strategy = GenerationType.SEQUENCE, generator = "my_db_sequence" ) diff --git a/hibernate-core/src/test/java/org/hibernate/test/jpa/compliance/tck2_2/caching/CachingWithSecondaryTablesTests.java b/hibernate-core/src/test/java/org/hibernate/test/jpa/compliance/tck2_2/caching/CachingWithSecondaryTablesTests.java index 8d2c1da0e2ed..fad99b9f7521 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/jpa/compliance/tck2_2/caching/CachingWithSecondaryTablesTests.java +++ b/hibernate-core/src/test/java/org/hibernate/test/jpa/compliance/tck2_2/caching/CachingWithSecondaryTablesTests.java @@ -19,6 +19,7 @@ import org.hibernate.Hibernate; import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cfg.AvailableSettings; import org.hibernate.engine.spi.SessionFactoryImplementor; @@ -140,15 +141,20 @@ private SessionFactoryImplementor buildSessionFactory(Class entityClass, boolean settings.put( AvailableSettings.JPA_CACHING_COMPLIANCE, "true" ); } - final StandardServiceRegistryBuilder ssrb = new StandardServiceRegistryBuilder() - .applySettings( settings ); - - return (SessionFactoryImplementor) new MetadataSources( ssrb.build() ) - .addAnnotatedClass( Person.class ) - .addAnnotatedClass( VersionedPerson.class) - .buildMetadata() - .buildSessionFactory(); - + final StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder() + .applySettings( settings ) + .build(); + try { + return (SessionFactoryImplementor) new MetadataSources( serviceRegistry ) + .addAnnotatedClass( Person.class ) + .addAnnotatedClass( VersionedPerson.class ) + .buildMetadata() + .buildSessionFactory(); + } + catch (Throwable t) { + serviceRegistry.close(); + throw t; + } } @After diff --git a/hibernate-core/src/test/java/org/hibernate/test/mapping/ValueVisitorTest.java b/hibernate-core/src/test/java/org/hibernate/test/mapping/ValueVisitorTest.java index 8bec54a9bdb1..bf54e12a95e9 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/mapping/ValueVisitorTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/mapping/ValueVisitorTest.java @@ -63,21 +63,23 @@ public void testProperCallbacks() { final RootClass rootClass = new RootClass( metadataBuildingContext ); ValueVisitor vv = new ValueVisitorValidator(); - MetadataBuildingContextTestingImpl metadataBuildingContext = new MetadataBuildingContextTestingImpl(); - new Any( metadataBuildingContext, tbl ).accept( vv ); - new Array( metadataBuildingContext, rootClass ).accept( vv ); - new Bag( metadataBuildingContext, rootClass ).accept( vv ); - new Component( metadataBuildingContext, rootClass ).accept( vv ); - new DependantValue( metadataBuildingContext, tbl, null ).accept( vv ); - new IdentifierBag( metadataBuildingContext, rootClass ).accept( vv ); - new List( metadataBuildingContext, rootClass ).accept( vv ); - new ManyToOne( metadataBuildingContext, tbl ).accept( vv ); - new Map( metadataBuildingContext, rootClass ).accept( vv ); - new OneToMany( metadataBuildingContext, rootClass ).accept( vv ); - new OneToOne( metadataBuildingContext, tbl, rootClass ).accept( vv ); - new PrimitiveArray( metadataBuildingContext, rootClass ).accept( vv ); - new Set( metadataBuildingContext, rootClass ).accept( vv ); - new SimpleValue( metadataBuildingContext ).accept( vv ); + try ( StandardServiceRegistry serviceRegistry = new StandardServiceRegistryBuilder().build()) { + MetadataBuildingContextTestingImpl metadataBuildingContext = new MetadataBuildingContextTestingImpl( serviceRegistry ); + new Any( metadataBuildingContext, tbl ).accept( vv ); + new Array( metadataBuildingContext, rootClass ).accept( vv ); + new Bag( metadataBuildingContext, rootClass ).accept( vv ); + new Component( metadataBuildingContext, rootClass ).accept( vv ); + new DependantValue( metadataBuildingContext, tbl, null ).accept( vv ); + new IdentifierBag( metadataBuildingContext, rootClass ).accept( vv ); + new List( metadataBuildingContext, rootClass ).accept( vv ); + new ManyToOne( metadataBuildingContext, tbl ).accept( vv ); + new Map( metadataBuildingContext, rootClass ).accept( vv ); + new OneToMany( metadataBuildingContext, rootClass ).accept( vv ); + new OneToOne( metadataBuildingContext, tbl, rootClass ).accept( vv ); + new PrimitiveArray( metadataBuildingContext, rootClass ).accept( vv ); + new Set( metadataBuildingContext, rootClass ).accept( vv ); + new SimpleValue( metadataBuildingContext ).accept( vv ); + } } static public class ValueVisitorValidator implements ValueVisitor { diff --git a/hibernate-core/src/test/java/org/hibernate/test/multitenancy/discriminator/DiscriminatorMultiTenancyTest.java b/hibernate-core/src/test/java/org/hibernate/test/multitenancy/discriminator/DiscriminatorMultiTenancyTest.java index 6600182eb26f..165b4b7eaa93 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/multitenancy/discriminator/DiscriminatorMultiTenancyTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/multitenancy/discriminator/DiscriminatorMultiTenancyTest.java @@ -68,48 +68,54 @@ public void setUp() { .applySettings(settings) .build(); - MetadataSources ms = new MetadataSources(serviceRegistry); - ms.addAnnotatedClass(Customer.class); - - Metadata metadata = ms.buildMetadata(); - final PersistentClass customerMapping = metadata.getEntityBinding( Customer.class.getName() ); - customerMapping.setCached( true ); - ((RootClass) customerMapping ).setCacheConcurrencyStrategy( "read-write"); - - HibernateSchemaManagementTool tool = new HibernateSchemaManagementTool(); - tool.injectServices(serviceRegistry); - - connectionProvider = ConnectionProviderBuilder.buildConnectionProvider(); - - final GenerationTargetToDatabase target = new GenerationTargetToDatabase( - new DdlTransactionIsolatorTestingImpl( - serviceRegistry, - connectionProvider - ) - ); - - - new SchemaDropperImpl(serviceRegistry).doDrop( - metadata, - serviceRegistry, - settings, - true, - target - ); - - new SchemaCreatorImpl(serviceRegistry).doCreation( - metadata, - serviceRegistry, - settings, - true, - target - ); - - target.release(); - - final SessionFactoryBuilder sfb = metadata.getSessionFactoryBuilder(); - sessionFactory = (SessionFactoryImplementor) sfb.build(); - currentTenantResolver.setHibernateBooted(); + try { + MetadataSources ms = new MetadataSources( serviceRegistry ); + ms.addAnnotatedClass( Customer.class ); + + Metadata metadata = ms.buildMetadata(); + final PersistentClass customerMapping = metadata.getEntityBinding( Customer.class.getName() ); + customerMapping.setCached( true ); + ( (RootClass) customerMapping ).setCacheConcurrencyStrategy( "read-write" ); + + HibernateSchemaManagementTool tool = new HibernateSchemaManagementTool(); + tool.injectServices( serviceRegistry ); + + connectionProvider = ConnectionProviderBuilder.buildConnectionProvider(); + + final GenerationTargetToDatabase target = new GenerationTargetToDatabase( + new DdlTransactionIsolatorTestingImpl( + serviceRegistry, + connectionProvider + ) + ); + + + new SchemaDropperImpl( serviceRegistry ).doDrop( + metadata, + serviceRegistry, + settings, + true, + target + ); + + new SchemaCreatorImpl( serviceRegistry ).doCreation( + metadata, + serviceRegistry, + settings, + true, + target + ); + + target.release(); + + final SessionFactoryBuilder sfb = metadata.getSessionFactoryBuilder(); + sessionFactory = (SessionFactoryImplementor) sfb.build(); + currentTenantResolver.setHibernateBooted(); + } + catch (Throwable t) { + serviceRegistry.close(); + throw t; + } } @After diff --git a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaUpdateSchemaNameTest.java b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaUpdateSchemaNameTest.java index 92971c38e9ff..17638d052cb7 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaUpdateSchemaNameTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaUpdateSchemaNameTest.java @@ -75,8 +75,7 @@ public void cleanup() { .applySettings( cfg.getProperties() ) .build(); - SessionFactory sf = cfg.buildSessionFactory( ssr ); - try { + try (SessionFactory sf = cfg.buildSessionFactory();) { Session session = sf.openSession(); try { session.getTransaction().begin(); @@ -93,9 +92,6 @@ public void cleanup() { session.close(); } } - finally { - sf.close(); - } } finally { StandardServiceRegistryBuilder.destroy( ssr ); @@ -112,8 +108,7 @@ public void testSqlAlterWithTableSchemaName() throws Exception { cfg.getStandardServiceRegistryBuilder().getAggregatedCfgXml() ) .applySettings( cfg.getProperties() ) .build(); - SessionFactory sf = cfg.buildSessionFactory( ssr ); - try { + try (SessionFactory sf = cfg.buildSessionFactory( ssr )) { Session session = sf.openSession(); try { session.getTransaction().begin(); @@ -130,9 +125,6 @@ public void testSqlAlterWithTableSchemaName() throws Exception { session.close(); } } - finally { - sf.close(); - } } finally { StandardServiceRegistryBuilder.destroy( ssr ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/inheritance/hhh_x/InheritanceSchemaUpdateTest.java b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/inheritance/hhh_x/InheritanceSchemaUpdateTest.java index c4852f6944a2..0fe51032337d 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/inheritance/hhh_x/InheritanceSchemaUpdateTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/inheritance/hhh_x/InheritanceSchemaUpdateTest.java @@ -31,13 +31,13 @@ public class InheritanceSchemaUpdateTest extends BaseUnitTestCase { public void testBidirectionalOneToManyReferencingRootEntity() throws Exception { StandardServiceRegistry ssr = new StandardServiceRegistryBuilder().build(); - MetadataImplementor metadata = (MetadataImplementor) new MetadataSources( ssr ) - .addAnnotatedClass( Step.class ) - .addAnnotatedClass( GroupStep.class ) - .buildMetadata(); - metadata.validate(); - try { + MetadataImplementor metadata = (MetadataImplementor) new MetadataSources( ssr ) + .addAnnotatedClass( Step.class ) + .addAnnotatedClass( GroupStep.class ) + .buildMetadata(); + metadata.validate(); + try { new SchemaUpdate().execute( EnumSet.of( TargetType.DATABASE ), metadata ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/sql/storedproc/StoredProcedureResultSetMappingTest.java b/hibernate-core/src/test/java/org/hibernate/test/sql/storedproc/StoredProcedureResultSetMappingTest.java index fe27012a35e0..f42071233df6 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/sql/storedproc/StoredProcedureResultSetMappingTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/sql/storedproc/StoredProcedureResultSetMappingTest.java @@ -123,8 +123,7 @@ public void testPartialResults() { .addAnnotatedClass( Employee.class ) .setProperty( AvailableSettings.HBM2DDL_AUTO, "create-drop" ); cfg.addAuxiliaryDatabaseObject( new ProcedureDefinition() ); - SessionFactory sf = cfg.buildSessionFactory(); - try { + try (SessionFactory sf = cfg.buildSessionFactory()) { Session session = sf.openSession(); session.beginTransaction(); @@ -137,8 +136,5 @@ public void testPartialResults() { session.getTransaction().commit(); session.close(); } - finally { - sf.close(); - } } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/stats/StatsTest.java b/hibernate-core/src/test/java/org/hibernate/test/stats/StatsTest.java index ea1eb4c3275e..fbad8036f7da 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/stats/StatsTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/stats/StatsTest.java @@ -145,91 +145,91 @@ private Configuration buildBaseConfiguration() { @Test public void testQueryStatGathering() { - SessionFactory sf = buildBaseConfiguration() + try (SessionFactory sf = buildBaseConfiguration() .setProperty( AvailableSettings.HBM2DDL_AUTO, "create-drop" ) - .buildSessionFactory(); - - Session s = sf.openSession(); - Transaction tx = s.beginTransaction(); - fillDb(s); - tx.commit(); - s.close(); - - s = sf.openSession(); - tx = s.beginTransaction(); - final String continents = "from Continent"; - int results = s.createQuery( continents ).list().size(); - QueryStatistics continentStats = sf.getStatistics().getQueryStatistics( continents ); - assertNotNull( "stats were null", continentStats ); - assertEquals( "unexpected execution count", 1, continentStats.getExecutionCount() ); - assertEquals( "unexpected row count", results, continentStats.getExecutionRowCount() ); - long maxTime = continentStats.getExecutionMaxTime(); - assertEquals( maxTime, sf.getStatistics().getQueryExecutionMaxTime() ); + .buildSessionFactory()) { + + Session s = sf.openSession(); + Transaction tx = s.beginTransaction(); + fillDb( s ); + tx.commit(); + s.close(); + + s = sf.openSession(); + tx = s.beginTransaction(); + final String continents = "from Continent"; + int results = s.createQuery( continents ).list().size(); + QueryStatistics continentStats = sf.getStatistics().getQueryStatistics( continents ); + assertNotNull( "stats were null", continentStats ); + assertEquals( "unexpected execution count", 1, continentStats.getExecutionCount() ); + assertEquals( "unexpected row count", results, continentStats.getExecutionRowCount() ); + long maxTime = continentStats.getExecutionMaxTime(); + assertEquals( maxTime, sf.getStatistics().getQueryExecutionMaxTime() ); // assertEquals( continents, stats.getQueryExecutionMaxTimeQueryString() ); - Iterator itr = s.createQuery( continents ).iterate(); - // iterate() should increment the execution count - assertEquals( "unexpected execution count", 2, continentStats.getExecutionCount() ); - // but should not effect the cumulative row count - assertEquals( "unexpected row count", results, continentStats.getExecutionRowCount() ); - Hibernate.close( itr ); - - ScrollableResults scrollableResults = s.createQuery( continents ).scroll(); - // same deal with scroll()... - assertEquals( "unexpected execution count", 3, continentStats.getExecutionCount() ); - assertEquals( "unexpected row count", results, continentStats.getExecutionRowCount() ); - // scroll through data because SybaseASE15Dialect throws NullPointerException - // if data is not read before closing the ResultSet - while ( scrollableResults.next() ) { - // do nothing - } - scrollableResults.close(); - tx.commit(); - s.close(); - - // explicitly check that statistics for "split queries" get collected - // under the original query - sf.getStatistics().clear(); - - s = sf.openSession(); - tx = s.beginTransaction(); - final String localities = "from Locality"; - results = s.createQuery( localities ).list().size(); - QueryStatistics localityStats = sf.getStatistics().getQueryStatistics( localities ); - assertNotNull( "stats were null", localityStats ); - // ...one for each split query - assertEquals( "unexpected execution count", 2, localityStats.getExecutionCount() ); - assertEquals( "unexpected row count", results, localityStats.getExecutionRowCount() ); - maxTime = localityStats.getExecutionMaxTime(); - assertEquals( maxTime, sf.getStatistics().getQueryExecutionMaxTime() ); + Iterator itr = s.createQuery( continents ).iterate(); + // iterate() should increment the execution count + assertEquals( "unexpected execution count", 2, continentStats.getExecutionCount() ); + // but should not effect the cumulative row count + assertEquals( "unexpected row count", results, continentStats.getExecutionRowCount() ); + Hibernate.close( itr ); + + ScrollableResults scrollableResults = s.createQuery( continents ).scroll(); + // same deal with scroll()... + assertEquals( "unexpected execution count", 3, continentStats.getExecutionCount() ); + assertEquals( "unexpected row count", results, continentStats.getExecutionRowCount() ); + // scroll through data because SybaseASE15Dialect throws NullPointerException + // if data is not read before closing the ResultSet + while ( scrollableResults.next() ) { + // do nothing + } + scrollableResults.close(); + tx.commit(); + s.close(); + + // explicitly check that statistics for "split queries" get collected + // under the original query + sf.getStatistics().clear(); + + s = sf.openSession(); + tx = s.beginTransaction(); + final String localities = "from Locality"; + results = s.createQuery( localities ).list().size(); + QueryStatistics localityStats = sf.getStatistics().getQueryStatistics( localities ); + assertNotNull( "stats were null", localityStats ); + // ...one for each split query + assertEquals( "unexpected execution count", 2, localityStats.getExecutionCount() ); + assertEquals( "unexpected row count", results, localityStats.getExecutionRowCount() ); + maxTime = localityStats.getExecutionMaxTime(); + assertEquals( maxTime, sf.getStatistics().getQueryExecutionMaxTime() ); // assertEquals( localities, stats.getQueryExecutionMaxTimeQueryString() ); - tx.commit(); - s.close(); - assertFalse( s.isOpen() ); - - // native sql queries - sf.getStatistics().clear(); - - s = sf.openSession(); - tx = s.beginTransaction(); - final String sql = "select id, name from Country"; - results = s.createSQLQuery( sql ).addEntity( Country.class ).list().size(); - QueryStatistics sqlStats = sf.getStatistics().getQueryStatistics( sql ); - assertNotNull( "sql stats were null", sqlStats ); - assertEquals( "unexpected execution count", 1, sqlStats.getExecutionCount() ); - assertEquals( "unexpected row count", results, sqlStats.getExecutionRowCount() ); - maxTime = sqlStats.getExecutionMaxTime(); - assertEquals( maxTime, sf.getStatistics().getQueryExecutionMaxTime() ); + tx.commit(); + s.close(); + assertFalse( s.isOpen() ); + + // native sql queries + sf.getStatistics().clear(); + + s = sf.openSession(); + tx = s.beginTransaction(); + final String sql = "select id, name from Country"; + results = s.createSQLQuery( sql ).addEntity( Country.class ).list().size(); + QueryStatistics sqlStats = sf.getStatistics().getQueryStatistics( sql ); + assertNotNull( "sql stats were null", sqlStats ); + assertEquals( "unexpected execution count", 1, sqlStats.getExecutionCount() ); + assertEquals( "unexpected row count", results, sqlStats.getExecutionRowCount() ); + maxTime = sqlStats.getExecutionMaxTime(); + assertEquals( maxTime, sf.getStatistics().getQueryExecutionMaxTime() ); // assertEquals( sql, stats.getQueryExecutionMaxTimeQueryString() ); - tx.commit(); - s.close(); - - s = sf.openSession(); - tx = s.beginTransaction(); - cleanDb( s ); - tx.commit(); - s.close(); - sf.close(); + tx.commit(); + s.close(); + + s = sf.openSession(); + tx = s.beginTransaction(); + cleanDb( s ); + tx.commit(); + s.close(); + } } private Continent fillDb(Session s) { diff --git a/hibernate-core/src/test/java/org/hibernate/test/tool/schema/DropSchemaDuringJtaTxnTest.java b/hibernate-core/src/test/java/org/hibernate/test/tool/schema/DropSchemaDuringJtaTxnTest.java index e432310f64f1..94df31d8aa02 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/tool/schema/DropSchemaDuringJtaTxnTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/tool/schema/DropSchemaDuringJtaTxnTest.java @@ -53,11 +53,16 @@ private SessionFactory buildSessionFactory() { settings.put( AvailableSettings.TRANSACTION_COORDINATOR_STRATEGY, "jta" ); final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder().applySettings( settings ).build(); - - return new MetadataSources( ssr ) - .addAnnotatedClass( TestEntity.class ) - .buildMetadata() - .buildSessionFactory(); + try { + return new MetadataSources( ssr ) + .addAnnotatedClass( TestEntity.class ) + .buildMetadata() + .buildSessionFactory(); + } + catch (Throwable t) { + ssr.close(); + throw t; + } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/util/jdbc/PreparedStatementSpyConnectionProvider.java b/hibernate-core/src/test/java/org/hibernate/test/util/jdbc/PreparedStatementSpyConnectionProvider.java index b4ac7872f3cc..fab695a6add8 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/util/jdbc/PreparedStatementSpyConnectionProvider.java +++ b/hibernate-core/src/test/java/org/hibernate/test/util/jdbc/PreparedStatementSpyConnectionProvider.java @@ -39,7 +39,7 @@ public class PreparedStatementSpyConnectionProvider extends ConnectionProviderDe private static final MockSettings MOCK_SETTINGS = Mockito.withSettings() .stubOnly() //important optimisation: uses far less memory, at tradeoff of mocked methods no longer being verifiable but we often don't need that. .defaultAnswer( org.mockito.Answers.CALLS_REAL_METHODS ); - private static final MockSettings VERIFIEABLE_MOCK_SETTINGS = Mockito.withSettings() + private static final MockSettings VERIFIABLE_MOCK_SETTINGS = Mockito.withSettings() .defaultAnswer( org.mockito.Answers.CALLS_REAL_METHODS ); // We must keep around the mocked connections, otherwise they are garbage collected and trigger finalizers // Since we use CALLS_REAL_METHODS this might close underlying IO resources which makes other objects unusable @@ -69,8 +69,8 @@ public PreparedStatementSpyConnectionProvider() { * When you really need to verify invocations, set the relevant constructor parameter to true. */ public PreparedStatementSpyConnectionProvider(boolean allowMockVerificationOnStatements, boolean allowMockVerificationOnConnections) { - this.settingsForStatements = allowMockVerificationOnStatements ? VERIFIEABLE_MOCK_SETTINGS : MOCK_SETTINGS; - this.settingsForConnections = allowMockVerificationOnConnections ? VERIFIEABLE_MOCK_SETTINGS : MOCK_SETTINGS; + this.settingsForStatements = allowMockVerificationOnStatements ? VERIFIABLE_MOCK_SETTINGS : MOCK_SETTINGS; + this.settingsForConnections = allowMockVerificationOnConnections ? VERIFIABLE_MOCK_SETTINGS : MOCK_SETTINGS; } protected Connection actualConnection() throws SQLException { diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/components/dynamic/AuditedDynamicComponentTest.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/components/dynamic/AuditedDynamicComponentTest.java index 85f069ad13c9..bf158f42ad57 100644 --- a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/components/dynamic/AuditedDynamicComponentTest.java +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/components/dynamic/AuditedDynamicComponentTest.java @@ -54,7 +54,7 @@ public void testAuditedDynamicComponentFailure() throws URISyntaxException { final ServiceRegistry serviceRegistry = ServiceRegistryBuilder.buildServiceRegistry( config.getProperties() ); try { - config.buildSessionFactory( serviceRegistry ); + config.buildSessionFactory( serviceRegistry ).close(); Assert.fail( "MappingException expected" ); } catch ( MappingException e ) { diff --git a/hibernate-jcache/src/test/java/org/hibernate/jcache/test/TestHelper.java b/hibernate-jcache/src/test/java/org/hibernate/jcache/test/TestHelper.java index fa1711d855e2..2020594f4d77 100644 --- a/hibernate-jcache/src/test/java/org/hibernate/jcache/test/TestHelper.java +++ b/hibernate-jcache/src/test/java/org/hibernate/jcache/test/TestHelper.java @@ -105,8 +105,13 @@ public static SessionFactoryImplementor buildStandardSessionFactory(Consumer getCacheRegionDefinitions() { public void release() { delegate.release(); } + + public void close() { + delegate.release(); + delegate.getServiceRegistry().close(); + } } diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/boot/MetadataBuildingContextTestingImpl.java b/hibernate-testing/src/main/java/org/hibernate/testing/boot/MetadataBuildingContextTestingImpl.java index 53bb698e9e38..affa2af7bb4c 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/boot/MetadataBuildingContextTestingImpl.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/boot/MetadataBuildingContextTestingImpl.java @@ -31,10 +31,6 @@ public class MetadataBuildingContextTestingImpl implements MetadataBuildingConte private final ObjectNameNormalizer objectNameNormalizer; - public MetadataBuildingContextTestingImpl() { - this( new StandardServiceRegistryBuilder().build() ); - } - public MetadataBuildingContextTestingImpl(StandardServiceRegistry serviceRegistry) { buildingOptions = new MetadataBuilderImpl.MetadataBuildingOptionsImpl( serviceRegistry ); bootstrapContext = new BootstrapContextImpl( serviceRegistry, buildingOptions ); diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseCoreFunctionalTestCase.java b/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseCoreFunctionalTestCase.java index d3dee0e2c494..b6504dced2a7 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseCoreFunctionalTestCase.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseCoreFunctionalTestCase.java @@ -112,16 +112,34 @@ protected void buildSessionFactory() { protected void buildSessionFactory(Consumer configurationAdapter) { // for now, build the configuration to get all the property settings - BootstrapServiceRegistry bootRegistry = buildBootstrapServiceRegistry(); - configuration = constructAndConfigureConfiguration( bootRegistry ); - if ( configurationAdapter != null ) { - configurationAdapter.accept(configuration); + BootstrapServiceRegistry bootRegistry = null; + try { + bootRegistry = buildBootstrapServiceRegistry(); + configuration = constructAndConfigureConfiguration( bootRegistry ); + if ( configurationAdapter != null ) { + configurationAdapter.accept( configuration ); + } + serviceRegistry = buildServiceRegistry( bootRegistry, configuration ); + // this is done here because Configuration does not currently support 4.0 xsd + afterConstructAndConfigureConfiguration( configuration ); + sessionFactory = (SessionFactoryImplementor) configuration.buildSessionFactory( serviceRegistry ); + afterSessionFactoryBuilt(); + } + catch (Throwable t) { + if ( sessionFactory != null ) { + sessionFactory.close(); + sessionFactory = null; + configuration = null; + } + if ( serviceRegistry != null ) { + serviceRegistry.destroy(); + serviceRegistry = null; + } + else if ( bootRegistry != null ) { + bootRegistry.close(); + } + throw t; } - serviceRegistry = buildServiceRegistry( bootRegistry, configuration ); - // this is done here because Configuration does not currently support 4.0 xsd - afterConstructAndConfigureConfiguration( configuration ); - sessionFactory = ( SessionFactoryImplementor ) configuration.buildSessionFactory( serviceRegistry ); - afterSessionFactoryBuilt(); } protected void rebuildSessionFactory() { @@ -277,17 +295,25 @@ protected void prepareBootstrapRegistryBuilder(BootstrapServiceRegistryBuilder b } protected StandardServiceRegistryImpl buildServiceRegistry(BootstrapServiceRegistry bootRegistry, Configuration configuration) { - Properties properties = new Properties(); - properties.putAll( configuration.getProperties() ); - ConfigurationHelper.resolvePlaceHolders( properties ); + try { + Properties properties = new Properties(); + properties.putAll( configuration.getProperties() ); + ConfigurationHelper.resolvePlaceHolders( properties ); - StandardServiceRegistryBuilder cfgRegistryBuilder = configuration.getStandardServiceRegistryBuilder(); + StandardServiceRegistryBuilder cfgRegistryBuilder = configuration.getStandardServiceRegistryBuilder(); - StandardServiceRegistryBuilder registryBuilder = new StandardServiceRegistryBuilder( bootRegistry, cfgRegistryBuilder.getAggregatedCfgXml() ) - .applySettings( properties ); + StandardServiceRegistryBuilder registryBuilder = new StandardServiceRegistryBuilder( bootRegistry, cfgRegistryBuilder.getAggregatedCfgXml() ) + .applySettings( properties ); - prepareBasicRegistryBuilder( registryBuilder ); - return (StandardServiceRegistryImpl) registryBuilder.build(); + prepareBasicRegistryBuilder( registryBuilder ); + return (StandardServiceRegistryImpl) registryBuilder.build(); + } + catch (Throwable t) { + if ( bootRegistry != null ) { + bootRegistry.close(); + } + throw t; + } } protected void prepareBasicRegistryBuilder(StandardServiceRegistryBuilder serviceRegistryBuilder) { diff --git a/hibernate-vibur/src/test/java/org/hibernate/test/vibur/ViburDBCPConnectionProviderTest.java b/hibernate-vibur/src/test/java/org/hibernate/test/vibur/ViburDBCPConnectionProviderTest.java index 7c092825d808..8cb6b7354a26 100644 --- a/hibernate-vibur/src/test/java/org/hibernate/test/vibur/ViburDBCPConnectionProviderTest.java +++ b/hibernate-vibur/src/test/java/org/hibernate/test/vibur/ViburDBCPConnectionProviderTest.java @@ -132,8 +132,8 @@ public void testSelectStatementWithStatementsCache() { @SuppressWarnings("unchecked") private static void executeAndVerifySelect(Session session) { - List list = session.createQuery("from Actor where firstName = ?0") - .setParameter(0, "CHRISTIAN").list(); + List list = session.createQuery("from Actor where firstName = ?1") + .setParameter(1, "CHRISTIAN").list(); Set expectedLastNames = new HashSet<>(Arrays.asList("GABLE", "AKROYD", "NEESON")); assertEquals(expectedLastNames.size(), list.size()); From 0cbf0e5bf849ef6554a8f5afd39519af6ddf48ae Mon Sep 17 00:00:00 2001 From: Jan Schatteman Date: Tue, 14 Sep 2021 00:25:50 +0200 Subject: [PATCH 307/644] Minor improvement to the previous backport commit Signed-off-by: Jan Schatteman --- .../collection/EmbeddableWithManyToMany_HHH_11302_Test.java | 5 +++++ .../collection/EmbeddableWithOneToMany_HHH_11302_Test.java | 5 +++++ .../collection/EmbeddableWithOneToMany_HHH_8564_Test.java | 5 +++++ .../collection/EmbeddableWithOneToMany_HHH_8860_Test.java | 5 +++++ 4 files changed, 20 insertions(+) diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/embeddables/collection/EmbeddableWithManyToMany_HHH_11302_Test.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/embeddables/collection/EmbeddableWithManyToMany_HHH_11302_Test.java index 734b430a0357..89bebd21b24e 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/embeddables/collection/EmbeddableWithManyToMany_HHH_11302_Test.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/embeddables/collection/EmbeddableWithManyToMany_HHH_11302_Test.java @@ -61,6 +61,11 @@ protected void buildSessionFactory() { "@OneToMany, @ManyToMany or @ElementCollection cannot be used inside an @Embeddable that is also contained within an @ElementCollection" ) ); } + finally { + if ( serviceRegistry() != null ) { + serviceRegistry().destroy(); + } + } } @Test diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/embeddables/collection/EmbeddableWithOneToMany_HHH_11302_Test.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/embeddables/collection/EmbeddableWithOneToMany_HHH_11302_Test.java index 5034d75f0ea6..b558b962ff4b 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/embeddables/collection/EmbeddableWithOneToMany_HHH_11302_Test.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/embeddables/collection/EmbeddableWithOneToMany_HHH_11302_Test.java @@ -61,6 +61,11 @@ protected void buildSessionFactory() { "@OneToMany, @ManyToMany or @ElementCollection cannot be used inside an @Embeddable that is also contained within an @ElementCollection" ) ); } + finally { + if ( serviceRegistry() != null ) { + serviceRegistry().destroy(); + } + } } @Test diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/embeddables/collection/EmbeddableWithOneToMany_HHH_8564_Test.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/embeddables/collection/EmbeddableWithOneToMany_HHH_8564_Test.java index 13c575f43c29..79112d8902a1 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/embeddables/collection/EmbeddableWithOneToMany_HHH_8564_Test.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/embeddables/collection/EmbeddableWithOneToMany_HHH_8564_Test.java @@ -55,6 +55,11 @@ protected void buildSessionFactory() { "@OneToMany, @ManyToMany or @ElementCollection cannot be used inside an @Embeddable that is also contained within an @ElementCollection" ) ); } + finally { + if ( serviceRegistry() != null ) { + serviceRegistry().destroy(); + } + } } @Test diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/embeddables/collection/EmbeddableWithOneToMany_HHH_8860_Test.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/embeddables/collection/EmbeddableWithOneToMany_HHH_8860_Test.java index 994b4e02a362..88f339408e4a 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/embeddables/collection/EmbeddableWithOneToMany_HHH_8860_Test.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/embeddables/collection/EmbeddableWithOneToMany_HHH_8860_Test.java @@ -53,6 +53,11 @@ protected void buildSessionFactory() { "@OneToMany, @ManyToMany or @ElementCollection cannot be used inside an @Embeddable that is also contained within an @ElementCollection" ) ); } + finally { + if ( serviceRegistry() != null ) { + serviceRegistry().destroy(); + } + } } @Test From caa84d3ad9baefb34514ad378d435331266811b5 Mon Sep 17 00:00:00 2001 From: Knut Wannheden Date: Mon, 13 Sep 2021 14:49:45 +0200 Subject: [PATCH 308/644] HHH-13999 Support SQL Server 2016 SQL Server 2016 (13.x) and later support the `if exists` clause for most `drop` DDL statements. The new `SQLServer2016Dialect` dialect accounts for this and offers the advantage that no error messages get logged when using `hibernate.hbm2ddl.auto=create-drop`. --- .../java/org/hibernate/dialect/Database.java | 12 ++++--- .../dialect/SQLServer2016Dialect.java | 33 +++++++++++++++++++ 2 files changed, 41 insertions(+), 4 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/dialect/SQLServer2016Dialect.java diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/Database.java b/hibernate-core/src/main/java/org/hibernate/dialect/Database.java index 309986ff24ab..9989f6250416 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/Database.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/Database.java @@ -480,7 +480,7 @@ public Dialect resolveDialect(DialectResolutionInfo info) { SQLSERVER { @Override public Class latestDialect() { - return SQLServer2012Dialect.class; + return SQLServer2016Dialect.class; } @Override @@ -501,16 +501,20 @@ public Dialect resolveDialect(DialectResolutionInfo info) { return new SQLServer2008Dialect(); } case 11: - case 12: - case 13: { + case 12: { return new SQLServer2012Dialect(); } + case 13: + case 14: + case 15: { + return new SQLServer2016Dialect(); + } default: { if ( majorVersion < 8 ) { return new SQLServerDialect(); } else { - // assume `majorVersion > 13` + // assume `majorVersion > 15` return latestDialectInstance( this ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServer2016Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServer2016Dialect.java new file mode 100644 index 000000000000..6ad124e26d19 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServer2016Dialect.java @@ -0,0 +1,33 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.dialect; + +/** + * Microsoft SQL Server 2016 Dialect + */ +public class SQLServer2016Dialect extends SQLServer2012Dialect { + + @Override + public boolean supportsIfExistsBeforeTableName() { + return true; + } + + @Override + public boolean supportsIfExistsBeforeConstraintName() { + return true; + } + + @Override + public String getDropSequenceString(String sequenceName) { + return "drop sequence if exists " + sequenceName; + } + + @Override + public String[] getDropSchemaCommand(String schemaName) { + return new String[] {"drop schema if exists " + schemaName}; + } +} From f6a03cf7715439ba09bac42afc5380414c545517 Mon Sep 17 00:00:00 2001 From: Rafael Lillo Date: Sun, 12 Sep 2021 20:28:00 +0200 Subject: [PATCH 309/644] HHH-5249 Add more details MappingException --- .../src/main/java/org/hibernate/mapping/Component.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Component.java b/hibernate-core/src/main/java/org/hibernate/mapping/Component.java index a60d6eea3d88..af85ad6fbbc5 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Component.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Component.java @@ -362,7 +362,7 @@ public Property getProperty(String propertyName) throws MappingException { return prop; } } - throw new MappingException("component property not found: " + propertyName); + throw new MappingException("component: " + componentClassName + " property not found: " + propertyName); } public String getRoleName() { From 170821c135ccd3b572b8208340f464d66fba7f3f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Thu, 16 Sep 2021 10:40:55 +0200 Subject: [PATCH 310/644] HHH-14827 Test using @AttributeOverride and also an orm.xml file --- ...XmlAndAnnotationAttributeOverrideTest.java | 125 ++++++++++++++++++ .../org/hibernate/test/util/SchemaUtil.java | 18 +++ .../org/hibernate/jpa/test/xml/orm-empty.xml | 13 ++ 3 files changed, 156 insertions(+) create mode 100644 hibernate-core/src/test/java/org/hibernate/jpa/test/xml/XmlAndAnnotationAttributeOverrideTest.java create mode 100644 hibernate-core/src/test/resources/org/hibernate/jpa/test/xml/orm-empty.xml diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/xml/XmlAndAnnotationAttributeOverrideTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/xml/XmlAndAnnotationAttributeOverrideTest.java new file mode 100644 index 000000000000..15b243fc2db6 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/xml/XmlAndAnnotationAttributeOverrideTest.java @@ -0,0 +1,125 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.jpa.test.xml; + +import static org.assertj.core.api.Assertions.assertThat; + +import javax.persistence.AttributeOverride; +import javax.persistence.Column; +import javax.persistence.Embeddable; +import javax.persistence.Embedded; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.MappedSuperclass; + +import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.test.util.SchemaUtil; +import org.junit.Test; + +public class XmlAndAnnotationAttributeOverrideTest extends BaseEntityManagerFunctionalTestCase { + @Test + @TestForIssue(jiraKey = "HHH-14827") + public void testDerivedClassAttributeOverriding() { + assertThat( SchemaUtil.getColumnNames( entityManagerFactory(), DerivedEntityType.class ) ) + .contains( "custom_name" ) + .doesNotContain( "name" ); + } + + @Test + public void testEmbeddedAttributeOverriding() { + assertThat( SchemaUtil.getColumnNames( entityManagerFactory(), DerivedEntityType.class ) ) + .contains( "custom_embeddable_name" ) + .doesNotContain( "embeddable_name" ); + } + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { MappedSuperclassType.class, DerivedEntityType.class, EmbeddableType.class }; + } + + @Override + public String[] getEjb3DD() { + return new String[] { + // Using an empty orm.xml: the mere presence of an orm.xml used to trigger the bug, + // regardless of its content. + "org/hibernate/jpa/test/xml/orm-empty.xml" + }; + } + + @MappedSuperclass + public static class MappedSuperclassType { + + private String name; + + public MappedSuperclassType() { + } + + public MappedSuperclassType(String name) { + this.name = name; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + } + + @Entity(name = "derivedentity") + @AttributeOverride(name = "name", column = @Column(name = "custom_name")) + public static class DerivedEntityType extends MappedSuperclassType { + + @Id + @GeneratedValue + private long id; + + @Embedded + @AttributeOverride(name = "embeddableName", column = @Column(name = "custom_embeddable_name")) + private EmbeddableType embedded; + + public DerivedEntityType() { + } + + public DerivedEntityType(String name) { + super( name ); + } + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + public EmbeddableType getEmbedded() { + return embedded; + } + + public void setEmbedded(EmbeddableType embedded) { + this.embedded = embedded; + } + } + + @Embeddable + public static class EmbeddableType { + private String embeddableName; + + public String getEmbeddableName() { + return embeddableName; + } + + public void setEmbeddableName(String embeddableName) { + this.embeddableName = embeddableName; + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/util/SchemaUtil.java b/hibernate-core/src/test/java/org/hibernate/test/util/SchemaUtil.java index 3cdb27891ee6..61d8001fdab9 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/util/SchemaUtil.java +++ b/hibernate-core/src/test/java/org/hibernate/test/util/SchemaUtil.java @@ -6,13 +6,17 @@ */ package org.hibernate.test.util; +import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.Set; +import javax.persistence.EntityManagerFactory; import org.hibernate.boot.Metadata; +import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.mapping.Column; import org.hibernate.mapping.Table; +import org.hibernate.persister.entity.AbstractEntityPersister; /** * Check that the Hibernate metamodel contains some database objects @@ -60,4 +64,18 @@ public static boolean isTablePresent(String tableName, Metadata metadata) { return false; } + + public static Set getColumnNames(EntityManagerFactory entityManagerFactory, Class entityType) { + Set result = new HashSet<>(); + AbstractEntityPersister persister = (AbstractEntityPersister) entityManagerFactory + .unwrap( SessionFactoryImplementor.class ) + .getMetamodel().entityPersister( entityType ); + if ( persister == null ) { + return result; + } + for ( String propertyName : persister.getPropertyNames() ) { + Collections.addAll( result, persister.getPropertyColumnNames( propertyName ) ); + } + return result; + } } diff --git a/hibernate-core/src/test/resources/org/hibernate/jpa/test/xml/orm-empty.xml b/hibernate-core/src/test/resources/org/hibernate/jpa/test/xml/orm-empty.xml new file mode 100644 index 000000000000..7e09f0ebc739 --- /dev/null +++ b/hibernate-core/src/test/resources/org/hibernate/jpa/test/xml/orm-empty.xml @@ -0,0 +1,13 @@ + + + + + \ No newline at end of file From 70d7ac6ecdb8373002f88ff2824fbe22d253a244 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Thu, 16 Sep 2021 10:50:56 +0200 Subject: [PATCH 311/644] HHH-14827 Fix @AttributeOverride at type level being ignored when also using orm.xml --- .../internal/JPAXMLOverriddenAnnotationReader.java | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenAnnotationReader.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenAnnotationReader.java index ae848b91305b..e668d0557d1a 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenAnnotationReader.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenAnnotationReader.java @@ -1880,9 +1880,10 @@ private void addAssociationOverrideIfNeeded(AssociationOverride annotation, List } private AttributeOverrides getAttributeOverrides(ManagedType root, XMLContext.Default defaults) { - return root instanceof JaxbEntity - ? getAttributeOverrides( ( (JaxbEntity) root ).getAttributeOverride(), defaults, true ) - : null; + return getAttributeOverrides( + root instanceof JaxbEntity ? ( (JaxbEntity) root ).getAttributeOverride() : Collections.emptyList(), + defaults, true + ); } /** From 86ad83f0b5b582bcf705d934d51921818cdc6b44 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Thu, 16 Sep 2021 10:51:31 +0200 Subject: [PATCH 312/644] HHH-14827 Fix @AssociationOverride/@PrimaryKeyJoinColumn at type level being ignored when also using orm.xml --- .../internal/JPAXMLOverriddenAnnotationReader.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenAnnotationReader.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenAnnotationReader.java index e668d0557d1a..8a8c3167522c 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenAnnotationReader.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenAnnotationReader.java @@ -1794,9 +1794,10 @@ private void getAccessType(List annotationList, AccessType type) { } private AssociationOverrides getAssociationOverrides(ManagedType root, XMLContext.Default defaults) { - return root instanceof JaxbEntity - ? getAssociationOverrides( ( (JaxbEntity) root ).getAssociationOverride(), defaults, true ) - : null; + return getAssociationOverrides( + root instanceof JaxbEntity ? ( (JaxbEntity) root ).getAssociationOverride() : Collections.emptyList(), + defaults, true + ); } /** @@ -2742,9 +2743,10 @@ else if ( defaults.canUseJavaAnnotations() ) { } private PrimaryKeyJoinColumns getPrimaryKeyJoinColumns(ManagedType root, XMLContext.Default defaults) { - return root instanceof JaxbEntity - ? getPrimaryKeyJoinColumns( ( (JaxbEntity) root ).getPrimaryKeyJoinColumn(), defaults, true ) - : null; + return getPrimaryKeyJoinColumns( + root instanceof JaxbEntity ? ( (JaxbEntity) root ).getPrimaryKeyJoinColumn() : Collections.emptyList(), + defaults, true + ); } /** From ad6af3af7d022a03a578e8806cf1acba2725810e Mon Sep 17 00:00:00 2001 From: Nathan Xu Date: Thu, 21 Jan 2021 15:21:01 -0500 Subject: [PATCH 313/644] HHH-14413 fix issue that EntityUpdateAction increments version despite veto on update --- .../action/internal/EntityUpdateAction.java | 42 +++++----- .../event/PreUpdateEventListenerVetoTest.java | 84 +++++++++++++++++++ 2 files changed, 105 insertions(+), 21 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/event/PreUpdateEventListenerVetoTest.java diff --git a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityUpdateAction.java b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityUpdateAction.java index f2cd99fee0e2..41bc9f9e653b 100644 --- a/hibernate-core/src/main/java/org/hibernate/action/internal/EntityUpdateAction.java +++ b/hibernate-core/src/main/java/org/hibernate/action/internal/EntityUpdateAction.java @@ -171,7 +171,9 @@ public void execute() throws HibernateException { final SharedSessionContractImplementor session = getSession(); final Object instance = getInstance(); - final boolean veto = preUpdate(); + if ( preUpdate() ) { + return; + } final SessionFactoryImplementor factory = session.getFactory(); Object previousVersion = this.previousVersion; @@ -196,27 +198,24 @@ public void execute() throws HibernateException { else { ck = null; } - - if ( !veto ) { - persister.update( - id, - state, - dirtyFields, - hasDirtyCollection, - previousState, - previousVersion, - instance, - rowId, - session - ); - } + persister.update( + id, + state, + dirtyFields, + hasDirtyCollection, + previousState, + previousVersion, + instance, + rowId, + session + ); final EntityEntry entry = session.getPersistenceContextInternal().getEntry( instance ); if ( entry == null ) { - throw new AssertionFailure( "possible nonthreadsafe access to session" ); + throw new AssertionFailure( "possible non thread safe access to session" ); } - if ( entry.getStatus()==Status.MANAGED || persister.isVersionPropertyGenerated() ) { + if ( entry.getStatus() == Status.MANAGED || persister.isVersionPropertyGenerated() ) { // get the updated snapshot of the entity state by cloning current state; // it is safe to copy in place, since by this time no-one else (should have) // has a reference to the array @@ -242,12 +241,12 @@ public void execute() throws HibernateException { final StatisticsImplementor statistics = factory.getStatistics(); if ( persister.canWriteToCache() ) { - if ( persister.isCacheInvalidationRequired() || entry.getStatus()!= Status.MANAGED ) { - persister.getCacheAccessStrategy().remove( session, ck); + if ( persister.isCacheInvalidationRequired() || entry.getStatus() != Status.MANAGED ) { + persister.getCacheAccessStrategy().remove( session, ck ); } else if ( session.getCacheMode().isPutEnabled() ) { //TODO: inefficient if that cache is just going to ignore the updated state! - final CacheEntry ce = persister.buildCacheEntry( instance,state, nextVersion, getSession() ); + final CacheEntry ce = persister.buildCacheEntry( instance, state, nextVersion, getSession() ); cacheEntry = persister.getCacheEntryStructure().structure( ce ); final boolean put = cacheUpdate( persister, previousVersion, ck ); @@ -270,9 +269,10 @@ else if ( session.getCacheMode().isPutEnabled() ) { postUpdate(); - if ( statistics.isStatisticsEnabled() && !veto ) { + if ( statistics.isStatisticsEnabled() ) { statistics.updateEntity( getPersister().getEntityName() ); } + } protected boolean cacheUpdate(EntityPersister persister, Object previousVersion, Object ck) { diff --git a/hibernate-core/src/test/java/org/hibernate/event/PreUpdateEventListenerVetoTest.java b/hibernate-core/src/test/java/org/hibernate/event/PreUpdateEventListenerVetoTest.java new file mode 100644 index 000000000000..f3ffaa9fa5fd --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/event/PreUpdateEventListenerVetoTest.java @@ -0,0 +1,84 @@ +package org.hibernate.event; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Version; + +import org.hibernate.event.service.spi.EventListenerRegistry; +import org.hibernate.event.spi.EventType; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.Before; +import org.junit.Test; + +import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; +import static org.junit.Assert.assertEquals; + +/** + * @author Nathan Xu + * @author Tassilo Karge + */ +@TestForIssue( jiraKey = "HHH-14413" ) +public class PreUpdateEventListenerVetoTest extends BaseCoreFunctionalTestCase { + + private static final Long EXAMPLE_ID_VALUE = 1L; + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { ExampleEntity.class }; + } + + @Override + protected void afterSessionFactoryBuilt() { + super.afterSessionFactoryBuilt(); + EventListenerRegistry registry = sessionFactory().getServiceRegistry().getService( EventListenerRegistry.class ); + registry.appendListeners( + EventType.PRE_UPDATE, + event -> true + ); + } + + @Before + public void setUp() { + doInHibernate( this::sessionFactory, session -> { + ExampleEntity entity = new ExampleEntity(); + entity.id = EXAMPLE_ID_VALUE; + entity.name = "old_name"; + session.save( entity ); + } ); + } + + @Test + public void testVersionNotChangedWhenPreUpdateEventVetoed() { + + doInHibernate( this::sessionFactory, session -> { + ExampleEntity entity = session.byId( ExampleEntity.class ).load( EXAMPLE_ID_VALUE ); + + entity.name = "new_name"; + session.update( entity ); + + final Long versionBeforeFlush = entity.version; + + session.flush(); + + final Long versionAfterFlush = entity.version; + + assertEquals( "The entity version must not change when update is vetoed", versionBeforeFlush, versionAfterFlush ); + + } ); + } + + @Entity(name = "ExampleEntity") + public static class ExampleEntity { + + @Id + Long id; + + String name; + + @Version + Long version; + + } +} From 24b9605c5201a9d4217d3454627fd7a74ab02354 Mon Sep 17 00:00:00 2001 From: "ENTERPRISE-X64\\bertiepinnock" Date: Sat, 11 Sep 2021 00:08:55 +0100 Subject: [PATCH 314/644] HHH-13661 | Added case to PostgreSQL Dialect to map client operation cancellation to QueryTimeoutException --- .../dialect/PostgreSQL81Dialect.java | 182 ++++++++++-------- .../dialect/PostgreSQL81DialectTestCase.java | 13 ++ 2 files changed, 117 insertions(+), 78 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL81Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL81Dialect.java index aee33307bcf8..ad4ee3a3eef4 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL81Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL81Dialect.java @@ -18,6 +18,7 @@ import org.hibernate.LockMode; import org.hibernate.LockOptions; import org.hibernate.PessimisticLockException; +import org.hibernate.QueryTimeoutException; import org.hibernate.cfg.Environment; import org.hibernate.dialect.function.NoArgSQLFunction; import org.hibernate.dialect.function.PositionSubstringFunction; @@ -66,7 +67,7 @@ public class PostgreSQL81Dialect extends Dialect { @Override public String processSql(String sql, RowSelection selection) { final boolean hasOffset = LimitHelper.hasFirstRow( selection ); - return sql + (hasOffset ? " limit ? offset ?" : " limit ?"); + return sql + ( hasOffset ? " limit ? offset ?" : " limit ?" ); } @Override @@ -118,75 +119,84 @@ public PostgreSQL81Dialect() { registerColumnType( Types.NUMERIC, "numeric($p, $s)" ); registerColumnType( Types.OTHER, "uuid" ); - registerFunction( "abs", new StandardSQLFunction("abs") ); - registerFunction( "sign", new StandardSQLFunction("sign", StandardBasicTypes.INTEGER) ); - - registerFunction( "acos", new StandardSQLFunction("acos", StandardBasicTypes.DOUBLE) ); - registerFunction( "asin", new StandardSQLFunction("asin", StandardBasicTypes.DOUBLE) ); - registerFunction( "atan", new StandardSQLFunction("atan", StandardBasicTypes.DOUBLE) ); - registerFunction( "cos", new StandardSQLFunction("cos", StandardBasicTypes.DOUBLE) ); - registerFunction( "cot", new StandardSQLFunction("cot", StandardBasicTypes.DOUBLE) ); - registerFunction( "exp", new StandardSQLFunction("exp", StandardBasicTypes.DOUBLE) ); - registerFunction( "ln", new StandardSQLFunction("ln", StandardBasicTypes.DOUBLE) ); - registerFunction( "log", new StandardSQLFunction("log", StandardBasicTypes.DOUBLE) ); - registerFunction( "sin", new StandardSQLFunction("sin", StandardBasicTypes.DOUBLE) ); - registerFunction( "sqrt", new StandardSQLFunction("sqrt", StandardBasicTypes.DOUBLE) ); - registerFunction( "cbrt", new StandardSQLFunction("cbrt", StandardBasicTypes.DOUBLE) ); - registerFunction( "tan", new StandardSQLFunction("tan", StandardBasicTypes.DOUBLE) ); - registerFunction( "radians", new StandardSQLFunction("radians", StandardBasicTypes.DOUBLE) ); - registerFunction( "degrees", new StandardSQLFunction("degrees", StandardBasicTypes.DOUBLE) ); - - registerFunction( "stddev", new StandardSQLFunction("stddev", StandardBasicTypes.DOUBLE) ); - registerFunction( "variance", new StandardSQLFunction("variance", StandardBasicTypes.DOUBLE) ); - - registerFunction( "random", new NoArgSQLFunction("random", StandardBasicTypes.DOUBLE) ); - registerFunction( "rand", new NoArgSQLFunction("random", StandardBasicTypes.DOUBLE) ); - - registerFunction( "round", new StandardSQLFunction("round") ); - registerFunction( "trunc", new StandardSQLFunction("trunc") ); - registerFunction( "ceil", new StandardSQLFunction("ceil") ); - registerFunction( "floor", new StandardSQLFunction("floor") ); - - registerFunction( "chr", new StandardSQLFunction("chr", StandardBasicTypes.CHARACTER) ); - registerFunction( "lower", new StandardSQLFunction("lower") ); - registerFunction( "upper", new StandardSQLFunction("upper") ); - registerFunction( "substr", new StandardSQLFunction("substr", StandardBasicTypes.STRING) ); - registerFunction( "initcap", new StandardSQLFunction("initcap") ); - registerFunction( "to_ascii", new StandardSQLFunction("to_ascii") ); - registerFunction( "quote_ident", new StandardSQLFunction("quote_ident", StandardBasicTypes.STRING) ); - registerFunction( "quote_literal", new StandardSQLFunction("quote_literal", StandardBasicTypes.STRING) ); - registerFunction( "md5", new StandardSQLFunction("md5", StandardBasicTypes.STRING) ); - registerFunction( "ascii", new StandardSQLFunction("ascii", StandardBasicTypes.INTEGER) ); - registerFunction( "char_length", new StandardSQLFunction("char_length", StandardBasicTypes.LONG) ); - registerFunction( "bit_length", new StandardSQLFunction("bit_length", StandardBasicTypes.LONG) ); - registerFunction( "octet_length", new StandardSQLFunction("octet_length", StandardBasicTypes.LONG) ); - - registerFunction( "age", new StandardSQLFunction("age") ); - registerFunction( "current_date", new NoArgSQLFunction("current_date", StandardBasicTypes.DATE, false) ); - registerFunction( "current_time", new NoArgSQLFunction("current_time", StandardBasicTypes.TIME, false) ); - registerFunction( "current_timestamp", new NoArgSQLFunction("current_timestamp", StandardBasicTypes.TIMESTAMP, false) ); + registerFunction( "abs", new StandardSQLFunction( "abs" ) ); + registerFunction( "sign", new StandardSQLFunction( "sign", StandardBasicTypes.INTEGER ) ); + + registerFunction( "acos", new StandardSQLFunction( "acos", StandardBasicTypes.DOUBLE ) ); + registerFunction( "asin", new StandardSQLFunction( "asin", StandardBasicTypes.DOUBLE ) ); + registerFunction( "atan", new StandardSQLFunction( "atan", StandardBasicTypes.DOUBLE ) ); + registerFunction( "cos", new StandardSQLFunction( "cos", StandardBasicTypes.DOUBLE ) ); + registerFunction( "cot", new StandardSQLFunction( "cot", StandardBasicTypes.DOUBLE ) ); + registerFunction( "exp", new StandardSQLFunction( "exp", StandardBasicTypes.DOUBLE ) ); + registerFunction( "ln", new StandardSQLFunction( "ln", StandardBasicTypes.DOUBLE ) ); + registerFunction( "log", new StandardSQLFunction( "log", StandardBasicTypes.DOUBLE ) ); + registerFunction( "sin", new StandardSQLFunction( "sin", StandardBasicTypes.DOUBLE ) ); + registerFunction( "sqrt", new StandardSQLFunction( "sqrt", StandardBasicTypes.DOUBLE ) ); + registerFunction( "cbrt", new StandardSQLFunction( "cbrt", StandardBasicTypes.DOUBLE ) ); + registerFunction( "tan", new StandardSQLFunction( "tan", StandardBasicTypes.DOUBLE ) ); + registerFunction( "radians", new StandardSQLFunction( "radians", StandardBasicTypes.DOUBLE ) ); + registerFunction( "degrees", new StandardSQLFunction( "degrees", StandardBasicTypes.DOUBLE ) ); + + registerFunction( "stddev", new StandardSQLFunction( "stddev", StandardBasicTypes.DOUBLE ) ); + registerFunction( "variance", new StandardSQLFunction( "variance", StandardBasicTypes.DOUBLE ) ); + + registerFunction( "random", new NoArgSQLFunction( "random", StandardBasicTypes.DOUBLE ) ); + registerFunction( "rand", new NoArgSQLFunction( "random", StandardBasicTypes.DOUBLE ) ); + + registerFunction( "round", new StandardSQLFunction( "round" ) ); + registerFunction( "trunc", new StandardSQLFunction( "trunc" ) ); + registerFunction( "ceil", new StandardSQLFunction( "ceil" ) ); + registerFunction( "floor", new StandardSQLFunction( "floor" ) ); + + registerFunction( "chr", new StandardSQLFunction( "chr", StandardBasicTypes.CHARACTER ) ); + registerFunction( "lower", new StandardSQLFunction( "lower" ) ); + registerFunction( "upper", new StandardSQLFunction( "upper" ) ); + registerFunction( "substr", new StandardSQLFunction( "substr", StandardBasicTypes.STRING ) ); + registerFunction( "initcap", new StandardSQLFunction( "initcap" ) ); + registerFunction( "to_ascii", new StandardSQLFunction( "to_ascii" ) ); + registerFunction( "quote_ident", new StandardSQLFunction( "quote_ident", StandardBasicTypes.STRING ) ); + registerFunction( "quote_literal", new StandardSQLFunction( "quote_literal", StandardBasicTypes.STRING ) ); + registerFunction( "md5", new StandardSQLFunction( "md5", StandardBasicTypes.STRING ) ); + registerFunction( "ascii", new StandardSQLFunction( "ascii", StandardBasicTypes.INTEGER ) ); + registerFunction( "char_length", new StandardSQLFunction( "char_length", StandardBasicTypes.LONG ) ); + registerFunction( "bit_length", new StandardSQLFunction( "bit_length", StandardBasicTypes.LONG ) ); + registerFunction( "octet_length", new StandardSQLFunction( "octet_length", StandardBasicTypes.LONG ) ); + + registerFunction( "age", new StandardSQLFunction( "age" ) ); + registerFunction( "current_date", new NoArgSQLFunction( "current_date", StandardBasicTypes.DATE, false ) ); + registerFunction( "current_time", new NoArgSQLFunction( "current_time", StandardBasicTypes.TIME, false ) ); + registerFunction( + "current_timestamp", + new NoArgSQLFunction( "current_timestamp", StandardBasicTypes.TIMESTAMP, false ) + ); registerFunction( "date_trunc", new StandardSQLFunction( "date_trunc", StandardBasicTypes.TIMESTAMP ) ); - registerFunction( "localtime", new NoArgSQLFunction("localtime", StandardBasicTypes.TIME, false) ); - registerFunction( "localtimestamp", new NoArgSQLFunction("localtimestamp", StandardBasicTypes.TIMESTAMP, false) ); - registerFunction( "now", new NoArgSQLFunction("now", StandardBasicTypes.TIMESTAMP) ); - registerFunction( "timeofday", new NoArgSQLFunction("timeofday", StandardBasicTypes.STRING) ); - - registerFunction( "current_user", new NoArgSQLFunction("current_user", StandardBasicTypes.STRING, false) ); - registerFunction( "session_user", new NoArgSQLFunction("session_user", StandardBasicTypes.STRING, false) ); - registerFunction( "user", new NoArgSQLFunction("user", StandardBasicTypes.STRING, false) ); - registerFunction( "current_database", new NoArgSQLFunction("current_database", StandardBasicTypes.STRING, true) ); - registerFunction( "current_schema", new NoArgSQLFunction("current_schema", StandardBasicTypes.STRING, true) ); + registerFunction( "localtime", new NoArgSQLFunction( "localtime", StandardBasicTypes.TIME, false ) ); + registerFunction( + "localtimestamp", + new NoArgSQLFunction( "localtimestamp", StandardBasicTypes.TIMESTAMP, false ) + ); + registerFunction( "now", new NoArgSQLFunction( "now", StandardBasicTypes.TIMESTAMP ) ); + registerFunction( "timeofday", new NoArgSQLFunction( "timeofday", StandardBasicTypes.STRING ) ); + + registerFunction( "current_user", new NoArgSQLFunction( "current_user", StandardBasicTypes.STRING, false ) ); + registerFunction( "session_user", new NoArgSQLFunction( "session_user", StandardBasicTypes.STRING, false ) ); + registerFunction( "user", new NoArgSQLFunction( "user", StandardBasicTypes.STRING, false ) ); + registerFunction( + "current_database", + new NoArgSQLFunction( "current_database", StandardBasicTypes.STRING, true ) + ); + registerFunction( "current_schema", new NoArgSQLFunction( "current_schema", StandardBasicTypes.STRING, true ) ); - registerFunction( "to_char", new StandardSQLFunction("to_char", StandardBasicTypes.STRING) ); - registerFunction( "to_date", new StandardSQLFunction("to_date", StandardBasicTypes.DATE) ); - registerFunction( "to_timestamp", new StandardSQLFunction("to_timestamp", StandardBasicTypes.TIMESTAMP) ); - registerFunction( "to_number", new StandardSQLFunction("to_number", StandardBasicTypes.BIG_DECIMAL) ); + registerFunction( "to_char", new StandardSQLFunction( "to_char", StandardBasicTypes.STRING ) ); + registerFunction( "to_date", new StandardSQLFunction( "to_date", StandardBasicTypes.DATE ) ); + registerFunction( "to_timestamp", new StandardSQLFunction( "to_timestamp", StandardBasicTypes.TIMESTAMP ) ); + registerFunction( "to_number", new StandardSQLFunction( "to_number", StandardBasicTypes.BIG_DECIMAL ) ); - registerFunction( "concat", new VarArgsSQLFunction( StandardBasicTypes.STRING, "(","||",")" ) ); + registerFunction( "concat", new VarArgsSQLFunction( StandardBasicTypes.STRING, "(", "||", ")" ) ); registerFunction( "locate", new PositionSubstringFunction() ); - registerFunction( "str", new SQLFunctionTemplate(StandardBasicTypes.STRING, "cast(?1 as varchar)") ); + registerFunction( "str", new SQLFunctionTemplate( StandardBasicTypes.STRING, "cast(?1 as varchar)" ) ); getDefaultProperties().setProperty( Environment.STATEMENT_BATCH_SIZE, DEFAULT_BATCH_SIZE ); getDefaultProperties().setProperty( Environment.NON_CONTEXTUAL_LOB_CREATION, "true" ); @@ -286,7 +296,7 @@ public boolean supportsLimit() { @Override public String getLimitString(String sql, boolean hasOffset) { - return sql + (hasOffset ? " limit ? offset ?" : " limit ?"); + return sql + ( hasOffset ? " limit ? offset ?" : " limit ?" ); } @Override @@ -317,12 +327,12 @@ public String getForUpdateString(String aliases, LockOptions lockOptions) { } } LockMode lockMode = lockOptions.getAliasSpecificLockMode( aliases ); - if (lockMode == null ) { + if ( lockMode == null ) { lockMode = lockOptions.getLockMode(); } switch ( lockMode ) { case UPGRADE: - return getForUpdateString(aliases); + return getForUpdateString( aliases ); case PESSIMISTIC_READ: return getReadLockString( aliases, lockOptions.getTimeOut() ); case PESSIMISTIC_WRITE: @@ -330,9 +340,9 @@ public String getForUpdateString(String aliases, LockOptions lockOptions) { case UPGRADE_NOWAIT: case FORCE: case PESSIMISTIC_FORCE_INCREMENT: - return getForUpdateNowaitString(aliases); + return getForUpdateNowaitString( aliases ); case UPGRADE_SKIPLOCKED: - return getForUpdateSkipLockedString(aliases); + return getForUpdateSkipLockedString( aliases ); default: return ""; } @@ -344,7 +354,7 @@ public String getNoColumnsInsertString() { } @Override - public String getCaseInsensitiveLike(){ + public String getCaseInsensitiveLike() { return "ilike"; } @@ -451,19 +461,29 @@ public ViolatedConstraintNameExtracter getViolatedConstraintNameExtracter() { @Override protected String doExtractConstraintName(SQLException sqle) throws NumberFormatException { final int sqlState = Integer.parseInt( JdbcExceptionHelper.extractSqlState( sqle ) ); - switch (sqlState) { + switch ( sqlState ) { // CHECK VIOLATION - case 23514: return extractUsingTemplate( "violates check constraint \"","\"", sqle.getMessage() ); + case 23514: + return extractUsingTemplate( "violates check constraint \"", "\"", sqle.getMessage() ); // UNIQUE VIOLATION - case 23505: return extractUsingTemplate( "violates unique constraint \"","\"", sqle.getMessage() ); + case 23505: + return extractUsingTemplate( "violates unique constraint \"", "\"", sqle.getMessage() ); // FOREIGN KEY VIOLATION - case 23503: return extractUsingTemplate( "violates foreign key constraint \"","\"", sqle.getMessage() ); + case 23503: + return extractUsingTemplate( "violates foreign key constraint \"", "\"", sqle.getMessage() ); // NOT NULL VIOLATION - case 23502: return extractUsingTemplate( "null value in column \"","\" violates not-null constraint", sqle.getMessage() ); + case 23502: + return extractUsingTemplate( + "null value in column \"", + "\" violates not-null constraint", + sqle.getMessage() + ); // TODO: RESTRICT VIOLATION - case 23001: return null; + case 23001: + return null; // ALL OTHER - default: return null; + default: + return null; } } }; @@ -485,6 +505,11 @@ public JDBCException convert(SQLException sqlException, String message, String s return new PessimisticLockException( message, sqlException, sql ); } + if ( "57014".equals( sqlState ) ) { + // Operation cancelled by user + return new QueryTimeoutException( message, sqlException, sql ); + } + // returning null allows other delegates to operate return null; } @@ -637,7 +662,8 @@ public CallableStatementSupport getCallableStatementSupport() { @Override public ResultSet getResultSet(CallableStatement statement, int position) throws SQLException { if ( position != 1 ) { - throw new UnsupportedOperationException( "PostgreSQL only supports REF_CURSOR parameters as the first parameter" ); + throw new UnsupportedOperationException( + "PostgreSQL only supports REF_CURSOR parameters as the first parameter" ); } return (ResultSet) statement.getObject( 1 ); } diff --git a/hibernate-core/src/test/java/org/hibernate/dialect/PostgreSQL81DialectTestCase.java b/hibernate-core/src/test/java/org/hibernate/dialect/PostgreSQL81DialectTestCase.java index 401578a1b58b..6b617b092afb 100644 --- a/hibernate-core/src/test/java/org/hibernate/dialect/PostgreSQL81DialectTestCase.java +++ b/hibernate-core/src/test/java/org/hibernate/dialect/PostgreSQL81DialectTestCase.java @@ -14,6 +14,7 @@ import org.hibernate.LockMode; import org.hibernate.LockOptions; import org.hibernate.PessimisticLockException; +import org.hibernate.QueryTimeoutException; import org.hibernate.exception.LockAcquisitionException; import org.hibernate.exception.spi.SQLExceptionConversionDelegate; @@ -57,6 +58,17 @@ public void testTimeoutException() { assertTrue(exception instanceof PessimisticLockException); } + @Test + @TestForIssue( jiraKey = "HHH-13661") + public void testQueryTimeoutException() { + final PostgreSQL81Dialect dialect = new PostgreSQL81Dialect(); + final SQLExceptionConversionDelegate delegate = dialect.buildSQLExceptionConversionDelegate(); + assertNotNull( delegate ); + + final JDBCException exception = delegate.convert( new SQLException("Client cancelled operation", "57014"), "", "" ); + assertTrue( exception instanceof QueryTimeoutException ); + } + /** * Tests that getForUpdateString(String aliases, LockOptions lockOptions) will return a String * that will effect the SELECT ... FOR UPDATE OF tableAlias1, ..., tableAliasN @@ -98,4 +110,5 @@ public void testMessageException() throws SQLException { assertEquals( "PostgreSQL only supports accessing REF_CURSOR parameters by position", e.getMessage() ); } } + } From d17861d928973ad8302391938e0987ea8a5d6673 Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Mon, 30 Aug 2021 18:16:40 -0700 Subject: [PATCH 315/644] HHH-14794 : More changes to support SchemaMigrator/SchemaValidator using Hibernate Reactive Changes required by SQL Server --- .../org/hibernate/dialect/SQLServer2012Dialect.java | 13 ++++++++++++- .../org/hibernate/dialect/SQLServerDialect.java | 9 +++++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServer2012Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServer2012Dialect.java index 6cfb6bed5175..e5a32322a24a 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServer2012Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServer2012Dialect.java @@ -49,7 +49,18 @@ public String getSequenceNextValString(String sequenceName) { @Override public String getQuerySequencesString() { // The upper-case name is necessary here so that both case-sensitive and case-insensitive collations work - return "select * from INFORMATION_SCHEMA.SEQUENCES"; + + // Internally, SQL server stores start_value, minimum_value, maximum_value, and increment + // in sql_variant columns. SQL Server's JDBC automatically converts these values + // to bigint. Vert.X does support sql_variant columns, so these columns need to be + // explicitly converted here. + + return "select sequence_name, sequence_catalog, sequence_schema, " + + "convert( bigint, start_value ) as start_value, " + + "convert( bigint, minimum_value ) as minimum_value, " + + "convert( bigint, maximum_value ) as maximum_value, " + + "convert( bigint, increment ) as increment " + + "from INFORMATION_SCHEMA.SEQUENCES"; } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java index 96bf1aa0a0a3..0a7f86461f06 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServerDialect.java @@ -24,6 +24,7 @@ import org.hibernate.engine.jdbc.env.spi.IdentifierCaseStrategy; import org.hibernate.engine.jdbc.env.spi.IdentifierHelper; import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder; +import org.hibernate.engine.jdbc.env.spi.NameQualifierSupport; import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.StringType; import org.hibernate.type.Type; @@ -117,6 +118,8 @@ public IdentifierHelper buildIdentifierHelper( IdentifierHelperBuilder builder, DatabaseMetaData dbMetaData) throws SQLException { if ( dbMetaData == null ) { + // TODO: if DatabaseMetaData != null, unquoted case strategy is set to IdentifierCaseStrategy.UPPER + // Check to see if this setting is correct. builder.setUnquotedCaseStrategy( IdentifierCaseStrategy.MIXED ); builder.setQuotedCaseStrategy( IdentifierCaseStrategy.MIXED ); } @@ -248,4 +251,10 @@ public String getCreateTemporaryTableColumnAnnotation(int sqlTypeCode) { return ""; } } + + @Override + public NameQualifierSupport getNameQualifierSupport() { + return NameQualifierSupport.BOTH; + } + } From e0286ba4b4a1a34c37292ff9d61ec546245e351f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Fri, 17 Sep 2021 15:20:44 +0200 Subject: [PATCH 316/644] HHH-14828 Test bytecode enhancement on entities/embeddables with a final field --- .../basic/FinalFieldEnhancementTest.java | 297 ++++++++++++++++++ 1 file changed, 297 insertions(+) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/basic/FinalFieldEnhancementTest.java diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/basic/FinalFieldEnhancementTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/basic/FinalFieldEnhancementTest.java new file mode 100644 index 000000000000..2bb38af83917 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/basic/FinalFieldEnhancementTest.java @@ -0,0 +1,297 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.bytecode.enhancement.basic; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.Serializable; +import java.util.Objects; +import java.util.UUID; +import javax.persistence.Embeddable; +import javax.persistence.Embedded; +import javax.persistence.EmbeddedId; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +import org.hibernate.annotations.Immutable; + +import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.Test; +import org.junit.runner.RunWith; + +@RunWith(BytecodeEnhancerRunner.class) +public class FinalFieldEnhancementTest extends BaseCoreFunctionalTestCase { + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + EntityWithFinalField.class, + EntityWithEmbeddedIdWithFinalField.class, EntityWithEmbeddedIdWithFinalField.EmbeddableId.class, + EntityWithEmbeddedNonIdWithFinalField.class, EntityWithEmbeddedNonIdWithFinalField.EmbeddableNonId.class + }; + } + + @Test + public void entityWithFinalField_constructor() { + EntityWithFinalField entity = new EntityWithFinalField( "foo" ); + assertThat( entity.immutableProperty ).isEqualTo( "foo" ); + } + + // Just test that the embedded non-ID works correctly over a persist/retrieve cycle + @Test + public void entityWithFinalField_smokeTest() { + EntityWithFinalField persistedEntity = new EntityWithFinalField( "foo" ); + persistedEntity.setName( "Some name" ); + inTransaction( s -> { + s.persist( persistedEntity ); + } ); + + inTransaction( s -> { + EntityWithFinalField entity = s.find( EntityWithFinalField.class, persistedEntity.getId() ); + assertThat( entity ).extracting( EntityWithFinalField::getImmutableProperty ) + .isEqualTo( persistedEntity.getImmutableProperty() ); + } ); + } + + // Just test that the embedded ID works correctly over a persist/retrieve cycle + @Test + public void embeddableIdWithFinalField_smokeTest() { + EntityWithEmbeddedIdWithFinalField persistedEntity = new EntityWithEmbeddedIdWithFinalField(); + persistedEntity.setName( "Some name" ); + inTransaction( s -> { + s.persist( persistedEntity ); + } ); + + // Read with the same ID instance + inTransaction( s -> { + EntityWithEmbeddedIdWithFinalField entity = s.find( EntityWithEmbeddedIdWithFinalField.class, persistedEntity.getId() ); + assertThat( entity ).extracting( EntityWithEmbeddedIdWithFinalField::getId ).extracting( i -> i.id ) + .isEqualTo( persistedEntity.getId().id ); + } ); + + // Read with a new ID instance + inTransaction( s -> { + EntityWithEmbeddedIdWithFinalField entity = s.find( EntityWithEmbeddedIdWithFinalField.class, EntityWithEmbeddedIdWithFinalField.EmbeddableId.of( persistedEntity.getId().id ) ); + assertThat( entity ).extracting( EntityWithEmbeddedIdWithFinalField::getId ).extracting( i -> i.id ) + .isEqualTo( persistedEntity.getId().id ); + } ); + + // Read with a query + // This is special because in this particular test, + // we know Hibernate ORM *has to* instantiate the EmbeddableIdType itself: + // it cannot reuse the ID we passed. + // And since the EmbeddableIdType has a final field, instantiation will not be able to use a no-arg constructor... + inTransaction( s -> { + EntityWithEmbeddedIdWithFinalField entity = + s.createQuery( "from embidwithfinal e where e.name = :name", EntityWithEmbeddedIdWithFinalField.class ) + .setParameter( "name", persistedEntity.getName() ) + .uniqueResult(); + assertThat( entity ).extracting( EntityWithEmbeddedIdWithFinalField::getId ).extracting( i -> i.id ) + .isEqualTo( persistedEntity.getId().id ); + } ); + } + + @Test + public void embeddableNonIdWithFinalField_constructor() { + EntityWithEmbeddedNonIdWithFinalField.EmbeddableNonId embeddable = + new EntityWithEmbeddedNonIdWithFinalField.EmbeddableNonId( "foo" ); + assertThat( embeddable.immutableProperty ).isEqualTo( "foo" ); + } + + // Just test that the embedded non-ID works correctly over a persist/retrieve cycle + @Test + public void embeddableNonIdWithFinalField_smokeTest() { + EntityWithEmbeddedNonIdWithFinalField persistedEntity = new EntityWithEmbeddedNonIdWithFinalField(); + persistedEntity.setName( "Some name" ); + persistedEntity.setEmbedded( new EntityWithEmbeddedNonIdWithFinalField.EmbeddableNonId( "foo" ) ); + inTransaction( s -> { + s.persist( persistedEntity ); + } ); + + inTransaction( s -> { + EntityWithEmbeddedNonIdWithFinalField entity = s.find( EntityWithEmbeddedNonIdWithFinalField.class, persistedEntity.getId() ); + assertThat( entity ).extracting( EntityWithEmbeddedNonIdWithFinalField::getEmbedded ) + .extracting( EntityWithEmbeddedNonIdWithFinalField.EmbeddableNonId::getImmutableProperty ) + .isEqualTo( persistedEntity.getEmbedded().getImmutableProperty() ); + } ); + } + + @Entity(name = "withfinal") + public static class EntityWithFinalField { + + @Id + @GeneratedValue + private Long id; + + private final String immutableProperty; + + private String name; + + // For Hibernate ORM + protected EntityWithFinalField() { + this.immutableProperty = null; + } + + private EntityWithFinalField(String id) { + this.immutableProperty = id; + } + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getImmutableProperty() { + return immutableProperty; + } + } + + @Entity(name = "embidwithfinal") + public static class EntityWithEmbeddedIdWithFinalField { + + @EmbeddedId + private EmbeddableId id; + + private String name; + + public EntityWithEmbeddedIdWithFinalField() { + this.id = EmbeddableId.of( UUID.randomUUID().toString() ); + } + + public EmbeddableId getId() { + return id; + } + + public void setId(EmbeddableId id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + @Immutable + @Embeddable + public static class EmbeddableId implements Serializable { + private final String id; + + // For Hibernate ORM + protected EmbeddableId() { + this.id = null; + } + + private EmbeddableId(String id) { + this.id = id; + } + + public static EmbeddableId of(String string) { + return new EmbeddableId( string ); + } + + @Override + public boolean equals(Object o) { + if ( this == o ) { + return true; + } + if ( !( o instanceof EmbeddableId ) ) { + return false; + } + EmbeddableId embeddableIdType = (EmbeddableId) o; + return Objects.equals( id, embeddableIdType.id ); + } + + @Override + public int hashCode() { + return Objects.hash( id ); + } + } + } + + @Entity(name = "embwithfinal") + public static class EntityWithEmbeddedNonIdWithFinalField { + + @Id + @GeneratedValue + private Long id; + + private String name; + + @Embedded + private EmbeddableNonId embedded; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public EmbeddableNonId getEmbedded() { + return embedded; + } + + public void setEmbedded( + EmbeddableNonId embedded) { + this.embedded = embedded; + } + + @Embeddable + public static class EmbeddableNonId { + private final String immutableProperty; + + private String mutableProperty; + + protected EmbeddableNonId() { + // For Hibernate ORM only - it will change the property value through reflection + this.immutableProperty = null; + } + + private EmbeddableNonId(String immutableProperty) { + this.immutableProperty = immutableProperty; + } + + public String getImmutableProperty() { + return immutableProperty; + } + + public String getMutableProperty() { + return mutableProperty; + } + + public void setMutableProperty(String mutableProperty) { + this.mutableProperty = mutableProperty; + } + } + } + +} From 1d3f9183e6422c9535c4c3612a932c9dd37fc7bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Fri, 17 Sep 2021 16:47:49 +0200 Subject: [PATCH 317/644] HHH-14828 Fix incorrect logging in FieldAccessEnhancer --- .../enhance/internal/bytebuddy/FieldAccessEnhancer.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/FieldAccessEnhancer.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/FieldAccessEnhancer.java index d990f913ad7a..14e7f02e694b 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/FieldAccessEnhancer.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/FieldAccessEnhancer.java @@ -77,11 +77,11 @@ public void visitFieldInsn(int opcode, String owner, String name, String desc) { && !field.getName().equals( "this$0" ) ) { log.debugf( - "Extended enhancement: Transforming access to field [%s.%s] from method [%s#%s]", - field.getType().asErasure(), + "Extended enhancement: Transforming access to field [%s#%s] from method [%s#%s()]", + declaredOwnerType.getName(), field.getName(), - field.getName(), - name + instrumentedType.getName(), + instrumentedMethod.getName() ); switch ( opcode ) { From 0b80bb73c9ecf4d18b99547937f8fcc86d48a548 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Fri, 17 Sep 2021 16:48:23 +0200 Subject: [PATCH 318/644] HHH-14828 Enable bytecode enhancement logging in core tests --- hibernate-core/src/test/resources/log4j2.properties | 3 +++ 1 file changed, 3 insertions(+) diff --git a/hibernate-core/src/test/resources/log4j2.properties b/hibernate-core/src/test/resources/log4j2.properties index f21f8c8748fc..72fc9823d4a6 100644 --- a/hibernate-core/src/test/resources/log4j2.properties +++ b/hibernate-core/src/test/resources/log4j2.properties @@ -63,6 +63,9 @@ logger.model-binder.level=debug logger.java-type-descriptor-registry.name=org.hibernate.type.descriptor.java.JavaTypeDescriptorRegistry logger.java-type-descriptor-registry.level=debug +logger.bytecode-enhancement.name=org.hibernate.bytecode.enhance +logger.bytecode-enhancement.level=debug + logger.entity-action.name=org.hibernate.action.internal.EntityAction #logger.entity-action.level=debug logger.cascade.name=org.hibernate.engine.internal.Cascade From d35b592762fe2b1ff93e5362598acba586fa801b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Fri, 17 Sep 2021 17:35:19 +0200 Subject: [PATCH 319/644] HHH-14828 Do not enhance final field write access --- .../bytebuddy/FieldAccessEnhancer.java | 9 +++-- .../PersistentAttributeTransformer.java | 39 ++++++++++++------- 2 files changed, 30 insertions(+), 18 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/FieldAccessEnhancer.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/FieldAccessEnhancer.java index 14e7f02e694b..7bb0f27e9bf3 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/FieldAccessEnhancer.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/FieldAccessEnhancer.java @@ -95,6 +95,11 @@ public void visitFieldInsn(int opcode, String owner, String name, String desc) { ); return; case Opcodes.PUTFIELD: + if ( field.getFieldDescription().isFinal() ) { + // Final fields will only be written to from the constructor, + // so there's no point trying to replace final field writes with a method call. + break; + } methodVisitor.visitMethodInsn( Opcodes.INVOKEVIRTUAL, owner, @@ -107,9 +112,7 @@ public void visitFieldInsn(int opcode, String owner, String name, String desc) { throw new EnhancementException( "Unexpected opcode: " + opcode ); } } - else { - super.visitFieldInsn( opcode, owner, name, desc ); - } + super.visitFieldInsn( opcode, owner, name, desc ); } }; } diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/PersistentAttributeTransformer.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/PersistentAttributeTransformer.java index 1e106de35f90..02eb26f25b8c 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/PersistentAttributeTransformer.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/PersistentAttributeTransformer.java @@ -15,10 +15,8 @@ import java.util.Collections; import java.util.List; import java.util.Objects; - import javax.persistence.Embedded; -import net.bytebuddy.utility.OpenedClassReader; import org.hibernate.bytecode.enhance.internal.bytebuddy.EnhancerImpl.AnnotatedFieldDescription; import org.hibernate.bytecode.enhance.spi.EnhancerConstants; import org.hibernate.engine.spi.CompositeOwner; @@ -42,6 +40,7 @@ import net.bytebuddy.jar.asm.Type; import net.bytebuddy.matcher.ElementMatcher.Junction; import net.bytebuddy.pool.TypePool; +import net.bytebuddy.utility.OpenedClassReader; final class PersistentAttributeTransformer implements AsmVisitorWrapper.ForDeclaredMethods.MethodVisitorWrapper { @@ -138,7 +137,8 @@ public MethodVisitor wrap( return new MethodVisitor( OpenedClassReader.ASM_API, methodVisitor ) { @Override public void visitFieldInsn(int opcode, String owner, String name, String desc) { - if ( isEnhanced( owner, name, desc ) ) { + AnnotatedFieldDescription enhancedField = getEnhancedField( owner, name, desc ); + if ( enhancedField != null ) { switch ( opcode ) { case Opcodes.GETFIELD: methodVisitor.visitMethodInsn( @@ -150,6 +150,11 @@ public void visitFieldInsn(int opcode, String owner, String name, String desc) { ); return; case Opcodes.PUTFIELD: + if ( enhancedField.getFieldDescription().isFinal() ) { + // Final fields will only be written to from the constructor, + // so there's no point trying to replace final field writes with a method call. + break; + } methodVisitor.visitMethodInsn( Opcodes.INVOKEVIRTUAL, owner, @@ -165,15 +170,15 @@ public void visitFieldInsn(int opcode, String owner, String name, String desc) { }; } - private boolean isEnhanced(String owner, String name, String desc) { + private AnnotatedFieldDescription getEnhancedField(String owner, String name, String desc) { for ( AnnotatedFieldDescription enhancedField : enhancedFields ) { if ( enhancedField.getName().equals( name ) && enhancedField.getDescriptor().equals( desc ) && enhancedField.getDeclaringType().asErasure().getInternalName().equals( owner ) ) { - return true; + return enhancedField; } } - return false; + return null; } DynamicType.Builder applyTo(DynamicType.Builder builder) { @@ -187,15 +192,19 @@ DynamicType.Builder applyTo(DynamicType.Builder builder) { enhancedField.getType().asErasure(), Visibility.PUBLIC ) - .intercept( fieldReader( enhancedField ) - ) - .defineMethod( - EnhancerConstants.PERSISTENT_FIELD_WRITER_PREFIX + enhancedField.getName(), - TypeDescription.VOID, - Visibility.PUBLIC - ) - .withParameters( enhancedField.getType().asErasure() ) - .intercept( fieldWriter( enhancedField ) ); + .intercept( fieldReader( enhancedField ) ); + // Final fields will only be written to from the constructor, + // so there's no point trying to replace final field writes with a method call. + if ( !enhancedField.getFieldDescription().isFinal() ) { + builder = builder + .defineMethod( + EnhancerConstants.PERSISTENT_FIELD_WRITER_PREFIX + enhancedField.getName(), + TypeDescription.VOID, + Visibility.PUBLIC + ) + .withParameters( enhancedField.getType().asErasure() ) + .intercept( fieldWriter( enhancedField ) ); + } if ( !compositeOwner && !enhancementContext.isMappedSuperclassClass( managedCtClass ) From 5e542b16cb22acac3a3f6357d49f413ad16270e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Mon, 20 Sep 2021 16:47:32 +0200 Subject: [PATCH 320/644] HHH-14828 Remove final modifier from enhanced fields We need to remove the final modifier if we want to address the possibility of that field being lazy. --- .../PersistentAttributeTransformer.java | 29 +++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/PersistentAttributeTransformer.java b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/PersistentAttributeTransformer.java index 02eb26f25b8c..287ce6b793e4 100644 --- a/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/PersistentAttributeTransformer.java +++ b/hibernate-core/src/main/java/org/hibernate/bytecode/enhance/internal/bytebuddy/PersistentAttributeTransformer.java @@ -6,6 +6,7 @@ */ package org.hibernate.bytecode.enhance.internal.bytebuddy; +import static net.bytebuddy.matcher.ElementMatchers.anyOf; import static net.bytebuddy.matcher.ElementMatchers.nameStartsWith; import static net.bytebuddy.matcher.ElementMatchers.not; @@ -25,8 +26,10 @@ import net.bytebuddy.asm.Advice; import net.bytebuddy.asm.AsmVisitorWrapper; +import net.bytebuddy.asm.ModifierAdjustment; import net.bytebuddy.description.field.FieldDescription; import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.description.modifier.ModifierContributor; import net.bytebuddy.description.modifier.Visibility; import net.bytebuddy.description.type.TypeDefinition; import net.bytebuddy.description.type.TypeDescription; @@ -47,6 +50,22 @@ final class PersistentAttributeTransformer implements AsmVisitorWrapper.ForDecla private static final CoreMessageLogger log = CoreLogging.messageLogger( PersistentAttributeTransformer.class ); private static final Junction NOT_HIBERNATE_GENERATED = not( nameStartsWith( "$$_hibernate_" ) ); + private static final ModifierContributor.ForField REMOVE_FINAL_MODIFIER = new ModifierContributor.ForField() { + @Override + public int getMask() { + return EMPTY_MASK; // Do not add any modifier + } + + @Override + public int getRange() { + return Opcodes.ACC_FINAL; // Remove the "final" modifier + } + + @Override + public boolean isDefault() { + return false; + } + }; private final TypeDescription managedCtClass; @@ -185,6 +204,16 @@ DynamicType.Builder applyTo(DynamicType.Builder builder) { boolean compositeOwner = false; builder = builder.visit( new AsmVisitorWrapper.ForDeclaredMethods().invokable( NOT_HIBERNATE_GENERATED, this ) ); + // Remove the final modifier from all enhanced fields, because: + // 1. We sometimes need to write to final fields when they are lazy. + // 2. Those fields are already written to by Hibernate ORM through reflection anyway. + // 3. The compiler already makes sure that final fields are not written to from the user's source code. + List enhancedFieldsAsDefined = new ArrayList<>(); + for ( AnnotatedFieldDescription f : enhancedFields ) { + enhancedFieldsAsDefined.add( f.asDefined() ); + } + builder = builder.visit( new ModifierAdjustment().withFieldModifiers( anyOf( enhancedFieldsAsDefined ), + REMOVE_FINAL_MODIFIER ) ); for ( AnnotatedFieldDescription enhancedField : enhancedFields ) { builder = builder .defineMethod( From b15433a49c3a443023bf75098c174e890d64bb27 Mon Sep 17 00:00:00 2001 From: Amit Mendapara Date: Fri, 17 Sep 2021 15:31:45 +0530 Subject: [PATCH 321/644] HHH-14826 Add test to check regression caused by OneToOne cache support --- .../onetoone/cache/OneToOneCacheTest.java | 132 ++++++++++++++++++ 1 file changed, 132 insertions(+) diff --git a/hibernate-core/src/test/java/org/hibernate/test/onetoone/cache/OneToOneCacheTest.java b/hibernate-core/src/test/java/org/hibernate/test/onetoone/cache/OneToOneCacheTest.java index d14e6c56a442..153f380da20c 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/onetoone/cache/OneToOneCacheTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/onetoone/cache/OneToOneCacheTest.java @@ -1,11 +1,15 @@ package org.hibernate.test.onetoone.cache; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; import java.io.Serializable; import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.List; +import java.util.concurrent.atomic.AtomicLong; import org.hibernate.Session; import org.hibernate.Transaction; @@ -17,6 +21,8 @@ import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; import org.junit.Test; +import javax.persistence.*; + public class OneToOneCacheTest extends BaseCoreFunctionalTestCase { @Override public String[] getMappings() { @@ -26,9 +32,18 @@ public String[] getMappings() { }; } + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + Product.class, + ProductConfig.class + }; + } + @Override protected void configure(Configuration configuration) { configuration.setProperty(AvailableSettings.USE_SECOND_LEVEL_CACHE, "true"); + configuration.setProperty(AvailableSettings.JPA_SHARED_CACHE_MODE, "ENABLE_SELECTIVE"); configuration.setProperty(AvailableSettings.GENERATE_STATISTICS, "true"); } @@ -117,4 +132,121 @@ public void OneToOneCacheByForeignKey() throws Exception { public void OneToOneCacheByRef() throws Exception { OneToOneTest(PersonByRef.class, DetailsByRef.class); } + + @Test + public void testFieldShouldNotBeNull2() { + final AtomicLong pid = new AtomicLong(); + + // create Product + inTransaction(s -> { + Product product = new Product(); + s.persist(product); + pid.set(product.getId()); + }); + + // create ProductConfig and associate with a Product + inTransaction(s -> { + Product product = s.find(Product.class, pid.get()); + ProductConfig config = new ProductConfig(); + config.setProduct(product); + s.persist(config); + }); + + assertTrue(sessionFactory().getCache().containsEntity(Product.class, pid.get())); + + sessionFactory().getStatistics().clear(); + + // now fetch the Product again + inTransaction(s -> { + Product product = s.find(Product.class, pid.get()); + + // should have been from cache + assertNotEquals (0, sessionFactory().getStatistics().getSecondLevelCacheHitCount()); + + // this should not fail + assertNotNull("one-to-one field should not be null", product.getConfig()); + }); + } + + @Entity(name = "Product") + @Cacheable + public static class Product { + + @Id + @GeneratedValue + private Long id; + + @Version + private Integer version; + + @OneToOne(mappedBy = "product", fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST, CascadeType.MERGE }) + private ProductConfig config; + + public Product() {} + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Integer getVersion() { + return version; + } + + public void setVersion(Integer version) { + this.version = version; + } + + public ProductConfig getConfig() { + return config; + } + + public void setConfig(ProductConfig config) { + this.config = config; + } + } + + @Entity(name = "ProductConfig") + @Cacheable + public static class ProductConfig { + + @Id + @GeneratedValue + private Long id; + + @Version + private Integer version; + + @OneToOne(fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST, CascadeType.MERGE }) + private Product product; + + public ProductConfig() {} + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Integer getVersion() { + return version; + } + + public void setVersion(Integer version) { + this.version = version; + } + + public Product getProduct() { + return product; + } + + public void setProduct(Product product) { + this.product = product; + } + } } From a652822ff5f5d8d533acb9b7fb6eea867fc4e456 Mon Sep 17 00:00:00 2001 From: Amit Mendapara Date: Fri, 17 Sep 2021 15:32:50 +0530 Subject: [PATCH 322/644] HHH-14826 Fix regression caused by one-to-one L2 cache support --- .../src/main/java/org/hibernate/type/OneToOneType.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hibernate-core/src/main/java/org/hibernate/type/OneToOneType.java b/hibernate-core/src/main/java/org/hibernate/type/OneToOneType.java index 07311e32bf10..120a3a040d34 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/OneToOneType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/OneToOneType.java @@ -219,7 +219,7 @@ public Object assemble(Serializable oid, SharedSessionContractImplementor sessio Serializable id = ( Serializable ) getIdentifierType( session ).assemble( oid, session, null ); if ( id == null ) { - return null; + return resolve( session.getContextEntityIdentifier(owner), session, owner ); } return resolveIdentifier( id, session ); From 340b9012d93d94d8becc21cc71fd99554f283705 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Fri, 17 Sep 2021 13:07:04 +0200 Subject: [PATCH 323/644] HHH-14826 Extract issue specific tests from OneToOneCacheTest --- .../OneToOneCacheEnableSelectingTest.java | 158 ++++++++++++++++++ .../onetoone/cache/OneToOneCacheTest.java | 132 --------------- 2 files changed, 158 insertions(+), 132 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/onetoone/cache/OneToOneCacheEnableSelectingTest.java diff --git a/hibernate-core/src/test/java/org/hibernate/test/onetoone/cache/OneToOneCacheEnableSelectingTest.java b/hibernate-core/src/test/java/org/hibernate/test/onetoone/cache/OneToOneCacheEnableSelectingTest.java new file mode 100644 index 000000000000..35b0aa031efe --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/onetoone/cache/OneToOneCacheEnableSelectingTest.java @@ -0,0 +1,158 @@ +package org.hibernate.test.onetoone.cache; + +import java.util.concurrent.atomic.AtomicLong; +import javax.persistence.Cacheable; +import javax.persistence.CascadeType; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.OneToOne; +import javax.persistence.Version; + +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.cfg.Configuration; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.Test; + +import static org.junit.Assert.assertNotEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +@TestForIssue( jiraKey = "HHH-14826") +public class OneToOneCacheEnableSelectingTest extends BaseCoreFunctionalTestCase { + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + Product.class, + ProductConfig.class + }; + } + + @Override + protected void configure(Configuration configuration) { + configuration.setProperty( AvailableSettings.USE_SECOND_LEVEL_CACHE, "true"); + configuration.setProperty(AvailableSettings.JPA_SHARED_CACHE_MODE, "ENABLE_SELECTIVE"); + configuration.setProperty(AvailableSettings.GENERATE_STATISTICS, "true"); + } + + @Test + public void testFieldShouldNotBeNull() { + final AtomicLong pid = new AtomicLong(); + + // create Product + inTransaction(s -> { + Product product = new Product(); + s.persist(product); + pid.set(product.getId()); + }); + + // create ProductConfig and associate with a Product + inTransaction(s -> { + Product product = s.find(Product.class, pid.get()); + ProductConfig config = new ProductConfig(); + config.setProduct(product); + s.persist(config); + }); + + assertTrue(sessionFactory().getCache().containsEntity(Product.class, pid.get())); + + sessionFactory().getStatistics().clear(); + + // now fetch the Product again + inTransaction(s -> { + Product product = s.find(Product.class, pid.get()); + + // should have been from cache + assertNotEquals (0, sessionFactory().getStatistics().getSecondLevelCacheHitCount()); + + // this should not fail + assertNotNull("one-to-one field should not be null", product.getConfig()); + }); + } + + @Entity(name = "Product") + @Cacheable + public static class Product { + + @Id + @GeneratedValue + private Long id; + + @Version + private Integer version; + + @OneToOne(mappedBy = "product", fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST, CascadeType.MERGE }) + private ProductConfig config; + + public Product() {} + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Integer getVersion() { + return version; + } + + public void setVersion(Integer version) { + this.version = version; + } + + public ProductConfig getConfig() { + return config; + } + + public void setConfig(ProductConfig config) { + this.config = config; + } + } + + @Entity(name = "ProductConfig") + @Cacheable + public static class ProductConfig { + + @Id + @GeneratedValue + private Long id; + + @Version + private Integer version; + + @OneToOne(fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST, CascadeType.MERGE }) + private Product product; + + public ProductConfig() {} + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Integer getVersion() { + return version; + } + + public void setVersion(Integer version) { + this.version = version; + } + + public Product getProduct() { + return product; + } + + public void setProduct(Product product) { + this.product = product; + } + } + +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/onetoone/cache/OneToOneCacheTest.java b/hibernate-core/src/test/java/org/hibernate/test/onetoone/cache/OneToOneCacheTest.java index 153f380da20c..d14e6c56a442 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/onetoone/cache/OneToOneCacheTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/onetoone/cache/OneToOneCacheTest.java @@ -1,15 +1,11 @@ package org.hibernate.test.onetoone.cache; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.assertNotEquals; -import static org.junit.Assert.assertNotNull; import java.io.Serializable; import java.lang.reflect.Constructor; import java.util.ArrayList; import java.util.List; -import java.util.concurrent.atomic.AtomicLong; import org.hibernate.Session; import org.hibernate.Transaction; @@ -21,8 +17,6 @@ import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; import org.junit.Test; -import javax.persistence.*; - public class OneToOneCacheTest extends BaseCoreFunctionalTestCase { @Override public String[] getMappings() { @@ -32,18 +26,9 @@ public String[] getMappings() { }; } - @Override - protected Class[] getAnnotatedClasses() { - return new Class[] { - Product.class, - ProductConfig.class - }; - } - @Override protected void configure(Configuration configuration) { configuration.setProperty(AvailableSettings.USE_SECOND_LEVEL_CACHE, "true"); - configuration.setProperty(AvailableSettings.JPA_SHARED_CACHE_MODE, "ENABLE_SELECTIVE"); configuration.setProperty(AvailableSettings.GENERATE_STATISTICS, "true"); } @@ -132,121 +117,4 @@ public void OneToOneCacheByForeignKey() throws Exception { public void OneToOneCacheByRef() throws Exception { OneToOneTest(PersonByRef.class, DetailsByRef.class); } - - @Test - public void testFieldShouldNotBeNull2() { - final AtomicLong pid = new AtomicLong(); - - // create Product - inTransaction(s -> { - Product product = new Product(); - s.persist(product); - pid.set(product.getId()); - }); - - // create ProductConfig and associate with a Product - inTransaction(s -> { - Product product = s.find(Product.class, pid.get()); - ProductConfig config = new ProductConfig(); - config.setProduct(product); - s.persist(config); - }); - - assertTrue(sessionFactory().getCache().containsEntity(Product.class, pid.get())); - - sessionFactory().getStatistics().clear(); - - // now fetch the Product again - inTransaction(s -> { - Product product = s.find(Product.class, pid.get()); - - // should have been from cache - assertNotEquals (0, sessionFactory().getStatistics().getSecondLevelCacheHitCount()); - - // this should not fail - assertNotNull("one-to-one field should not be null", product.getConfig()); - }); - } - - @Entity(name = "Product") - @Cacheable - public static class Product { - - @Id - @GeneratedValue - private Long id; - - @Version - private Integer version; - - @OneToOne(mappedBy = "product", fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST, CascadeType.MERGE }) - private ProductConfig config; - - public Product() {} - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public Integer getVersion() { - return version; - } - - public void setVersion(Integer version) { - this.version = version; - } - - public ProductConfig getConfig() { - return config; - } - - public void setConfig(ProductConfig config) { - this.config = config; - } - } - - @Entity(name = "ProductConfig") - @Cacheable - public static class ProductConfig { - - @Id - @GeneratedValue - private Long id; - - @Version - private Integer version; - - @OneToOne(fetch = FetchType.LAZY, cascade = { CascadeType.PERSIST, CascadeType.MERGE }) - private Product product; - - public ProductConfig() {} - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public Integer getVersion() { - return version; - } - - public void setVersion(Integer version) { - this.version = version; - } - - public Product getProduct() { - return product; - } - - public void setProduct(Product product) { - this.product = product; - } - } } From 5ffed50f1fa5cfbbf09b8a1c111f6df73d1d8eca Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Fri, 17 Sep 2021 13:14:39 +0200 Subject: [PATCH 324/644] HHH-14826 Fix failure of o.h.test.onetoone.cache.OneToOneCacheTest#OneToOneCacheByForeignKey() --- .../src/main/java/org/hibernate/type/OneToOneType.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/hibernate-core/src/main/java/org/hibernate/type/OneToOneType.java b/hibernate-core/src/main/java/org/hibernate/type/OneToOneType.java index 120a3a040d34..29e5fe2e28c1 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/OneToOneType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/OneToOneType.java @@ -215,11 +215,19 @@ public Serializable disassemble(Object value, SharedSessionContractImplementor s @Override public Object assemble(Serializable oid, SharedSessionContractImplementor session, Object owner) throws HibernateException { + + if ( oid == null ) { + if ( uniqueKeyPropertyName != null ) { + return resolve( session.getContextEntityIdentifier( owner ), session, owner ); + } + return null; + } + //the owner of the association is not the owner of the id Serializable id = ( Serializable ) getIdentifierType( session ).assemble( oid, session, null ); if ( id == null ) { - return resolve( session.getContextEntityIdentifier(owner), session, owner ); + return null; } return resolveIdentifier( id, session ); From 99f027166d285cc48a33eb87f48530040f3def8a Mon Sep 17 00:00:00 2001 From: Yanming Zhou Date: Fri, 23 Oct 2020 15:08:36 +0800 Subject: [PATCH 325/644] HHH-4369 Introduce @Comment for comment on column --- .../org/hibernate/annotations/Comment.java | 28 +++++++ .../org/hibernate/cfg/AnnotationBinder.java | 6 ++ .../java/org/hibernate/cfg/BinderHelper.java | 1 + .../org/hibernate/cfg/ColumnsBuilder.java | 8 ++ .../java/org/hibernate/cfg/Ejb3Column.java | 26 +++++++ .../org/hibernate/cfg/Ejb3JoinColumn.java | 15 +++- .../cfg/annotations/IdBagBinder.java | 1 + .../test/annotations/comment/CommentTest.java | 76 +++++++++++++++++++ 8 files changed, 159 insertions(+), 2 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/annotations/Comment.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/annotations/comment/CommentTest.java diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/Comment.java b/hibernate-core/src/main/java/org/hibernate/annotations/Comment.java new file mode 100644 index 000000000000..b1910cb7bb6d --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/annotations/Comment.java @@ -0,0 +1,28 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.annotations; + +import java.lang.annotation.Retention; +import java.lang.annotation.Target; + +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; + +/** + * SQL column comment which can be defined at property level. + * + * @author Yanming Zhou + */ +@Target({METHOD, FIELD}) +@Retention(RUNTIME) +public @interface Comment { + /** + * The comment string. + */ + String value(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java b/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java index 344b1e234c62..d519f164c761 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java @@ -83,6 +83,7 @@ import org.hibernate.annotations.Check; import org.hibernate.annotations.CollectionId; import org.hibernate.annotations.Columns; +import org.hibernate.annotations.Comment; import org.hibernate.annotations.DiscriminatorFormula; import org.hibernate.annotations.DiscriminatorOptions; import org.hibernate.annotations.Fetch; @@ -1998,6 +1999,7 @@ else if ( property.isAnnotationPresent( OneToMany.class ) elementColumns = Ejb3Column.buildColumnFromAnnotation( new Column[] { ann }, formulaAnn, + property.getAnnotation( Comment.class ), nullability, propertyHolder, virtualProperty, @@ -2010,6 +2012,7 @@ else if ( property.isAnnotationPresent( Columns.class ) ) { elementColumns = Ejb3Column.buildColumnFromAnnotation( anns.columns(), null, + property.getAnnotation( Comment.class ), nullability, propertyHolder, virtualProperty, @@ -2021,6 +2024,7 @@ else if ( property.isAnnotationPresent( Columns.class ) ) { elementColumns = Ejb3Column.buildColumnFromAnnotation( null, null, + property.getAnnotation( Comment.class ), nullability, propertyHolder, virtualProperty, @@ -2050,6 +2054,7 @@ else if ( property.isAnnotationPresent( Columns.class ) ) { Ejb3Column[] mapColumns = Ejb3Column.buildColumnFromAnnotation( keyColumns, null, + property.getAnnotation( Comment.class ), Nullability.FORCED_NOT_NULL, propertyHolder, isJPA2 ? inferredData : mapKeyVirtualProperty, @@ -2098,6 +2103,7 @@ else if ( property.isAnnotationPresent( MapKeyJoinColumn.class ) ) { PropertyData mapKeyVirtualProperty = new WrappedInferredData( inferredData, "mapkey" ); Ejb3JoinColumn[] mapJoinColumns = Ejb3JoinColumn.buildJoinColumnsWithDefaultColumnSuffix( joinKeyColumns, + property.getAnnotation( Comment.class ), null, entityBinder.getSecondaryTables(), propertyHolder, diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/BinderHelper.java b/hibernate-core/src/main/java/org/hibernate/cfg/BinderHelper.java index 93a08a145f24..a7f61dc18ce7 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/BinderHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/BinderHelper.java @@ -998,6 +998,7 @@ public static Any buildAnyValue( Ejb3Column[] metaColumns = Ejb3Column.buildColumnFromAnnotation( new javax.persistence.Column[] { metaColumn }, null, + null, nullability, propertyHolder, inferredData, diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/ColumnsBuilder.java b/hibernate-core/src/main/java/org/hibernate/cfg/ColumnsBuilder.java index 9482f4282641..0feb7cf643b0 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/ColumnsBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/ColumnsBuilder.java @@ -17,6 +17,7 @@ import org.hibernate.AnnotationException; import org.hibernate.annotations.Columns; +import org.hibernate.annotations.Comment; import org.hibernate.annotations.Formula; import org.hibernate.annotations.JoinColumnOrFormula; import org.hibernate.annotations.JoinColumnsOrFormulas; @@ -78,6 +79,7 @@ public ColumnsBuilder extractMetadata() { columns = Ejb3Column.buildColumnFromAnnotation( new Column[] { ann }, formulaAnn, + property.getAnnotation( Comment.class ), nullability, propertyHolder, inferredData, @@ -90,6 +92,7 @@ else if ( property.isAnnotationPresent( Columns.class ) ) { columns = Ejb3Column.buildColumnFromAnnotation( anns.columns(), null, + property.getAnnotation( Comment.class ), nullability, propertyHolder, inferredData, @@ -115,6 +118,7 @@ else if ( joinColumns == null && ""; joinColumns = Ejb3JoinColumn.buildJoinColumns( null, + property.getAnnotation( Comment.class ), mappedBy, entityBinder.getSecondaryTables(), propertyHolder, @@ -131,6 +135,7 @@ else if ( joinColumns == null && property.isAnnotationPresent( org.hibernate.ann columns = Ejb3Column.buildColumnFromAnnotation( null, null, + property.getAnnotation( Comment.class ), nullability, propertyHolder, inferredData, @@ -154,6 +159,7 @@ Ejb3JoinColumn[] buildDefaultJoinColumnsForXToOne(XProperty property, PropertyDa if ( joinTableAnn != null ) { joinColumns = Ejb3JoinColumn.buildJoinColumns( joinTableAnn.inverseJoinColumns(), + property.getAnnotation( Comment.class ), null, entityBinder.getSecondaryTables(), propertyHolder, @@ -174,6 +180,7 @@ Ejb3JoinColumn[] buildDefaultJoinColumnsForXToOne(XProperty property, PropertyDa : null; joinColumns = Ejb3JoinColumn.buildJoinColumns( null, + property.getAnnotation( Comment.class ), mappedBy, entityBinder.getSecondaryTables(), propertyHolder, @@ -203,6 +210,7 @@ else if ( property.isAnnotationPresent( JoinColumns.class ) ) { if ( joinColumnAnnotations != null ) { return Ejb3JoinColumn.buildJoinColumns( joinColumnAnnotations, + property.getAnnotation( Comment.class ), null, entityBinder.getSecondaryTables(), propertyHolder, diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/Ejb3Column.java b/hibernate-core/src/main/java/org/hibernate/cfg/Ejb3Column.java index 90f691692057..795ebb63bfc5 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/Ejb3Column.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/Ejb3Column.java @@ -13,6 +13,7 @@ import org.hibernate.annotations.ColumnDefault; import org.hibernate.annotations.ColumnTransformer; import org.hibernate.annotations.ColumnTransformers; +import org.hibernate.annotations.Comment; import org.hibernate.annotations.Index; import org.hibernate.annotations.common.reflection.XProperty; import org.hibernate.boot.model.naming.Identifier; @@ -70,6 +71,8 @@ public class Ejb3Column { private String defaultValue; + private String comment; + public void setTable(Table table) { this.table = table; } @@ -193,6 +196,14 @@ public void setDefaultValue(String defaultValue) { this.defaultValue = defaultValue; } + public String getComment() { + return comment; + } + + public void setComment(String comment) { + this.comment = comment; + } + public Ejb3Column() { } @@ -209,6 +220,9 @@ public void bind() { if ( defaultValue != null ) { mappingColumn.setDefaultValue( defaultValue ); } + if ( StringHelper.isNotEmpty( comment ) ) { + mappingColumn.setComment (comment ); + } if ( LOG.isDebugEnabled() ) { LOG.debugf( "Binding column: %s", toString() ); } @@ -471,6 +485,7 @@ public void forceNotNull() { public static Ejb3Column[] buildColumnFromAnnotation( javax.persistence.Column[] anns, org.hibernate.annotations.Formula formulaAnn, + Comment commentAnn, Nullability nullability, PropertyHolder propertyHolder, PropertyData inferredData, @@ -479,6 +494,7 @@ public static Ejb3Column[] buildColumnFromAnnotation( return buildColumnFromAnnotation( anns, formulaAnn, + commentAnn, nullability, propertyHolder, inferredData, @@ -490,6 +506,7 @@ public static Ejb3Column[] buildColumnFromAnnotation( public static Ejb3Column[] buildColumnFromAnnotation( javax.persistence.Column[] anns, org.hibernate.annotations.Formula formulaAnn, + Comment commentAnn, Nullability nullability, PropertyHolder propertyHolder, PropertyData inferredData, @@ -525,6 +542,7 @@ public static Ejb3Column[] buildColumnFromAnnotation( suffixForDefaultColumnName, secondaryTables, propertyHolder, + commentAnn, nullability, context ); @@ -601,6 +619,9 @@ public static Ejb3Column[] buildColumnFromAnnotation( column.setNullable( col.nullable() ); //TODO force to not null if available? This is a (bad) user choice. + if ( commentAnn != null ) { + column.setComment( commentAnn.value() ); + } column.setUnique( col.unique() ); column.setInsertable( col.insertable() ); column.setUpdatable( col.updatable() ); @@ -676,12 +697,17 @@ private static Ejb3Column[] buildImplicitColumn( String suffixForDefaultColumnName, Map secondaryTables, PropertyHolder propertyHolder, + Comment comment, Nullability nullability, MetadataBuildingContext context) { Ejb3Column column = new Ejb3Column(); Ejb3Column[] columns = new Ejb3Column[1]; columns[0] = column; + if ( comment != null ) { + column.setComment( comment.value() ); + } + //not following the spec but more clean if ( nullability != Nullability.FORCED_NULL && inferredData.getClassOrElement().isPrimitive() diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/Ejb3JoinColumn.java b/hibernate-core/src/main/java/org/hibernate/cfg/Ejb3JoinColumn.java index 9dc1c1d84ea6..77be05530038 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/Ejb3JoinColumn.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/Ejb3JoinColumn.java @@ -17,6 +17,7 @@ import org.hibernate.AnnotationException; import org.hibernate.AssertionFailure; import org.hibernate.MappingException; +import org.hibernate.annotations.Comment; import org.hibernate.annotations.JoinColumnOrFormula; import org.hibernate.annotations.JoinFormula; import org.hibernate.annotations.common.reflection.XClass; @@ -98,6 +99,7 @@ private Ejb3JoinColumn() { private Ejb3JoinColumn( String sqlType, String name, + String comment, boolean nullable, boolean unique, boolean insertable, @@ -114,6 +116,7 @@ private Ejb3JoinColumn( setImplicit( isImplicit ); setSqlType( sqlType ); setLogicalColumnName( name ); + setComment( comment ); setNullable( nullable ); setUnique( unique ); setInsertable( insertable ); @@ -150,7 +153,7 @@ public static Ejb3JoinColumn[] buildJoinColumnsOrFormulas( } else { joinColumns[i] = buildJoinColumns( - new JoinColumn[] { join.column() }, mappedBy, joins, propertyHolder, propertyName, buildingContext + new JoinColumn[] { join.column() }, null, mappedBy, joins, propertyHolder, propertyName, buildingContext )[0]; } } @@ -181,18 +184,20 @@ public static Ejb3JoinColumn buildJoinFormula( public static Ejb3JoinColumn[] buildJoinColumns( JoinColumn[] anns, + Comment comment, String mappedBy, Map joins, PropertyHolder propertyHolder, String propertyName, MetadataBuildingContext buildingContext) { return buildJoinColumnsWithDefaultColumnSuffix( - anns, mappedBy, joins, propertyHolder, propertyName, "", buildingContext + anns, comment, mappedBy, joins, propertyHolder, propertyName, "", buildingContext ); } public static Ejb3JoinColumn[] buildJoinColumnsWithDefaultColumnSuffix( JoinColumn[] anns, + Comment comment, String mappedBy, Map joins, PropertyHolder propertyHolder, @@ -207,6 +212,7 @@ public static Ejb3JoinColumn[] buildJoinColumnsWithDefaultColumnSuffix( return new Ejb3JoinColumn[] { buildJoinColumn( null, + comment, mappedBy, joins, propertyHolder, @@ -222,6 +228,7 @@ public static Ejb3JoinColumn[] buildJoinColumnsWithDefaultColumnSuffix( for (int index = 0; index < size; index++) { result[index] = buildJoinColumn( actualColumns[index], + comment, mappedBy, joins, propertyHolder, @@ -239,6 +246,7 @@ public static Ejb3JoinColumn[] buildJoinColumnsWithDefaultColumnSuffix( */ private static Ejb3JoinColumn buildJoinColumn( JoinColumn ann, + Comment comment, String mappedBy, Map joins, PropertyHolder propertyHolder, String propertyName, @@ -252,6 +260,7 @@ private static Ejb3JoinColumn buildJoinColumn( ); } Ejb3JoinColumn joinColumn = new Ejb3JoinColumn(); + joinColumn.setComment( comment != null ? comment.value() : null ); joinColumn.setBuildingContext( buildingContext ); joinColumn.setJoinAnnotation( ann, null ); if ( StringHelper.isEmpty( joinColumn.getLogicalColumnName() ) @@ -376,6 +385,7 @@ public static Ejb3JoinColumn buildJoinColumn( return new Ejb3JoinColumn( sqlType, name, + null, false, false, true, @@ -395,6 +405,7 @@ public static Ejb3JoinColumn buildJoinColumn( return new Ejb3JoinColumn( null, defaultName, + null, false, false, true, diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/IdBagBinder.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/IdBagBinder.java index 09d26222e9c4..f4ca1c974469 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/IdBagBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/IdBagBinder.java @@ -72,6 +72,7 @@ property, unique, associationTableBinder, ignoreNotFound, getBuildingContext() Ejb3Column[] idColumns = Ejb3Column.buildColumnFromAnnotation( collectionIdAnn.columns(), null, + null, Nullability.FORCED_NOT_NULL, propertyHolder, propertyData, diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/comment/CommentTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/comment/CommentTest.java new file mode 100644 index 000000000000..e9b16c52b52c --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/comment/CommentTest.java @@ -0,0 +1,76 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.annotations.comment; + +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertThat; + +import java.util.Iterator; +import java.util.stream.StreamSupport; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; + +import org.hibernate.annotations.Comment; +import org.hibernate.boot.Metadata; +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistry; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.mapping.Column; +import org.hibernate.mapping.Table; +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseUnitTestCase; +import org.junit.Test; + +/** + * @author Yanming Zhou + */ +public class CommentTest extends BaseUnitTestCase { + + private static final String TABLE_NAME = "TestEntity"; + private static final String TABLE_COMMENT = "I am table"; + + @Test + @TestForIssue(jiraKey = "HHH-4369") + public void testComments() { + StandardServiceRegistry ssr = new StandardServiceRegistryBuilder().build(); + Metadata metadata = new MetadataSources(ssr).addAnnotatedClass(TestEntity.class).buildMetadata(); + Table table = StreamSupport.stream(metadata.getDatabase().getNamespaces().spliterator(), false) + .flatMap(namespace -> namespace.getTables().stream()).filter(t -> t.getName().equals(TABLE_NAME)) + .findFirst().orElse(null); + assertThat(table.getComment(), is(TABLE_COMMENT)); + Iterator it = table.getColumnIterator(); + while (it.hasNext()) { + Column col = it.next(); + assertThat(col.getComment(), is("I am " + col.getName())); + } + } + + @Entity(name = "Person") + @javax.persistence.Table(name = TABLE_NAME) + @org.hibernate.annotations.Table(comment = TABLE_COMMENT, appliesTo = TABLE_NAME) + public static class TestEntity { + + @Id + @GeneratedValue + @Comment("I am id") + private Long id; + + @Comment("I am name") + @javax.persistence.Column(length = 50) + private String name; + + @ManyToOne + @JoinColumn(name = "other") + @Comment("I am other") + private TestEntity other; + + } +} From 8e744f0dc2a9439709c3a11bcfa588eb6310f6f7 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Mon, 20 Sep 2021 23:03:52 +0100 Subject: [PATCH 326/644] HHH-14833 Upgrade to Byte Buddy 1.11.16 --- gradle/libraries.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libraries.gradle b/gradle/libraries.gradle index b3f6ccdc05d1..c242741843b0 100644 --- a/gradle/libraries.gradle +++ b/gradle/libraries.gradle @@ -24,7 +24,7 @@ ext { weldVersion = '3.1.5.Final' jakartaWeldVersion = '4.0.1.SP1' - byteBuddyVersion = '1.11.12' + byteBuddyVersion = '1.11.16' agroalVersion = '1.9' From 1321725abaf7cd19b214b11b8803c443f449b456 Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Mon, 20 Sep 2021 22:40:29 +0000 Subject: [PATCH 327/644] 5.6.0.Beta2 --- changelog.txt | 30 ++++++++++++++++++++++++++++++ gradle/version.properties | 2 +- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 3b5e99fe0bfc..d907d10be4b9 100644 --- a/changelog.txt +++ b/changelog.txt @@ -3,6 +3,36 @@ Hibernate 5 Changelog Note: Please refer to JIRA to learn more about each issue. +Changes in 5.6.0.Beta2 (September 20, 2021) +------------------------------------------------------------------------------------------------------------------------ + +https://hibernate.atlassian.net/projects/HHH/versions/31980 + +** Bug + * [HHH-14828] - Bytecode enhancement generates invalid bytecode for final fields + * [HHH-14827] - @AttributeOverride at type level does not work when also using orm.xml + * [HHH-14826] - Regression: OneToOne fields are always null if parent is loaded from L2 cache + * [HHH-14811] - org.hibernate.AssertionFailure thrown instead of LazyInitializationException when trying to access a lazy property on a deleted entity + * [HHH-14796] - Cannot replace an existing JPQL NamedQuery with a native NamedQuery + * [HHH-14757] - Cannot save (dirty check failed) single element GeometryCollection + * [HHH-14413] - EntityUpdateAction increments version despite veto on update + * [HHH-13661] - Postgresql query timeout not translated to org.hibernate.QueryTimeoutException + +** Improvement + * [HHH-13999] - Add dialect for SQL Server 2016 + * [HHH-5249] - Component.java MappingException needs more detail + +** Sub-task + * [HHH-4369] - Support @Comment or column attribute on @Table and @Column + +** Task + * [HHH-14833] - Upgrade to Byte Buddy 1.11.16 + * [HHH-14813] - Update DB2 dialect with bind parameters limit + * [HHH-14812] - Upgrade integration tests to use Oracle JDBC driver v 21.3.0.0 + * [HHH-14794] - More changes to support SchemaMigrator/SchemaValidator using Hibernate Reactive + * [HHH-14633] - Upgrade to latest geolatte-geom version 1.8.2 + + Changes in 5.6.0.Beta1 (August 27, 2021) ------------------------------------------------------------------------------------------------------------------------ diff --git a/gradle/version.properties b/gradle/version.properties index b6875391f169..94eacfe73b1c 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -hibernateVersion=5.6.0-SNAPSHOT \ No newline at end of file +hibernateVersion=5.6.0.Beta2 \ No newline at end of file From ec841c0d6c97c03b9f0877fc924e462e3b9ec8d2 Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Mon, 20 Sep 2021 22:45:22 +0000 Subject: [PATCH 328/644] 5.6.0-SNAPSHOT --- gradle/version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/version.properties b/gradle/version.properties index 94eacfe73b1c..b6875391f169 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -hibernateVersion=5.6.0.Beta2 \ No newline at end of file +hibernateVersion=5.6.0-SNAPSHOT \ No newline at end of file From dec331362ce8eda9aa66a7ba98971a302e8ca535 Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Mon, 20 Sep 2021 22:02:02 -0700 Subject: [PATCH 329/644] HHH-14835 : More changes to support SchemaMigrator/SchemaValidator using Hibernate Reactive Changes required for sequences to be created with a default catalog --- .../dialect/SQLServer2012Dialect.java | 34 +++++++ .../internal/StandardSequenceExporter.java | 21 +++-- ...erverWithSequenceDefaultSchemaCatalog.java | 94 +++++++++++++++++++ 3 files changed, 139 insertions(+), 10 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaExportSqlServerWithSequenceDefaultSchemaCatalog.java diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServer2012Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServer2012Dialect.java index e5a32322a24a..b25672486650 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServer2012Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServer2012Dialect.java @@ -6,8 +6,14 @@ */ package org.hibernate.dialect; +import org.hibernate.boot.Metadata; +import org.hibernate.boot.model.relational.QualifiedSequenceName; +import org.hibernate.boot.model.relational.Sequence; import org.hibernate.dialect.pagination.LimitHandler; import org.hibernate.dialect.pagination.SQLServer2012LimitHandler; +import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; +import org.hibernate.tool.schema.internal.StandardSequenceExporter; +import org.hibernate.tool.schema.spi.Exporter; /** * Microsoft SQL Server 2012 Dialect @@ -15,6 +21,11 @@ * @author Brett Meyer */ public class SQLServer2012Dialect extends SQLServer2008Dialect { + private final Exporter sequenceExporter; + + public SQLServer2012Dialect() { + sequenceExporter = new SqlServerSequenceExporter( this ); + } @Override public boolean supportsSequences() { @@ -26,6 +37,11 @@ public boolean supportsPooledSequences() { return true; } + @Override + public Exporter getSequenceExporter() { + return sequenceExporter; + } + @Override public String getCreateSequenceString(String sequenceName) { return "create sequence " + sequenceName; @@ -94,4 +110,22 @@ public boolean supportsLimitOffset() { protected LimitHandler getDefaultLimitHandler() { return new SQLServer2012LimitHandler(); } + + private class SqlServerSequenceExporter extends StandardSequenceExporter { + + public SqlServerSequenceExporter(Dialect dialect) { + super( dialect ); + } + + @Override + protected String getFormattedSequenceName(QualifiedSequenceName name, Metadata metadata) { + if ( name.getCatalogName() != null ) { + // SQL Server does not allow the catalog in the sequence name. + // See https://docs.microsoft.com/en-us/sql/t-sql/statements/create-sequence-transact-sql?view=sql-server-ver15&viewFallbackFrom=sql-server-ver12 + // Keeping the catalog in the name does not break on ORM, but it fails using Vert.X for Reactive. + name = new QualifiedSequenceName( null, name.getSchemaName(), name.getObjectName() ); + } + return super.getFormattedSequenceName( name, metadata ); + } + } } diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardSequenceExporter.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardSequenceExporter.java index 9b97d5496da5..cb04d29b5514 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardSequenceExporter.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardSequenceExporter.java @@ -7,6 +7,7 @@ package org.hibernate.tool.schema.internal; import org.hibernate.boot.Metadata; +import org.hibernate.boot.model.relational.QualifiedSequenceName; import org.hibernate.boot.model.relational.Sequence; import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; @@ -24,12 +25,8 @@ public StandardSequenceExporter(Dialect dialect) { @Override public String[] getSqlCreateStrings(Sequence sequence, Metadata metadata) { - final JdbcEnvironment jdbcEnvironment = metadata.getDatabase().getJdbcEnvironment(); return dialect.getCreateSequenceStrings( - jdbcEnvironment.getQualifiedObjectNameFormatter().format( - sequence.getName(), - jdbcEnvironment.getDialect() - ), + getFormattedSequenceName( sequence.getName(), metadata ), sequence.getInitialValue(), sequence.getIncrementSize() ); @@ -37,12 +34,16 @@ public String[] getSqlCreateStrings(Sequence sequence, Metadata metadata) { @Override public String[] getSqlDropStrings(Sequence sequence, Metadata metadata) { - final JdbcEnvironment jdbcEnvironment = metadata.getDatabase().getJdbcEnvironment(); return dialect.getDropSequenceStrings( - jdbcEnvironment.getQualifiedObjectNameFormatter().format( - sequence.getName(), - jdbcEnvironment.getDialect() - ) + getFormattedSequenceName( sequence.getName(), metadata ) + ); + } + + protected String getFormattedSequenceName(QualifiedSequenceName name, Metadata metadata) { + final JdbcEnvironment jdbcEnvironment = metadata.getDatabase().getJdbcEnvironment(); + return jdbcEnvironment.getQualifiedObjectNameFormatter().format( + name, + jdbcEnvironment.getDialect() ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaExportSqlServerWithSequenceDefaultSchemaCatalog.java b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaExportSqlServerWithSequenceDefaultSchemaCatalog.java new file mode 100644 index 000000000000..b9044abc6f05 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaExportSqlServerWithSequenceDefaultSchemaCatalog.java @@ -0,0 +1,94 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.schemaupdate; + +import java.util.EnumSet; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; +import javax.persistence.Table; + +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.boot.spi.MetadataImplementor; +import org.hibernate.cfg.Environment; +import org.hibernate.dialect.SQLServer2012Dialect; +import org.hibernate.service.ServiceRegistry; +import org.hibernate.tool.hbm2ddl.SchemaExport; +import org.hibernate.tool.schema.TargetType; + +import org.hibernate.testing.RequiresDialect; +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.CustomRunner; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.hamcrest.core.Is.is; +import static org.junit.Assert.assertThat; + +/** + * @author Andrea Boriero + */ +@TestForIssue(jiraKey = "HHH-XXX") +@RunWith(CustomRunner.class) +@RequiresDialect(SQLServer2012Dialect.class) +public class SchemaExportSqlServerWithSequenceDefaultSchemaCatalog { + protected ServiceRegistry serviceRegistry; + protected MetadataImplementor metadata; + + @Test + public void shouldCreateIndex() { + SchemaExport schemaExport = new SchemaExport(); + schemaExport.create( EnumSet.of( TargetType.DATABASE, TargetType.STDOUT ), metadata ); + assertThat( schemaExport.getExceptions().size(), is( 0 ) ); + } + + @Before + public void setUp() { + serviceRegistry = new StandardServiceRegistryBuilder() + .applySetting( Environment.DEFAULT_SCHEMA, "dbo" ) + .applySetting( Environment.DEFAULT_CATALOG, "hibernate_orm_test" ) + .build(); + metadata = (MetadataImplementor) new MetadataSources( serviceRegistry ) + .addAnnotatedClass( MyEntity.class ) + .buildMetadata(); + + System.out.println( "********* Starting SchemaExport for START-UP *************************" ); + new SchemaExport().create( EnumSet.of( TargetType.DATABASE, TargetType.STDOUT ), metadata ); + System.out.println( "********* Completed SchemaExport for START-UP *************************" ); + } + + + @After + public void tearDown() { + System.out.println( "********* Starting SchemaExport (drop) for TEAR-DOWN *************************" ); + new SchemaExport().drop( EnumSet.of( TargetType.DATABASE, TargetType.STDOUT ), metadata ); + System.out.println( "********* Completed SchemaExport (drop) for TEAR-DOWN *************************" ); + + StandardServiceRegistryBuilder.destroy( serviceRegistry ); + serviceRegistry = null; + } + + + @Entity + @Table(name = "MyEntity") + public static class MyEntity { + private int id; + + @Id + @GeneratedValue + public int getId() { + return this.id; + } + + public void setId(final int id) { + this.id = id; + } + } +} From 8cecdd3f43796c134688d99b6387d59600e75738 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Mon, 30 Aug 2021 17:45:57 +0200 Subject: [PATCH 330/644] HHH-14835 : Fix Sybase Connection#getSchema() throws an exception (cherry picked from commit aaba4767fe2842c442104dff0a377a0f63ecffdd) --- .../org/hibernate/dialect/SybaseDialect.java | 23 +++++++++++++++++++ .../AbstractInformationExtractorImpl.java | 6 +++++ 2 files changed, 29 insertions(+) diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/SybaseDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/SybaseDialect.java index b20284657c69..d6e7186b5f65 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SybaseDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SybaseDialect.java @@ -6,8 +6,14 @@ */ package org.hibernate.dialect; +import java.sql.DatabaseMetaData; +import java.sql.SQLException; import java.sql.Types; +import org.hibernate.engine.jdbc.env.spi.IdentifierCaseStrategy; +import org.hibernate.engine.jdbc.env.spi.IdentifierHelper; +import org.hibernate.engine.jdbc.env.spi.IdentifierHelperBuilder; +import org.hibernate.engine.jdbc.env.spi.NameQualifierSupport; import org.hibernate.type.descriptor.sql.BlobTypeDescriptor; import org.hibernate.type.descriptor.sql.ClobTypeDescriptor; import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; @@ -48,4 +54,21 @@ public String getNullColumnString() { public String getCurrentSchemaCommand() { return "select db_name()"; } + + @Override + public IdentifierHelper buildIdentifierHelper(IdentifierHelperBuilder builder, DatabaseMetaData dbMetaData) + throws SQLException { + if ( dbMetaData == null ) { + builder.setUnquotedCaseStrategy( IdentifierCaseStrategy.MIXED ); + builder.setQuotedCaseStrategy( IdentifierCaseStrategy.MIXED ); + } + + return super.buildIdentifierHelper( builder, dbMetaData ); + } + + @Override + public NameQualifierSupport getNameQualifierSupport() { + return NameQualifierSupport.CATALOG; + } + } diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/AbstractInformationExtractorImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/AbstractInformationExtractorImpl.java index 6bb723c2c0d1..bd6dc598adf5 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/AbstractInformationExtractorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/AbstractInformationExtractorImpl.java @@ -407,6 +407,9 @@ public TableInformation getTable(Identifier catalog, Identifier schema, Identifi } private Identifier getCurrentSchema(JdbcEnvironment jdbcEnvironment) { + if ( jdbcEnvironment.getNameQualifierSupport() == NameQualifierSupport.CATALOG ) { + return null; + } if ( currentSchema != null ) { return currentSchema; } @@ -428,6 +431,9 @@ private Identifier getCurrentSchema(JdbcEnvironment jdbcEnvironment) { } private Identifier getCurrentCatalog(JdbcEnvironment jdbcEnvironment) { + if ( jdbcEnvironment.getNameQualifierSupport() == NameQualifierSupport.SCHEMA ) { + return null; + } if ( currentCatalog != null ) { return currentCatalog; } From c6e3bf2ef868ff81850d46a9d525af9afbbdb563 Mon Sep 17 00:00:00 2001 From: Gail Badner Date: Thu, 23 Sep 2021 11:47:59 -0700 Subject: [PATCH 331/644] HHH-14835 : More changes to support SchemaMigrator/SchemaValidator using Hibernate Reactive Add jira key to test case --- .../SchemaExportSqlServerWithSequenceDefaultSchemaCatalog.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaExportSqlServerWithSequenceDefaultSchemaCatalog.java b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaExportSqlServerWithSequenceDefaultSchemaCatalog.java index b9044abc6f05..12630dadb33b 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaExportSqlServerWithSequenceDefaultSchemaCatalog.java +++ b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaExportSqlServerWithSequenceDefaultSchemaCatalog.java @@ -35,7 +35,7 @@ /** * @author Andrea Boriero */ -@TestForIssue(jiraKey = "HHH-XXX") +@TestForIssue(jiraKey = "HHH-14835") @RunWith(CustomRunner.class) @RequiresDialect(SQLServer2012Dialect.class) public class SchemaExportSqlServerWithSequenceDefaultSchemaCatalog { From 87e5de74aa7820db9c75f0a5dba0d5d3fccf2c31 Mon Sep 17 00:00:00 2001 From: taghizadeh87 <84373927+taghizadeh87@users.noreply.github.com> Date: Mon, 27 Sep 2021 18:42:59 +0330 Subject: [PATCH 332/644] Fix typo --- .../hibernate/testing/junit4/BaseCoreFunctionalTestCase.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseCoreFunctionalTestCase.java b/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseCoreFunctionalTestCase.java index b6504dced2a7..d1db00709e39 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseCoreFunctionalTestCase.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/junit4/BaseCoreFunctionalTestCase.java @@ -447,7 +447,7 @@ protected void cleanupTestData() throws Exception { } else { // Because of https://hibernate.atlassian.net/browse/HHH-5529, - // we can'trely on a Bulk Delete query which will not clear the link tables in @ElementCollection or unidirectional collections + // we can't rely on a Bulk Delete query which will not clear the link tables in @ElementCollection or unidirectional collections doInHibernate( this::sessionFactory, s -> { s.createQuery( "from java.lang.Object" ).list().forEach( s::remove ); } ); From 694a0e4aed83640c056e6bbdb0cb9e99786eb213 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Mon, 27 Sep 2021 22:46:35 +0100 Subject: [PATCH 333/644] HHH-14852 Upgrade GraalVM to version 21.2.0 --- gradle/libraries.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libraries.gradle b/gradle/libraries.gradle index c242741843b0..11fe8b853b12 100644 --- a/gradle/libraries.gradle +++ b/gradle/libraries.gradle @@ -44,7 +44,7 @@ ext { jakartaJaxbRuntimeVersion = '3.0.0' //GraalVM - graalvmVersion = '19.3.1' + graalvmVersion = '21.2.0' micrometerVersion = '1.6.1' From 35b951394354870fc5622366c3bda1bf8161fd16 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Mon, 27 Sep 2021 12:39:26 -0500 Subject: [PATCH 334/644] HHH-14845 - Deprecate JACC support --- .../org/hibernate/cfg/AvailableSettings.java | 19 +++++++++++++++---- .../internal/log/DeprecationLogger.java | 8 ++++++++ .../AbstractJaccSecurableEventListener.java | 3 +++ .../internal/JaccPreDeleteEventListener.java | 3 +++ .../internal/JaccPreInsertEventListener.java | 3 +++ .../internal/JaccPreLoadEventListener.java | 3 +++ .../internal/JaccPreUpdateEventListener.java | 3 +++ .../secure/internal/JaccSecurityListener.java | 3 +++ .../internal/StandardJaccServiceImpl.java | 3 +++ .../secure/spi/GrantedPermission.java | 3 +++ .../hibernate/secure/spi/JaccIntegrator.java | 10 ++++++++++ .../spi/JaccPermissionDeclarations.java | 3 +++ .../org/hibernate/secure/spi/JaccService.java | 3 +++ .../secure/spi/PermissibleAction.java | 3 +++ .../spi/PermissionCheckEntityInformation.java | 3 +++ 15 files changed, 69 insertions(+), 4 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java index 37704d3f5180..0e66765190b2 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java @@ -2053,10 +2053,6 @@ public interface AvailableSettings extends org.hibernate.jpa.AvailableSettings { */ String JTA_TRACK_BY_THREAD = "hibernate.jta.track_by_thread"; - String JACC_CONTEXT_ID = "hibernate.jacc_context_id"; - String JACC_PREFIX = "hibernate.jacc"; - String JACC_ENABLED = "hibernate.jacc.enabled"; - /** * If enabled, allows schema update and validation to support synonyms. Due * to the possibility that this would return duplicate tables (especially in @@ -2460,4 +2456,19 @@ public interface AvailableSettings extends org.hibernate.jpa.AvailableSettings { */ String OMIT_JOIN_OF_SUPERCLASS_TABLES = "hibernate.query.omit_join_of_superclass_tables"; + /** + * @deprecated Support for JACC will be removed in 6.0 + */ + @Deprecated + String JACC_CONTEXT_ID = "hibernate.jacc_context_id"; + /** + * @deprecated Support for JACC will be removed in 6.0 + */ + @Deprecated + String JACC_PREFIX = "hibernate.jacc"; + /** + * @deprecated Support for JACC will be removed in 6.0 + */ + @Deprecated + String JACC_ENABLED = "hibernate.jacc.enabled"; } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java b/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java index a3084bc76b1b..b8ba0f552e50 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java @@ -258,4 +258,12 @@ void connectionProviderClassDeprecated( "This is deprecated and will be removed in a future version. Every property mapping combination should have its own java class" ) void deprecatedComponentMapping(String name); + + @LogMessage(level = WARN) + @Message( + id = 90000026, + value = "JACC integration was enabled. Support for JACC integration will be removed in version 6.0. Use of" + + "`%s`, `%s` or `%s` settings is discouraged" + ) + void deprecatedJaccUsage(String jaccEnabled, String jaccContextId, String jaccPrefix); } diff --git a/hibernate-core/src/main/java/org/hibernate/secure/internal/AbstractJaccSecurableEventListener.java b/hibernate-core/src/main/java/org/hibernate/secure/internal/AbstractJaccSecurableEventListener.java index e21d3a2df733..95c172d0ed0f 100644 --- a/hibernate-core/src/main/java/org/hibernate/secure/internal/AbstractJaccSecurableEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/secure/internal/AbstractJaccSecurableEventListener.java @@ -16,7 +16,10 @@ * Base class for JACC-securable event listeners * * @author Steve Ebersole + * + * @deprecated Support for JACC will be removed in 6.0 */ +@Deprecated public abstract class AbstractJaccSecurableEventListener implements JaccSecurityListener { private JaccService jaccService; diff --git a/hibernate-core/src/main/java/org/hibernate/secure/internal/JaccPreDeleteEventListener.java b/hibernate-core/src/main/java/org/hibernate/secure/internal/JaccPreDeleteEventListener.java index 41fea761320f..ebec86244919 100644 --- a/hibernate-core/src/main/java/org/hibernate/secure/internal/JaccPreDeleteEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/secure/internal/JaccPreDeleteEventListener.java @@ -15,7 +15,10 @@ * * @author Kabir Khan * @author Steve Ebersole + * + * @deprecated Support for JACC will be removed in 6.0 */ +@Deprecated public class JaccPreDeleteEventListener extends AbstractJaccSecurableEventListener implements PreDeleteEventListener { public JaccPreDeleteEventListener() { } diff --git a/hibernate-core/src/main/java/org/hibernate/secure/internal/JaccPreInsertEventListener.java b/hibernate-core/src/main/java/org/hibernate/secure/internal/JaccPreInsertEventListener.java index c9ff548d5af8..6836c0ed2642 100644 --- a/hibernate-core/src/main/java/org/hibernate/secure/internal/JaccPreInsertEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/secure/internal/JaccPreInsertEventListener.java @@ -15,7 +15,10 @@ * * @author Kabir Khan * @author Steve Ebersole + * + * @deprecated Support for JACC will be removed in 6.0 */ +@Deprecated public class JaccPreInsertEventListener extends AbstractJaccSecurableEventListener implements PreInsertEventListener { public JaccPreInsertEventListener() { } diff --git a/hibernate-core/src/main/java/org/hibernate/secure/internal/JaccPreLoadEventListener.java b/hibernate-core/src/main/java/org/hibernate/secure/internal/JaccPreLoadEventListener.java index 7f3dc7b4ba5f..51d531ed0aa5 100644 --- a/hibernate-core/src/main/java/org/hibernate/secure/internal/JaccPreLoadEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/secure/internal/JaccPreLoadEventListener.java @@ -15,7 +15,10 @@ * * @author Kabir Khan * @author Steve Ebersole + * + * @deprecated Support for JACC will be removed in 6.0 */ +@Deprecated public class JaccPreLoadEventListener extends AbstractJaccSecurableEventListener implements PreLoadEventListener { public JaccPreLoadEventListener() { } diff --git a/hibernate-core/src/main/java/org/hibernate/secure/internal/JaccPreUpdateEventListener.java b/hibernate-core/src/main/java/org/hibernate/secure/internal/JaccPreUpdateEventListener.java index fa5a0abfbb75..7ced461c7553 100644 --- a/hibernate-core/src/main/java/org/hibernate/secure/internal/JaccPreUpdateEventListener.java +++ b/hibernate-core/src/main/java/org/hibernate/secure/internal/JaccPreUpdateEventListener.java @@ -15,7 +15,10 @@ * * @author Kabir Khan * @author Steve Ebersole + * + * @deprecated Support for JACC will be removed in 6.0 */ +@Deprecated public class JaccPreUpdateEventListener extends AbstractJaccSecurableEventListener implements PreUpdateEventListener { public JaccPreUpdateEventListener() { } diff --git a/hibernate-core/src/main/java/org/hibernate/secure/internal/JaccSecurityListener.java b/hibernate-core/src/main/java/org/hibernate/secure/internal/JaccSecurityListener.java index 3828a8085879..6fc8a717690a 100644 --- a/hibernate-core/src/main/java/org/hibernate/secure/internal/JaccSecurityListener.java +++ b/hibernate-core/src/main/java/org/hibernate/secure/internal/JaccSecurityListener.java @@ -11,6 +11,9 @@ * {@link org.hibernate.secure.spi.JaccIntegrator} for details. * * @author Kabir Khan + * + * @deprecated Support for JACC will be removed in 6.0 */ +@Deprecated public interface JaccSecurityListener { } diff --git a/hibernate-core/src/main/java/org/hibernate/secure/internal/StandardJaccServiceImpl.java b/hibernate-core/src/main/java/org/hibernate/secure/internal/StandardJaccServiceImpl.java index 959314938a6c..bf0c1fedbde7 100644 --- a/hibernate-core/src/main/java/org/hibernate/secure/internal/StandardJaccServiceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/secure/internal/StandardJaccServiceImpl.java @@ -34,7 +34,10 @@ /** * @author Steve Ebersole + * + * @deprecated Support for JACC will be removed in 6.0 */ +@Deprecated public class StandardJaccServiceImpl implements JaccService, Configurable { private static final Logger log = Logger.getLogger( StandardJaccServiceImpl.class ); diff --git a/hibernate-core/src/main/java/org/hibernate/secure/spi/GrantedPermission.java b/hibernate-core/src/main/java/org/hibernate/secure/spi/GrantedPermission.java index 92d7fe458e83..17b71ebb2d7c 100644 --- a/hibernate-core/src/main/java/org/hibernate/secure/spi/GrantedPermission.java +++ b/hibernate-core/src/main/java/org/hibernate/secure/spi/GrantedPermission.java @@ -10,7 +10,10 @@ * Describes a Hibernate (persistence) permission. * * @author Steve Ebersole + * + * @deprecated Support for JACC will be removed in 6.0 */ +@Deprecated public class GrantedPermission { private final String role; private final String entityName; diff --git a/hibernate-core/src/main/java/org/hibernate/secure/spi/JaccIntegrator.java b/hibernate-core/src/main/java/org/hibernate/secure/spi/JaccIntegrator.java index 36f61ce2b85a..0779e7fc11ec 100644 --- a/hibernate-core/src/main/java/org/hibernate/secure/spi/JaccIntegrator.java +++ b/hibernate-core/src/main/java/org/hibernate/secure/spi/JaccIntegrator.java @@ -17,6 +17,7 @@ import org.hibernate.event.service.spi.EventListenerRegistry; import org.hibernate.event.spi.EventType; import org.hibernate.integrator.spi.ServiceContributingIntegrator; +import org.hibernate.internal.log.DeprecationLogger; import org.hibernate.secure.internal.DisabledJaccServiceImpl; import org.hibernate.secure.internal.JaccPreDeleteEventListener; import org.hibernate.secure.internal.JaccPreInsertEventListener; @@ -32,7 +33,10 @@ * Integrator for setting up JACC integration * * @author Steve Ebersole + * + * @deprecated Support for JACC will be removed in 6.0 */ +@Deprecated public class JaccIntegrator implements ServiceContributingIntegrator { private static final Logger log = Logger.getLogger( JaccIntegrator.class ); @@ -81,6 +85,12 @@ private void doIntegration( return; } + DeprecationLogger.DEPRECATION_LOGGER.deprecatedJaccUsage( + AvailableSettings.JACC_ENABLED, + AvailableSettings.JACC_CONTEXT_ID, + AvailableSettings.JACC_PREFIX + ); + final String contextId = (String) properties.get( AvailableSettings.JACC_CONTEXT_ID ); if ( contextId == null ) { throw new IntegrationException( "JACC context id must be specified" ); diff --git a/hibernate-core/src/main/java/org/hibernate/secure/spi/JaccPermissionDeclarations.java b/hibernate-core/src/main/java/org/hibernate/secure/spi/JaccPermissionDeclarations.java index 9fbaeff2ddcd..53441bfe8e51 100644 --- a/hibernate-core/src/main/java/org/hibernate/secure/spi/JaccPermissionDeclarations.java +++ b/hibernate-core/src/main/java/org/hibernate/secure/spi/JaccPermissionDeclarations.java @@ -12,7 +12,10 @@ /** * @author Steve Ebersole + * + * @deprecated Support for JACC will be removed in 6.0 */ +@Deprecated public class JaccPermissionDeclarations { private final String contextId; private List permissionDeclarations; diff --git a/hibernate-core/src/main/java/org/hibernate/secure/spi/JaccService.java b/hibernate-core/src/main/java/org/hibernate/secure/spi/JaccService.java index 2b784c6eb29b..50d70a810f90 100644 --- a/hibernate-core/src/main/java/org/hibernate/secure/spi/JaccService.java +++ b/hibernate-core/src/main/java/org/hibernate/secure/spi/JaccService.java @@ -12,7 +12,10 @@ * Service describing Hibernate integration with JACC for security service. * * @author Steve Ebersole + * + * @deprecated Support for JACC will be removed in 6.0 */ +@Deprecated public interface JaccService extends Service { /** * Obtain the JACC context-id in effect for this service. {@code null} indicates no diff --git a/hibernate-core/src/main/java/org/hibernate/secure/spi/PermissibleAction.java b/hibernate-core/src/main/java/org/hibernate/secure/spi/PermissibleAction.java index 761eaa169ea3..c5c2963d2cef 100644 --- a/hibernate-core/src/main/java/org/hibernate/secure/spi/PermissibleAction.java +++ b/hibernate-core/src/main/java/org/hibernate/secure/spi/PermissibleAction.java @@ -8,7 +8,10 @@ /** * @author Steve Ebersole + * + * @deprecated Support for JACC will be removed in 6.0 */ +@Deprecated public enum PermissibleAction { INSERT( "insert" ), UPDATE( "update" ), diff --git a/hibernate-core/src/main/java/org/hibernate/secure/spi/PermissionCheckEntityInformation.java b/hibernate-core/src/main/java/org/hibernate/secure/spi/PermissionCheckEntityInformation.java index 7aa7c6ad417e..acc038901ce2 100644 --- a/hibernate-core/src/main/java/org/hibernate/secure/spi/PermissionCheckEntityInformation.java +++ b/hibernate-core/src/main/java/org/hibernate/secure/spi/PermissionCheckEntityInformation.java @@ -10,7 +10,10 @@ /** * @author Steve Ebersole + * + * @deprecated Support for JACC will be removed in 6.0 */ +@Deprecated public interface PermissionCheckEntityInformation { public Object getEntity(); public String getEntityName(); From e59028fbcf98f769e512c9d9bc0a54b9e90b02ff Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Mon, 27 Sep 2021 12:47:40 -0500 Subject: [PATCH 335/644] HHH-14845 - Deprecate JACC support --- .../hibernate/boot/cfgxml/spi/LoadedConfig.java | 15 ++++++++++++--- .../hibernate/internal/log/DeprecationLogger.java | 7 +++++++ 2 files changed, 19 insertions(+), 3 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/boot/cfgxml/spi/LoadedConfig.java b/hibernate-core/src/main/java/org/hibernate/boot/cfgxml/spi/LoadedConfig.java index 156f334d09ea..f94171998161 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/cfgxml/spi/LoadedConfig.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/cfgxml/spi/LoadedConfig.java @@ -24,6 +24,7 @@ import org.hibernate.boot.jaxb.cfg.spi.JaxbCfgHibernateConfiguration; import org.hibernate.boot.jaxb.cfg.spi.JaxbCfgMappingReferenceType; import org.hibernate.event.spi.EventType; +import org.hibernate.internal.log.DeprecationLogger; import org.hibernate.secure.spi.GrantedPermission; import org.hibernate.secure.spi.JaccPermissionDeclarations; @@ -59,10 +60,18 @@ public Map getConfigurationValues() { return configurationValues; } + /** + * @deprecated Support for JACC will be removed in 6.0 + */ + @Deprecated public Map getJaccPermissionsByContextId() { return jaccPermissionsByContextId; } + /** + * @deprecated Support for JACC will be removed in 6.0 + */ + @Deprecated public JaccPermissionDeclarations getJaccPermissions(String jaccContextId) { return jaccPermissionsByContextId.get( jaccContextId ); } @@ -102,11 +111,11 @@ public static LoadedConfig consume(JaxbCfgHibernateConfiguration jaxbCfg) { cfg.addCacheRegionDefinition( parseCacheRegionDefinition( cacheDeclaration ) ); } - if ( jaxbCfg.getSecurity() != null ) { + if ( jaxbCfg.getSecurity() != null && ! jaxbCfg.getSecurity().getGrant().isEmpty() ) { + DeprecationLogger.DEPRECATION_LOGGER.deprecatedJaccCfgXmlSettings(); for ( JaxbCfgHibernateConfiguration.JaxbCfgSecurity.JaxbCfgGrant grant : jaxbCfg.getSecurity().getGrant() ) { final JaccPermissionDeclarations jaccPermissions = cfg.getOrCreateJaccPermissions( - jaxbCfg.getSecurity() - .getContext() + jaxbCfg.getSecurity().getContext() ); jaccPermissions.addPermissionDeclaration( new GrantedPermission( diff --git a/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java b/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java index b8ba0f552e50..c08ec09024ed 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java @@ -266,4 +266,11 @@ void connectionProviderClassDeprecated( "`%s`, `%s` or `%s` settings is discouraged" ) void deprecatedJaccUsage(String jaccEnabled, String jaccContextId, String jaccPrefix); + + @LogMessage(level = WARN) + @Message( + id = 90000027, + value = "JACC settings encountered in hibernate `cfg.xml` file. JACC integration is deprecated and will be removed in version 6.0" + ) + void deprecatedJaccCfgXmlSettings(); } From ba9c3201ebefc84e465223e7297db3aa54a48d50 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Mon, 27 Sep 2021 12:54:34 -0500 Subject: [PATCH 336/644] HHH-14845 - Deprecate JACC support --- .../event/spi/AbstractPreDatabaseOperationEvent.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/AbstractPreDatabaseOperationEvent.java b/hibernate-core/src/main/java/org/hibernate/event/spi/AbstractPreDatabaseOperationEvent.java index 8d31f09d5ae1..bd58a1aa317e 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/spi/AbstractPreDatabaseOperationEvent.java +++ b/hibernate-core/src/main/java/org/hibernate/event/spi/AbstractPreDatabaseOperationEvent.java @@ -47,8 +47,11 @@ public AbstractPreDatabaseOperationEvent( * Retrieves the entity involved in the database operation. * * @return The entity. + * + * @deprecated Support for JACC will be removed in 6.0 */ @Override + @Deprecated public Object getEntity() { return entity; } @@ -88,12 +91,20 @@ public EventSource getSource() { return getSession(); } + /** + * @deprecated Support for JACC will be removed in 6.0 + */ @Override + @Deprecated public String getEntityName() { return persister.getEntityName(); } + /** + * @deprecated Support for JACC will be removed in 6.0 + */ @Override + @Deprecated public Serializable getIdentifier() { return id; } From ff4db00aece4a8f9bea694c1893fdb4a21884c65 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Mon, 27 Sep 2021 12:12:53 -0500 Subject: [PATCH 337/644] HHH-14847 - Deprecate JMX support --- .../org/hibernate/cfg/AvailableSettings.java | 45 ++++++++++++++++--- .../internal/log/DeprecationLogger.java | 24 ++++++++++ .../jmx/internal/JmxServiceImpl.java | 9 ++++ .../jmx/internal/JmxServiceInitiator.java | 9 ++-- .../org/hibernate/jmx/spi/JmxService.java | 4 ++ .../org/hibernate/service/spi/Manageable.java | 4 ++ 6 files changed, 85 insertions(+), 10 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java index 0e66765190b2..49bc50d2dfd7 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java @@ -1903,13 +1903,6 @@ public interface AvailableSettings extends org.hibernate.jpa.AvailableSettings { */ String HBM2DDL_DEFAULT_CONSTRAINT_MODE = "hibernate.hbm2ddl.default_constraint_mode"; - String JMX_ENABLED = "hibernate.jmx.enabled"; - String JMX_PLATFORM_SERVER = "hibernate.jmx.usePlatformServer"; - String JMX_AGENT_ID = "hibernate.jmx.agentId"; - String JMX_DOMAIN_NAME = "hibernate.jmx.defaultDomain"; - String JMX_SF_NAME = "hibernate.jmx.sessionFactoryName"; - String JMX_DEFAULT_OBJ_NAME_DOMAIN = "org.hibernate.core"; - /** * Setting to identify a {@link org.hibernate.CustomEntityDirtinessStrategy} to use. May point to * either a class name or instance. @@ -2471,4 +2464,42 @@ public interface AvailableSettings extends org.hibernate.jpa.AvailableSettings { */ @Deprecated String JACC_ENABLED = "hibernate.jacc.enabled"; + + /** + * @deprecated Scheduled for removal in 6.0; see https://hibernate.atlassian.net/browse/HHH-14847 + * and https://hibernate.atlassian.net/browse/HHH-14846 + */ + @Deprecated + String JMX_ENABLED = "hibernate.jmx.enabled"; + /** + * @deprecated Scheduled for removal in 6.0; see https://hibernate.atlassian.net/browse/HHH-14847 + * and https://hibernate.atlassian.net/browse/HHH-14846 + */ + @Deprecated + String JMX_PLATFORM_SERVER = "hibernate.jmx.usePlatformServer"; + /** + * @deprecated Scheduled for removal in 6.0; see https://hibernate.atlassian.net/browse/HHH-14847 + * and https://hibernate.atlassian.net/browse/HHH-14846 + */ + @Deprecated + String JMX_AGENT_ID = "hibernate.jmx.agentId"; + /** + * @deprecated Scheduled for removal in 6.0; see https://hibernate.atlassian.net/browse/HHH-14847 + * and https://hibernate.atlassian.net/browse/HHH-14846 + */ + @Deprecated + String JMX_DOMAIN_NAME = "hibernate.jmx.defaultDomain"; + /** + * @deprecated Scheduled for removal in 6.0; see https://hibernate.atlassian.net/browse/HHH-14847 + * and https://hibernate.atlassian.net/browse/HHH-14846 + */ + @Deprecated + String JMX_SF_NAME = "hibernate.jmx.sessionFactoryName"; + /** + * @deprecated Scheduled for removal in 6.0; see https://hibernate.atlassian.net/browse/HHH-14847 + * and https://hibernate.atlassian.net/browse/HHH-14846 + */ + @Deprecated + String JMX_DEFAULT_OBJ_NAME_DOMAIN = "org.hibernate.core"; + } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java b/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java index c08ec09024ed..9ecfe081bf67 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java @@ -273,4 +273,28 @@ void connectionProviderClassDeprecated( value = "JACC settings encountered in hibernate `cfg.xml` file. JACC integration is deprecated and will be removed in version 6.0" ) void deprecatedJaccCfgXmlSettings(); + + @LogMessage(level = WARN) + @Message( + id = 90000028, + value = "Manageable service was registered with JMX support (`%s`). JMX support is scheduled for removal in 6.0" + ) + void deprecatedJmxManageableServiceRegistration(String jmxEnabledSetting); + + @LogMessage(level = WARN) + @Message( + id = 90000029, + + value = "JMX support has been enabled via `%s`. This feature is scheduled for removal in 6.0" + ) + void deprecatedJmxSupport(String jmxEnabledSetting); + + + @LogMessage(level = WARN) + @Message( + id = 90000030, + value = "MBean was registered with JMX support (`%s`). JMX support is scheduled for removal in 6.0" + ) + void deprecatedJmxBeanRegistration(String name); + } diff --git a/hibernate-core/src/main/java/org/hibernate/jmx/internal/JmxServiceImpl.java b/hibernate-core/src/main/java/org/hibernate/jmx/internal/JmxServiceImpl.java index e63ef9a63c5e..b155409eec76 100644 --- a/hibernate-core/src/main/java/org/hibernate/jmx/internal/JmxServiceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/jmx/internal/JmxServiceImpl.java @@ -19,6 +19,7 @@ import org.hibernate.cfg.Environment; import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreMessageLogger; +import org.hibernate.internal.log.DeprecationLogger; import org.hibernate.internal.util.config.ConfigurationHelper; import org.hibernate.jmx.spi.JmxService; import org.hibernate.service.Service; @@ -119,6 +120,12 @@ public void stop() { @Override public void registerService(Manageable service, Class serviceRole) { + if ( service == null ) { + return; + } + + DeprecationLogger.DEPRECATION_LOGGER.deprecatedJmxManageableServiceRegistration( service.getClass().getName() ); + if ( OptionallyManageable.class.isInstance( service ) ) { for ( Manageable realManageable : ( (OptionallyManageable) service ).getRealManageables() ) { registerService( realManageable,serviceRole ); @@ -151,6 +158,8 @@ public void registerService(Manageable service, Class service @Override public void registerMBean(ObjectName objectName, Object mBean) { + DeprecationLogger.DEPRECATION_LOGGER.deprecatedJmxBeanRegistration( mBean.getClass().getName() ); + MBeanServer mBeanServer = findServer(); if ( mBeanServer == null ) { if ( startedServer ) { diff --git a/hibernate-core/src/main/java/org/hibernate/jmx/internal/JmxServiceInitiator.java b/hibernate-core/src/main/java/org/hibernate/jmx/internal/JmxServiceInitiator.java index 6c16036854d7..b8c371bb4773 100644 --- a/hibernate-core/src/main/java/org/hibernate/jmx/internal/JmxServiceInitiator.java +++ b/hibernate-core/src/main/java/org/hibernate/jmx/internal/JmxServiceInitiator.java @@ -10,6 +10,7 @@ import org.hibernate.boot.registry.StandardServiceInitiator; import org.hibernate.cfg.AvailableSettings; +import org.hibernate.internal.log.DeprecationLogger; import org.hibernate.internal.util.config.ConfigurationHelper; import org.hibernate.jmx.spi.JmxService; import org.hibernate.service.spi.ServiceRegistryImplementor; @@ -29,8 +30,10 @@ public Class getServiceInitiated() { @Override public JmxService initiateService(Map configurationValues, ServiceRegistryImplementor registry) { - return ConfigurationHelper.getBoolean( AvailableSettings.JMX_ENABLED, configurationValues, false ) - ? new JmxServiceImpl( configurationValues ) - : DisabledJmxServiceImpl.INSTANCE; + if ( ConfigurationHelper.getBoolean( AvailableSettings.JMX_ENABLED, configurationValues, false ) ) { + DeprecationLogger.DEPRECATION_LOGGER.deprecatedJmxSupport( AvailableSettings.JMX_ENABLED ); + return new JmxServiceImpl( configurationValues ); + } + return DisabledJmxServiceImpl.INSTANCE; } } diff --git a/hibernate-core/src/main/java/org/hibernate/jmx/spi/JmxService.java b/hibernate-core/src/main/java/org/hibernate/jmx/spi/JmxService.java index 5050696583c0..94e3383c3dd4 100644 --- a/hibernate-core/src/main/java/org/hibernate/jmx/spi/JmxService.java +++ b/hibernate-core/src/main/java/org/hibernate/jmx/spi/JmxService.java @@ -15,7 +15,11 @@ * Service providing simplified access to JMX related features needed by Hibernate. * * @author Steve Ebersole + * + * @deprecated Scheduled for removal in 6.0; see https://hibernate.atlassian.net/browse/HHH-14847 + * and https://hibernate.atlassian.net/browse/HHH-14846 */ +@Deprecated public interface JmxService extends Service { /** * Handles registration of a manageable service. diff --git a/hibernate-core/src/main/java/org/hibernate/service/spi/Manageable.java b/hibernate-core/src/main/java/org/hibernate/service/spi/Manageable.java index afc47301bc4d..16fdda7e93a3 100644 --- a/hibernate-core/src/main/java/org/hibernate/service/spi/Manageable.java +++ b/hibernate-core/src/main/java/org/hibernate/service/spi/Manageable.java @@ -10,7 +10,11 @@ * Optional {@link org.hibernate.service.Service} contract for services which can be managed in JMX * * @author Steve Ebersole + * + * @deprecated Scheduled for removal in 6.0; see https://hibernate.atlassian.net/browse/HHH-14847 + * and https://hibernate.atlassian.net/browse/HHH-14846 */ +@Deprecated public interface Manageable { /** * Get the domain name to be used in registering the management bean. May be {@code null} to indicate Hibernate's From 2ec769b5e410e71123754f81bf8911b4fac9f174 Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Wed, 29 Sep 2021 13:46:39 +0000 Subject: [PATCH 338/644] 5.6.0.CR1 --- changelog.txt | 16 ++++++++++++++++ gradle/version.properties | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index d907d10be4b9..c464d96e7164 100644 --- a/changelog.txt +++ b/changelog.txt @@ -3,6 +3,22 @@ Hibernate 5 Changelog Note: Please refer to JIRA to learn more about each issue. +Changes in 5.6.0.CR1 (September 29, 2021) +------------------------------------------------------------------------------------------------------------------------ + +https://hibernate.atlassian.net/projects/HHH/versions/31986 + +** Bug + * [HHH-14852] - Upgrade GraalVM to version 21.2.0 + +** Deprecation + * [HHH-14847] - Deprecate JMX integration + * [HHH-14845] - Deprecate JACC integration + +** Task + * [HHH-14835] - More changes to support SchemaMigrator/SchemaValidator using Hibernate Reactive + + Changes in 5.6.0.Beta2 (September 20, 2021) ------------------------------------------------------------------------------------------------------------------------ diff --git a/gradle/version.properties b/gradle/version.properties index b6875391f169..76881bc8b65c 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -hibernateVersion=5.6.0-SNAPSHOT \ No newline at end of file +hibernateVersion=5.6.0.CR1 \ No newline at end of file From 2396dfbb3d4b606916c8407403c9f9b95d9d9b35 Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Wed, 29 Sep 2021 13:51:37 +0000 Subject: [PATCH 339/644] 5.6.0-SNAPSHOT --- gradle/version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/version.properties b/gradle/version.properties index 76881bc8b65c..b6875391f169 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -hibernateVersion=5.6.0.CR1 \ No newline at end of file +hibernateVersion=5.6.0-SNAPSHOT \ No newline at end of file From 7906a27b6ae1218ceadd8d55deb2c911d14a80f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Fri, 8 Oct 2021 16:30:12 +0200 Subject: [PATCH 340/644] HHH-13295 Always perform @MapsId's second pass after entity ID second passes --- .../internal/InFlightMetadataCollectorImpl.java | 15 --------------- .../cfg/PkDrivenByDefaultMapsIdSecondPass.java | 16 +++++++++++++++- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java index fdb5caad8eee..b362de7fc5b7 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java @@ -62,7 +62,6 @@ import org.hibernate.cfg.FkSecondPass; import org.hibernate.cfg.IdGeneratorResolverSecondPass; import org.hibernate.cfg.JPAIndexHolder; -import org.hibernate.cfg.PkDrivenByDefaultMapsIdSecondPass; import org.hibernate.cfg.PropertyData; import org.hibernate.cfg.QuerySecondPass; import org.hibernate.cfg.RecoverableException; @@ -1504,7 +1503,6 @@ public Join locateJoin(Identifier tableName) { } private ArrayList idGeneratorResolverSecondPassList; - private ArrayList pkDrivenByDefaultMapsIdSecondPassList; private ArrayList setSimpleValueTypeSecondPassList; private ArrayList copyIdentifierComponentSecondPasList; private ArrayList fkSecondPassList; @@ -1525,9 +1523,6 @@ public void addSecondPass(SecondPass secondPass, boolean onTopOfTheQueue) { if ( secondPass instanceof IdGeneratorResolverSecondPass ) { addIdGeneratorResolverSecondPass( (IdGeneratorResolverSecondPass) secondPass, onTopOfTheQueue ); } - else if ( secondPass instanceof PkDrivenByDefaultMapsIdSecondPass ) { - addPkDrivenByDefaultMapsIdSecondPass( (PkDrivenByDefaultMapsIdSecondPass) secondPass, onTopOfTheQueue ); - } else if ( secondPass instanceof SetSimpleValueTypeSecondPass ) { addSetSimpleValueTypeSecondPass( (SetSimpleValueTypeSecondPass) secondPass, onTopOfTheQueue ); } @@ -1558,15 +1553,6 @@ else if ( secondPass instanceof ImplicitColumnNamingSecondPass ) { } } - private void addPkDrivenByDefaultMapsIdSecondPass( - PkDrivenByDefaultMapsIdSecondPass secondPass, - boolean onTopOfTheQueue) { - if ( pkDrivenByDefaultMapsIdSecondPassList == null ) { - pkDrivenByDefaultMapsIdSecondPassList = new ArrayList<>(); - } - addSecondPass( secondPass, pkDrivenByDefaultMapsIdSecondPassList, onTopOfTheQueue ); - } - private void addSecondPass(T secondPass, ArrayList secondPassList, boolean onTopOfTheQueue) { if ( onTopOfTheQueue ) { secondPassList.add( 0, secondPass ); @@ -1647,7 +1633,6 @@ public void processSecondPasses(MetadataBuildingContext buildingContext) { try { processSecondPasses( idGeneratorResolverSecondPassList ); processSecondPasses( implicitColumnNamingSecondPassList ); - processSecondPasses( pkDrivenByDefaultMapsIdSecondPassList ); processSecondPasses( setSimpleValueTypeSecondPassList ); processCopyIdentifierSecondPassesInOrder(); diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/PkDrivenByDefaultMapsIdSecondPass.java b/hibernate-core/src/main/java/org/hibernate/cfg/PkDrivenByDefaultMapsIdSecondPass.java index ca4ac36e28a7..07f69c89d20f 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/PkDrivenByDefaultMapsIdSecondPass.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/PkDrivenByDefaultMapsIdSecondPass.java @@ -16,17 +16,31 @@ /** * @author Emmanuel Bernard */ -public class PkDrivenByDefaultMapsIdSecondPass implements SecondPass { +public class PkDrivenByDefaultMapsIdSecondPass extends FkSecondPass { private final String referencedEntityName; private final Ejb3JoinColumn[] columns; private final SimpleValue value; public PkDrivenByDefaultMapsIdSecondPass(String referencedEntityName, Ejb3JoinColumn[] columns, SimpleValue value) { + super( value, columns ); this.referencedEntityName = referencedEntityName; this.columns = columns; this.value = value; } + @Override + public String getReferencedEntityName() { + return referencedEntityName; + } + + @Override + public boolean isInPrimaryKey() { + // @MapsId is not itself in the primary key, + // so it's safe to simply process it after all the primary keys have been processed. + return true; + } + + @Override public void doSecondPass(Map persistentClasses) throws MappingException { PersistentClass referencedEntity = (PersistentClass) persistentClasses.get( referencedEntityName ); if ( referencedEntity == null ) { From 88a0afc8e285f0ef70f867205027fcc6e85732f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Fri, 8 Oct 2021 16:03:07 +0200 Subject: [PATCH 341/644] HHH-13295 Test @EmbeddedId + @MapsId targeting a derived entity --- ...dWithMapsIdTargetingDerivedEntityTest.java | 227 ++++++++++++++++++ 1 file changed, 227 insertions(+) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/ecid/EmbeddedIdWithMapsIdTargetingDerivedEntityTest.java diff --git a/hibernate-core/src/test/java/org/hibernate/test/ecid/EmbeddedIdWithMapsIdTargetingDerivedEntityTest.java b/hibernate-core/src/test/java/org/hibernate/test/ecid/EmbeddedIdWithMapsIdTargetingDerivedEntityTest.java new file mode 100644 index 000000000000..4b0507a4e62a --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/ecid/EmbeddedIdWithMapsIdTargetingDerivedEntityTest.java @@ -0,0 +1,227 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.test.ecid; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hibernate.test.util.SchemaUtil.getColumnNames; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import javax.persistence.Column; +import javax.persistence.Embeddable; +import javax.persistence.EmbeddedId; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.Id; +import javax.persistence.Inheritance; +import javax.persistence.InheritanceType; +import javax.persistence.ManyToOne; +import javax.persistence.MapsId; +import javax.persistence.OneToMany; +import javax.persistence.Table; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; +import org.junit.Test; + +/** + * Test that bootstrap doesn't throw an exception + * when an entity has an {@link EmbeddedId} and a {@link MapsId} that references a derived identity. + *

    + * This test used to fail on bootstrap with the following error: + *

    + * java.util.NoSuchElementException + * at java.base/java.util.ArrayList$Itr.next(ArrayList.java:1000) + * at org.hibernate.cfg.annotations.TableBinder.linkJoinColumnWithValueOverridingNameIfImplicit(TableBinder.java:714) + * at org.hibernate.cfg.PkDrivenByDefaultMapsIdSecondPass.doSecondPass(PkDrivenByDefaultMapsIdSecondPass.java:37) + * at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1693) + * at org.hibernate.boot.internal.InFlightMetadataCollectorImpl.processSecondPasses(InFlightMetadataCollectorImpl.java:1650) + * at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:295) + * at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.build(MetadataBuildingProcess.java:86) + * at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:479) + * at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:85) + * at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:709) + * at org.hibernate.testing.junit4.BaseCoreFunctionalTestCase.buildSessionFactory(BaseCoreFunctionalTestCase.java:125) + * at org.hibernate.testing.junit4.BaseCoreFunctionalTestCase.buildSessionFactory(BaseCoreFunctionalTestCase.java:110) + * at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + * at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) + * at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + * at java.base/java.lang.reflect.Method.invoke(Method.java:566) + * at org.hibernate.testing.junit4.TestClassMetadata.performCallbackInvocation(TestClassMetadata.java:205) + */ +@TestForIssue(jiraKey = "HHH-13295") +public class EmbeddedIdWithMapsIdTargetingDerivedEntityTest extends BaseNonConfigCoreFunctionalTestCase { + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { Attendance.class, AttendanceId.class, Lecture.class, Student.class, User.class }; + } + + @Test + public void metadataTest() { + assertThat( getColumnNames( "attendance", metadata() ) ) + // Just check we're using @MapsId; otherwise the test wouldn't be able to reproduce HHH-13295. + .containsExactlyInAnyOrder( "student_id", "lecture_id" ); + } + + // The main goal of the test is to check that bootstrap doesn't throw an exception, + // but it feels wrong to have a test class with just an empty test method, + // so just check that persisting/loading works correctly. + @Test + public void smokeTest() { + inTransaction( s -> { + Lecture lecture = new Lecture( 1L ); + s.persist( lecture ); + Student student = new Student( 2L ); + s.persist( student ); + Attendance attendance = new Attendance( lecture, student ); + student.getAttendances().add( attendance ); + lecture.getAttendances().add( attendance ); + s.persist( attendance ); + } ); + + inTransaction( s -> { + Attendance attendance = s.get( Attendance.class, new AttendanceId( 1L, 2L ) ); + assertThat( attendance.getId() ) + .extracting( AttendanceId::getLectureId ) + .isEqualTo( 1L ); + assertThat( attendance.getId() ) + .extracting( AttendanceId::getStudentId ) + .isEqualTo( 2L ); + assertThat( attendance.getLecture() ) + .extracting( Lecture::getId ) + .isEqualTo( 1L ); + assertThat( attendance.getStudent() ) + .extracting( Student::getId ) + .isEqualTo( 2L ); + } ); + } + + @Entity + @Table(name = "attendance") + public static class Attendance { + @EmbeddedId + private AttendanceId id; + + @ManyToOne(fetch = FetchType.LAZY) + @MapsId("lectureId") + private Lecture lecture; + + @ManyToOne(fetch = FetchType.LAZY) + @MapsId("studentId") + private Student student; + + Attendance() { + } + + public Attendance(Lecture lecture, Student student) { + this.id = new AttendanceId( lecture.getId(), student.getId() ); + this.lecture = lecture; + this.student = student; + } + + public AttendanceId getId() { + return id; + } + + public Lecture getLecture() { + return lecture; + } + + public Student getStudent() { + return student; + } + } + + @Embeddable + public static class AttendanceId implements Serializable { + @Column + private Long lectureId; + + @Column + private Long studentId; + + AttendanceId() { + } + + public AttendanceId(Long lectureId, Long studentId) { + this.lectureId = lectureId; + this.studentId = studentId; + } + + public Long getLectureId() { + return lectureId; + } + + public Long getStudentId() { + return studentId; + } + } + + @Entity + @Table(name = "users") + @Inheritance(strategy = InheritanceType.JOINED) + public static abstract class User { + @Id + private Long id; + + User() { + } + + public User(Long id) { + this.id = id; + } + + public Long getId() { + return id; + } + } + + @Entity + @Table(name = "student") + public static class Student extends User { + @OneToMany(mappedBy = "student", fetch = FetchType.LAZY) + private List attendances = new ArrayList<>(); + + Student() { + } + + public Student(Long id) { + super( id ); + } + + public List getAttendances() { + return attendances; + } + } + + @Entity + @Table(name = "lecture") + public static class Lecture { + @Id + private Long id; + + @OneToMany(mappedBy = "lecture", fetch = FetchType.LAZY) + private List attendances = new ArrayList<>(); + + Lecture() { + } + + public Lecture(Long id) { + this.id = id; + } + + public Long getId() { + return id; + } + + public List getAttendances() { + return attendances; + } + } +} From 34a9fa2e5582859de2520b7873f3192a23bc5df1 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Mon, 11 Oct 2021 11:36:08 +0100 Subject: [PATCH 342/644] HHH-14868 Upgrade to ByteBuddy 1.11.20 --- gradle/libraries.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libraries.gradle b/gradle/libraries.gradle index 11fe8b853b12..1b74f018c203 100644 --- a/gradle/libraries.gradle +++ b/gradle/libraries.gradle @@ -24,7 +24,7 @@ ext { weldVersion = '3.1.5.Final' jakartaWeldVersion = '4.0.1.SP1' - byteBuddyVersion = '1.11.16' + byteBuddyVersion = '1.11.20' agroalVersion = '1.9' From 48068e0311e99b31636cad15daf9631f9221eb94 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Wed, 29 Sep 2021 01:37:48 -0500 Subject: [PATCH 343/644] HHH-14857 Deprecations in preparation for 6 --- .../userguide/collections/MapKeyTypeTest.java | 2 +- ...ityTypeChangeAuditDefaultTrackingTest.java | 2 +- .../envers/EntityTypeChangeAuditTest.java | 2 +- ...angeAuditTrackingRevisionListenerTest.java | 2 +- .../envers/ValidityStrategyAuditTest.java | 1 - .../org/hibernate/annotations/AnyMetaDef.java | 3 + .../hibernate/annotations/AnyMetaDefs.java | 3 + .../hibernate/annotations/CollectionId.java | 8 +- .../hibernate/annotations/CollectionType.java | 3 + .../org/hibernate/annotations/MapKeyType.java | 3 + .../java/org/hibernate/annotations/Type.java | 3 + .../org/hibernate/annotations/TypeDef.java | 3 + .../org/hibernate/annotations/TypeDefs.java | 3 + .../hibernate/boot/internal/MetadataImpl.java | 36 +++-- .../SessionFactoryOptionsBuilder.java | 82 ++++++---- .../boot/spi/SessionFactoryOptions.java | 5 + .../org/hibernate/cfg/AvailableSettings.java | 62 ++++++++ .../cfg/annotations/IdBagBinder.java | 16 +- .../internal/FastSessionServices.java | 39 +++-- .../org/hibernate/internal/SessionImpl.java | 22 ++- .../org/hibernate/jpa/AvailableSettings.java | 48 ++++-- .../jpa/HibernateEntityManagerFactory.java | 17 +- .../EntityManagerFactoryBuilderImpl.java | 150 ++++++++++++++---- .../query/procedure/ProcedureParameter.java | 4 + .../internal/CdiBeanContainerBuilder.java | 19 ++- .../hibernate/cfg/CfgFilePropertyTest.java | 2 +- .../BaseEntityManagerFunctionalTestCase.java | 6 +- .../test/EntityManagerFactoryClosedTest.java | 2 +- .../hibernate/jpa/test/EntityManagerTest.java | 2 +- .../ValidatorFactory2PhaseInjectionTest.java | 2 +- .../annotation/ConfigurationTest.java | 11 +- .../cacheable/api/JpaCacheApiUsageTest.java | 10 +- .../cachemodes/SharedCacheModesTest.java | 58 +++---- .../hbmxml/MappingClassMoreThanOnceTest.java | 4 +- .../test/cdi/NoCdiAvailableTestDelegate.java | 2 +- ...eDiscardPersistenceContextOnCloseTest.java | 2 +- ...eDiscardPersistenceContextOnCloseTest.java | 4 +- .../ejb3configuration/InterceptorTest.java | 13 +- .../PersisterClassProviderTest.java | 2 +- .../SessionFactoryObserverTest.java | 13 +- ...entifierGeneratorStrategyProviderTest.java | 2 +- .../org/hibernate/jpa/test/lock/LockTest.java | 26 +-- .../test/lock/LockTimeoutPropertyTest.java | 10 +- .../jpa/test/lock/QueryLockingTest.java | 4 +- .../MappedSuperclassWithAttributesTest.java | 2 +- .../MappedSuperclassWithEmbeddedTest.java | 7 +- .../MappedSuperclassWithEmbeddedIdTest.java | 7 +- ...edSuperclassWithEntityWithIdClassTest.java | 7 +- ...SuperclassWithOverriddenAttributeTest.java | 2 +- .../jpa/test/ops/RemoveOrderingTest.java | 4 +- .../packaging/PackagedEntityManagerTest.java | 5 +- ...TwoPersistenceUnits2LCDisabledEnabled.java | 2 +- .../test/procedure/DateTimeParameterTest.java | 2 +- .../jpa/test/procedure/JpaTckUsageTest.java | 2 +- .../jpa/test/query/CachedQueryTest.java | 13 +- ...DropUtf8WithoutHbm2DdlCharsetNameTest.java | 14 +- ...hemaDatabaseFileGenerationFailureTest.java | 4 +- ...SchemaScriptFileGenerationFailureTest.java | 6 +- .../SchemaScriptFileGenerationTest.java | 9 +- ...ntityManagerWithActiveTransactionTest.java | 6 +- .../JtaGetTransactionThrowsExceptionTest.java | 6 +- .../transaction/SynchronizationTypeTest.java | 4 +- .../transaction/TransactionJoiningTest.java | 4 +- ...actionRolledBackInDifferentThreadTest.java | 10 +- .../org/hibernate/jpa/test/xml/XmlTest.java | 4 +- .../jpa/PersistenceUnitOverridesTests.java | 4 +- .../idbag/IdBagElementNullBasicTest.java | 5 +- ...paOrNativeBootstrapFunctionalTestCase.java | 10 +- .../test/BaseEnversJPAFunctionalTestCase.java | 21 ++- .../AbstractEntityManagerTest.java | 6 +- 70 files changed, 594 insertions(+), 285 deletions(-) diff --git a/documentation/src/test/java/org/hibernate/userguide/collections/MapKeyTypeTest.java b/documentation/src/test/java/org/hibernate/userguide/collections/MapKeyTypeTest.java index 67c80a2e4b39..7cb01e72ef08 100644 --- a/documentation/src/test/java/org/hibernate/userguide/collections/MapKeyTypeTest.java +++ b/documentation/src/test/java/org/hibernate/userguide/collections/MapKeyTypeTest.java @@ -69,7 +69,7 @@ public void testLifecycle() { try { Map settings = buildSettings(); settings.put( - org.hibernate.jpa.AvailableSettings.LOADED_CLASSES, + org.hibernate.cfg.AvailableSettings.LOADED_CLASSES, Collections.singletonList( Person.class ) diff --git a/documentation/src/test/java/org/hibernate/userguide/envers/EntityTypeChangeAuditDefaultTrackingTest.java b/documentation/src/test/java/org/hibernate/userguide/envers/EntityTypeChangeAuditDefaultTrackingTest.java index 2f94703a7de7..f397cd758455 100644 --- a/documentation/src/test/java/org/hibernate/userguide/envers/EntityTypeChangeAuditDefaultTrackingTest.java +++ b/documentation/src/test/java/org/hibernate/userguide/envers/EntityTypeChangeAuditDefaultTrackingTest.java @@ -59,7 +59,7 @@ public void testLifecycle() { try { Map settings = buildSettings(); settings.put( - org.hibernate.jpa.AvailableSettings.LOADED_CLASSES, + AvailableSettings.LOADED_CLASSES, Arrays.asList( ApplicationCustomer.class, CustomTrackingRevisionEntity.class diff --git a/documentation/src/test/java/org/hibernate/userguide/envers/EntityTypeChangeAuditTest.java b/documentation/src/test/java/org/hibernate/userguide/envers/EntityTypeChangeAuditTest.java index 2bf61b6040dc..b6fc6d3bdc5e 100644 --- a/documentation/src/test/java/org/hibernate/userguide/envers/EntityTypeChangeAuditTest.java +++ b/documentation/src/test/java/org/hibernate/userguide/envers/EntityTypeChangeAuditTest.java @@ -83,7 +83,7 @@ public void test() { try { Map settings = buildSettings(); settings.put( - org.hibernate.jpa.AvailableSettings.LOADED_CLASSES, + AvailableSettings.LOADED_CLASSES, Arrays.asList( ApplicationCustomer.class, CustomTrackingRevisionEntity.class diff --git a/documentation/src/test/java/org/hibernate/userguide/envers/EntityTypeChangeAuditTrackingRevisionListenerTest.java b/documentation/src/test/java/org/hibernate/userguide/envers/EntityTypeChangeAuditTrackingRevisionListenerTest.java index 2ed026030d02..02479e8ccf1f 100644 --- a/documentation/src/test/java/org/hibernate/userguide/envers/EntityTypeChangeAuditTrackingRevisionListenerTest.java +++ b/documentation/src/test/java/org/hibernate/userguide/envers/EntityTypeChangeAuditTrackingRevisionListenerTest.java @@ -75,7 +75,7 @@ public void testLifecycle() { try { Map settings = buildSettings(); settings.put( - org.hibernate.jpa.AvailableSettings.LOADED_CLASSES, + AvailableSettings.LOADED_CLASSES, Arrays.asList( ApplicationCustomer.class, CustomTrackingRevisionEntity.class, diff --git a/documentation/src/test/java/org/hibernate/userguide/envers/ValidityStrategyAuditTest.java b/documentation/src/test/java/org/hibernate/userguide/envers/ValidityStrategyAuditTest.java index 468a66b79252..3a5688b59d69 100644 --- a/documentation/src/test/java/org/hibernate/userguide/envers/ValidityStrategyAuditTest.java +++ b/documentation/src/test/java/org/hibernate/userguide/envers/ValidityStrategyAuditTest.java @@ -21,7 +21,6 @@ import org.hibernate.envers.Audited; import org.hibernate.envers.configuration.EnversSettings; import org.hibernate.envers.strategy.ValidityAuditStrategy; -import org.hibernate.jpa.AvailableSettings; import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; import org.junit.Test; diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/AnyMetaDef.java b/hibernate-core/src/main/java/org/hibernate/annotations/AnyMetaDef.java index 30b6a21e6063..b6180c47118c 100644 --- a/hibernate-core/src/main/java/org/hibernate/annotations/AnyMetaDef.java +++ b/hibernate-core/src/main/java/org/hibernate/annotations/AnyMetaDef.java @@ -22,7 +22,10 @@ * * @author Emmanuel Bernard * @author Steve Ebersole + * + * @deprecated To be removed in 6.0 */ +@Deprecated @java.lang.annotation.Target( { PACKAGE, TYPE, METHOD, FIELD } ) @Retention( RUNTIME ) @Repeatable(AnyMetaDefs.class) diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/AnyMetaDefs.java b/hibernate-core/src/main/java/org/hibernate/annotations/AnyMetaDefs.java index 6c9364dc4080..c276d1e1f663 100644 --- a/hibernate-core/src/main/java/org/hibernate/annotations/AnyMetaDefs.java +++ b/hibernate-core/src/main/java/org/hibernate/annotations/AnyMetaDefs.java @@ -17,9 +17,12 @@ * * @author Emmanuel Bernard * @author Steve Ebersole + * + * @deprecated To be removed in 6.0 */ @java.lang.annotation.Target( { PACKAGE, TYPE } ) @Retention( RUNTIME ) +@Deprecated public @interface AnyMetaDefs { /** * The collective set of any meta-defs. diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/CollectionId.java b/hibernate-core/src/main/java/org/hibernate/annotations/CollectionId.java index 4bdecabe92b5..7fdbd9958a52 100644 --- a/hibernate-core/src/main/java/org/hibernate/annotations/CollectionId.java +++ b/hibernate-core/src/main/java/org/hibernate/annotations/CollectionId.java @@ -26,8 +26,14 @@ public @interface CollectionId { /** * Collection id column(s). + * + * @deprecated Only basic (single column) collection-ids are supported. + * Use {@link #column} instead */ - Column[] columns(); + @Deprecated + Column[] columns() default {}; + + Column column() default @Column; /** * id type, type.type() must be set. diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/CollectionType.java b/hibernate-core/src/main/java/org/hibernate/annotations/CollectionType.java index 0bd221dbf904..3a2706f3697e 100644 --- a/hibernate-core/src/main/java/org/hibernate/annotations/CollectionType.java +++ b/hibernate-core/src/main/java/org/hibernate/annotations/CollectionType.java @@ -20,9 +20,12 @@ * @see org.hibernate.usertype.UserCollectionType * * @author Steve Ebersole + * + * @deprecated Custom handling for "collection types" will be handled differently in 6.0 */ @java.lang.annotation.Target({FIELD, METHOD}) @Retention(RUNTIME) +@Deprecated public @interface CollectionType { /** * Names the type. diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/MapKeyType.java b/hibernate-core/src/main/java/org/hibernate/annotations/MapKeyType.java index edc9aa3696a1..36c9ad61b2e8 100644 --- a/hibernate-core/src/main/java/org/hibernate/annotations/MapKeyType.java +++ b/hibernate-core/src/main/java/org/hibernate/annotations/MapKeyType.java @@ -16,9 +16,12 @@ * Allows defining the type of the key of a persistent map. * * @author Steve Ebersole + * + * @deprecated 6.0 will introduce a new type-safe {@code CustomType} annotation */ @java.lang.annotation.Target({METHOD, FIELD}) @Retention(RUNTIME) +@Deprecated public @interface MapKeyType { /** * The map key type definition. diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/Type.java b/hibernate-core/src/main/java/org/hibernate/annotations/Type.java index 8b8e40ea172b..3290021b77c8 100644 --- a/hibernate-core/src/main/java/org/hibernate/annotations/Type.java +++ b/hibernate-core/src/main/java/org/hibernate/annotations/Type.java @@ -24,9 +24,12 @@ * * @author Emmanuel Bernard * @author Steve Ebersole + * + * @deprecated 6.0 will introduce a new type-safe {@code CustomType} annotation */ @Target({FIELD, METHOD}) @Retention(RUNTIME) +@Deprecated public @interface Type { /** * The Hibernate type name. Usually the fully qualified name of an implementation class for diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/TypeDef.java b/hibernate-core/src/main/java/org/hibernate/annotations/TypeDef.java index 4810824de0e6..51f7c8abe7d4 100644 --- a/hibernate-core/src/main/java/org/hibernate/annotations/TypeDef.java +++ b/hibernate-core/src/main/java/org/hibernate/annotations/TypeDef.java @@ -28,10 +28,13 @@ * * @author Emmanuel Bernard * @author Steve Ebersole + * + * @deprecated 6.0 will introduce a new series of type-safe annotations to serve the same purpose */ @Target({TYPE, PACKAGE}) @Retention(RUNTIME) @Repeatable(TypeDefs.class) +@Deprecated public @interface TypeDef { /** * The type name. This is the name that would be used in other locations. diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/TypeDefs.java b/hibernate-core/src/main/java/org/hibernate/annotations/TypeDefs.java index 6f05951eafc4..cdc175b0e282 100644 --- a/hibernate-core/src/main/java/org/hibernate/annotations/TypeDefs.java +++ b/hibernate-core/src/main/java/org/hibernate/annotations/TypeDefs.java @@ -18,9 +18,12 @@ * * @author Emmanuel Bernard * @author Steve Ebersole + * + * @deprecated 6.0 will introduce a new series of type-safe annotations to serve the same purpose */ @Target({TYPE, PACKAGE}) @Retention(RUNTIME) +@Deprecated public @interface TypeDefs { /** * The grouping of type definitions. diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/MetadataImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/MetadataImpl.java index 9b524ffb4211..0e31e27b9c64 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/MetadataImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/MetadataImpl.java @@ -46,6 +46,9 @@ import org.hibernate.event.spi.EventType; import org.hibernate.id.factory.spi.MutableIdentifierGeneratorFactory; import org.hibernate.internal.SessionFactoryImpl; +import org.hibernate.internal.log.DeprecationLogger; +import org.hibernate.internal.util.NullnessHelper; +import org.hibernate.jpa.AvailableSettings; import org.hibernate.mapping.Collection; import org.hibernate.mapping.FetchProfile; import org.hibernate.mapping.MappedSuperclass; @@ -59,6 +62,8 @@ import org.hibernate.type.TypeResolver; import org.hibernate.type.spi.TypeConfiguration; +import static org.hibernate.cfg.AvailableSettings.EVENT_LISTENER_PREFIX; + /** * Container for configuration data collected during binding the metamodel. * @@ -376,21 +381,32 @@ public void initSessionFactory(SessionFactoryImplementor sessionFactory) { final ConfigurationService cfgService = sessionFactoryServiceRegistry.getService( ConfigurationService.class ); final ClassLoaderService classLoaderService = sessionFactoryServiceRegistry.getService( ClassLoaderService.class ); - for ( Map.Entry entry : ( (Map) cfgService.getSettings() ).entrySet() ) { + for ( Map.Entry entry : ( (Map) cfgService.getSettings() ).entrySet() ) { if ( !String.class.isInstance( entry.getKey() ) ) { continue; } final String propertyName = (String) entry.getKey(); - if ( !propertyName.startsWith( org.hibernate.jpa.AvailableSettings.EVENT_LISTENER_PREFIX ) ) { - continue; - } - final String eventTypeName = propertyName.substring( - org.hibernate.jpa.AvailableSettings.EVENT_LISTENER_PREFIX.length() + 1 + final String listenerPrefix = NullnessHelper.coalesceSuppliedValues( + () -> propertyName.startsWith( EVENT_LISTENER_PREFIX ) ? EVENT_LISTENER_PREFIX : null, + () -> { + if ( propertyName.startsWith( AvailableSettings.EVENT_LISTENER_PREFIX ) ) { + DeprecationLogger.DEPRECATION_LOGGER.deprecatedSetting( + AvailableSettings.EVENT_LISTENER_PREFIX, + EVENT_LISTENER_PREFIX + ); + return AvailableSettings.EVENT_LISTENER_PREFIX; + } + return null; + }, + () -> null ); - final EventType eventType = EventType.resolveEventTypeByName( eventTypeName ); - final EventListenerGroup eventListenerGroup = eventListenerRegistry.getEventListenerGroup( eventType ); - for ( String listenerImpl : LISTENER_SEPARATION_PATTERN.split( ( (String) entry.getValue() ) ) ) { - eventListenerGroup.appendListener( instantiate( listenerImpl, classLoaderService ) ); + if ( listenerPrefix != null ) { + final String eventTypeName = propertyName.substring( listenerPrefix.length() + 1 ); + final EventType eventType = EventType.resolveEventTypeByName( eventTypeName ); + final EventListenerGroup eventListenerGroup = eventListenerRegistry.getEventListenerGroup( eventType ); + for ( String listenerImpl : LISTENER_SEPARATION_PATTERN.split( ( (String) entry.getValue() ) ) ) { + eventListenerGroup.appendListener( instantiate( listenerImpl, classLoaderService ) ); + } } } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java index 2f8bf765a9bc..ac6163fdfad6 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java @@ -49,6 +49,7 @@ import org.hibernate.id.uuid.LocalObjectUuidHelper; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.log.DeprecationLogger; +import org.hibernate.internal.util.NullnessHelper; import org.hibernate.internal.util.config.ConfigurationHelper; import org.hibernate.jpa.spi.JpaCompliance; import org.hibernate.jpa.spi.MutableJpaCompliance; @@ -93,6 +94,7 @@ import static org.hibernate.cfg.AvailableSettings.IN_CLAUSE_PARAMETER_PADDING; import static org.hibernate.cfg.AvailableSettings.JDBC_TIME_ZONE; import static org.hibernate.cfg.AvailableSettings.JDBC_TYLE_PARAMS_ZERO_BASE; +import static org.hibernate.cfg.AvailableSettings.JPA_CALLBACKS_ENABLED; import static org.hibernate.cfg.AvailableSettings.JTA_TRACK_BY_THREAD; import static org.hibernate.cfg.AvailableSettings.LOG_SESSION_METRICS; import static org.hibernate.cfg.AvailableSettings.MAX_FETCH_DEPTH; @@ -100,12 +102,12 @@ import static org.hibernate.cfg.AvailableSettings.NATIVE_EXCEPTION_HANDLING_51_COMPLIANCE; import static org.hibernate.cfg.AvailableSettings.OMIT_JOIN_OF_SUPERCLASS_TABLES; import static org.hibernate.cfg.AvailableSettings.ORDER_INSERTS; -import static org.hibernate.cfg.AvailableSettings.JPA_CALLBACKS_ENABLED; import static org.hibernate.cfg.AvailableSettings.ORDER_UPDATES; import static org.hibernate.cfg.AvailableSettings.PREFER_USER_TRANSACTION; import static org.hibernate.cfg.AvailableSettings.PROCEDURE_NULL_PARAM_PASSING; import static org.hibernate.cfg.AvailableSettings.QUERY_CACHE_FACTORY; import static org.hibernate.cfg.AvailableSettings.QUERY_STARTUP_CHECKING; +import static org.hibernate.cfg.AvailableSettings.QUERY_STATISTICS_MAX_SIZE; import static org.hibernate.cfg.AvailableSettings.QUERY_SUBSTITUTIONS; import static org.hibernate.cfg.AvailableSettings.RELEASE_CONNECTIONS; import static org.hibernate.cfg.AvailableSettings.SESSION_FACTORY_NAME; @@ -114,7 +116,6 @@ import static org.hibernate.cfg.AvailableSettings.STATEMENT_BATCH_SIZE; import static org.hibernate.cfg.AvailableSettings.STATEMENT_FETCH_SIZE; import static org.hibernate.cfg.AvailableSettings.STATEMENT_INSPECTOR; -import static org.hibernate.cfg.AvailableSettings.QUERY_STATISTICS_MAX_SIZE; import static org.hibernate.cfg.AvailableSettings.USE_DIRECT_REFERENCE_CACHE_ENTRIES; import static org.hibernate.cfg.AvailableSettings.USE_GET_GENERATED_KEYS; import static org.hibernate.cfg.AvailableSettings.USE_IDENTIFIER_ROLLBACK; @@ -126,9 +127,9 @@ import static org.hibernate.cfg.AvailableSettings.USE_STRUCTURED_CACHE; import static org.hibernate.cfg.AvailableSettings.VALIDATE_QUERY_PARAMETERS; import static org.hibernate.cfg.AvailableSettings.WRAP_RESULT_SETS; +import static org.hibernate.cfg.AvailableSettings.DISCARD_PC_ON_CLOSE; import static org.hibernate.engine.config.spi.StandardConverters.BOOLEAN; import static org.hibernate.internal.CoreLogging.messageLogger; -import static org.hibernate.jpa.AvailableSettings.DISCARD_PC_ON_CLOSE; /** * In-flight state of {@link org.hibernate.boot.spi.SessionFactoryOptions} @@ -465,11 +466,25 @@ public SessionFactoryOptionsBuilder(StandardServiceRegistry serviceRegistry, Boo false ); - this.releaseResourcesOnCloseEnabled = ConfigurationHelper.getBoolean( - DISCARD_PC_ON_CLOSE, - configurationSettings, - false + this.releaseResourcesOnCloseEnabled = NullnessHelper.coalesceSuppliedValues( + () -> ConfigurationHelper.getBooleanWrapper( DISCARD_PC_ON_CLOSE, configurationSettings, null ), + () -> { + final Boolean oldSetting = ConfigurationHelper.getBooleanWrapper( + org.hibernate.jpa.AvailableSettings.DISCARD_PC_ON_CLOSE, + configurationSettings, + null + ); + if ( oldSetting != null ) { + DeprecationLogger.DEPRECATION_LOGGER.deprecatedSetting( + org.hibernate.jpa.AvailableSettings.DISCARD_PC_ON_CLOSE, + DISCARD_PC_ON_CLOSE + ); + } + return oldSetting; + }, + () -> false ); + Object jdbcTimeZoneValue = configurationSettings.get( JDBC_TIME_ZONE ); @@ -542,39 +557,40 @@ else if ( jdbcTimeZoneValue != null ) { @SuppressWarnings("deprecation") private static Interceptor determineInterceptor(Map configurationSettings, StrategySelector strategySelector) { - Object setting = configurationSettings.get( INTERCEPTOR ); - if ( setting == null ) { - // try the legacy (deprecated) JPA name - setting = configurationSettings.get( org.hibernate.jpa.AvailableSettings.INTERCEPTOR ); - if ( setting != null ) { - DeprecationLogger.DEPRECATION_LOGGER.deprecatedSetting( - org.hibernate.jpa.AvailableSettings.INTERCEPTOR, - INTERCEPTOR - ); - } - } - - return strategySelector.resolveStrategy( - Interceptor.class, - setting + final Object setting = NullnessHelper.coalesceSuppliedValues( + () -> configurationSettings.get( INTERCEPTOR ), + () -> { + final Object oldSetting = configurationSettings.get( org.hibernate.jpa.AvailableSettings.INTERCEPTOR ); + if ( oldSetting != null ) { + DeprecationLogger.DEPRECATION_LOGGER.deprecatedSetting( + org.hibernate.jpa.AvailableSettings.INTERCEPTOR, + INTERCEPTOR + ); + } + return oldSetting; + } ); + + return strategySelector.resolveStrategy( Interceptor.class, setting ); } @SuppressWarnings({"unchecked", "deprecation"}) private static Supplier determineStatelessInterceptor( Map configurationSettings, StrategySelector strategySelector) { - Object setting = configurationSettings.get( SESSION_SCOPED_INTERCEPTOR ); - if ( setting == null ) { - // try the legacy (deprecated) JPA name - setting = configurationSettings.get( org.hibernate.jpa.AvailableSettings.SESSION_INTERCEPTOR ); - if ( setting != null ) { - DeprecationLogger.DEPRECATION_LOGGER.deprecatedSetting( - org.hibernate.jpa.AvailableSettings.SESSION_INTERCEPTOR, - SESSION_SCOPED_INTERCEPTOR - ); - } - } + Object setting = NullnessHelper.coalesceSuppliedValues( + () -> configurationSettings.get( SESSION_SCOPED_INTERCEPTOR ), + () -> { + final Object oldSetting = configurationSettings.get( org.hibernate.jpa.AvailableSettings.SESSION_INTERCEPTOR ); + if ( oldSetting != null ) { + DeprecationLogger.DEPRECATION_LOGGER.deprecatedSetting( + org.hibernate.jpa.AvailableSettings.SESSION_INTERCEPTOR, + SESSION_SCOPED_INTERCEPTOR + ); + } + return oldSetting; + } + ); if ( setting == null ) { return null; diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java index 632abf1cb970..93cb7516128e 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java @@ -260,6 +260,11 @@ default boolean doesConnectionProviderDisableAutoCommit() { boolean isPreferUserTransaction(); + /** + * @deprecated with no replacement. See {@link org.hibernate.cfg.AvailableSettings#PROCEDURE_NULL_PARAM_PASSING} + * for details + */ + @Deprecated boolean isProcedureParameterNullPassingEnabled(); boolean isCollectionJoinSubqueryRewriteEnabled(); diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java index 49bc50d2dfd7..f4da85d6817a 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java @@ -881,6 +881,31 @@ public interface AvailableSettings extends org.hibernate.jpa.AvailableSettings { // SessionFactoryBuilder level settings // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + /** + * Event configuration should follow the following pattern + * hibernate.event.listener.[eventType] f.q.c.n.EventListener1, f.q.c.n.EventListener12 ... + */ + String EVENT_LISTENER_PREFIX = "hibernate.event.listener"; + + /** + * Used to pass along the name of the persistence unit. + */ + String PERSISTENCE_UNIT_NAME = "hibernate.persistenceUnitName"; + + /** + * SessionFactoryObserver class name, the class must have a no-arg constructor + */ + String SESSION_FACTORY_OBSERVER = "hibernate.session_factory_observer"; + + /** + * IdentifierGeneratorStrategyProvider class name, the class must have a no-arg constructor + * + * @deprecated with no replacement. Hooking in to Hibernate's id-generator determination + * will be done very differently in Hibernate 6 + */ + @Deprecated + String IDENTIFIER_GENERATOR_STRATEGY_PROVIDER = "hibernate.identifier_generator_strategy_provider"; + /** * Setting used to name the Hibernate {@link org.hibernate.SessionFactory}. * @@ -896,6 +921,13 @@ public interface AvailableSettings extends org.hibernate.jpa.AvailableSettings { */ String SESSION_FACTORY_NAME = "hibernate.session_factory_name"; + /** + * EntityManagerFactory name. Same purpose as {@value #SESSION_FACTORY_NAME} + * + * @see #SESSION_FACTORY_NAME + */ + String EMF_NAME = "hibernate.entitymanager_factory_name"; + /** * Does the value defined by {@link #SESSION_FACTORY_NAME} represent a JNDI namespace into which * the {@link org.hibernate.SessionFactory} should be bound and made accessible? @@ -910,6 +942,36 @@ public interface AvailableSettings extends org.hibernate.jpa.AvailableSettings { */ String SESSION_FACTORY_NAME_IS_JNDI = "hibernate.session_factory_name_is_jndi"; + /** + * Whether to discard persistent context on {@link org.hibernate.Session#close} / + * {@link javax.persistence.EntityManager#close}. + * + * The default (and spec compliant behavior) is false + */ + String DISCARD_PC_ON_CLOSE = "hibernate.discard_pc_on_close"; + + /** + * Used to specify a Hibernate {@code cfg.xml} config file + */ + String CFG_XML_FILE = "hibernate.cfg_xml_file"; + String HBM_XML_FILES = "hibernate.hbm_xml_files"; + String ORM_XML_FILES = "hibernate.orm_xml_files"; + String LOADED_CLASSES = "hibernate.loaded_classes"; + + /** + * Caching configuration should follow the following pattern + * {@code hibernate.ejb.classcache. usage[, region]} + * where usage is the cache strategy used and region the cache region name + */ + String CLASS_CACHE_PREFIX = "hibernate.classcache"; + + /** + * Caching configuration should follow the following pattern + * {@code hibernate.ejb.collectioncache.. usage[, region]} + * where usage is the cache strategy used and region the cache region name + */ + String COLLECTION_CACHE_PREFIX = "hibernate.collectioncache"; + /** * Enable logging of generated SQL to the console */ diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/IdBagBinder.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/IdBagBinder.java index f4ca1c974469..34ef384638e7 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/IdBagBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/IdBagBinder.java @@ -9,6 +9,8 @@ import java.util.Collections; import java.util.Map; +import javax.persistence.Column; + import org.hibernate.AnnotationException; import org.hibernate.annotations.CollectionId; import org.hibernate.annotations.Type; @@ -70,7 +72,7 @@ property, unique, associationTableBinder, ignoreNotFound, getBuildingContext() "id" ); Ejb3Column[] idColumns = Ejb3Column.buildColumnFromAnnotation( - collectionIdAnn.columns(), + determineColumns( collectionIdAnn ), null, null, Nullability.FORCED_NOT_NULL, @@ -131,4 +133,16 @@ property, unique, associationTableBinder, ignoreNotFound, getBuildingContext() } return result; } + + private Column[] determineColumns(CollectionId collectionIdAnn) { + if ( collectionIdAnn.columns().length > 0 ) { + return collectionIdAnn.columns(); + } + final Column column = collectionIdAnn.column(); + if ( StringHelper.isNotEmpty( column.name() ) ) { + return new Column[] { column }; + } + // this should mimic the old behavior when `#columns` was not specified + return new Column[0]; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/FastSessionServices.java b/hibernate-core/src/main/java/org/hibernate/internal/FastSessionServices.java index a8fac37fe30d..69dae836c9de 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/FastSessionServices.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/FastSessionServices.java @@ -6,17 +6,25 @@ */ package org.hibernate.internal; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import javax.persistence.CacheRetrieveMode; +import javax.persistence.CacheStoreMode; +import javax.persistence.PessimisticLockScope; + import org.hibernate.CacheMode; import org.hibernate.FlushMode; import org.hibernate.LockOptions; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.spi.SessionFactoryOptions; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.BaselineSessionEventsListenerBuilder; import org.hibernate.cfg.Environment; import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider; import org.hibernate.engine.jdbc.connections.spi.MultiTenantConnectionProvider; -import org.hibernate.engine.jdbc.spi.ConnectionObserver; import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.event.service.spi.EventListenerGroup; import org.hibernate.event.service.spi.EventListenerRegistry; @@ -52,7 +60,8 @@ import org.hibernate.event.spi.ReplicateEventListener; import org.hibernate.event.spi.ResolveNaturalIdEventListener; import org.hibernate.event.spi.SaveOrUpdateEventListener; -import org.hibernate.jpa.AvailableSettings; +import org.hibernate.internal.log.DeprecationLogger; +import org.hibernate.internal.util.NullnessHelper; import org.hibernate.jpa.QueryHints; import org.hibernate.jpa.internal.util.CacheModeHelper; import org.hibernate.jpa.internal.util.ConfigurationHelper; @@ -61,16 +70,6 @@ import org.hibernate.service.spi.ServiceRegistryImplementor; import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Objects; - -import javax.persistence.CacheRetrieveMode; -import javax.persistence.CacheStoreMode; -import javax.persistence.PessimisticLockScope; - import static org.hibernate.cfg.AvailableSettings.JAKARTA_JPA_LOCK_SCOPE; import static org.hibernate.cfg.AvailableSettings.JAKARTA_JPA_LOCK_TIMEOUT; import static org.hibernate.cfg.AvailableSettings.JAKARTA_JPA_SHARED_CACHE_RETRIEVE_MODE; @@ -241,8 +240,20 @@ public final class FastSessionServices { } private static FlushMode initializeDefaultFlushMode(Map defaultSessionProperties) { - Object setMode = defaultSessionProperties.get( AvailableSettings.FLUSH_MODE ); - return ConfigurationHelper.getFlushMode( setMode, FlushMode.AUTO ); + final Object setting = NullnessHelper.coalesceSuppliedValues( + () -> defaultSessionProperties.get( AvailableSettings.FLUSH_MODE ), + () -> { + final Object oldSetting = defaultSessionProperties.get( org.hibernate.jpa.AvailableSettings.FLUSH_MODE ); + if ( oldSetting != null ) { + DeprecationLogger.DEPRECATION_LOGGER.deprecatedSetting( + org.hibernate.jpa.AvailableSettings.FLUSH_MODE, + AvailableSettings.FLUSH_MODE + ); + } + return oldSetting; + } + ); + return ConfigurationHelper.getFlushMode( setting, FlushMode.AUTO ); } private static LockOptions initializeDefaultLockOptions(final Map defaultSessionProperties) { diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java index 10d9719bcb55..6489891016e6 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java @@ -71,8 +71,8 @@ import org.hibernate.UnresolvableObjectException; import org.hibernate.bytecode.enhance.spi.interceptor.BytecodeLazyAttributeInterceptor; import org.hibernate.bytecode.enhance.spi.interceptor.EnhancementAsProxyLazinessInterceptor; -import org.hibernate.bytecode.enhance.spi.interceptor.LazyAttributeLoadingInterceptor; import org.hibernate.bytecode.spi.BytecodeEnhancementMetadata; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.collection.spi.PersistentCollection; import org.hibernate.criterion.NaturalIdentifier; import org.hibernate.engine.internal.StatefulPersistenceContext; @@ -91,8 +91,6 @@ import org.hibernate.engine.spi.LoadQueryInfluencers; import org.hibernate.engine.spi.NamedQueryDefinition; import org.hibernate.engine.spi.PersistenceContext; -import org.hibernate.engine.spi.PersistentAttributeInterceptable; -import org.hibernate.engine.spi.PersistentAttributeInterceptor; import org.hibernate.engine.spi.QueryParameters; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionImplementor; @@ -140,7 +138,7 @@ import org.hibernate.hql.spi.QueryTranslator; import org.hibernate.internal.CriteriaImpl.CriterionEntry; import org.hibernate.internal.log.DeprecationLogger; -import org.hibernate.jpa.AvailableSettings; +import org.hibernate.internal.util.NullnessHelper; import org.hibernate.jpa.QueryHints; import org.hibernate.jpa.internal.util.CacheModeHelper; import org.hibernate.jpa.internal.util.ConfigurationHelper; @@ -271,6 +269,19 @@ public SessionImpl(SessionFactoryImpl factory, SessionCreationOptions options) { initialMode = fastSessionServices.initialSessionFlushMode; } else { + final Object setting = NullnessHelper.coalesceSuppliedValues( + () -> getSessionProperty( AvailableSettings.FLUSH_MODE ), + () -> { + final Object oldSetting = getSessionProperty( org.hibernate.jpa.AvailableSettings.FLUSH_MODE ); + if ( oldSetting != null ) { + DeprecationLogger.DEPRECATION_LOGGER.deprecatedSetting( + org.hibernate.jpa.AvailableSettings.FLUSH_MODE, + AvailableSettings.FLUSH_MODE + ); + } + return oldSetting; + } + ); initialMode = ConfigurationHelper.getFlushMode( getSessionProperty( AvailableSettings.FLUSH_MODE ), FlushMode.AUTO ); } getSession().setHibernateFlushMode( initialMode ); @@ -3603,7 +3614,8 @@ public void setProperty(String propertyName, Object value) { //now actually update settings, if it's any of these which have a direct impact on this Session state: - if ( AvailableSettings.FLUSH_MODE.equals( propertyName ) ) { + if ( AvailableSettings.FLUSH_MODE.equals( propertyName ) + || org.hibernate.jpa.AvailableSettings.FLUSH_MODE.equals( propertyName ) ) { setHibernateFlushMode( ConfigurationHelper.getFlushMode( value, FlushMode.AUTO ) ); } else if ( JPA_LOCK_SCOPE.equals( propertyName ) || JPA_LOCK_TIMEOUT.equals( propertyName ) diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/AvailableSettings.java b/hibernate-core/src/main/java/org/hibernate/jpa/AvailableSettings.java index 1bff9be0187d..8f27c54b5041 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/AvailableSettings.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/AvailableSettings.java @@ -12,7 +12,10 @@ * NOTE : Does *not* include {@link org.hibernate.cfg.Environment} values. * * @author Steve Ebersole + * + * @deprecated Use {@link org.hibernate.cfg.AvailableSettings} instead. Will be removed in 6.0 */ +@Deprecated public interface AvailableSettings { // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -278,37 +281,48 @@ public interface AvailableSettings { /** * cfg.xml configuration file used + * + * @deprecated Use {@link org.hibernate.cfg.AvailableSettings#CFG_XML_FILE} */ + @Deprecated String CFG_FILE = "hibernate.ejb.cfgfile"; /** - * Caching configuration should follow the following pattern - * {@code hibernate.ejb.classcache. usage[, region]} - * where usage is the cache strategy used and region the cache region name + * @deprecated Use {@link org.hibernate.cfg.AvailableSettings#CLASS_CACHE_PREFIX} */ + @Deprecated String CLASS_CACHE_PREFIX = "hibernate.ejb.classcache"; /** - * Caching configuration should follow the following pattern - * {@code hibernate.ejb.collectioncache.. usage[, region]} - * where usage is the cache strategy used and region the cache region name + * @deprecated Use {@link org.hibernate.cfg.AvailableSettings#COLLECTION_CACHE_PREFIX} */ + @Deprecated String COLLECTION_CACHE_PREFIX = "hibernate.ejb.collectioncache"; /** * SessionFactoryObserver class name, the class must have a no-arg constructor + * + * @deprecated Use {@link org.hibernate.cfg.AvailableSettings#SESSION_FACTORY_OBSERVER} instead */ + @Deprecated String SESSION_FACTORY_OBSERVER = "hibernate.ejb.session_factory_observer"; /** * IdentifierGeneratorStrategyProvider class name, the class must have a no-arg constructor + * + * @deprecated Use {@link org.hibernate.cfg.AvailableSettings#IDENTIFIER_GENERATOR_STRATEGY_PROVIDER} + * instead */ + @Deprecated String IDENTIFIER_GENERATOR_STRATEGY_PROVIDER = "hibernate.ejb.identifier_generator_strategy_provider"; /** * Event configuration should follow the following pattern * hibernate.ejb.event.[eventType] f.q.c.n.EventListener1, f.q.c.n.EventListener12 ... + * + * @deprecated Use {@link org.hibernate.cfg.AvailableSettings#EVENT_LISTENER_PREFIX} instead */ + @Deprecated String EVENT_LISTENER_PREFIX = "hibernate.ejb.event"; /** @@ -327,9 +341,9 @@ public interface AvailableSettings { String ENHANCER_ENABLE_ASSOCIATION_MANAGEMENT = "hibernate.enhancer.enableAssociationManagement"; /** - * Whether or not discard persistent context on entityManager.close() - * The EJB3 compliant and default choice is false + * @deprecated Use {@link org.hibernate.cfg.AvailableSettings#DISCARD_PC_ON_CLOSE} instead */ + @Deprecated String DISCARD_PC_ON_CLOSE = "hibernate.ejb.discard_pc_on_close"; @@ -342,22 +356,36 @@ public interface AvailableSettings { /** * EntityManagerFactory name + * + * @deprecated Use {@link org.hibernate.cfg.AvailableSettings#EMF_NAME} instead */ + @Deprecated String ENTITY_MANAGER_FACTORY_NAME = "hibernate.ejb.entitymanager_factory_name"; /** - * List of classes names - * Internal use only + * @deprecated Use {@link org.hibernate.cfg.AvailableSettings#ORM_XML_FILES} */ + @Deprecated String XML_FILE_NAMES = "hibernate.ejb.xml_files"; + /** + * @deprecated Use {@link org.hibernate.cfg.AvailableSettings#HBM_XML_FILES} + */ + @Deprecated String HBXML_FILES = "hibernate.hbmxml.files"; + /** + * @deprecated Use {@link org.hibernate.cfg.AvailableSettings#LOADED_CLASSES} + */ + @Deprecated String LOADED_CLASSES = "hibernate.ejb.loaded.classes"; /** * Used to pass along the name of the persistence unit. + * + * @deprecated Use {@link org.hibernate.cfg.AvailableSettings#PERSISTENCE_UNIT_NAME} instead */ + @Deprecated String PERSISTENCE_UNIT_NAME = "hibernate.ejb.persistenceUnitName"; /** diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/HibernateEntityManagerFactory.java b/hibernate-core/src/main/java/org/hibernate/jpa/HibernateEntityManagerFactory.java index d1416ce7e2d9..5f18d27698cf 100755 --- a/hibernate-core/src/main/java/org/hibernate/jpa/HibernateEntityManagerFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/HibernateEntityManagerFactory.java @@ -14,7 +14,10 @@ import org.hibernate.Metamodel; import org.hibernate.boot.spi.SessionFactoryOptions; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.internal.log.DeprecationLogger; +import org.hibernate.internal.util.NullnessHelper; /** * Contract giving access to the underlying {@link org.hibernate.SessionFactory} from an {@link javax.persistence.EntityManagerFactory} @@ -64,7 +67,19 @@ default SessionFactoryImplementor getSessionFactory() { */ @Deprecated default String getEntityManagerFactoryName() { - return (String) getProperties().get( AvailableSettings.ENTITY_MANAGER_FACTORY_NAME ); + return NullnessHelper.coalesceSuppliedValues( + () -> (String) getProperties().get( AvailableSettings.EMF_NAME ), + () -> { + final String oldSetting = (String) getProperties().get( AvailableSettings.ENTITY_MANAGER_FACTORY_NAME ); + if ( oldSetting != null ) { + DeprecationLogger.DEPRECATION_LOGGER.deprecatedSetting( + AvailableSettings.ENTITY_MANAGER_FACTORY_NAME, + AvailableSettings.EMF_NAME + ); + } + return oldSetting; + } + ); } /** diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java b/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java index ac2cc7bc303c..8445e9257f76 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/boot/internal/EntityManagerFactoryBuilderImpl.java @@ -33,7 +33,6 @@ import org.hibernate.boot.cfgxml.spi.CfgXmlAccessService; import org.hibernate.boot.cfgxml.spi.LoadedConfig; import org.hibernate.boot.cfgxml.spi.MappingReference; -import org.hibernate.boot.model.convert.spi.ConverterDescriptor; import org.hibernate.boot.model.process.spi.ManagedResources; import org.hibernate.boot.model.process.spi.MetadataBuildingProcess; import org.hibernate.boot.registry.BootstrapServiceRegistry; @@ -53,6 +52,7 @@ import org.hibernate.bytecode.enhance.spi.UnloadedClass; import org.hibernate.bytecode.enhance.spi.UnloadedField; import org.hibernate.cfg.AttributeConverterDefinition; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.Environment; import org.hibernate.cfg.beanvalidation.BeanValidationIntegrator; import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider; @@ -60,10 +60,10 @@ import org.hibernate.id.factory.spi.MutableIdentifierGeneratorFactory; import org.hibernate.integrator.spi.Integrator; import org.hibernate.internal.EntityManagerMessageLogger; +import org.hibernate.internal.log.DeprecationLogger; import org.hibernate.internal.util.NullnessHelper; import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.config.ConfigurationHelper; -import org.hibernate.jpa.AvailableSettings; import org.hibernate.jpa.boot.spi.EntityManagerFactoryBuilder; import org.hibernate.jpa.boot.spi.IntegratorProvider; import org.hibernate.jpa.boot.spi.PersistenceUnitDescriptor; @@ -87,6 +87,7 @@ import org.jboss.jandex.Index; +import static org.hibernate.cfg.AvailableSettings.CFG_XML_FILE; import static org.hibernate.cfg.AvailableSettings.DATASOURCE; import static org.hibernate.cfg.AvailableSettings.DRIVER; import static org.hibernate.cfg.AvailableSettings.JACC_CONTEXT_ID; @@ -111,6 +112,7 @@ import static org.hibernate.cfg.AvailableSettings.JPA_TRANSACTION_TYPE; import static org.hibernate.cfg.AvailableSettings.JPA_VALIDATION_MODE; import static org.hibernate.cfg.AvailableSettings.PASS; +import static org.hibernate.cfg.AvailableSettings.PERSISTENCE_UNIT_NAME; import static org.hibernate.cfg.AvailableSettings.SESSION_FACTORY_NAME; import static org.hibernate.cfg.AvailableSettings.TRANSACTION_COORDINATOR_STRATEGY; import static org.hibernate.cfg.AvailableSettings.URL; @@ -119,7 +121,6 @@ import static org.hibernate.jpa.AvailableSettings.CFG_FILE; import static org.hibernate.jpa.AvailableSettings.CLASS_CACHE_PREFIX; import static org.hibernate.jpa.AvailableSettings.COLLECTION_CACHE_PREFIX; -import static org.hibernate.jpa.AvailableSettings.PERSISTENCE_UNIT_NAME; /** * @author Steve Ebersole @@ -505,11 +506,25 @@ private MergedSettings mergeSettings( mergedSettings.processPersistenceUnitDescriptorProperties( persistenceUnit ); // see if the persistence.xml settings named a Hibernate config file.... - String cfgXmlResourceName = (String) mergedSettings.configurationValues.remove( CFG_FILE ); - if ( StringHelper.isEmpty( cfgXmlResourceName ) ) { - // see if integration settings named a Hibernate config file.... - cfgXmlResourceName = (String) integrationSettings.get( CFG_FILE ); - } + final String cfgXmlResourceName = NullnessHelper.coalesceSuppliedValues( + // first see if we can find it in the configurationValues + () -> (String) mergedSettings.configurationValues.remove( CFG_XML_FILE ), + () -> { + final String oldSetting = (String) mergedSettings.configurationValues.remove( CFG_FILE ); + if ( oldSetting != null ) { + DeprecationLogger.DEPRECATION_LOGGER.deprecatedSetting( CFG_FILE, CFG_XML_FILE); + } + return oldSetting; + }, + () -> (String) integrationSettings.get( CFG_XML_FILE ), + () -> { + final String oldSetting = (String) integrationSettings.get( CFG_FILE ); + if ( oldSetting != null ) { + DeprecationLogger.DEPRECATION_LOGGER.deprecatedSetting( CFG_FILE, CFG_XML_FILE); + } + return oldSetting; + } + ); if ( StringHelper.isNotEmpty( cfgXmlResourceName ) ) { processHibernateConfigXmlResources( ssrBuilder, mergedSettings, cfgXmlResourceName ); @@ -524,16 +539,16 @@ private MergedSettings mergeSettings( // 2) additional cache region declarations // // we will also clean up any references with null entries - Iterator itr = mergedSettings.configurationValues.entrySet().iterator(); + Iterator itr = mergedSettings.configurationValues.entrySet().iterator(); while ( itr.hasNext() ) { - final Map.Entry entry = (Map.Entry) itr.next(); + final Map.Entry entry = itr.next(); if ( entry.getValue() == null ) { // remove entries with null values itr.remove(); break; } - if ( String.class.isInstance( entry.getKey() ) && String.class.isInstance( entry.getValue() ) ) { + if ( entry.getKey() instanceof String && entry.getValue() instanceof String ) { final String keyString = (String) entry.getKey(); final String valueString = (String) entry.getValue(); @@ -552,7 +567,20 @@ private MergedSettings mergeSettings( } } } + else if ( keyString.startsWith( AvailableSettings.CLASS_CACHE_PREFIX ) ) { + mergedSettings.addCacheRegionDefinition( + parseCacheRegionDefinitionEntry( + keyString.substring( AvailableSettings.CLASS_CACHE_PREFIX.length() + 1 ), + valueString, + CacheRegionDefinition.CacheRegionType.ENTITY + ) + ); + } else if ( keyString.startsWith( CLASS_CACHE_PREFIX ) ) { + DeprecationLogger.DEPRECATION_LOGGER.deprecatedSetting( + CLASS_CACHE_PREFIX, + AvailableSettings.CLASS_CACHE_PREFIX + ); mergedSettings.addCacheRegionDefinition( parseCacheRegionDefinitionEntry( keyString.substring( CLASS_CACHE_PREFIX.length() + 1 ), @@ -561,7 +589,20 @@ else if ( keyString.startsWith( CLASS_CACHE_PREFIX ) ) { ) ); } + else if ( keyString.startsWith( AvailableSettings.COLLECTION_CACHE_PREFIX ) ) { + mergedSettings.addCacheRegionDefinition( + parseCacheRegionDefinitionEntry( + keyString.substring( AvailableSettings.COLLECTION_CACHE_PREFIX.length() + 1 ), + (String) entry.getValue(), + CacheRegionDefinition.CacheRegionType.COLLECTION + ) + ); + } else if ( keyString.startsWith( COLLECTION_CACHE_PREFIX ) ) { + DeprecationLogger.DEPRECATION_LOGGER.deprecatedSetting( + COLLECTION_CACHE_PREFIX, + AvailableSettings.COLLECTION_CACHE_PREFIX + ); mergedSettings.addCacheRegionDefinition( parseCacheRegionDefinitionEntry( keyString.substring( COLLECTION_CACHE_PREFIX.length() + 1 ), @@ -1152,14 +1193,14 @@ private CacheRegionDefinition parseCacheRegionDefinitionEntry(String role, Strin if ( !params.hasMoreTokens() ) { StringBuilder error = new StringBuilder( "Illegal usage of " ); if ( cacheType == CacheRegionDefinition.CacheRegionType.ENTITY ) { - error.append( CLASS_CACHE_PREFIX ) + error.append( AvailableSettings.CLASS_CACHE_PREFIX ) .append( ": " ) - .append( CLASS_CACHE_PREFIX ); + .append( AvailableSettings.CLASS_CACHE_PREFIX ); } else { - error.append( COLLECTION_CACHE_PREFIX ) + error.append( AvailableSettings.COLLECTION_CACHE_PREFIX ) .append( ": " ) - .append( COLLECTION_CACHE_PREFIX ); + .append( AvailableSettings.COLLECTION_CACHE_PREFIX ); } error.append( '.' ) .append( role ) @@ -1191,10 +1232,24 @@ private void configureIdentifierGenerators(StandardServiceRegistry ssr) { final StrategySelector strategySelector = ssr.getService( StrategySelector.class ); // apply id generators - final Object idGeneratorStrategyProviderSetting = configurationValues.remove( AvailableSettings.IDENTIFIER_GENERATOR_STRATEGY_PROVIDER ); + final Object idGeneratorStrategyProviderSetting = NullnessHelper.coalesceSuppliedValues( + () -> configurationValues.remove( AvailableSettings.IDENTIFIER_GENERATOR_STRATEGY_PROVIDER ), + () -> { + final Object oldSetting = configurationValues.remove( org.hibernate.jpa.AvailableSettings.IDENTIFIER_GENERATOR_STRATEGY_PROVIDER ); + if ( oldSetting != null ) { + DeprecationLogger.DEPRECATION_LOGGER.deprecatedSetting( + org.hibernate.jpa.AvailableSettings.IDENTIFIER_GENERATOR_STRATEGY_PROVIDER, + AvailableSettings.IDENTIFIER_GENERATOR_STRATEGY_PROVIDER + ); + } + return oldSetting; + } + ); if ( idGeneratorStrategyProviderSetting != null ) { - final IdentifierGeneratorStrategyProvider idGeneratorStrategyProvider = - strategySelector.resolveStrategy( IdentifierGeneratorStrategyProvider.class, idGeneratorStrategyProviderSetting ); + final IdentifierGeneratorStrategyProvider idGeneratorStrategyProvider = strategySelector.resolveStrategy( + IdentifierGeneratorStrategyProvider.class, + idGeneratorStrategyProviderSetting + ); final MutableIdentifierGeneratorFactory identifierGeneratorFactory = ssr.getService( MutableIdentifierGeneratorFactory.class ); if ( identifierGeneratorFactory == null ) { throw persistenceException( @@ -1256,9 +1311,17 @@ private List applyMappingResources(MetadataSources List attributeConverterDefinitions = null; // add any explicit Class references passed in - final List loadedAnnotatedClasses = (List) configurationValues.remove( AvailableSettings.LOADED_CLASSES ); - if ( loadedAnnotatedClasses != null ) { - for ( Class cls : loadedAnnotatedClasses ) { + final List annotatedClasses = (List) configurationValues.remove( AvailableSettings.LOADED_CLASSES ); + final List oldAnnotatedClasses = (List) configurationValues.remove( org.hibernate.jpa.AvailableSettings.LOADED_CLASSES ); + if ( oldAnnotatedClasses != null && ! oldAnnotatedClasses.isEmpty() ) { + DeprecationLogger.DEPRECATION_LOGGER.deprecatedSetting( + org.hibernate.jpa.AvailableSettings.LOADED_CLASSES, + AvailableSettings.LOADED_CLASSES + ); + } + final List explicitAnnotatedClasses = NullnessHelper.coalesce( annotatedClasses, oldAnnotatedClasses ); + if ( explicitAnnotatedClasses != null ) { + for ( Class cls : explicitAnnotatedClasses ) { if ( AttributeConverter.class.isAssignableFrom( cls ) ) { if ( attributeConverterDefinitions == null ) { attributeConverterDefinitions = new ArrayList<>(); @@ -1272,15 +1335,31 @@ private List applyMappingResources(MetadataSources } // add any explicit hbm.xml references passed in - final String explicitHbmXmls = (String) configurationValues.remove( AvailableSettings.HBXML_FILES ); - if ( explicitHbmXmls != null ) { - for ( String hbmXml : StringHelper.split( ", ", explicitHbmXmls ) ) { + final String hbmXmlFiles = (String) configurationValues.remove( AvailableSettings.HBM_XML_FILES ); + final String oldHbmXmlFiles = (String) configurationValues.remove( AvailableSettings.HBXML_FILES ); + if ( oldHbmXmlFiles != null ) { + DeprecationLogger.DEPRECATION_LOGGER.deprecatedSetting( + AvailableSettings.HBXML_FILES, + AvailableSettings.HBM_XML_FILES + ); + } + final String explicitHbmXmlFiles = NullnessHelper.coalesce( hbmXmlFiles, oldHbmXmlFiles ); + if ( explicitHbmXmlFiles != null ) { + for ( String hbmXml : StringHelper.split( ", ", explicitHbmXmlFiles ) ) { metadataSources.addResource( hbmXml ); } } // add any explicit orm.xml references passed in - final List explicitOrmXmlList = (List) configurationValues.remove( AvailableSettings.XML_FILE_NAMES ); + final List ormXmlFiles = (List) configurationValues.remove( AvailableSettings.ORM_XML_FILES ); + final List oldOrmXmlFiles = (List) configurationValues.remove( AvailableSettings.XML_FILE_NAMES ); + if ( oldOrmXmlFiles != null ) { + DeprecationLogger.DEPRECATION_LOGGER.deprecatedSetting( + AvailableSettings.XML_FILE_NAMES, + AvailableSettings.ORM_XML_FILES + ); + } + final List explicitOrmXmlList = NullnessHelper.coalesce( ormXmlFiles, oldOrmXmlFiles ); if ( explicitOrmXmlList != null ) { explicitOrmXmlList.forEach( metadataSources::addResource ); } @@ -1455,10 +1534,24 @@ protected void populateSfBuilder(SessionFactoryBuilder sfBuilder, StandardServic } // Locate and apply any requested SessionFactoryObserver - final Object sessionFactoryObserverSetting = configurationValues.remove( AvailableSettings.SESSION_FACTORY_OBSERVER ); + final Object sessionFactoryObserverSetting = NullnessHelper.coalesceSuppliedValues( + () -> configurationValues.remove( AvailableSettings.SESSION_FACTORY_OBSERVER ), + () -> { + final Object oldSetting = configurationValues.remove( org.hibernate.jpa.AvailableSettings.SESSION_FACTORY_OBSERVER ); + if ( oldSetting != null ) { + DeprecationLogger.DEPRECATION_LOGGER.deprecatedSetting( + org.hibernate.jpa.AvailableSettings.SESSION_FACTORY_OBSERVER, + AvailableSettings.SESSION_FACTORY_OBSERVER + ); + } + return oldSetting; + } + ); if ( sessionFactoryObserverSetting != null ) { - final SessionFactoryObserver suppliedSessionFactoryObserver = - strategySelector.resolveStrategy( SessionFactoryObserver.class, sessionFactoryObserverSetting ); + final SessionFactoryObserver suppliedSessionFactoryObserver = strategySelector.resolveStrategy( + SessionFactoryObserver.class, + sessionFactoryObserverSetting + ); sfBuilder.addSessionFactoryObservers( suppliedSessionFactoryObserver ); } @@ -1529,6 +1622,7 @@ public void processPersistenceUnitDescriptorProperties(PersistenceUnitDescriptor } configurationValues.put( PERSISTENCE_UNIT_NAME, persistenceUnit.getName() ); + configurationValues.put( org.hibernate.jpa.AvailableSettings.PERSISTENCE_UNIT_NAME, persistenceUnit.getName() ); } diff --git a/hibernate-core/src/main/java/org/hibernate/query/procedure/ProcedureParameter.java b/hibernate-core/src/main/java/org/hibernate/query/procedure/ProcedureParameter.java index 0bd9c4a2fde3..62f357d0ddd8 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/procedure/ProcedureParameter.java +++ b/hibernate-core/src/main/java/org/hibernate/query/procedure/ProcedureParameter.java @@ -44,6 +44,10 @@ public interface ProcedureParameter extends QueryParameter { * @param enabled {@code true} indicates that the NULL should be passed; {@code false} indicates it should not. * * @see org.hibernate.procedure.ParameterRegistration#enablePassingNulls + * + * @deprecated with no replacement. See {@link org.hibernate.cfg.AvailableSettings#PROCEDURE_NULL_PARAM_PASSING} + * for details */ + @Deprecated void enablePassingNulls(boolean enabled); } diff --git a/hibernate-core/src/main/java/org/hibernate/resource/beans/container/internal/CdiBeanContainerBuilder.java b/hibernate-core/src/main/java/org/hibernate/resource/beans/container/internal/CdiBeanContainerBuilder.java index a9f0133a022f..bf79c91cd334 100644 --- a/hibernate-core/src/main/java/org/hibernate/resource/beans/container/internal/CdiBeanContainerBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/resource/beans/container/internal/CdiBeanContainerBuilder.java @@ -12,10 +12,12 @@ import org.hibernate.HibernateException; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.engine.config.spi.ConfigurationService; import org.hibernate.engine.config.spi.StandardConverters; +import org.hibernate.internal.log.DeprecationLogger; +import org.hibernate.internal.util.NullnessHelper; import org.hibernate.internal.util.ReflectHelper; -import org.hibernate.jpa.AvailableSettings; import org.hibernate.resource.beans.container.spi.BeanContainer; import org.hibernate.resource.beans.spi.ManagedBeanRegistryInitiator; import org.hibernate.service.ServiceRegistry; @@ -56,7 +58,20 @@ public static BeanContainer fromBeanManagerReference( ctorArgType = beanManagerClass; final ConfigurationService cfgService = serviceRegistry.getService( ConfigurationService.class ); - final boolean delayAccessToCdi = cfgService.getSetting( AvailableSettings.DELAY_CDI_ACCESS, StandardConverters.BOOLEAN, false ); + final boolean delayAccessToCdi = NullnessHelper.coalesceSuppliedValues( + () -> cfgService.getSetting( AvailableSettings.DELAY_CDI_ACCESS, StandardConverters.BOOLEAN ), + () -> { + final Boolean oldSetting = cfgService.getSetting( org.hibernate.jpa.AvailableSettings.DELAY_CDI_ACCESS, StandardConverters.BOOLEAN ); + if ( oldSetting != null ) { + DeprecationLogger.DEPRECATION_LOGGER.deprecatedSetting( + org.hibernate.jpa.AvailableSettings.DELAY_CDI_ACCESS, + AvailableSettings.DELAY_CDI_ACCESS + ); + } + return oldSetting; + }, + () -> false + ); if ( delayAccessToCdi ) { containerClass = getHibernateClass( CONTAINER_FQN_DELAYED ); } diff --git a/hibernate-core/src/test/java/org/hibernate/cfg/CfgFilePropertyTest.java b/hibernate-core/src/test/java/org/hibernate/cfg/CfgFilePropertyTest.java index a58fd2e10b7f..d19286a4c471 100644 --- a/hibernate-core/src/test/java/org/hibernate/cfg/CfgFilePropertyTest.java +++ b/hibernate-core/src/test/java/org/hibernate/cfg/CfgFilePropertyTest.java @@ -36,7 +36,7 @@ public void test() throws InterruptedException { Thread thread = new Thread( () -> { try { final Properties props = new Properties(); - props.setProperty( AvailableSettings.CFG_FILE, "/org/hibernate/test/boot/cfgXml/hibernate.cfg.xml" ); + props.setProperty( AvailableSettings.CFG_XML_FILE, "/org/hibernate/test/boot/cfgXml/hibernate.cfg.xml" ); Persistence.createEntityManagerFactory( "ExcludeUnlistedClassesTest1", props ); } diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/BaseEntityManagerFunctionalTestCase.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/BaseEntityManagerFunctionalTestCase.java index 68d5d7542c21..6de0cd22c31e 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/BaseEntityManagerFunctionalTestCase.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/BaseEntityManagerFunctionalTestCase.java @@ -198,7 +198,7 @@ protected Map buildSettings() { protected void addMappings(Map settings) { String[] mappings = getMappings(); if ( mappings != null ) { - settings.put( AvailableSettings.HBXML_FILES, String.join( ",", mappings ) ); + settings.put( AvailableSettings.HBM_XML_FILES, String.join( ",", mappings ) ); } } @@ -223,9 +223,9 @@ protected Map getConfig() { config.put( AvailableSettings.COLLECTION_CACHE_PREFIX + "." + entry.getKey(), entry.getValue() ); } if ( getEjb3DD().length > 0 ) { - ArrayList dds = new ArrayList(); + ArrayList dds = new ArrayList<>(); dds.addAll( Arrays.asList( getEjb3DD() ) ); - config.put( AvailableSettings.XML_FILE_NAMES, dds ); + config.put( AvailableSettings.ORM_XML_FILES, dds ); } config.put( GlobalTemporaryTableBulkIdStrategy.DROP_ID_TABLES, "true" ); diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/EntityManagerFactoryClosedTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/EntityManagerFactoryClosedTest.java index 542e50cf3063..474c6fc89d28 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/EntityManagerFactoryClosedTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/EntityManagerFactoryClosedTest.java @@ -12,8 +12,8 @@ import java.util.Map; import javax.persistence.EntityManagerFactory; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.engine.transaction.internal.jta.JtaStatusHelper; -import org.hibernate.jpa.AvailableSettings; import org.hibernate.testing.jta.TestingJtaBootstrap; import org.hibernate.testing.jta.TestingJtaPlatformImpl; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/EntityManagerTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/EntityManagerTest.java index 6bc16d95652a..1aac25c75b60 100755 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/EntityManagerTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/EntityManagerTest.java @@ -27,8 +27,8 @@ import org.hibernate.FlushMode; import org.hibernate.HibernateException; import org.hibernate.Session; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.Environment; -import org.hibernate.jpa.AvailableSettings; import org.hibernate.jpa.HibernateEntityManagerFactory; import org.hibernate.jpa.QueryHints; import org.hibernate.stat.Statistics; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/beanvalidation/ValidatorFactory2PhaseInjectionTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/beanvalidation/ValidatorFactory2PhaseInjectionTest.java index d567c9c22f72..f329ead786bb 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/beanvalidation/ValidatorFactory2PhaseInjectionTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/beanvalidation/ValidatorFactory2PhaseInjectionTest.java @@ -13,7 +13,7 @@ import javax.validation.Validation; import javax.validation.ValidatorFactory; -import org.hibernate.jpa.AvailableSettings; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.jpa.HibernatePersistenceProvider; import org.hibernate.jpa.boot.spi.Bootstrap; import org.hibernate.jpa.boot.spi.EntityManagerFactoryBuilder; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/cacheable/annotation/ConfigurationTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/cacheable/annotation/ConfigurationTest.java index 30722b0d6881..1e27fa95fdb5 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/cacheable/annotation/ConfigurationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/cacheable/annotation/ConfigurationTest.java @@ -14,8 +14,7 @@ import org.hibernate.boot.spi.MetadataImplementor; import org.hibernate.cache.spi.access.AccessType; -import org.hibernate.cfg.Environment; -import org.hibernate.jpa.AvailableSettings; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl; import org.hibernate.jpa.boot.spi.Bootstrap; import org.hibernate.jpa.test.PersistenceUnitInfoAdapter; @@ -114,11 +113,11 @@ public void testSharedCacheModeDisable() { assertTrue( pc.isCached() ); } - @SuppressWarnings("unchecked") + @SuppressWarnings({ "unchecked", "rawtypes" }) private MetadataImplementor buildMetadata(SharedCacheMode mode) { - Map settings = new HashMap(); - settings.put( AvailableSettings.SHARED_CACHE_MODE, mode ); - settings.put( Environment.CACHE_REGION_FACTORY, CustomRegionFactory.class.getName() ); + final Map settings = new HashMap<>(); + settings.put( AvailableSettings.JPA_SHARED_CACHE_MODE, mode ); + settings.put( AvailableSettings.CACHE_REGION_FACTORY, CustomRegionFactory.class.getName() ); settings.put( AvailableSettings.LOADED_CLASSES, Arrays.asList( diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/cacheable/api/JpaCacheApiUsageTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/cacheable/api/JpaCacheApiUsageTest.java index f867160152ba..6ca658fd046b 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/cacheable/api/JpaCacheApiUsageTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/cacheable/api/JpaCacheApiUsageTest.java @@ -6,17 +6,15 @@ */ package org.hibernate.jpa.test.cacheable.api; +import java.util.Map; import javax.persistence.EntityManager; import javax.persistence.SharedCacheMode; -import java.util.Map; - import org.hibernate.cfg.AvailableSettings; import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; -import org.junit.Test; - import org.hibernate.testing.cache.CachingRegionFactory; +import org.junit.Test; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; @@ -33,10 +31,8 @@ protected Class[] getAnnotatedClasses() { @Override @SuppressWarnings("unchecked") protected void addConfigOptions(Map options) { -// options.put( AvailableSettings.USE_SECOND_LEVEL_CACHE, "true" ); options.put( AvailableSettings.CACHE_REGION_FACTORY, CachingRegionFactory.class.getName() ); -// options.put( AvailableSettings.DEFAULT_CACHE_CONCURRENCY_STRATEGY, "read-write" ); - options.put( org.hibernate.jpa.AvailableSettings.SHARED_CACHE_MODE, SharedCacheMode.ALL ); + options.put( AvailableSettings.JPA_SHARED_CACHE_MODE, SharedCacheMode.ALL ); } @Test diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/cacheable/cachemodes/SharedCacheModesTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/cacheable/cachemodes/SharedCacheModesTest.java index 3e791e2d2d85..43455bf80565 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/cacheable/cachemodes/SharedCacheModesTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/cacheable/cachemodes/SharedCacheModesTest.java @@ -12,7 +12,7 @@ import org.hibernate.CacheMode; import org.hibernate.Session; -import org.hibernate.jpa.AvailableSettings; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.jpa.HibernateEntityManager; import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; @@ -39,62 +39,62 @@ public void testEntityManagerCacheModes() { session = ( (HibernateEntityManager) em ).getSession(); // defaults... - assertEquals( CacheStoreMode.USE, em.getProperties().get( AvailableSettings.SHARED_CACHE_STORE_MODE ) ); - assertEquals( CacheRetrieveMode.USE, em.getProperties().get( AvailableSettings.SHARED_CACHE_RETRIEVE_MODE ) ); + assertEquals( CacheStoreMode.USE, em.getProperties().get( AvailableSettings.JPA_SHARED_CACHE_STORE_MODE ) ); + assertEquals( CacheRetrieveMode.USE, em.getProperties().get( AvailableSettings.JPA_SHARED_CACHE_RETRIEVE_MODE ) ); assertEquals( CacheMode.NORMAL, session.getCacheMode() ); // overrides... - em.setProperty( AvailableSettings.SHARED_CACHE_STORE_MODE, CacheStoreMode.REFRESH ); - assertEquals( CacheStoreMode.REFRESH, em.getProperties().get( AvailableSettings.SHARED_CACHE_STORE_MODE ) ); + em.setProperty( AvailableSettings.JPA_SHARED_CACHE_STORE_MODE, CacheStoreMode.REFRESH ); + assertEquals( CacheStoreMode.REFRESH, em.getProperties().get( AvailableSettings.JPA_SHARED_CACHE_STORE_MODE ) ); assertEquals( CacheMode.REFRESH, session.getCacheMode() ); - em.setProperty( AvailableSettings.SHARED_CACHE_STORE_MODE, CacheStoreMode.BYPASS ); - assertEquals( CacheStoreMode.BYPASS, em.getProperties().get( AvailableSettings.SHARED_CACHE_STORE_MODE ) ); + em.setProperty( AvailableSettings.JPA_SHARED_CACHE_STORE_MODE, CacheStoreMode.BYPASS ); + assertEquals( CacheStoreMode.BYPASS, em.getProperties().get( AvailableSettings.JPA_SHARED_CACHE_STORE_MODE ) ); assertEquals( CacheMode.GET, session.getCacheMode() ); - em.setProperty( AvailableSettings.SHARED_CACHE_RETRIEVE_MODE, CacheRetrieveMode.BYPASS ); - assertEquals( CacheRetrieveMode.BYPASS, em.getProperties().get( AvailableSettings.SHARED_CACHE_RETRIEVE_MODE ) ); + em.setProperty( AvailableSettings.JPA_SHARED_CACHE_RETRIEVE_MODE, CacheRetrieveMode.BYPASS ); + assertEquals( CacheRetrieveMode.BYPASS, em.getProperties().get( AvailableSettings.JPA_SHARED_CACHE_RETRIEVE_MODE ) ); assertEquals( CacheMode.IGNORE, session.getCacheMode() ); - em.setProperty( AvailableSettings.SHARED_CACHE_STORE_MODE, CacheStoreMode.USE ); - assertEquals( CacheStoreMode.USE, em.getProperties().get( AvailableSettings.SHARED_CACHE_STORE_MODE ) ); + em.setProperty( AvailableSettings.JPA_SHARED_CACHE_STORE_MODE, CacheStoreMode.USE ); + assertEquals( CacheStoreMode.USE, em.getProperties().get( AvailableSettings.JPA_SHARED_CACHE_STORE_MODE ) ); assertEquals( CacheMode.PUT, session.getCacheMode() ); - em.setProperty( AvailableSettings.SHARED_CACHE_STORE_MODE, CacheStoreMode.REFRESH ); - assertEquals( CacheStoreMode.REFRESH, em.getProperties().get( AvailableSettings.SHARED_CACHE_STORE_MODE ) ); + em.setProperty( AvailableSettings.JPA_SHARED_CACHE_STORE_MODE, CacheStoreMode.REFRESH ); + assertEquals( CacheStoreMode.REFRESH, em.getProperties().get( AvailableSettings.JPA_SHARED_CACHE_STORE_MODE ) ); assertEquals( CacheMode.REFRESH, session.getCacheMode() ); } @Test public void testQueryCacheModes() { EntityManager em = getOrCreateEntityManager(); - org.hibernate.query.Query query = em.createQuery( "from SimpleEntity" ).unwrap( org.hibernate.query.Query.class ); + org.hibernate.query.Query query = em.createQuery( "from SimpleEntity" ).unwrap( org.hibernate.query.Query.class ); - query.setHint( AvailableSettings.SHARED_CACHE_STORE_MODE, CacheStoreMode.USE ); - assertEquals( CacheStoreMode.USE, query.getHints().get( AvailableSettings.SHARED_CACHE_STORE_MODE ) ); + query.setHint( AvailableSettings.JPA_SHARED_CACHE_STORE_MODE, CacheStoreMode.USE ); + assertEquals( CacheStoreMode.USE, query.getHints().get( AvailableSettings.JPA_SHARED_CACHE_STORE_MODE ) ); assertEquals( CacheMode.NORMAL, query.getCacheMode() ); - query.setHint( AvailableSettings.SHARED_CACHE_STORE_MODE, CacheStoreMode.BYPASS ); - assertEquals( CacheStoreMode.BYPASS, query.getHints().get( AvailableSettings.SHARED_CACHE_STORE_MODE ) ); + query.setHint( AvailableSettings.JPA_SHARED_CACHE_STORE_MODE, CacheStoreMode.BYPASS ); + assertEquals( CacheStoreMode.BYPASS, query.getHints().get( AvailableSettings.JPA_SHARED_CACHE_STORE_MODE ) ); assertEquals( CacheMode.GET, query.getCacheMode() ); - query.setHint( AvailableSettings.SHARED_CACHE_STORE_MODE, CacheStoreMode.REFRESH ); - assertEquals( CacheStoreMode.REFRESH, query.getHints().get( AvailableSettings.SHARED_CACHE_STORE_MODE ) ); + query.setHint( AvailableSettings.JPA_SHARED_CACHE_STORE_MODE, CacheStoreMode.REFRESH ); + assertEquals( CacheStoreMode.REFRESH, query.getHints().get( AvailableSettings.JPA_SHARED_CACHE_STORE_MODE ) ); assertEquals( CacheMode.REFRESH, query.getCacheMode() ); - query.setHint( AvailableSettings.SHARED_CACHE_RETRIEVE_MODE, CacheRetrieveMode.BYPASS ); - assertEquals( CacheRetrieveMode.BYPASS, query.getHints().get( AvailableSettings.SHARED_CACHE_RETRIEVE_MODE ) ); - assertEquals( CacheStoreMode.REFRESH, query.getHints().get( AvailableSettings.SHARED_CACHE_STORE_MODE ) ); + query.setHint( AvailableSettings.JPA_SHARED_CACHE_RETRIEVE_MODE, CacheRetrieveMode.BYPASS ); + assertEquals( CacheRetrieveMode.BYPASS, query.getHints().get( AvailableSettings.JPA_SHARED_CACHE_RETRIEVE_MODE ) ); + assertEquals( CacheStoreMode.REFRESH, query.getHints().get( AvailableSettings.JPA_SHARED_CACHE_STORE_MODE ) ); assertEquals( CacheMode.REFRESH, query.getCacheMode() ); - query.setHint( AvailableSettings.SHARED_CACHE_STORE_MODE, CacheStoreMode.BYPASS ); - assertEquals( CacheRetrieveMode.BYPASS, query.getHints().get( AvailableSettings.SHARED_CACHE_RETRIEVE_MODE ) ); - assertEquals( CacheStoreMode.BYPASS, query.getHints().get( AvailableSettings.SHARED_CACHE_STORE_MODE ) ); + query.setHint( AvailableSettings.JPA_SHARED_CACHE_STORE_MODE, CacheStoreMode.BYPASS ); + assertEquals( CacheRetrieveMode.BYPASS, query.getHints().get( AvailableSettings.JPA_SHARED_CACHE_RETRIEVE_MODE ) ); + assertEquals( CacheStoreMode.BYPASS, query.getHints().get( AvailableSettings.JPA_SHARED_CACHE_STORE_MODE ) ); assertEquals( CacheMode.IGNORE, query.getCacheMode() ); - query.setHint( AvailableSettings.SHARED_CACHE_STORE_MODE, CacheStoreMode.USE ); - assertEquals( CacheRetrieveMode.BYPASS, query.getHints().get( AvailableSettings.SHARED_CACHE_RETRIEVE_MODE ) ); - assertEquals( CacheStoreMode.USE, query.getHints().get( AvailableSettings.SHARED_CACHE_STORE_MODE ) ); + query.setHint( AvailableSettings.JPA_SHARED_CACHE_STORE_MODE, CacheStoreMode.USE ); + assertEquals( CacheRetrieveMode.BYPASS, query.getHints().get( AvailableSettings.JPA_SHARED_CACHE_RETRIEVE_MODE ) ); + assertEquals( CacheStoreMode.USE, query.getHints().get( AvailableSettings.JPA_SHARED_CACHE_STORE_MODE ) ); assertEquals( CacheMode.PUT, query.getCacheMode() ); } diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/callbacks/hbmxml/MappingClassMoreThanOnceTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/callbacks/hbmxml/MappingClassMoreThanOnceTest.java index a163be042ad8..65d2a86b897b 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/callbacks/hbmxml/MappingClassMoreThanOnceTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/callbacks/hbmxml/MappingClassMoreThanOnceTest.java @@ -9,7 +9,7 @@ import java.util.HashMap; import java.util.Map; -import org.hibernate.jpa.AvailableSettings; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.jpa.HibernateEntityManagerFactory; import org.hibernate.jpa.boot.spi.Bootstrap; import org.hibernate.jpa.boot.spi.EntityManagerFactoryBuilder; @@ -31,7 +31,7 @@ public class MappingClassMoreThanOnceTest extends BaseUnitTestCase { // @FailureExpected(jiraKey = "HHH-8775") public void testBootstrapWithClassMappedMOreThanOnce() { Map settings = new HashMap( ); - settings.put( AvailableSettings.HBXML_FILES, "org/hibernate/jpa/test/callbacks/hbmxml/ClassMappedMoreThanOnce.hbm.xml" ); + settings.put( AvailableSettings.HBM_XML_FILES, "org/hibernate/jpa/test/callbacks/hbmxml/ClassMappedMoreThanOnce.hbm.xml" ); final EntityManagerFactoryBuilder builder = Bootstrap.getEntityManagerFactoryBuilder( new BaseEntityManagerFunctionalTestCase.TestingPersistenceUnitDescriptorImpl( getClass().getSimpleName() ), diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/cdi/NoCdiAvailableTestDelegate.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/cdi/NoCdiAvailableTestDelegate.java index f683442f06a8..78dd047d1364 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/cdi/NoCdiAvailableTestDelegate.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/cdi/NoCdiAvailableTestDelegate.java @@ -10,7 +10,7 @@ import javax.persistence.EntityManagerFactory; -import org.hibernate.jpa.AvailableSettings; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.jpa.HibernatePersistenceProvider; import org.hibernate.jpa.test.PersistenceUnitInfoAdapter; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/ejb3configuration/DisableDiscardPersistenceContextOnCloseTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/ejb3configuration/DisableDiscardPersistenceContextOnCloseTest.java index a6d0777fde39..935194e5216e 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/ejb3configuration/DisableDiscardPersistenceContextOnCloseTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/ejb3configuration/DisableDiscardPersistenceContextOnCloseTest.java @@ -10,8 +10,8 @@ import java.util.Map; import javax.persistence.EntityManager; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider; -import org.hibernate.jpa.AvailableSettings; import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; import org.hibernate.jpa.test.Wallet; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/ejb3configuration/EnableDiscardPersistenceContextOnCloseTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/ejb3configuration/EnableDiscardPersistenceContextOnCloseTest.java index 328a1eb25e8a..40148b861fb6 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/ejb3configuration/EnableDiscardPersistenceContextOnCloseTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/ejb3configuration/EnableDiscardPersistenceContextOnCloseTest.java @@ -9,15 +9,13 @@ import java.util.Map; import javax.persistence.EntityManager; -import org.hibernate.dialect.DB2Dialect; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider; -import org.hibernate.jpa.AvailableSettings; import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; import org.hibernate.jpa.test.Wallet; import org.hibernate.testing.DialectChecks; import org.hibernate.testing.RequiresDialectFeature; -import org.hibernate.testing.SkipForDialect; import org.hibernate.test.util.jdbc.PreparedStatementSpyConnectionProvider; import org.junit.Test; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/ejb3configuration/InterceptorTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/ejb3configuration/InterceptorTest.java index bcf77cf558bc..d4eb9fc6bdc0 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/ejb3configuration/InterceptorTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/ejb3configuration/InterceptorTest.java @@ -16,13 +16,10 @@ import org.hibernate.boot.Metadata; import org.hibernate.boot.MetadataSources; import org.hibernate.boot.SessionFactoryBuilder; -import org.hibernate.boot.model.naming.ImplicitNamingStrategyJpaCompliantImpl; -import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.boot.registry.internal.StandardServiceRegistryImpl; -import org.hibernate.cfg.Environment; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.dialect.Dialect; -import org.hibernate.jpa.AvailableSettings; import org.hibernate.jpa.boot.spi.Bootstrap; import org.hibernate.jpa.test.Distributor; import org.hibernate.jpa.test.Item; @@ -89,7 +86,7 @@ public void testDeprecatedConfiguredInterceptor() { @Test public void testDeprecatedConfiguredSessionInterceptor() { Map settings = basicSettings(); - settings.put( AvailableSettings.SESSION_INTERCEPTOR, LocalExceptionInterceptor.class.getName() ); + settings.put( AvailableSettings.SESSION_SCOPED_INTERCEPTOR, LocalExceptionInterceptor.class.getName() ); buildEntityManagerFactory( settings ); Item i = new Item(); @@ -275,9 +272,9 @@ public void testOnLoadCallInInterceptor() { protected Map basicSettings() { return SettingsGenerator.generateSettings( - Environment.HBM2DDL_AUTO, "create-drop", - Environment.USE_NEW_ID_GENERATOR_MAPPINGS, "true", - Environment.DIALECT, Dialect.getDialect().getClass().getName(), + AvailableSettings.HBM2DDL_AUTO, "create-drop", + AvailableSettings.USE_NEW_ID_GENERATOR_MAPPINGS, "true", + AvailableSettings.DIALECT, Dialect.getDialect().getClass().getName(), AvailableSettings.LOADED_CLASSES, Arrays.asList( getAnnotatedClasses() ) ); } diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/ejb3configuration/PersisterClassProviderTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/ejb3configuration/PersisterClassProviderTest.java index 1a94099a537c..b23fa56901fc 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/ejb3configuration/PersisterClassProviderTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/ejb3configuration/PersisterClassProviderTest.java @@ -25,6 +25,7 @@ import org.hibernate.cache.spi.access.NaturalIdDataAccess; import org.hibernate.cache.spi.entry.CacheEntry; import org.hibernate.cache.spi.entry.CacheEntryStructure; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.engine.internal.MutableEntityEntryFactory; import org.hibernate.engine.spi.CascadeStyle; import org.hibernate.engine.spi.EntityEntryFactory; @@ -33,7 +34,6 @@ import org.hibernate.engine.spi.ValueInclusion; import org.hibernate.id.IdentifierGenerator; import org.hibernate.internal.FilterAliasGenerator; -import org.hibernate.jpa.AvailableSettings; import org.hibernate.jpa.boot.spi.Bootstrap; import org.hibernate.jpa.test.PersistenceUnitDescriptorAdapter; import org.hibernate.jpa.test.SettingsGenerator; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/ejb3configuration/SessionFactoryObserverTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/ejb3configuration/SessionFactoryObserverTest.java index 78c96840f996..0b86551ca62c 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/ejb3configuration/SessionFactoryObserverTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/ejb3configuration/SessionFactoryObserverTest.java @@ -6,19 +6,18 @@ */ package org.hibernate.jpa.test.ejb3configuration; -import javax.persistence.EntityManagerFactory; - import java.util.Collections; - -import org.junit.Assert; -import org.junit.Test; +import javax.persistence.EntityManagerFactory; import org.hibernate.SessionFactory; import org.hibernate.SessionFactoryObserver; -import org.hibernate.jpa.test.PersistenceUnitInfoAdapter; -import org.hibernate.jpa.AvailableSettings; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.jpa.boot.spi.Bootstrap; import org.hibernate.jpa.boot.spi.EntityManagerFactoryBuilder; +import org.hibernate.jpa.test.PersistenceUnitInfoAdapter; + +import org.junit.Assert; +import org.junit.Test; /** * @author Emmanuel Bernard diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/ejb3configuration/id/IdentifierGeneratorStrategyProviderTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/ejb3configuration/id/IdentifierGeneratorStrategyProviderTest.java index 655f8a9591f4..48e651977096 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/ejb3configuration/id/IdentifierGeneratorStrategyProviderTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/ejb3configuration/id/IdentifierGeneratorStrategyProviderTest.java @@ -13,8 +13,8 @@ import java.util.HashMap; import java.util.Map; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.jpa.test.PersistenceUnitInfoAdapter; -import org.hibernate.jpa.AvailableSettings; import org.hibernate.jpa.boot.spi.Bootstrap; import org.junit.Assert; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/lock/LockTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/lock/LockTest.java index b4661b3ccf0d..0a6cecbf14d9 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/lock/LockTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/lock/LockTest.java @@ -21,9 +21,11 @@ import javax.persistence.PessimisticLockException; import javax.persistence.Query; import javax.persistence.QueryTimeoutException; + import org.hibernate.LockOptions; import org.hibernate.Session; import org.hibernate.TransactionException; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.dialect.CockroachDB192Dialect; import org.hibernate.dialect.DerbyDialect; import org.hibernate.dialect.Dialect; @@ -31,20 +33,20 @@ import org.hibernate.dialect.Oracle10gDialect; import org.hibernate.dialect.PostgreSQL81Dialect; import org.hibernate.dialect.SQLServerDialect; -import org.hibernate.jpa.AvailableSettings; import org.hibernate.jpa.QueryHints; import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; + import org.hibernate.testing.DialectChecks; import org.hibernate.testing.RequiresDialect; import org.hibernate.testing.RequiresDialectFeature; import org.hibernate.testing.SkipForDialect; import org.hibernate.testing.TestForIssue; -import org.hibernate.testing.jdbc.SharedDriverManagerConnectionProviderImpl; import org.hibernate.testing.transaction.TransactionUtil; import org.hibernate.testing.util.ExceptionUtil; -import org.jboss.logging.Logger; import org.junit.Test; +import org.jboss.logging.Logger; + import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; @@ -62,7 +64,7 @@ public class LockTest extends BaseEntityManagerFunctionalTestCase { protected void addConfigOptions(Map options) { super.addConfigOptions( options ); // We can't use a shared connection provider if we use TransactionUtil.setJdbcTimeout because that is set on the connection level - options.remove( org.hibernate.cfg.AvailableSettings.CONNECTION_PROVIDER ); + options.remove( AvailableSettings.CONNECTION_PROVIDER ); } @Test @@ -78,7 +80,7 @@ public void testFindWithTimeoutHint() { doInJPA( this::entityManagerFactory, em -> { Map properties = new HashMap(); - properties.put( AvailableSettings.LOCK_TIMEOUT, 0L ); + properties.put( AvailableSettings.JPA_LOCK_TIMEOUT, 0L ); em.find( Lock.class, 1, LockModeType.PESSIMISTIC_WRITE, properties ); } ); @@ -110,7 +112,7 @@ public void testFindWithPessimisticWriteLockTimeoutException() { try { TransactionUtil.setJdbcTimeout( entityManager.unwrap( Session.class ) ); Map properties = new HashMap(); - properties.put( AvailableSettings.LOCK_TIMEOUT, 0L ); + properties.put( AvailableSettings.JPA_LOCK_TIMEOUT, 0L ); entityManager.find( Lock.class, lock.getId(), LockModeType.PESSIMISTIC_WRITE, properties ); fail( "Exception should be thrown" ); @@ -284,7 +286,7 @@ public void testUpdateWithPessimisticReadLockSkipLocked() { doInJPA( this::entityManagerFactory, _entityManagaer -> { Map properties = new HashMap<>(); - properties.put( org.hibernate.cfg.AvailableSettings.JPA_LOCK_TIMEOUT, LockOptions.SKIP_LOCKED ); + properties.put( AvailableSettings.JPA_LOCK_TIMEOUT, LockOptions.SKIP_LOCKED ); _entityManagaer.find( Lock.class, lock.getId(), LockModeType.PESSIMISTIC_READ, properties ); try { @@ -680,7 +682,7 @@ public void testContendedPessimisticReadLockTimeout() throws Exception { log.info( "testContendedPessimisticReadLockTimeout: (BG) read write-locked entity" ); Map props = new HashMap(); // timeout is in milliseconds - props.put( AvailableSettings.LOCK_TIMEOUT, 1000 ); + props.put( AvailableSettings.JPA_LOCK_TIMEOUT, 1000 ); try { _entityManager.lock( lock2, LockModeType.PESSIMISTIC_READ, props ); } @@ -763,7 +765,7 @@ public void testContendedPessimisticWriteLockTimeout() throws Exception { log.info( "testContendedPessimisticWriteLockTimeout: (BG) read write-locked entity" ); Map props = new HashMap(); // timeout is in milliseconds - props.put( AvailableSettings.LOCK_TIMEOUT, 1000 ); + props.put( AvailableSettings.JPA_LOCK_TIMEOUT, 1000 ); try { _entityManager.lock( lock2, LockModeType.PESSIMISTIC_WRITE, props ); } @@ -843,7 +845,7 @@ public void testContendedPessimisticWriteLockNoWait() throws Exception { log.info( "testContendedPessimisticWriteLockNoWait: (BG) read write-locked entity" ); Map props = new HashMap(); // timeout of zero means no wait (for lock) - props.put( AvailableSettings.LOCK_TIMEOUT, 0 ); + props.put( AvailableSettings.JPA_LOCK_TIMEOUT, 0 ); try { _entityManager.lock( lock2, LockModeType.PESSIMISTIC_WRITE, props ); } @@ -1081,7 +1083,7 @@ public void testLockTimeoutEMProps() throws Exception { final CountDownLatch latch = new CountDownLatch( 1 ); final Map timeoutProps = new HashMap(); - timeoutProps.put( AvailableSettings.LOCK_TIMEOUT, 1000 ); // 1 second timeout + timeoutProps.put( AvailableSettings.JPA_LOCK_TIMEOUT, 1000 ); // 1 second timeout final Lock lock = new Lock(); FutureTask bgTask = new FutureTask<>( @@ -1095,7 +1097,7 @@ public void testLockTimeoutEMProps() throws Exception { Lock lock2 = _entityManager.getReference( Lock.class, lock.getId() ); lock2.getName(); // force entity to be read log.info( "testLockTimeoutEMProps: (BG) read write-locked entity" ); - // em2 already has AvailableSettings.LOCK_TIMEOUT of 1 second applied + // em2 already has AvailableSettings.JPA_LOCK_TIMEOUT of 1 second applied try { _entityManager.lock( lock2, LockModeType.PESSIMISTIC_WRITE ); } diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/lock/LockTimeoutPropertyTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/lock/LockTimeoutPropertyTest.java index cfc744343645..0453e047fdfc 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/lock/LockTimeoutPropertyTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/lock/LockTimeoutPropertyTest.java @@ -11,8 +11,8 @@ import javax.persistence.LockModeType; import javax.persistence.Query; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.dialect.H2Dialect; -import org.hibernate.jpa.AvailableSettings; import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; import org.hibernate.testing.RequiresDialect; @@ -31,7 +31,7 @@ public class LockTimeoutPropertyTest extends BaseEntityManagerFunctionalTestCase { @Override protected void addConfigOptions(Map options) { - options.put( AvailableSettings.LOCK_TIMEOUT, "2000" ); + options.put( AvailableSettings.JPA_LOCK_TIMEOUT, "2000" ); } @Test @@ -51,9 +51,9 @@ public void testLockTimeoutASNamedQueryHint(){ public void testTimeoutHint(){ EntityManager em = getOrCreateEntityManager(); em.getTransaction().begin(); - boolean b= em.getProperties().containsKey( AvailableSettings.LOCK_TIMEOUT ); + boolean b= em.getProperties().containsKey( AvailableSettings.JPA_LOCK_TIMEOUT ); assertTrue( b ); - int timeout = Integer.valueOf( em.getProperties().get( AvailableSettings.LOCK_TIMEOUT ).toString() ); + int timeout = Integer.valueOf( em.getProperties().get( AvailableSettings.JPA_LOCK_TIMEOUT ).toString() ); assertEquals( 2000, timeout); org.hibernate.query.Query q = (org.hibernate.query.Query) em.createQuery( "select u from UnversionedLock u" ); timeout = q.getLockOptions().getTimeOut(); @@ -61,7 +61,7 @@ public void testTimeoutHint(){ Query query = em.createQuery( "select u from UnversionedLock u" ); query.setLockMode(LockModeType.PESSIMISTIC_WRITE); - query.setHint( AvailableSettings.LOCK_TIMEOUT, 3000 ); + query.setHint( AvailableSettings.JPA_LOCK_TIMEOUT, 3000 ); q = (org.hibernate.query.Query) query; timeout = q.getLockOptions().getTimeOut(); assertEquals( 3000, timeout ); diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/lock/QueryLockingTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/lock/QueryLockingTest.java index 1229ae4f5fb2..ca136f02c56d 100755 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/lock/QueryLockingTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/lock/QueryLockingTest.java @@ -19,14 +19,16 @@ import javax.persistence.criteria.JoinType; import javax.persistence.criteria.ParameterExpression; import javax.persistence.criteria.Root; + import org.hibernate.LockMode; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.dialect.CockroachDB192Dialect; import org.hibernate.dialect.SQLServerDialect; import org.hibernate.internal.SessionImpl; -import org.hibernate.jpa.AvailableSettings; import org.hibernate.jpa.QueryHints; import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; import org.hibernate.query.NativeQuery; + import org.hibernate.testing.DialectChecks; import org.hibernate.testing.RequiresDialect; import org.hibernate.testing.RequiresDialectFeature; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/metagen/mappedsuperclass/attribute/MappedSuperclassWithAttributesTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/metagen/mappedsuperclass/attribute/MappedSuperclassWithAttributesTest.java index ba056b2522eb..af64f3f6240f 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/metagen/mappedsuperclass/attribute/MappedSuperclassWithAttributesTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/metagen/mappedsuperclass/attribute/MappedSuperclassWithAttributesTest.java @@ -9,7 +9,7 @@ import java.util.Arrays; import javax.persistence.EntityManagerFactory; -import org.hibernate.jpa.AvailableSettings; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.jpa.test.TestingEntityManagerFactoryGenerator; import org.hibernate.testing.TestForIssue; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/metagen/mappedsuperclass/embedded/MappedSuperclassWithEmbeddedTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/metagen/mappedsuperclass/embedded/MappedSuperclassWithEmbeddedTest.java index 43c4a6ba500a..aebc3934c864 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/metagen/mappedsuperclass/embedded/MappedSuperclassWithEmbeddedTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/metagen/mappedsuperclass/embedded/MappedSuperclassWithEmbeddedTest.java @@ -6,16 +6,15 @@ */ package org.hibernate.jpa.test.metagen.mappedsuperclass.embedded; -import javax.persistence.EntityManagerFactory; import java.util.Arrays; +import javax.persistence.EntityManagerFactory; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.jpa.test.TestingEntityManagerFactoryGenerator; -import org.hibernate.jpa.AvailableSettings; - -import org.junit.Test; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.junit4.BaseUnitTestCase; +import org.junit.Test; import static org.junit.Assert.assertNotNull; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/metagen/mappedsuperclass/embeddedid/MappedSuperclassWithEmbeddedIdTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/metagen/mappedsuperclass/embeddedid/MappedSuperclassWithEmbeddedIdTest.java index cb97be727eb0..297ef82d88cc 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/metagen/mappedsuperclass/embeddedid/MappedSuperclassWithEmbeddedIdTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/metagen/mappedsuperclass/embeddedid/MappedSuperclassWithEmbeddedIdTest.java @@ -6,16 +6,15 @@ */ package org.hibernate.jpa.test.metagen.mappedsuperclass.embeddedid; -import javax.persistence.EntityManagerFactory; import java.util.Arrays; +import javax.persistence.EntityManagerFactory; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.jpa.test.TestingEntityManagerFactoryGenerator; -import org.hibernate.jpa.AvailableSettings; - -import org.junit.Test; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.junit4.BaseUnitTestCase; +import org.junit.Test; import static org.junit.Assert.assertNotNull; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/metagen/mappedsuperclass/idclass/MappedSuperclassWithEntityWithIdClassTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/metagen/mappedsuperclass/idclass/MappedSuperclassWithEntityWithIdClassTest.java index 7758440160b2..2e71b9c72712 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/metagen/mappedsuperclass/idclass/MappedSuperclassWithEntityWithIdClassTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/metagen/mappedsuperclass/idclass/MappedSuperclassWithEntityWithIdClassTest.java @@ -6,16 +6,15 @@ */ package org.hibernate.jpa.test.metagen.mappedsuperclass.idclass; -import javax.persistence.EntityManagerFactory; import java.util.Arrays; +import javax.persistence.EntityManagerFactory; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.jpa.test.TestingEntityManagerFactoryGenerator; -import org.hibernate.jpa.AvailableSettings; - -import org.junit.Test; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.junit4.BaseUnitTestCase; +import org.junit.Test; import static org.junit.Assert.assertNotNull; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/metagen/mappedsuperclass/overridden/MappedSuperclassWithOverriddenAttributeTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/metagen/mappedsuperclass/overridden/MappedSuperclassWithOverriddenAttributeTest.java index d3d4fed79dc0..b25cb2b0a800 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/metagen/mappedsuperclass/overridden/MappedSuperclassWithOverriddenAttributeTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/metagen/mappedsuperclass/overridden/MappedSuperclassWithOverriddenAttributeTest.java @@ -9,7 +9,7 @@ import java.util.Arrays; import javax.persistence.EntityManagerFactory; -import org.hibernate.jpa.AvailableSettings; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.jpa.test.TestingEntityManagerFactoryGenerator; import org.hibernate.testing.FailureExpected; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/ops/RemoveOrderingTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/ops/RemoveOrderingTest.java index 3cbe72f63267..7415986f26a7 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/ops/RemoveOrderingTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/ops/RemoveOrderingTest.java @@ -15,7 +15,7 @@ import javax.persistence.Table; import java.util.Map; -import org.hibernate.jpa.AvailableSettings; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; import org.junit.Test; @@ -30,7 +30,7 @@ public class RemoveOrderingTest extends BaseEntityManagerFunctionalTestCase { @Override protected void addConfigOptions(Map options) { super.addConfigOptions( options ); - options.put( AvailableSettings.VALIDATION_MODE, "NONE" ); + options.put( AvailableSettings.JPA_VALIDATION_MODE, "NONE" ); } @Override diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/packaging/PackagedEntityManagerTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/packaging/PackagedEntityManagerTest.java index aed7664b0684..b61c05139d90 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/packaging/PackagedEntityManagerTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/packaging/PackagedEntityManagerTest.java @@ -15,11 +15,11 @@ import javax.persistence.Persistence; import javax.persistence.PersistenceException; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.event.service.spi.EventListenerRegistry; import org.hibernate.event.spi.EventType; import org.hibernate.internal.util.ConfigHelper; -import org.hibernate.jpa.AvailableSettings; import org.hibernate.jpa.HibernateEntityManagerFactory; import org.hibernate.jpa.test.Distributor; import org.hibernate.jpa.test.Item; @@ -44,7 +44,6 @@ import org.hibernate.stat.Statistics; import org.junit.After; -import org.junit.Before; import org.junit.Test; import static org.junit.Assert.assertEquals; @@ -295,7 +294,7 @@ public void testOverriddenPar() throws Exception { addPackageToClasspath( testPackage ); HashMap properties = new HashMap(); - properties.put( AvailableSettings.JTA_DATASOURCE, null ); + properties.put( AvailableSettings.JPA_JTA_DATASOURCE, null ); Properties p = new Properties(); p.load( ConfigHelper.getResourceAsStream( "/overridenpar.properties" ) ); properties.putAll( p ); diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/persistenceunit/TwoPersistenceUnits2LCDisabledEnabled.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/persistenceunit/TwoPersistenceUnits2LCDisabledEnabled.java index af22ffdd77fb..d90594956420 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/persistenceunit/TwoPersistenceUnits2LCDisabledEnabled.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/persistenceunit/TwoPersistenceUnits2LCDisabledEnabled.java @@ -36,7 +36,7 @@ public class TwoPersistenceUnits2LCDisabledEnabled { @TestForIssue( jiraKey = "HHH-11516" ) public void testDisabledEnabled() { final Map config = Environment.getProperties(); - config.put( org.hibernate.jpa.AvailableSettings.LOADED_CLASSES, Collections.singletonList( AnEntity.class ) ); + config.put( AvailableSettings.LOADED_CLASSES, Collections.singletonList( AnEntity.class ) ); config.put( "javax.persistence.sharedCache.mode", SharedCacheMode.ENABLE_SELECTIVE ); config.put( AvailableSettings.USE_SECOND_LEVEL_CACHE, "false" ); diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/procedure/DateTimeParameterTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/procedure/DateTimeParameterTest.java index 335ddbef4305..343719430568 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/procedure/DateTimeParameterTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/procedure/DateTimeParameterTest.java @@ -30,11 +30,11 @@ import javax.persistence.Temporal; import javax.persistence.TemporalType; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.dialect.DerbyTenSevenDialect; import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess; import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.engine.spi.SessionFactoryImplementor; -import org.hibernate.jpa.AvailableSettings; import org.hibernate.jpa.HibernateEntityManagerFactory; import org.hibernate.jpa.boot.spi.Bootstrap; import org.hibernate.jpa.boot.spi.PersistenceUnitDescriptor; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/procedure/JpaTckUsageTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/procedure/JpaTckUsageTest.java index 4aee30970c53..0aa68a3856a7 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/procedure/JpaTckUsageTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/procedure/JpaTckUsageTest.java @@ -19,11 +19,11 @@ import javax.persistence.EntityManager; import javax.persistence.StoredProcedureQuery; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.dialect.DerbyTenSevenDialect; import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess; import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.engine.spi.SessionFactoryImplementor; -import org.hibernate.jpa.AvailableSettings; import org.hibernate.jpa.HibernateEntityManagerFactory; import org.hibernate.jpa.boot.spi.Bootstrap; import org.hibernate.jpa.boot.spi.PersistenceUnitDescriptor; diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/query/CachedQueryTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/query/CachedQueryTest.java index 083efefe93e6..e3ab7a0da3ff 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/query/CachedQueryTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/query/CachedQueryTest.java @@ -12,8 +12,7 @@ import javax.persistence.SharedCacheMode; import javax.persistence.TypedQuery; -import org.hibernate.cfg.Environment; -import org.hibernate.jpa.AvailableSettings; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.jpa.HibernateEntityManagerFactory; import org.hibernate.jpa.QueryHints; import org.hibernate.jpa.spi.HibernateEntityManagerImplementor; @@ -42,7 +41,7 @@ public void testCacheableQuery() { em.getTransaction().commit(); em.close(); - HibernateEntityManagerFactory hemf = (HibernateEntityManagerFactory) entityManagerFactory(); + HibernateEntityManagerFactory hemf = entityManagerFactory(); Statistics stats = hemf.getSessionFactory().getStatistics(); assertEquals( 0, stats.getQueryCacheHitCount() ); @@ -157,10 +156,10 @@ public void testCacheableQuery() { } protected void addConfigOptions(Map options) { - options.put( AvailableSettings.SHARED_CACHE_MODE, SharedCacheMode.ALL ); - options.put( Environment.GENERATE_STATISTICS, "true" ); - options.put( Environment.USE_QUERY_CACHE, "true" ); - options.put( Environment.USE_SECOND_LEVEL_CACHE, "true" ); + options.put( AvailableSettings.JPA_SHARED_CACHE_MODE, SharedCacheMode.ALL ); + options.put( AvailableSettings.GENERATE_STATISTICS, "true" ); + options.put( AvailableSettings.USE_QUERY_CACHE, "true" ); + options.put( AvailableSettings.USE_SECOND_LEVEL_CACHE, "true" ); } @Override diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/schemagen/SchemaCreateDropUtf8WithoutHbm2DdlCharsetNameTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/schemagen/SchemaCreateDropUtf8WithoutHbm2DdlCharsetNameTest.java index 167370990cb0..115b3d67988a 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/schemagen/SchemaCreateDropUtf8WithoutHbm2DdlCharsetNameTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/schemagen/SchemaCreateDropUtf8WithoutHbm2DdlCharsetNameTest.java @@ -21,12 +21,16 @@ import org.hibernate.jpa.boot.spi.Bootstrap; import org.hibernate.jpa.boot.spi.EntityManagerFactoryBuilder; import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; -import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.TestForIssue; import org.junit.After; import org.junit.Before; import org.junit.Test; +import static org.hibernate.cfg.AvailableSettings.HBM2DDL_SCRIPTS_ACTION; +import static org.hibernate.cfg.AvailableSettings.HBM2DDL_SCRIPTS_CREATE_TARGET; +import static org.hibernate.cfg.AvailableSettings.HBM2DDL_SCRIPTS_DROP_TARGET; +import static org.hibernate.cfg.AvailableSettings.LOADED_CLASSES; import static org.junit.Assert.assertTrue; /** @@ -41,13 +45,13 @@ public class SchemaCreateDropUtf8WithoutHbm2DdlCharsetNameTest { protected Map getConfig() { final Map config = Environment.getProperties(); - config.put( org.hibernate.cfg.AvailableSettings.HBM2DDL_SCRIPTS_CREATE_TARGET, createSchema.toPath() ); - config.put( org.hibernate.cfg.AvailableSettings.HBM2DDL_SCRIPTS_DROP_TARGET, dropSchema.toPath() ); - config.put( org.hibernate.cfg.AvailableSettings.HBM2DDL_SCRIPTS_ACTION, "drop-and-create" ); + config.put( HBM2DDL_SCRIPTS_CREATE_TARGET, createSchema.toPath() ); + config.put( HBM2DDL_SCRIPTS_DROP_TARGET, dropSchema.toPath() ); + config.put( HBM2DDL_SCRIPTS_ACTION, "drop-and-create" ); ArrayList classes = new ArrayList(); classes.addAll( Arrays.asList( new Class[] {TestEntity.class} ) ); - config.put( org.hibernate.jpa.AvailableSettings.LOADED_CLASSES, classes ); + config.put( LOADED_CLASSES, classes ); return config; } diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/schemagen/SchemaDatabaseFileGenerationFailureTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/schemagen/SchemaDatabaseFileGenerationFailureTest.java index 84491e51f19a..5d42636c9949 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/schemagen/SchemaDatabaseFileGenerationFailureTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/schemagen/SchemaDatabaseFileGenerationFailureTest.java @@ -27,8 +27,8 @@ import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; import org.hibernate.tool.schema.spi.CommandAcceptanceException; import org.hibernate.tool.schema.spi.SchemaManagementException; -import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.TestForIssue; import org.junit.After; import org.junit.Before; import org.junit.Test; @@ -123,7 +123,7 @@ private Map getConfig() { ArrayList classes = new ArrayList<>(); classes.addAll( Arrays.asList( new Class[] { TestEntity.class } ) ); - config.put( org.hibernate.jpa.AvailableSettings.LOADED_CLASSES, classes ); + config.put( AvailableSettings.LOADED_CLASSES, classes ); return config; } } diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/schemagen/SchemaScriptFileGenerationFailureTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/schemagen/SchemaScriptFileGenerationFailureTest.java index 3fb7307a8b7e..b851314e988f 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/schemagen/SchemaScriptFileGenerationFailureTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/schemagen/SchemaScriptFileGenerationFailureTest.java @@ -110,13 +110,13 @@ private PersistenceUnitDescriptor buildPersistenceUnitDescriptor() { private Map getConfig() { final Map config = Environment.getProperties(); - config.put( org.hibernate.cfg.AvailableSettings.HBM2DDL_SCRIPTS_DROP_TARGET, writer ); - config.put( org.hibernate.cfg.AvailableSettings.HBM2DDL_SCRIPTS_ACTION, "drop-and-create" ); + config.put( AvailableSettings.HBM2DDL_SCRIPTS_DROP_TARGET, writer ); + config.put( AvailableSettings.HBM2DDL_SCRIPTS_ACTION, "drop-and-create" ); config.put( AvailableSettings.HBM2DDL_HALT_ON_ERROR, "true" ); ArrayList classes = new ArrayList<>(); classes.addAll( Arrays.asList( new Class[] { TestEntity.class } ) ); - config.put( org.hibernate.jpa.AvailableSettings.LOADED_CLASSES, classes ); + config.put( AvailableSettings.LOADED_CLASSES, classes ); return config; } diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/schemagen/SchemaScriptFileGenerationTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/schemagen/SchemaScriptFileGenerationTest.java index 02ca66ac7241..078576424afd 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/schemagen/SchemaScriptFileGenerationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/schemagen/SchemaScriptFileGenerationTest.java @@ -18,6 +18,7 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.Environment; import org.hibernate.jpa.boot.spi.Bootstrap; import org.hibernate.jpa.boot.spi.EntityManagerFactoryBuilder; @@ -108,13 +109,13 @@ private PersistenceUnitDescriptor buildPersistenceUnitDescriptor() { private Map getConfig() { final Map config = Environment.getProperties(); - config.put( org.hibernate.cfg.AvailableSettings.HBM2DDL_SCRIPTS_CREATE_TARGET, createSchema.toPath() ); - config.put( org.hibernate.cfg.AvailableSettings.HBM2DDL_SCRIPTS_DROP_TARGET, dropSchema.toPath() ); - config.put( org.hibernate.cfg.AvailableSettings.HBM2DDL_SCRIPTS_ACTION, "drop-and-create" ); + config.put( AvailableSettings.HBM2DDL_SCRIPTS_CREATE_TARGET, createSchema.toPath() ); + config.put( AvailableSettings.HBM2DDL_SCRIPTS_DROP_TARGET, dropSchema.toPath() ); + config.put( AvailableSettings.HBM2DDL_SCRIPTS_ACTION, "drop-and-create" ); ArrayList classes = new ArrayList(); classes.addAll( Arrays.asList( new Class[] {TestEntity.class} ) ); - config.put( org.hibernate.jpa.AvailableSettings.LOADED_CLASSES, classes ); + config.put( AvailableSettings.LOADED_CLASSES, classes ); return config; } } diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/transaction/CloseEntityManagerWithActiveTransactionTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/transaction/CloseEntityManagerWithActiveTransactionTest.java index bd81641e846c..082328a61213 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/transaction/CloseEntityManagerWithActiveTransactionTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/transaction/CloseEntityManagerWithActiveTransactionTest.java @@ -26,9 +26,9 @@ import javax.transaction.TransactionManager; import org.hibernate.Session; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl; import org.hibernate.internal.SessionImpl; -import org.hibernate.jpa.AvailableSettings; import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; import org.hibernate.testing.TestForIssue; @@ -49,8 +49,8 @@ public class CloseEntityManagerWithActiveTransactionTest extends BaseEntityManag protected void addConfigOptions(Map options) { super.addConfigOptions( options ); TestingJtaBootstrap.prepare( options ); - options.put( AvailableSettings.TRANSACTION_TYPE, "JTA" ); - options.put( org.hibernate.cfg.AvailableSettings.JPA_TRANSACTION_COMPLIANCE, "true" ); + options.put( AvailableSettings.JPA_TRANSACTION_TYPE, "JTA" ); + options.put( AvailableSettings.JPA_TRANSACTION_COMPLIANCE, "true" ); } @Override diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/transaction/JtaGetTransactionThrowsExceptionTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/transaction/JtaGetTransactionThrowsExceptionTest.java index 003a69beaca3..89cef09a36a8 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/transaction/JtaGetTransactionThrowsExceptionTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/transaction/JtaGetTransactionThrowsExceptionTest.java @@ -10,7 +10,7 @@ import javax.persistence.EntityManager; -import org.hibernate.jpa.AvailableSettings; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; import org.hibernate.testing.TestForIssue; @@ -27,8 +27,8 @@ public class JtaGetTransactionThrowsExceptionTest extends BaseEntityManagerFunct protected void addConfigOptions(Map options) { super.addConfigOptions( options ); TestingJtaBootstrap.prepare( options ); - options.put( AvailableSettings.TRANSACTION_TYPE, "JTA" ); - options.put( org.hibernate.cfg.AvailableSettings.JPA_TRANSACTION_COMPLIANCE, "true" ); + options.put( AvailableSettings.JPA_TRANSACTION_TYPE, "JTA" ); + options.put( AvailableSettings.JPA_TRANSACTION_COMPLIANCE, "true" ); } @Test(expected = IllegalStateException.class) diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/transaction/SynchronizationTypeTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/transaction/SynchronizationTypeTest.java index ed6a6cde378d..a784fe3dfd64 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/transaction/SynchronizationTypeTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/transaction/SynchronizationTypeTest.java @@ -14,9 +14,9 @@ import javax.persistence.criteria.CriteriaDelete; import javax.persistence.criteria.CriteriaUpdate; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.transaction.internal.jta.JtaStatusHelper; -import org.hibernate.jpa.AvailableSettings; import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; import org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorImpl; @@ -43,7 +43,7 @@ public class SynchronizationTypeTest extends BaseEntityManagerFunctionalTestCase protected void addConfigOptions(Map options) { super.addConfigOptions( options ); TestingJtaBootstrap.prepare( options ); - options.put( AvailableSettings.TRANSACTION_TYPE, "JTA" ); + options.put( AvailableSettings.JPA_TRANSACTION_TYPE, "JTA" ); } @Override diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/transaction/TransactionJoiningTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/transaction/TransactionJoiningTest.java index c444e653b65a..ec47af6bf84b 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/transaction/TransactionJoiningTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/transaction/TransactionJoiningTest.java @@ -15,10 +15,10 @@ import javax.transaction.Status; import org.hibernate.HibernateException; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.engine.transaction.internal.jta.JtaStatusHelper; import org.hibernate.internal.SessionImpl; -import org.hibernate.jpa.AvailableSettings; import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; import org.hibernate.resource.transaction.backend.jta.internal.JtaTransactionCoordinatorImpl; @@ -42,7 +42,7 @@ public class TransactionJoiningTest extends BaseEntityManagerFunctionalTestCase protected void addConfigOptions(Map options) { super.addConfigOptions( options ); TestingJtaBootstrap.prepare( options ); - options.put( AvailableSettings.TRANSACTION_TYPE, "JTA" ); + options.put( AvailableSettings.JPA_TRANSACTION_TYPE, "JTA" ); } @Test diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/transaction/TransactionRolledBackInDifferentThreadTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/transaction/TransactionRolledBackInDifferentThreadTest.java index fd88c254482b..cfec8c2ee781 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/transaction/TransactionRolledBackInDifferentThreadTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/transaction/TransactionRolledBackInDifferentThreadTest.java @@ -6,21 +6,19 @@ */ package org.hibernate.jpa.test.transaction; +import java.util.Map; import javax.persistence.EntityManager; import javax.transaction.RollbackException; import javax.transaction.Status; import javax.transaction.SystemException; -import java.util.Map; import org.hibernate.HibernateException; -import org.hibernate.jpa.AvailableSettings; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; -import org.junit.Ignore; -import org.junit.Test; - import org.hibernate.testing.jta.TestingJtaBootstrap; import org.hibernate.testing.jta.TestingJtaPlatformImpl; +import org.junit.Test; import static org.junit.Assert.fail; @@ -35,7 +33,7 @@ public class TransactionRolledBackInDifferentThreadTest extends BaseEntityManage protected void addConfigOptions(Map options) { super.addConfigOptions( options ); TestingJtaBootstrap.prepare( options ); - options.put( AvailableSettings.TRANSACTION_TYPE, "JTA" ); + options.put( AvailableSettings.JPA_TRANSACTION_TYPE, "JTA" ); } @Test diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/xml/XmlTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/xml/XmlTest.java index b094704db953..d927393e3452 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/xml/XmlTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/xml/XmlTest.java @@ -10,8 +10,8 @@ import javax.persistence.EntityManager; import javax.persistence.SharedCacheMode; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.jpa.AvailableSettings; import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; import org.hibernate.persister.entity.EntityPersister; @@ -42,7 +42,7 @@ public Class[] getAnnotatedClasses() { } protected void addConfigOptions(Map options) { - options.put( AvailableSettings.SHARED_CACHE_MODE, SharedCacheMode.ENABLE_SELECTIVE ); + options.put( AvailableSettings.JPA_SHARED_CACHE_MODE, SharedCacheMode.ENABLE_SELECTIVE ); } @Override diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/jpa/PersistenceUnitOverridesTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/jpa/PersistenceUnitOverridesTests.java index 422ee62c7e15..0deba30d7dd6 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/jpa/PersistenceUnitOverridesTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/jpa/PersistenceUnitOverridesTests.java @@ -396,7 +396,7 @@ public void testCfgXmlBaseline() { final PersistenceUnitInfoAdapter info = new PersistenceUnitInfoAdapter() { private final Properties props = new Properties(); { - props.put( org.hibernate.jpa.AvailableSettings.CFG_FILE, "org/hibernate/orm/test/bootstrap/jpa/hibernate.cfg.xml" ); + props.put( AvailableSettings.CFG_XML_FILE, "org/hibernate/orm/test/bootstrap/jpa/hibernate.cfg.xml" ); } @Override @@ -437,7 +437,7 @@ public void testIntegrationOverridesOfCfgXml() { final PersistenceUnitInfoAdapter info = new PersistenceUnitInfoAdapter() { private final Properties props = new Properties(); { - props.put( org.hibernate.jpa.AvailableSettings.CFG_FILE, "org/hibernate/orm/test/bootstrap/jpa/hibernate.cfg.xml" ); + props.put( AvailableSettings.CFG_XML_FILE, "org/hibernate/orm/test/bootstrap/jpa/hibernate.cfg.xml" ); } @Override diff --git a/hibernate-core/src/test/java/org/hibernate/test/collection/idbag/IdBagElementNullBasicTest.java b/hibernate-core/src/test/java/org/hibernate/test/collection/idbag/IdBagElementNullBasicTest.java index 87a6f6f9dc31..cd90737b6530 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/collection/idbag/IdBagElementNullBasicTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/collection/idbag/IdBagElementNullBasicTest.java @@ -177,10 +177,11 @@ public static class AnEntity { @ElementCollection @CollectionTable(name = "AnEntity_aCollection", joinColumns = { @JoinColumn( name = "AnEntity_id" ) }) @CollectionId( - columns = { @Column }, + //columns = { @Column }, + column = @Column( name = "collection_id" ), type = @Type(type = "long"), generator = "increment" ) - private List aCollection = new ArrayList(); + private List aCollection = new ArrayList<>(); } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/exceptionhandling/BaseJpaOrNativeBootstrapFunctionalTestCase.java b/hibernate-core/src/test/java/org/hibernate/test/exceptionhandling/BaseJpaOrNativeBootstrapFunctionalTestCase.java index 3821563406ea..0223827208f2 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/exceptionhandling/BaseJpaOrNativeBootstrapFunctionalTestCase.java +++ b/hibernate-core/src/test/java/org/hibernate/test/exceptionhandling/BaseJpaOrNativeBootstrapFunctionalTestCase.java @@ -26,13 +26,13 @@ import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.boot.registry.internal.StandardServiceRegistryImpl; import org.hibernate.bytecode.enhance.spi.EnhancementContext; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.Configuration; import org.hibernate.cfg.Environment; import org.hibernate.dialect.Dialect; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.internal.util.config.ConfigurationHelper; -import org.hibernate.jpa.AvailableSettings; import org.hibernate.jpa.HibernatePersistenceProvider; import org.hibernate.jpa.boot.spi.Bootstrap; import org.hibernate.jpa.boot.spi.PersistenceUnitDescriptor; @@ -273,7 +273,7 @@ private StandardServiceRegistryImpl buildServiceRegistry(BootstrapServiceRegistr private Properties buildProperties() { Properties properties = Environment.getProperties(); - properties.put( org.hibernate.cfg.AvailableSettings.CACHE_REGION_FACTORY, CachingRegionFactory.class.getName() ); + properties.put( AvailableSettings.CACHE_REGION_FACTORY, CachingRegionFactory.class.getName() ); for ( Map.Entry entry : getCachedClasses().entrySet() ) { properties.put( AvailableSettings.CLASS_CACHE_PREFIX + "." + entry.getKey().getName(), entry.getValue() ); } @@ -284,10 +284,10 @@ private Properties buildProperties() { configure( properties ); if ( createSchema() ) { - properties.put( org.hibernate.cfg.AvailableSettings.HBM2DDL_AUTO, "create-drop" ); + properties.put( AvailableSettings.HBM2DDL_AUTO, "create-drop" ); } - properties.put( org.hibernate.cfg.AvailableSettings.USE_NEW_ID_GENERATOR_MAPPINGS, "true" ); - properties.put( org.hibernate.cfg.AvailableSettings.DIALECT, getDialect().getClass().getName() ); + properties.put( AvailableSettings.USE_NEW_ID_GENERATOR_MAPPINGS, "true" ); + properties.put( AvailableSettings.DIALECT, getDialect().getClass().getName() ); return properties; } diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/BaseEnversJPAFunctionalTestCase.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/BaseEnversJPAFunctionalTestCase.java index 4525a1423b05..1b26b8506744 100644 --- a/hibernate-envers/src/test/java/org/hibernate/envers/test/BaseEnversJPAFunctionalTestCase.java +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/BaseEnversJPAFunctionalTestCase.java @@ -16,11 +16,11 @@ import org.hibernate.boot.registry.internal.StandardServiceRegistryImpl; import org.hibernate.boot.spi.MetadataImplementor; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.Environment; import org.hibernate.dialect.Dialect; import org.hibernate.dialect.H2Dialect; import org.hibernate.engine.spi.SessionFactoryImplementor; -import org.hibernate.engine.spi.SessionImplementor; import org.hibernate.engine.transaction.internal.jta.JtaStatusHelper; import org.hibernate.envers.AuditReader; import org.hibernate.envers.AuditReaderFactory; @@ -29,17 +29,16 @@ import org.hibernate.hql.spi.id.global.GlobalTemporaryTableBulkIdStrategy; import org.hibernate.hql.spi.id.local.LocalTemporaryTableBulkIdStrategy; import org.hibernate.internal.util.StringHelper; -import org.hibernate.jpa.AvailableSettings; import org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl; import org.hibernate.jpa.boot.spi.Bootstrap; import org.hibernate.jpa.boot.spi.PersistenceUnitDescriptor; import org.hibernate.jpa.test.PersistenceUnitDescriptorAdapter; + import org.hibernate.testing.AfterClassOnce; import org.hibernate.testing.BeforeClassOnce; import org.hibernate.testing.jdbc.SharedDriverManagerConnectionProviderImpl; import org.hibernate.testing.jta.TestingJtaPlatformImpl; import org.hibernate.testing.junit4.Helper; -import org.jboss.logging.Logger; import org.junit.After; /** @@ -99,7 +98,7 @@ private Map buildSettings() { addMappings( settings ); if ( createSchema() ) { - settings.put( org.hibernate.cfg.AvailableSettings.HBM2DDL_AUTO, "create-drop" ); + settings.put( AvailableSettings.HBM2DDL_AUTO, "create-drop" ); final String secondSchemaName = createSecondSchema(); if ( StringHelper.isNotEmpty( secondSchemaName ) ) { if ( !(getDialect() instanceof H2Dialect) ) { @@ -119,8 +118,8 @@ private Map buildSettings() { settings.put( EnversSettings.USE_REVISION_ENTITY_WITH_NATIVE_ID, "false" ); - settings.put( org.hibernate.cfg.AvailableSettings.USE_NEW_ID_GENERATOR_MAPPINGS, "true" ); - settings.put( org.hibernate.cfg.AvailableSettings.DIALECT, getDialect().getClass().getName() ); + settings.put( AvailableSettings.USE_NEW_ID_GENERATOR_MAPPINGS, "true" ); + settings.put( AvailableSettings.DIALECT, getDialect().getClass().getName() ); return settings; } @@ -138,16 +137,16 @@ protected Map getConfig() { } if ( getEjb3DD().length > 0 ) { - ArrayList dds = new ArrayList(); + ArrayList dds = new ArrayList<>(); dds.addAll( Arrays.asList( getEjb3DD() ) ); - config.put( AvailableSettings.XML_FILE_NAMES, dds ); + config.put( AvailableSettings.ORM_XML_FILES, dds ); } config.put( GlobalTemporaryTableBulkIdStrategy.DROP_ID_TABLES, "true" ); config.put( LocalTemporaryTableBulkIdStrategy.DROP_ID_TABLES, "true" ); - if ( !Environment.getProperties().containsKey( Environment.CONNECTION_PROVIDER ) ) { + if ( ! Environment.getProperties().containsKey( AvailableSettings.CONNECTION_PROVIDER ) ) { config.put( - org.hibernate.cfg.AvailableSettings.CONNECTION_PROVIDER, + AvailableSettings.CONNECTION_PROVIDER, SharedDriverManagerConnectionProviderImpl.getInstance() ); } @@ -160,7 +159,7 @@ protected Map getConfig() { protected void addMappings(Map settings) { String[] mappings = getMappings(); if ( mappings != null ) { - settings.put( AvailableSettings.HBXML_FILES, String.join( ",", mappings ) ); + settings.put( AvailableSettings.HBM_XML_FILES, String.join( ",", mappings ) ); } } diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/performance/AbstractEntityManagerTest.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/performance/AbstractEntityManagerTest.java index a29d9f7fc4af..9230a0c787d5 100644 --- a/hibernate-envers/src/test/java/org/hibernate/envers/test/performance/AbstractEntityManagerTest.java +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/performance/AbstractEntityManagerTest.java @@ -13,6 +13,7 @@ import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder; import org.hibernate.boot.registry.internal.StandardServiceRegistryImpl; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.Environment; import org.hibernate.dialect.Dialect; import org.hibernate.envers.AuditReader; @@ -20,7 +21,6 @@ import org.hibernate.envers.configuration.EnversSettings; import org.hibernate.envers.boot.internal.EnversIntegrator; import org.hibernate.envers.test.AbstractEnversTest; -import org.hibernate.jpa.AvailableSettings; import org.hibernate.jpa.HibernateEntityManagerFactory; import org.hibernate.jpa.boot.internal.EntityManagerFactoryBuilderImpl; import org.hibernate.jpa.boot.spi.Bootstrap; @@ -83,8 +83,8 @@ protected void init(boolean audited, String auditStrategy) throws IOException { configurationProperties.setProperty( EnversIntegrator.AUTO_REGISTER, "false" ); } if ( createSchema() ) { - configurationProperties.setProperty( Environment.HBM2DDL_AUTO, "create-drop" ); - configurationProperties.setProperty( Environment.USE_NEW_ID_GENERATOR_MAPPINGS, "true" ); + configurationProperties.setProperty( AvailableSettings.HBM2DDL_AUTO, "create-drop" ); + configurationProperties.setProperty( AvailableSettings.USE_NEW_ID_GENERATOR_MAPPINGS, "true" ); configurationProperties.setProperty( EnversSettings.USE_REVISION_ENTITY_WITH_NATIVE_ID, "false" ); } if ( auditStrategy != null && !"".equals( auditStrategy ) ) { From e19eea19d1e1db5b80c0144093c0593ce4ff880b Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Mon, 11 Oct 2021 21:19:02 +0000 Subject: [PATCH 344/644] 5.6.0.Final --- changelog.txt | 15 +++++++++++++++ gradle/version.properties | 2 +- 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index c464d96e7164..73d54a5aa0c7 100644 --- a/changelog.txt +++ b/changelog.txt @@ -3,6 +3,21 @@ Hibernate 5 Changelog Note: Please refer to JIRA to learn more about each issue. +Changes in 5.6.0.Final (October 11, 2021) +------------------------------------------------------------------------------------------------------------------------ + +https://hibernate.atlassian.net/projects/HHH/versions/31985 + +** Bug + * [HHH-13295] - @EmbeddedId + @MapsId targeting a derived entity giving an error on bootstraping + +** Deprecation + * [HHH-14857] - Some more APIs marked as deprecated in preparation for v. 6 + +** Improvement + * [HHH-14868] - Upgrade to ByteBuddy 1.11.20 + + Changes in 5.6.0.CR1 (September 29, 2021) ------------------------------------------------------------------------------------------------------------------------ diff --git a/gradle/version.properties b/gradle/version.properties index b6875391f169..77592ac87414 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -hibernateVersion=5.6.0-SNAPSHOT \ No newline at end of file +hibernateVersion=5.6.0.Final \ No newline at end of file From d998696a0ff230f607e9aea4e9932f9f20a76ae7 Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Mon, 11 Oct 2021 21:23:51 +0000 Subject: [PATCH 345/644] 5.6.1-SNAPSHOT --- gradle/version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/version.properties b/gradle/version.properties index 77592ac87414..390986338952 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -hibernateVersion=5.6.0.Final \ No newline at end of file +hibernateVersion=5.6.1-SNAPSHOT \ No newline at end of file From 5f6e53334cfcc8973a4291e7fec01028fedf9244 Mon Sep 17 00:00:00 2001 From: Andrea Boriero Date: Mon, 2 Dec 2019 10:57:37 +0000 Subject: [PATCH 346/644] HHH-13766 Add test for issue --- .../AttributeConverterTest.java | 183 ++++++++++++++++++ 1 file changed, 183 insertions(+) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/AttributeConverterTest.java diff --git a/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/AttributeConverterTest.java b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/AttributeConverterTest.java new file mode 100644 index 000000000000..be6f07cdc420 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/bytecode/enhancement/lazy/proxy/inlinedirtychecking/AttributeConverterTest.java @@ -0,0 +1,183 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.test.bytecode.enhancement.lazy.proxy.inlinedirtychecking; + +import java.util.Objects; +import javax.persistence.AttributeConverter; +import javax.persistence.Column; +import javax.persistence.Convert; +import javax.persistence.Converter; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.validation.constraints.NotNull; + +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.cfg.AvailableSettings; + +import org.hibernate.testing.FailureExpected; +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.bytecode.enhancement.BytecodeEnhancerRunner; +import org.hibernate.testing.bytecode.enhancement.CustomEnhancementContext; +import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; + +/** + * @author Andrea Boriero + */ +@RunWith(BytecodeEnhancerRunner.class) +@CustomEnhancementContext({ DirtyCheckEnhancementContext.class }) +@TestForIssue( jiraKey = "HHH-13766") +public class AttributeConverterTest extends BaseNonConfigCoreFunctionalTestCase { + @Override + protected void configureStandardServiceRegistryBuilder(StandardServiceRegistryBuilder ssrb) { + super.configureStandardServiceRegistryBuilder( ssrb ); + ssrb.applySetting( AvailableSettings.ALLOW_ENHANCEMENT_AS_PROXY, "true" ); + } + + @Override + protected void applyMetadataSources(MetadataSources sources) { + super.applyMetadataSources( sources ); + sources.addAnnotatedClass( TestEntity.class ); + } + + private Long testEntityId; + + @Before + public void setUp() { + TestEntity entity = new TestEntity(); + inTransaction( + session -> { + TestData testData = new TestData(); + testData.setValue( "initial" ); + entity.setData( testData ); + session.save( entity ); + } + ); + testEntityId = entity.getId(); + } + + @Test + public void testUpdate() { + inTransaction( + session -> { + TestEntity entity = session.find( TestEntity.class, testEntityId ); + entity.getData().setValue( "new" ); + + } + ); + + inTransaction( + session -> { + TestEntity entity = session.find( TestEntity.class, testEntityId ); + assertThat( entity.getData().getValue(), is( "new" ) ); + } + ); + + } + + @Test + public void testUpdate2() { + inTransaction( + session -> { + TestEntity entity = session.find( TestEntity.class, testEntityId ); + TestData testData = new TestData(); + testData.setValue( "new" ); + entity.setData( testData ); + } + ); + + inTransaction( + session -> { + TestEntity entity = session.find( TestEntity.class, testEntityId ); + assertThat( entity.getData().getValue(), is( "new" ) ); + } + ); + + } + + @Entity(name = "TestEntity") + public static class TestEntity { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Long id; + + @NotNull + @Convert(converter = TestConverter.class) + @Column(name = "data") + private TestData data; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public TestData getData() { + return data; + } + + public void setData(TestData data) { + this.data = data; + } + } + + @Converter + public static class TestConverter implements AttributeConverter { + + @Override + public String convertToDatabaseColumn(TestData attribute) { + return attribute.getValue(); + } + + @Override + public TestData convertToEntityAttribute(String dbData) { + TestData testData = new TestData(); + testData.setValue( dbData ); + return testData; + } + } + + public static class TestData { + private String value; + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } + + @Override + public boolean equals(Object o) { + if ( this == o ) { + return true; + } + if ( o == null || getClass() != o.getClass() ) { + return false; + } + TestData testData = (TestData) o; + return Objects.equals( value, testData.value ); + } + + @Override + public int hashCode() { + return Objects.hash( value ); + } + } +} From fc636995c3cf624d941549225c2accc35a93a34b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Thu, 14 Oct 2021 14:31:41 +0200 Subject: [PATCH 347/644] HHH-14880 orm.xml: Take into account for --- .../reflection/internal/XMLContext.java | 6 ++-- .../converter/AttributeConverterTest.java | 31 +++++++++++++++++++ .../org/hibernate/test/converter/package.xml | 13 ++++++++ 3 files changed, 47 insertions(+), 3 deletions(-) create mode 100644 hibernate-core/src/test/resources/org/hibernate/test/converter/package.xml diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/XMLContext.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/XMLContext.java index 32e5aac98223..c949c2d09a0e 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/XMLContext.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/XMLContext.java @@ -107,7 +107,7 @@ public List addDocument(JaxbEntityMappings entityMappings) { entityMappingDefault.setAccess( entityMappings.getAccess() ); defaultElements.add( entityMappings ); - setLocalAttributeConverterDefinitions( entityMappings.getConverter() ); + setLocalAttributeConverterDefinitions( entityMappings.getConverter(), packageName ); addClass( entityMappings.getEntity(), packageName, entityMappingDefault, addedClasses ); @@ -168,14 +168,14 @@ private List addEntityListenerClasses(JaxbEntityListeners listeners, Str } @SuppressWarnings("unchecked") - private void setLocalAttributeConverterDefinitions(List converterElements) { + private void setLocalAttributeConverterDefinitions(List converterElements, String packageName) { for ( JaxbConverter converterElement : converterElements ) { final String className = converterElement.getClazz(); final boolean autoApply = Boolean.TRUE.equals( converterElement.isAutoApply() ); try { final Class attributeConverterClass = classLoaderAccess.classForName( - className + buildSafeClassName( className, packageName ) ); attributeConverterInfoList.add( new AttributeConverterDefinition( attributeConverterClass.newInstance(), autoApply ) diff --git a/hibernate-core/src/test/java/org/hibernate/test/converter/AttributeConverterTest.java b/hibernate-core/src/test/java/org/hibernate/test/converter/AttributeConverterTest.java index 2d71536d6e3c..0e726cc81c9a 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/converter/AttributeConverterTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/converter/AttributeConverterTest.java @@ -210,6 +210,37 @@ public void testBasicOrmXmlConverterApplication() { } } + @Test + @TestForIssue(jiraKey = "HHH-14881") + public void testBasicOrmXmlConverterWithOrmXmlPackage() { + final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder().build(); + + try { + MetadataImplementor metadata = (MetadataImplementor) new MetadataSources( ssr ) + .addAnnotatedClass( Tester.class ) + .addURL( ConfigHelper.findAsResource( "org/hibernate/test/converter/package.xml" ) ) + .getMetadataBuilder() + .build(); + + PersistentClass tester = metadata.getEntityBinding( Tester.class.getName() ); + Property nameProp = tester.getProperty( "name" ); + SimpleValue nameValue = (SimpleValue) nameProp.getValue(); + Type type = nameValue.getType(); + assertNotNull( type ); + if ( !AttributeConverterTypeAdapter.class.isInstance( type ) ) { + fail( "AttributeConverter not applied" ); + } + final AttributeConverterTypeAdapter basicType = assertTyping( AttributeConverterTypeAdapter.class, type ); + assertSame( StringTypeDescriptor.INSTANCE, basicType.getJavaTypeDescriptor() ); + final SqlTypeDescriptor sqlTypeDescriptor = basicType.getSqlTypeDescriptor(); + assertEquals( Dialect.getDialect().remapSqlTypeDescriptor(ClobTypeDescriptor.CLOB_BINDING).getSqlType(), sqlTypeDescriptor.getSqlType() ); + } + finally { + StandardServiceRegistryBuilder.destroy( ssr ); + } + } + + @Test public void testBasicConverterDisableApplication() { final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder().build(); diff --git a/hibernate-core/src/test/resources/org/hibernate/test/converter/package.xml b/hibernate-core/src/test/resources/org/hibernate/test/converter/package.xml new file mode 100644 index 000000000000..60a730d8268e --- /dev/null +++ b/hibernate-core/src/test/resources/org/hibernate/test/converter/package.xml @@ -0,0 +1,13 @@ + + + + + org.hibernate.test.converter + + From 7cc0c8370b589fd766e1a157c2c040662e3f4b1c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Thu, 14 Oct 2021 15:11:06 +0200 Subject: [PATCH 348/644] HHH-14881 Allow providing attribute converters through CDI when configured through orm.xml --- .../JPAXMLOverriddenMetadataProvider.java | 2 +- .../reflection/internal/XMLContext.java | 27 ++++++++----------- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenMetadataProvider.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenMetadataProvider.java index f65c1f275202..fef5c77f0b3f 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenMetadataProvider.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenMetadataProvider.java @@ -54,7 +54,7 @@ public final class JPAXMLOverriddenMetadataProvider implements MetadataProvider public JPAXMLOverriddenMetadataProvider(BootstrapContext bootstrapContext) { this.classLoaderAccess = bootstrapContext.getClassLoaderAccess(); - this.xmlContext = new XMLContext( classLoaderAccess ); + this.xmlContext = new XMLContext( bootstrapContext ); this.xmlMappingEnabled = bootstrapContext.getMetadataBuildingOptions().isXmlMappingEnabled(); } diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/XMLContext.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/XMLContext.java index c949c2d09a0e..06f1da27f913 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/XMLContext.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/XMLContext.java @@ -15,7 +15,7 @@ import javax.persistence.AttributeConverter; import org.hibernate.AnnotationException; -import org.hibernate.boot.AttributeConverterInfo; +import org.hibernate.boot.internal.ClassmateContext; import org.hibernate.boot.jaxb.mapping.spi.JaxbConverter; import org.hibernate.boot.jaxb.mapping.spi.JaxbEntity; import org.hibernate.boot.jaxb.mapping.spi.JaxbEntityListener; @@ -25,10 +25,11 @@ import org.hibernate.boot.jaxb.mapping.spi.JaxbPersistenceUnitDefaults; import org.hibernate.boot.jaxb.mapping.spi.JaxbPersistenceUnitMetadata; import org.hibernate.boot.jaxb.mapping.spi.ManagedType; +import org.hibernate.boot.model.convert.internal.ClassBasedConverterDescriptor; +import org.hibernate.boot.model.convert.spi.ConverterDescriptor; import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; import org.hibernate.boot.spi.BootstrapContext; import org.hibernate.boot.spi.ClassLoaderAccess; -import org.hibernate.cfg.AttributeConverterDefinition; import org.hibernate.cfg.annotations.reflection.AttributeConverterDefinitionCollector; import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreMessageLogger; @@ -44,6 +45,7 @@ public class XMLContext implements Serializable { private static final CoreMessageLogger LOG = CoreLogging.messageLogger( XMLContext.class ); private final ClassLoaderAccess classLoaderAccess; + private final ClassmateContext classmateContext; private Default globalDefaults; private final Map managedTypeOverride = new HashMap<>(); @@ -53,16 +55,9 @@ public class XMLContext implements Serializable { private final List defaultEntityListeners = new ArrayList<>(); private boolean hasContext = false; - /** - * @deprecated Use {@link #XMLContext(BootstrapContext)} instead. - */ - @Deprecated - public XMLContext(ClassLoaderAccess classLoaderAccess) { - this.classLoaderAccess = classLoaderAccess; - } - public XMLContext(BootstrapContext bootstrapContext) { this.classLoaderAccess = bootstrapContext.getClassLoaderAccess(); + this.classmateContext = bootstrapContext.getClassmateContext(); } /** @@ -177,8 +172,8 @@ private void setLocalAttributeConverterDefinitions(List converter final Class attributeConverterClass = classLoaderAccess.classForName( buildSafeClassName( className, packageName ) ); - attributeConverterInfoList.add( - new AttributeConverterDefinition( attributeConverterClass.newInstance(), autoApply ) + converterDescriptors.add( + new ClassBasedConverterDescriptor( attributeConverterClass, autoApply, classmateContext ) ); } catch (ClassLoadingException e) { @@ -227,13 +222,13 @@ public boolean hasContext() { return hasContext; } - private List attributeConverterInfoList = new ArrayList<>(); + private List converterDescriptors = new ArrayList<>(); public void applyDiscoveredAttributeConverters(AttributeConverterDefinitionCollector collector) { - for ( AttributeConverterInfo info : attributeConverterInfoList ) { - collector.addAttributeConverter( info ); + for ( ConverterDescriptor descriptor : converterDescriptors ) { + collector.addAttributeConverter( descriptor ); } - attributeConverterInfoList.clear(); + converterDescriptors.clear(); } public static class Default implements Serializable { From 97f75f2aeb822f86f4cb28bcb1f1ca01bc8b941c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Thu, 14 Oct 2021 15:02:37 +0200 Subject: [PATCH 349/644] HHH-14881 Test attribute converters provided through CDI and configured through orm.xml --- .../hibernate/test/cdi/converters/MyData.java | 37 ++++++++++ .../cdi/converters/OrmXmlConverterBean.java | 36 +++++++++ .../test/cdi/converters/TheOrmXmlEntity.java | 47 ++++++++++++ .../standard/CdiHostedConverterTest.java | 74 ++++++++++++++++++- .../org/hibernate/test/cdi/converters/orm.xml | 19 +++++ 5 files changed, 212 insertions(+), 1 deletion(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/cdi/converters/MyData.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/cdi/converters/OrmXmlConverterBean.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/cdi/converters/TheOrmXmlEntity.java create mode 100644 hibernate-core/src/test/resources/org/hibernate/test/cdi/converters/orm.xml diff --git a/hibernate-core/src/test/java/org/hibernate/test/cdi/converters/MyData.java b/hibernate-core/src/test/java/org/hibernate/test/cdi/converters/MyData.java new file mode 100644 index 000000000000..089d7fc9632a --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/cdi/converters/MyData.java @@ -0,0 +1,37 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.test.cdi.converters; + +import java.util.Objects; + +import org.hibernate.annotations.Immutable; + +@Immutable +public class MyData { + public final String value; + + public MyData(String value) { + this.value = value; + } + + @Override + public boolean equals(Object o) { + if ( this == o ) { + return true; + } + if ( o == null || getClass() != o.getClass() ) { + return false; + } + MyData myData = (MyData) o; + return value.equals( myData.value ); + } + + @Override + public int hashCode() { + return Objects.hash( value ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/cdi/converters/OrmXmlConverterBean.java b/hibernate-core/src/test/java/org/hibernate/test/cdi/converters/OrmXmlConverterBean.java new file mode 100644 index 000000000000..75b49b402788 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/cdi/converters/OrmXmlConverterBean.java @@ -0,0 +1,36 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.test.cdi.converters; + +import javax.persistence.AttributeConverter; + +public class OrmXmlConverterBean implements AttributeConverter { + private final MonitorBean monitor; + + @javax.inject.Inject + public OrmXmlConverterBean(MonitorBean monitor) { + this.monitor = monitor; + } + + @Override + public String convertToDatabaseColumn(MyData attribute) { + monitor.toDbCalled(); + if ( attribute == null ) { + return null; + } + return attribute.value; + } + + @Override + public MyData convertToEntityAttribute(String dbData) { + monitor.fromDbCalled(); + if ( dbData == null ) { + return null; + } + return new MyData( dbData ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/cdi/converters/TheOrmXmlEntity.java b/hibernate-core/src/test/java/org/hibernate/test/cdi/converters/TheOrmXmlEntity.java new file mode 100644 index 000000000000..41b36b333bc8 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/cdi/converters/TheOrmXmlEntity.java @@ -0,0 +1,47 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.test.cdi.converters; + +// This entity is mapped using an orm.xml file +public class TheOrmXmlEntity { + private Integer id; + private String name; + private MyData data; + + public TheOrmXmlEntity() { + } + + public TheOrmXmlEntity(Integer id, String name, MyData data) { + this.id = id; + this.name = name; + this.data = data; + } + + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public MyData getData() { + return data; + } + + public void setData(MyData data) { + this.data = data; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/cdi/converters/standard/CdiHostedConverterTest.java b/hibernate-core/src/test/java/org/hibernate/test/cdi/converters/standard/CdiHostedConverterTest.java index 6eaac0493275..5f3011a0c1a6 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/cdi/converters/standard/CdiHostedConverterTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/cdi/converters/standard/CdiHostedConverterTest.java @@ -18,10 +18,14 @@ import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.tool.schema.Action; +import org.hibernate.testing.TestForIssue; import org.hibernate.testing.junit4.BaseUnitTestCase; import org.hibernate.test.cdi.converters.ConverterBean; import org.hibernate.test.cdi.converters.MonitorBean; +import org.hibernate.test.cdi.converters.MyData; +import org.hibernate.test.cdi.converters.OrmXmlConverterBean; import org.hibernate.test.cdi.converters.TheEntity; +import org.hibernate.test.cdi.converters.TheOrmXmlEntity; import org.junit.Test; import static org.hibernate.testing.transaction.TransactionUtil2.inTransaction; @@ -34,7 +38,7 @@ */ public class CdiHostedConverterTest extends BaseUnitTestCase { @Test - public void testIt() { + public void testAnnotations() { MonitorBean.reset(); final SeContainerInitializer cdiInitializer = SeContainerInitializer.newInstance() @@ -99,4 +103,72 @@ public void testIt() { } } } + + @Test + @TestForIssue(jiraKey = "HHH-14881\n") + public void testOrmXml() { + MonitorBean.reset(); + + final SeContainerInitializer cdiInitializer = SeContainerInitializer.newInstance() + .disableDiscovery() + .addBeanClasses( MonitorBean.class, OrmXmlConverterBean.class ); + try ( final SeContainer cdiContainer = cdiInitializer.initialize() ) { + BootstrapServiceRegistry bsr = new BootstrapServiceRegistryBuilder().build(); + + final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder( bsr ) + .applySetting( AvailableSettings.HBM2DDL_AUTO, Action.CREATE_DROP ) + .applySetting( AvailableSettings.CDI_BEAN_MANAGER, cdiContainer.getBeanManager() ) + .build(); + + final SessionFactoryImplementor sessionFactory; + + try { + sessionFactory = (SessionFactoryImplementor) new MetadataSources( ssr ) + .addResource( "org/hibernate/test/cdi/converters/orm.xml" ) + .buildMetadata() + .getSessionFactoryBuilder() + .build(); + } + catch ( Exception e ) { + StandardServiceRegistryBuilder.destroy( ssr ); + throw e; + } + + // The CDI bean should have been built immediately... + assertTrue( MonitorBean.wasInstantiated() ); + assertEquals( 0, MonitorBean.currentFromDbCount() ); + assertEquals( 0, MonitorBean.currentToDbCount() ); + + try { + inTransaction( + sessionFactory, + session -> session.persist( new TheOrmXmlEntity( 1, "me", new MyData( "foo" ) ) ) + ); + + assertEquals( 0, MonitorBean.currentFromDbCount() ); + assertEquals( 1, MonitorBean.currentToDbCount() ); + + inTransaction( + sessionFactory, + session -> { + TheOrmXmlEntity it = session.find( TheOrmXmlEntity.class, 1 ); + assertNotNull( it ); + } + ); + + assertEquals( 1, MonitorBean.currentFromDbCount() ); + assertEquals( 1, MonitorBean.currentToDbCount() ); + } + finally { + inTransaction( + sessionFactory, + session -> { + session.createQuery( "delete TheOrmXmlEntity" ).executeUpdate(); + } + ); + + sessionFactory.close(); + } + } + } } diff --git a/hibernate-core/src/test/resources/org/hibernate/test/cdi/converters/orm.xml b/hibernate-core/src/test/resources/org/hibernate/test/cdi/converters/orm.xml new file mode 100644 index 000000000000..21f0d63bb588 --- /dev/null +++ b/hibernate-core/src/test/resources/org/hibernate/test/cdi/converters/orm.xml @@ -0,0 +1,19 @@ + + + + + + + + + + + + + From acc42253c3ffef2f3cf65de4559ab25d8cc5757f Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Thu, 14 Oct 2021 22:06:01 +0100 Subject: [PATCH 350/644] Fixed typo in migration-guide.adoc --- migration-guide.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/migration-guide.adoc b/migration-guide.adoc index 6e038bba594c..fe220a2b9b41 100644 --- a/migration-guide.adoc +++ b/migration-guide.adoc @@ -1,7 +1,7 @@ = 5.6 Migration Guide :toc: -This guide discusses migration from Hibernate ORM version 5.5 to version 5.5. +This guide discusses migration from Hibernate ORM version 5.5 to version 5.6. For migration from other versions, see https://github.com/hibernate/hibernate-orm/wiki/Migration-Guides . From 965f5bd92528364a828b3a4f3b78599ee7263575 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Mon, 11 Oct 2021 15:21:04 +0200 Subject: [PATCH 351/644] HHH-14869 Extract JPA listener definitions when building metadata rather than when creating the SessionFactory --- .../org/hibernate/cfg/AnnotationBinder.java | 31 ++++- .../org/hibernate/event/spi/EventEngine.java | 36 +----- ...CallbackDefinitionResolverLegacyImpl.java} | 111 +++++------------- .../internal/CallbackRegistryImplementor.java | 4 +- .../jpa/event/internal/CallbacksFactory.java | 85 +++++++++++--- .../event/internal/EmbeddableCallback.java | 22 +++- .../event/internal/EmptyCallbackBuilder.java | 29 ----- .../jpa/event/internal/EntityCallback.java | 20 +++- .../jpa/event/internal/ListenerCallback.java | 24 +++- .../jpa/event/spi/CallbackBuilder.java | 16 ++- .../jpa/event/spi/CallbackDefinition.java | 17 +++ .../jpa/event/spi/CallbackRegistrar.java | 19 +++ .../hibernate/mapping/PersistentClass.java | 19 +++ .../java/org/hibernate/mapping/Property.java | 21 ++++ 14 files changed, 274 insertions(+), 180 deletions(-) rename hibernate-core/src/main/java/org/hibernate/jpa/event/internal/{CallbackBuilderLegacyImpl.java => CallbackDefinitionResolverLegacyImpl.java} (71%) delete mode 100644 hibernate-core/src/main/java/org/hibernate/jpa/event/internal/EmptyCallbackBuilder.java create mode 100644 hibernate-core/src/main/java/org/hibernate/jpa/event/spi/CallbackDefinition.java create mode 100644 hibernate-core/src/main/java/org/hibernate/jpa/event/spi/CallbackRegistrar.java diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java b/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java index d519f164c761..786acc6b1296 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java @@ -152,6 +152,8 @@ import org.hibernate.id.PersistentIdentifierGenerator; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.StringHelper; +import org.hibernate.jpa.event.internal.CallbackDefinitionResolverLegacyImpl; +import org.hibernate.jpa.event.spi.CallbackType; import org.hibernate.loader.PropertyPath; import org.hibernate.mapping.Any; import org.hibernate.mapping.Component; @@ -837,6 +839,8 @@ else if ( InheritanceType.SINGLE_TABLE.equals( inheritanceState.getType() ) ) { entityBinder.processComplementaryTableDefinitions( clazzToProcess.getAnnotation( org.hibernate.annotations.Table.class ) ); entityBinder.processComplementaryTableDefinitions( clazzToProcess.getAnnotation( org.hibernate.annotations.Tables.class ) ); entityBinder.processComplementaryTableDefinitions( tabAnn ); + + bindCallbacks( clazzToProcess, persistentClass, context ); } /** @@ -1420,6 +1424,32 @@ private static void bindTypeDef(TypeDef defAnn, MetadataBuildingContext context) } + private static void bindCallbacks(XClass entityClass, PersistentClass persistentClass, + MetadataBuildingContext context) { + ReflectionManager reflectionManager = context.getBootstrapContext().getReflectionManager(); + + for ( CallbackType callbackType : CallbackType.values() ) { + persistentClass.addCallbackDefinitions( CallbackDefinitionResolverLegacyImpl.resolveEntityCallbacks( + reflectionManager, entityClass, callbackType ) ); + } + + context.getMetadataCollector().addSecondPass( new SecondPass() { + @Override + public void doSecondPass(Map persistentClasses) throws MappingException { + for ( @SuppressWarnings("unchecked") Iterator propertyIterator = persistentClass.getDeclaredPropertyIterator(); + propertyIterator.hasNext(); ) { + Property property = propertyIterator.next(); + if ( property.isComposite() ) { + for ( CallbackType callbackType : CallbackType.values() ) { + property.addCallbackDefinitions( CallbackDefinitionResolverLegacyImpl.resolveEmbeddableCallbacks( + reflectionManager, persistentClass.getMappedClass(), property, callbackType ) ); + } + } + } + } + } ); + } + public static void bindFetchProfilesForClass(XClass clazzToProcess, MetadataBuildingContext context) { bindFetchProfiles( clazzToProcess, context ); } @@ -1464,7 +1494,6 @@ private static void bindFetchProfile(FetchProfile fetchProfileAnnotation, Metada } } - private static void bindDiscriminatorColumnToRootPersistentClass( RootClass rootClass, Ejb3DiscriminatorColumn discriminatorColumn, diff --git a/hibernate-core/src/main/java/org/hibernate/event/spi/EventEngine.java b/hibernate-core/src/main/java/org/hibernate/event/spi/EventEngine.java index 48bb777680a8..7456828649fa 100644 --- a/hibernate-core/src/main/java/org/hibernate/event/spi/EventEngine.java +++ b/hibernate-core/src/main/java/org/hibernate/event/spi/EventEngine.java @@ -9,7 +9,6 @@ import java.util.Collection; import java.util.Collections; import java.util.HashMap; -import java.util.Iterator; import java.util.Map; import java.util.function.Consumer; @@ -23,9 +22,6 @@ import org.hibernate.internal.util.collections.CollectionHelper; import org.hibernate.jpa.event.internal.CallbackRegistryImplementor; import org.hibernate.jpa.event.internal.CallbacksFactory; -import org.hibernate.jpa.event.spi.CallbackBuilder; -import org.hibernate.mapping.PersistentClass; -import org.hibernate.mapping.Property; import org.hibernate.service.spi.Stoppable; /** @@ -39,7 +35,6 @@ public class EventEngine { private final EventListenerRegistry listenerRegistry; private final CallbackRegistryImplementor callbackRegistry; - private final CallbackBuilder callbackBuilder; public EventEngine( MetadataImplementor mappings, @@ -48,33 +43,8 @@ public EventEngine( // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // resolve (JPA) callback handlers - this.callbackRegistry = CallbacksFactory.buildCallbackRegistry( sessionFactory.getSessionFactoryOptions() ); - this.callbackBuilder = CallbacksFactory.buildCallbackBuilder( - sessionFactory.getSessionFactoryOptions(), - sessionFactory.getServiceRegistry(), - mappings.getMetadataBuildingOptions().getReflectionManager() - ); - - for ( PersistentClass persistentClass : mappings.getEntityBindings() ) { - if ( persistentClass.getClassName() == null ) { - // we can have dynamic (non-java class) mapping - continue; - } - - this.callbackBuilder.buildCallbacksForEntity( persistentClass.getMappedClass(), callbackRegistry ); - - for ( Iterator propertyIterator = persistentClass.getDeclaredPropertyIterator(); propertyIterator.hasNext(); ) { - final Property property = propertyIterator.next(); - - if ( property.isComposite() ) { - this.callbackBuilder.buildCallbacksForEmbeddable( - property, - persistentClass.getMappedClass(), - callbackRegistry - ); - } - } - } + this.callbackRegistry = CallbacksFactory.buildCallbackRegistry( sessionFactory.getSessionFactoryOptions(), + sessionFactory.getServiceRegistry(), mappings.getEntityBindings() ); // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -192,7 +162,5 @@ public void stop() { } callbackRegistry.release(); - - callbackBuilder.release(); } } diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/CallbackBuilderLegacyImpl.java b/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/CallbackDefinitionResolverLegacyImpl.java similarity index 71% rename from hibernate-core/src/main/java/org/hibernate/jpa/event/internal/CallbackBuilderLegacyImpl.java rename to hibernate-core/src/main/java/org/hibernate/jpa/event/internal/CallbackDefinitionResolverLegacyImpl.java index d7fac04bc1f6..9b0b6e0d43b0 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/CallbackBuilderLegacyImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/CallbackDefinitionResolverLegacyImpl.java @@ -19,88 +19,39 @@ import javax.persistence.MappedSuperclass; import javax.persistence.PersistenceException; -import org.hibernate.MappingException; import org.hibernate.annotations.common.reflection.ReflectionManager; import org.hibernate.annotations.common.reflection.XClass; import org.hibernate.annotations.common.reflection.XMethod; import org.hibernate.internal.util.ReflectHelper; -import org.hibernate.jpa.event.spi.Callback; -import org.hibernate.jpa.event.spi.CallbackBuilder; +import org.hibernate.jpa.event.spi.CallbackDefinition; import org.hibernate.jpa.event.spi.CallbackType; +import org.hibernate.mapping.PersistentClass; import org.hibernate.mapping.Property; import org.hibernate.property.access.spi.Getter; -import org.hibernate.resource.beans.spi.ManagedBeanRegistry; import org.jboss.logging.Logger; /** - * EntityCallbackBuilder implementation using HCANN ReflectionManager. "legacy" in that - * we want to move to Jandex instead. + * Resolves JPA callback definitions using a HCANN ReflectionManager. + *

    + * "legacy" in that we want to move to Jandex instead. * * @author Steve Ebersole */ -final class CallbackBuilderLegacyImpl implements CallbackBuilder { - private static final Logger log = Logger.getLogger( CallbackBuilderLegacyImpl.class ); - - private final ManagedBeanRegistry managedBeanRegistry; - private final ReflectionManager reflectionManager; - - CallbackBuilderLegacyImpl(ManagedBeanRegistry managedBeanRegistry, ReflectionManager reflectionManager) { - this.managedBeanRegistry = managedBeanRegistry; - this.reflectionManager = reflectionManager; - } - - @Override - public void buildCallbacksForEntity(Class entityClass, CallbackRegistrar callbackRegistrar) { - for ( CallbackType callbackType : CallbackType.values() ) { - if ( callbackRegistrar.hasRegisteredCallbacks( entityClass, callbackType ) ) { - // this most likely means we have a class mapped multiple times using the hbm.xml - // "entity name" feature - if ( log.isDebugEnabled() ) { - log.debugf( - "CallbackRegistry reported that Class [%s] already had %s callbacks registered; " + - "assuming this means the class was mapped twice " + - "(using hbm.xml entity-name support) - skipping subsequent registrations", - entityClass.getName(), - callbackType.getCallbackAnnotation().getSimpleName() - ); - } - continue; - } - final Callback[] callbacks = resolveEntityCallbacks( entityClass, callbackType, reflectionManager ); - callbackRegistrar.registerCallbacks( entityClass, callbacks ); - } - } - - @Override - public void buildCallbacksForEmbeddable( - Property embeddableProperty, Class entityClass, CallbackRegistrar callbackRegistrar) { - for ( CallbackType callbackType : CallbackType.values() ) { - final Callback[] callbacks = resolveEmbeddableCallbacks( - entityClass, - embeddableProperty, - callbackType, - reflectionManager - ); - callbackRegistrar.registerCallbacks( entityClass, callbacks ); - } - } - - @Override - public void release() { - // nothing to do - } +public final class CallbackDefinitionResolverLegacyImpl { + private static final Logger log = Logger.getLogger( CallbackDefinitionResolverLegacyImpl.class ); @SuppressWarnings({"unchecked", "WeakerAccess"}) - public Callback[] resolveEntityCallbacks(Class entityClass, CallbackType callbackType, ReflectionManager reflectionManager) { - List callbacks = new ArrayList<>(); + public static List resolveEntityCallbacks(ReflectionManager reflectionManager, + XClass entityClass, CallbackType callbackType) { + List callbackDefinitions = new ArrayList<>(); List callbacksMethodNames = new ArrayList<>(); List orderedListeners = new ArrayList<>(); - XClass currentClazz = reflectionManager.toXClass( entityClass ); + XClass currentClazz = entityClass; boolean stopListeners = false; boolean stopDefaultListeners = false; do { - Callback callback = null; + CallbackDefinition callbackDefinition = null; List methods = currentClazz.getDeclaredMethods(); for ( final XMethod xMethod : methods ) { if ( xMethod.isAnnotationPresent( callbackType.getCallbackAnnotation() ) ) { @@ -108,8 +59,8 @@ public Callback[] resolveEntityCallbacks(Class entityClass, CallbackType callbac final String methodName = method.getName(); if ( !callbacksMethodNames.contains( methodName ) ) { //overridden method, remove the superclass overridden method - if ( callback == null ) { - callback = new EntityCallback( method, callbackType ); + if ( callbackDefinition == null ) { + callbackDefinition = new EntityCallback.Definition( method, callbackType ); Class returnType = method.getReturnType(); Class[] args = method.getParameterTypes(); if ( returnType != Void.TYPE || args.length != 0 ) { @@ -127,7 +78,7 @@ public Callback[] resolveEntityCallbacks(Class entityClass, CallbackType callbac entityClass.getName() ); } - callbacks.add( 0, callback ); //superclass first + callbackDefinitions.add( 0, callbackDefinition ); //superclass first callbacksMethodNames.add( 0, methodName ); } else { @@ -168,7 +119,7 @@ public Callback[] resolveEntityCallbacks(Class entityClass, CallbackType callbac } for ( Class listener : orderedListeners ) { - Callback callback = null; + CallbackDefinition callbackDefinition = null; if ( listener != null ) { XClass xListener = reflectionManager.toXClass( listener ); callbacksMethodNames = new ArrayList<>(); @@ -179,12 +130,8 @@ public Callback[] resolveEntityCallbacks(Class entityClass, CallbackType callbac final String methodName = method.getName(); if ( !callbacksMethodNames.contains( methodName ) ) { //overridden method, remove the superclass overridden method - if ( callback == null ) { - callback = new ListenerCallback( - managedBeanRegistry.getBean( listener ), - method, - callbackType - ); + if ( callbackDefinition == null ) { + callbackDefinition = new ListenerCallback.Definition( listener, method, callbackType ); Class returnType = method.getReturnType(); Class[] args = method.getParameterTypes(); @@ -203,7 +150,7 @@ public Callback[] resolveEntityCallbacks(Class entityClass, CallbackType callbac entityClass.getName() ); } - callbacks.add( 0, callback ); // listeners first + callbackDefinitions.add( 0, callbackDefinition ); // listeners first } else { throw new PersistenceException( @@ -218,20 +165,20 @@ public Callback[] resolveEntityCallbacks(Class entityClass, CallbackType callbac } } } - return callbacks.toArray( new Callback[callbacks.size()] ); + return callbackDefinitions; } - @SuppressWarnings({"unchecked", "WeakerAccess"}) - public Callback[] resolveEmbeddableCallbacks(Class entityClass, Property embeddableProperty, CallbackType callbackType, ReflectionManager reflectionManager) { - + public static List resolveEmbeddableCallbacks(ReflectionManager reflectionManager, + Class entityClass, Property embeddableProperty, + CallbackType callbackType) { final Class embeddableClass = embeddableProperty.getType().getReturnedClass(); final XClass embeddableXClass = reflectionManager.toXClass( embeddableClass ); final Getter embeddableGetter = embeddableProperty.getGetter( entityClass ); - final List callbacks = new ArrayList<>(); + final List callbackDefinitions = new ArrayList<>(); final List callbacksMethodNames = new ArrayList<>(); XClass currentClazz = embeddableXClass; do { - Callback callback = null; + CallbackDefinition callbackDefinition = null; List methods = currentClazz.getDeclaredMethods(); for ( final XMethod xMethod : methods ) { if ( xMethod.isAnnotationPresent( callbackType.getCallbackAnnotation() ) ) { @@ -239,8 +186,8 @@ public Callback[] resolveEmbeddableCallbacks(Class entityClass, Property embedda final String methodName = method.getName(); if ( !callbacksMethodNames.contains( methodName ) ) { //overridden method, remove the superclass overridden method - if ( callback == null ) { - callback = new EmbeddableCallback( embeddableGetter, method, callbackType ); + if ( callbackDefinition == null ) { + callbackDefinition = new EmbeddableCallback.Definition( embeddableGetter, method, callbackType ); Class returnType = method.getReturnType(); Class[] args = method.getParameterTypes(); if ( returnType != Void.TYPE || args.length != 0 ) { @@ -258,7 +205,7 @@ public Callback[] resolveEmbeddableCallbacks(Class entityClass, Property embedda embeddableXClass.getName() ); } - callbacks.add( 0, callback ); //superclass first + callbackDefinitions.add( 0, callbackDefinition ); //superclass first callbacksMethodNames.add( 0, methodName ); } else { @@ -278,7 +225,7 @@ public Callback[] resolveEmbeddableCallbacks(Class entityClass, Property embedda } while ( currentClazz != null ); - return callbacks.toArray( new Callback[callbacks.size()] ); + return callbackDefinitions; } private static boolean useAnnotationAnnotatedByListener; diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/CallbackRegistryImplementor.java b/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/CallbackRegistryImplementor.java index 6805b73b7e7b..9444bad0941d 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/CallbackRegistryImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/CallbackRegistryImplementor.java @@ -7,9 +7,9 @@ package org.hibernate.jpa.event.internal; import org.hibernate.jpa.event.spi.CallbackBuilder; -import org.hibernate.jpa.event.spi.CallbackRegistry; +import org.hibernate.jpa.event.spi.CallbackRegistrar; -public interface CallbackRegistryImplementor extends CallbackRegistry, CallbackBuilder.CallbackRegistrar { +public interface CallbackRegistryImplementor extends CallbackRegistrar, CallbackBuilder.CallbackRegistrar { void release(); diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/CallbacksFactory.java b/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/CallbacksFactory.java index 0561b8edbc04..f62753638d61 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/CallbacksFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/CallbacksFactory.java @@ -6,42 +6,89 @@ */ package org.hibernate.jpa.event.internal; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + import org.hibernate.annotations.common.reflection.ReflectionManager; import org.hibernate.boot.spi.SessionFactoryOptions; -import org.hibernate.engine.spi.SessionFactoryImplementor; -import org.hibernate.jpa.event.spi.CallbackBuilder; +import org.hibernate.jpa.event.spi.Callback; +import org.hibernate.jpa.event.spi.CallbackDefinition; +import org.hibernate.jpa.event.spi.CallbackType; +import org.hibernate.mapping.PersistentClass; +import org.hibernate.mapping.Property; import org.hibernate.resource.beans.spi.ManagedBeanRegistry; import org.hibernate.service.ServiceRegistry; +import org.jboss.logging.Logger; + /** * The intent of this class is to use a lighter implementation * when JPA callbacks are disabled via * {@link org.hibernate.boot.spi.SessionFactoryOptions#areJPACallbacksEnabled()} */ public final class CallbacksFactory { - public static CallbackRegistryImplementor buildCallbackRegistry(SessionFactoryOptions options) { - if ( jpaCallBacksEnabled( options ) ) { - return new CallbackRegistryImpl(); - } - else { + private static final Logger log = Logger.getLogger( CallbacksFactory.class ); + + public static CallbackRegistryImplementor buildCallbackRegistry(SessionFactoryOptions options, + ServiceRegistry serviceRegistry, Collection entityBindings) { + if ( !jpaCallBacksEnabled( options ) ) { return new EmptyCallbackRegistryImpl(); } + ManagedBeanRegistry beanRegistry = serviceRegistry.getService( ManagedBeanRegistry.class ); + CallbackRegistryImplementor registry = new CallbackRegistryImpl(); + Set> entityClasses = new HashSet<>(); + + for ( PersistentClass persistentClass : entityBindings ) { + if ( persistentClass.getClassName() == null ) { + // we can have dynamic (non-java class) mapping + continue; + } + + Class entityClass = persistentClass.getMappedClass(); + + if ( !entityClasses.add( entityClass ) ) { + // this most likely means we have a class mapped multiple times using the hbm.xml + // "entity name" feature + if ( log.isDebugEnabled() ) { + log.debugf( + "Class [%s] already has callbacks registered; " + + "assuming this means the class was mapped twice " + + "(using hbm.xml entity-name support) - skipping subsequent registrations" + + "to avoid duplicates", + entityClass.getName() + ); + } + continue; + } + + registry.registerCallbacks( persistentClass.getMappedClass(), + buildCallbacks( persistentClass.getCallbackDefinitions(), beanRegistry ) ); + + for ( @SuppressWarnings("unchecked") Iterator propertyIterator = persistentClass.getDeclaredPropertyIterator(); + propertyIterator.hasNext(); ) { + final Property property = propertyIterator.next(); + registry.registerCallbacks( persistentClass.getMappedClass(), + buildCallbacks( property.getCallbackDefinitions(), beanRegistry ) ); + } + } + + return registry; } - public static CallbackBuilder buildCallbackBuilder( - SessionFactoryOptions options, - ServiceRegistry serviceRegistry, - ReflectionManager reflectionManager) { - if ( jpaCallBacksEnabled( options ) ) { - final ManagedBeanRegistry managedBeanRegistry = serviceRegistry.getService( ManagedBeanRegistry.class ); - return new CallbackBuilderLegacyImpl( - managedBeanRegistry, - reflectionManager - ); + private static Callback[] buildCallbacks(List callbackDefinitions, + ManagedBeanRegistry beanRegistry) { + if ( callbackDefinitions == null || callbackDefinitions.isEmpty() ) { + return null; } - else { - return new EmptyCallbackBuilder(); + List callbacks = new ArrayList<>(); + for ( CallbackDefinition definition : callbackDefinitions ) { + callbacks.add( definition.createCallback( beanRegistry ) ); } + return callbacks.toArray( new Callback[0] ); } private static boolean jpaCallBacksEnabled(SessionFactoryOptions options) { diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/EmbeddableCallback.java b/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/EmbeddableCallback.java index e5fc177e0c93..a66cc0d8aa18 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/EmbeddableCallback.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/EmbeddableCallback.java @@ -9,8 +9,11 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import org.hibernate.jpa.event.spi.Callback; +import org.hibernate.jpa.event.spi.CallbackDefinition; import org.hibernate.jpa.event.spi.CallbackType; import org.hibernate.property.access.spi.Getter; +import org.hibernate.resource.beans.spi.ManagedBeanRegistry; /** * Represents a JPA callback on the embeddable type @@ -19,10 +22,27 @@ */ final class EmbeddableCallback extends AbstractCallback { + public static class Definition implements CallbackDefinition { + private final Getter embeddableGetter; + private final Method callbackMethod; + private final CallbackType callbackType; + + public Definition(Getter embeddableGetter, Method callbackMethod, CallbackType callbackType) { + this.embeddableGetter = embeddableGetter; + this.callbackMethod = callbackMethod; + this.callbackType = callbackType; + } + + @Override + public Callback createCallback(ManagedBeanRegistry beanRegistry) { + return new EmbeddableCallback( embeddableGetter, callbackMethod, callbackType ); + } + } + private final Getter embeddableGetter; private final Method callbackMethod; - EmbeddableCallback(Getter embeddableGetter, Method callbackMethod, CallbackType callbackType) { + private EmbeddableCallback(Getter embeddableGetter, Method callbackMethod, CallbackType callbackType) { super( callbackType ); this.embeddableGetter = embeddableGetter; this.callbackMethod = callbackMethod; diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/EmptyCallbackBuilder.java b/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/EmptyCallbackBuilder.java deleted file mode 100644 index 894790f14c76..000000000000 --- a/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/EmptyCallbackBuilder.java +++ /dev/null @@ -1,29 +0,0 @@ -/* - * Hibernate, Relational Persistence for Idiomatic Java - * - * License: GNU Lesser General Public License (LGPL), version 2.1 or later - * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html - */ -package org.hibernate.jpa.event.internal; - -import org.hibernate.jpa.event.spi.CallbackBuilder; -import org.hibernate.mapping.Property; - -final class EmptyCallbackBuilder implements CallbackBuilder { - - @Override - public void buildCallbacksForEntity(Class entityClass, CallbackRegistrar callbackRegistrar) { - //no-op - } - - @Override - public void buildCallbacksForEmbeddable(Property embeddableProperty, Class entityClass, CallbackRegistrar callbackRegistrar) { - //no-op - } - - @Override - public void release() { - //no-op - } - -} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/EntityCallback.java b/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/EntityCallback.java index 8bae4ed6a777..fd23d5459d7e 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/EntityCallback.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/EntityCallback.java @@ -9,7 +9,10 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import org.hibernate.jpa.event.spi.Callback; +import org.hibernate.jpa.event.spi.CallbackDefinition; import org.hibernate.jpa.event.spi.CallbackType; +import org.hibernate.resource.beans.spi.ManagedBeanRegistry; /** * Represents a JPA callback on the entity itself @@ -19,9 +22,24 @@ */ final class EntityCallback extends AbstractCallback { + public static class Definition implements CallbackDefinition { + private final Method callbackMethod; + private final CallbackType callbackType; + + public Definition(Method callbackMethod, CallbackType callbackType) { + this.callbackMethod = callbackMethod; + this.callbackType = callbackType; + } + + @Override + public Callback createCallback(ManagedBeanRegistry beanRegistry) { + return new EntityCallback( callbackMethod, callbackType ); + } + } + private final Method callbackMethod; - EntityCallback(Method callbackMethod, CallbackType callbackType) { + private EntityCallback(Method callbackMethod, CallbackType callbackType) { super( callbackType ); this.callbackMethod = callbackMethod; } diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/ListenerCallback.java b/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/ListenerCallback.java index e47c47a4d7c2..a8bf663a8a88 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/ListenerCallback.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/ListenerCallback.java @@ -9,8 +9,11 @@ import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; +import org.hibernate.jpa.event.spi.Callback; +import org.hibernate.jpa.event.spi.CallbackDefinition; import org.hibernate.jpa.event.spi.CallbackType; import org.hibernate.resource.beans.spi.ManagedBean; +import org.hibernate.resource.beans.spi.ManagedBeanRegistry; /** * Represents a JPA callback using a dedicated listener @@ -20,10 +23,27 @@ */ class ListenerCallback extends AbstractCallback { + public static class Definition implements CallbackDefinition { + private final Class listenerClass; + private final Method callbackMethod; + private final CallbackType callbackType; + + public Definition(Class listenerClass, Method callbackMethod, CallbackType callbackType) { + this.listenerClass = listenerClass; + this.callbackMethod = callbackMethod; + this.callbackType = callbackType; + } + + @Override + public Callback createCallback(ManagedBeanRegistry beanRegistry) { + return new ListenerCallback( beanRegistry.getBean( listenerClass ), callbackMethod, callbackType ); + } + } + private final Method callbackMethod; - private final ManagedBean listenerManagedBean; + private final ManagedBean listenerManagedBean; - ListenerCallback(ManagedBean listenerManagedBean, Method callbackMethod, CallbackType callbackType) { + ListenerCallback(ManagedBean listenerManagedBean, Method callbackMethod, CallbackType callbackType) { super( callbackType ); this.listenerManagedBean = listenerManagedBean; this.callbackMethod = callbackMethod; diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/event/spi/CallbackBuilder.java b/hibernate-core/src/main/java/org/hibernate/jpa/event/spi/CallbackBuilder.java index 41bfcda81afb..8db5b61884c4 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/event/spi/CallbackBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/event/spi/CallbackBuilder.java @@ -12,20 +12,18 @@ * Contract for walking an entity hierarchy and building a list of JPA callbacks * * @author Steve Ebersole + * + * @deprecated This SPI has never been functional and is no longer used. It will eventually be removed. */ +@Deprecated public interface CallbackBuilder { /** * Represents the target of JPA callback registrations as part the EntityCallbackBuilder + * + * @deprecated Use {@link org.hibernate.jpa.event.spi.CallbackRegistrar} instead. */ - interface CallbackRegistrar extends CallbackRegistry { - - /** - * Register the callback against the given entity. - * - * @param entityClass The entity Class to register the Callbacks against - * @param callbacks The Callbacks to register against the given entity Class - */ - void registerCallbacks(Class entityClass, Callback[] callbacks); + @Deprecated + interface CallbackRegistrar extends org.hibernate.jpa.event.spi.CallbackRegistrar { } void buildCallbacksForEntity(Class entityClass, CallbackRegistrar callbackRegistrar); diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/event/spi/CallbackDefinition.java b/hibernate-core/src/main/java/org/hibernate/jpa/event/spi/CallbackDefinition.java new file mode 100644 index 000000000000..3bed22602db2 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/jpa/event/spi/CallbackDefinition.java @@ -0,0 +1,17 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.jpa.event.spi; + +import java.io.Serializable; + +import org.hibernate.resource.beans.spi.ManagedBeanRegistry; + +public interface CallbackDefinition extends Serializable { + + Callback createCallback(ManagedBeanRegistry beanRegistry); + +} diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/event/spi/CallbackRegistrar.java b/hibernate-core/src/main/java/org/hibernate/jpa/event/spi/CallbackRegistrar.java new file mode 100644 index 000000000000..7b2bf2cbd423 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/jpa/event/spi/CallbackRegistrar.java @@ -0,0 +1,19 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.jpa.event.spi; + +public interface CallbackRegistrar extends CallbackRegistry { + + /** + * Register the callback against the given entity. + * + * @param entityClass The entity Class to register the Callbacks against + * @param callbacks The Callbacks to register against the given entity Class + */ + void registerCallbacks(Class entityClass, Callback[] callbacks); + +} diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/PersistentClass.java b/hibernate-core/src/main/java/org/hibernate/mapping/PersistentClass.java index 7703755e3003..9b9478dd08d5 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/PersistentClass.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/PersistentClass.java @@ -27,6 +27,7 @@ import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.collections.JoinedIterator; import org.hibernate.internal.util.collections.SingletonIterator; +import org.hibernate.jpa.event.spi.CallbackDefinition; import org.hibernate.service.ServiceRegistry; import org.hibernate.sql.Alias; @@ -73,6 +74,7 @@ public abstract class PersistentClass implements AttributeContainer, Serializabl private Boolean isAbstract; private boolean hasSubselectLoadableCollections; private Component identifierMapper; + private java.util.List callbackDefinitions; // Custom SQL private String customSQLInsert; @@ -978,6 +980,23 @@ public boolean hasIdentifierMapper() { return identifierMapper != null; } + public void addCallbackDefinitions(java.util.List callbackDefinitions) { + if ( callbackDefinitions == null || callbackDefinitions.isEmpty() ) { + return; + } + if ( this.callbackDefinitions == null ) { + this.callbackDefinitions = new ArrayList<>(); + } + this.callbackDefinitions.addAll( callbackDefinitions ); + } + + public java.util.List getCallbackDefinitions() { + if ( callbackDefinitions == null ) { + return Collections.emptyList(); + } + return Collections.unmodifiableList( callbackDefinitions ); + } + public void setIdentifierMapper(Component handle) { this.identifierMapper = handle; } diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Property.java b/hibernate-core/src/main/java/org/hibernate/mapping/Property.java index 697abe7a5be9..35b1525fd43d 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Property.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Property.java @@ -7,6 +7,8 @@ package org.hibernate.mapping; import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collections; import java.util.Iterator; import java.util.StringTokenizer; @@ -19,6 +21,7 @@ import org.hibernate.engine.spi.CascadeStyles; import org.hibernate.engine.spi.Mapping; import org.hibernate.internal.util.collections.ArrayHelper; +import org.hibernate.jpa.event.spi.CallbackDefinition; import org.hibernate.property.access.spi.Getter; import org.hibernate.property.access.spi.PropertyAccessStrategy; import org.hibernate.property.access.spi.PropertyAccessStrategyResolver; @@ -50,6 +53,7 @@ public class Property implements Serializable, MetaAttributable { private PersistentClass persistentClass; private boolean naturalIdentifier; private boolean lob; + private java.util.List callbackDefinitions; public boolean isBackRef() { return false; @@ -365,4 +369,21 @@ public void setLob(boolean lob) { this.lob = lob; } + public void addCallbackDefinitions(java.util.List callbackDefinitions) { + if ( callbackDefinitions == null || callbackDefinitions.isEmpty() ) { + return; + } + if ( this.callbackDefinitions == null ) { + this.callbackDefinitions = new ArrayList<>(); + } + this.callbackDefinitions.addAll( callbackDefinitions ); + } + + public java.util.List getCallbackDefinitions() { + if ( callbackDefinitions == null ) { + return Collections.emptyList(); + } + return Collections.unmodifiableList( callbackDefinitions ); + } + } From 8afce5b5ed72a8fa9e15fbaa608a5b2abb92e9de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Tue, 12 Oct 2021 19:03:15 +0200 Subject: [PATCH 352/644] HHH-14869 Fix CallbackRegistryImpl#registerCallbacks considering all given callbacks have the same type --- .../jpa/event/internal/CallbackRegistryImpl.java | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/CallbackRegistryImpl.java b/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/CallbackRegistryImpl.java index 90328f13bc3f..65c9cca3ef51 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/CallbackRegistryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/event/internal/CallbackRegistryImpl.java @@ -41,13 +41,15 @@ public void registerCallbacks(Class entityClass, Callback[] callbacks) { return; } - final HashMap map = determineAppropriateCallbackMap( callbacks[0].getCallbackType() ); - Callback[] entityCallbacks = map.get( entityClass ); - - if ( entityCallbacks != null ) { - callbacks = ArrayHelper.join( entityCallbacks, callbacks ); + for ( Callback callback : callbacks ) { + final HashMap map = determineAppropriateCallbackMap( callback.getCallbackType() ); + Callback[] entityCallbacks = map.get( entityClass ); + if ( entityCallbacks == null ) { + entityCallbacks = new Callback[0]; + } + entityCallbacks = ArrayHelper.join( entityCallbacks, callback ); + map.put( entityClass, entityCallbacks ); } - map.put( entityClass, callbacks ); } @Override From 8cf51a601ba1744ed3e432edd23d79a119292c3d Mon Sep 17 00:00:00 2001 From: "nathan.xu" Date: Sun, 17 Oct 2021 16:11:55 -0400 Subject: [PATCH 353/644] HHH-14883 Fix an Asciidoc defect and other verbiage issues in 'spatial' chapter in user guide --- .../userguide/chapters/query/spatial/Spatial.adoc | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/documentation/src/main/asciidoc/userguide/chapters/query/spatial/Spatial.adoc b/documentation/src/main/asciidoc/userguide/chapters/query/spatial/Spatial.adoc index 2baffcb4341c..f42d0e665acd 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/query/spatial/Spatial.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/query/spatial/Spatial.adoc @@ -12,10 +12,10 @@ and it allows you to deal with geographic data in a standardized way. Hibernate Spatial provides a standardized, cross-database interface to geographic data storage and query functions. It supports most of the functions described by the OGC Simple Feature Specification. Supported databases are Oracle 10g/11g, -PostgreSQL/PostGIS, MySQL, Microsoft SQL Server and H2/GeoDB. +PostgreSQL/PostGIS, MySQL, Microsoft SQL Server, DB2, CockroachDB and H2/GeoDB. Spatial data types are not part of the Java standard library, and they are absent from the JDBC specification. -Over the years https://tsusiatsoftware.net/jts/main.html[JTS] has emerged the _de facto_ standard to fill this gap. JTS is +Over the years https://tsusiatsoftware.net/jts/main.html[JTS] has emerged as the _de facto_ standard to fill this gap. JTS is an implementation of the https://portal.opengeospatial.org/files/?artifact_id=829[Simple Feature Specification (SFS)]. Many databases on the other hand implement the SQL/MM - Part 3: Spatial Data specification - a related, but broader specification. The biggest difference is that SFS is limited to 2D geometries in the projected plane (although JTS supports 3D coordinates), whereas @@ -26,7 +26,7 @@ https://github.com/GeoLatte/geolatte-geom[geolatte-geom]. As already mentioned, standard. Geolatte-geom (also written by the lead developer of Hibernate Spatial) is a more recent library that supports many features specified in SQL/MM but not available in JTS (such as support for 4D geometries, and support for extended WKT/WKB formats). Geolatte-geom also implements encoders/decoders for the database native types. Geolatte-geom has good interoperability with -JTS. Converting a Geolatte `geometry` to a JTS `geometry, for instance, doesn't require copying of the coordinates. +JTS. Converting a Geolatte `geometry` to a JTS `geometry`, for instance, doesn't require copying of the coordinates. It also delegates spatial processing to JTS. Whether you use JTS or Geolatte-geom, Hibernate spatial maps the database spatial types to your geometry model of choice. It will, however, @@ -260,7 +260,7 @@ create transform for db2gse.st_geometry db2_program ( Hibernate Spatial comes with the following types: jts_geometry:: - Handled by `org.hibernate.spatial.JTSGeometryType` it maps a database geometry column type to a `org.locationtech.jts.geom.Geometry` entity property type. + Handled by `org.hibernate.spatial.JTSGeometryType`, it maps a database geometry column type to a `org.locationtech.jts.geom.Geometry` entity property type. geolatte_geometry:: Handled by `org.hibernate.spatial.GeolatteGeometryType`, it maps a database geometry column type to an `org.geolatte.geom.Geometry` entity property type. From 8e0f0b412365458e2a3442b80a8c00be9e2ba35d Mon Sep 17 00:00:00 2001 From: Dariush Moshiri Date: Tue, 12 Oct 2021 13:10:36 +0200 Subject: [PATCH 354/644] HHH-14816 Can not set lock mode with QueryHint due to type case problem --- .../jpa/internal/util/LockModeTypeHelper.java | 4 ++-- .../hibernate/query/internal/NativeQueryImpl.java | 4 ++++ .../hibernate/jpa/test/query/NamedQueryTest.java | 14 ++++++++++++++ 3 files changed, 20 insertions(+), 2 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/internal/util/LockModeTypeHelper.java b/hibernate-core/src/main/java/org/hibernate/jpa/internal/util/LockModeTypeHelper.java index 97b6f11513e4..6da1cdadef2a 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/internal/util/LockModeTypeHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/internal/util/LockModeTypeHelper.java @@ -40,12 +40,12 @@ else if ( LockModeType.class.isInstance( value ) ) { } else if ( String.class.isInstance( value ) ) { // first try LockMode name - LockMode lockMode = LockMode.valueOf( (String) value ); + LockMode lockMode = LockMode.fromExternalForm( (String) value ); if ( lockMode == null ) { try { lockMode = getLockMode( LockModeType.valueOf( (String) value ) ); } - catch ( Exception ignore ) { + catch (Exception ignore) { } } if ( lockMode != null ) { diff --git a/hibernate-core/src/main/java/org/hibernate/query/internal/NativeQueryImpl.java b/hibernate-core/src/main/java/org/hibernate/query/internal/NativeQueryImpl.java index ec4dc2f87b36..d43b73812ad4 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/internal/NativeQueryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/internal/NativeQueryImpl.java @@ -47,6 +47,7 @@ import org.hibernate.graph.RootGraph; import org.hibernate.internal.util.StringHelper; import org.hibernate.internal.util.collections.CollectionHelper; +import org.hibernate.jpa.internal.util.LockModeTypeHelper; import org.hibernate.query.NativeQuery; import org.hibernate.query.ParameterMetadata; import org.hibernate.query.Query; @@ -613,6 +614,9 @@ protected boolean applyNativeQueryLockMode(Object value) { else if ( LockModeType.class.isInstance( value ) ) { applyLockModeTypeHint( (LockModeType) value ); } + else if ( String.class.isInstance( value ) ) { + applyHibernateLockModeHint( LockModeTypeHelper.interpretLockMode( value ) ); + } else { throw new IllegalArgumentException( String.format( diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/query/NamedQueryTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/query/NamedQueryTest.java index 309976b4f840..5919627c6b3c 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/query/NamedQueryTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/query/NamedQueryTest.java @@ -16,7 +16,9 @@ import javax.persistence.NamedQuery; import javax.persistence.Query; +import org.hibernate.LockMode; import org.hibernate.Session; +import org.hibernate.jpa.QueryHints; import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; import org.hibernate.query.NativeQuery; @@ -192,6 +194,18 @@ public void testNamedNativeQueryExceptionNoRedultDefined() { } ); } + @Test + @TestForIssue(jiraKey = "HHH-14816") + public void testQueryHintLockMode() { + doInJPA( this::entityManagerFactory, entityManager -> { + Query query = entityManager.createNamedQuery( "NamedNativeQuery" ); + query.setHint( QueryHints.HINT_NATIVE_LOCKMODE, "none" ); + query.setParameter( 1, GAME_TITLES[0] ); + assertEquals( LockMode.NONE, query.getHints().get( QueryHints.HINT_NATIVE_LOCKMODE ) ); + } + ); + } + @Entity(name = "Game") @NamedQueries(@NamedQuery(name = "NamedQuery", query = "select g from Game g where title = ?1")) @NamedNativeQueries(@NamedNativeQuery(name = "NamedNativeQuery", query = "select * from Game g where title = ?")) From 3bee3a1c7932f38b7e0cdc593a786cfbab395f28 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Mon, 18 Oct 2021 10:30:14 +0100 Subject: [PATCH 355/644] HHH-14816 Minor refactoring of LockModeTypeHelper conversions --- .../jpa/internal/util/LockModeTypeHelper.java | 15 ++------------- 1 file changed, 2 insertions(+), 13 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/jpa/internal/util/LockModeTypeHelper.java b/hibernate-core/src/main/java/org/hibernate/jpa/internal/util/LockModeTypeHelper.java index 6da1cdadef2a..20f358fa03c7 100644 --- a/hibernate-core/src/main/java/org/hibernate/jpa/internal/util/LockModeTypeHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/jpa/internal/util/LockModeTypeHelper.java @@ -39,21 +39,10 @@ else if ( LockModeType.class.isInstance( value ) ) { return getLockMode( (LockModeType) value ); } else if ( String.class.isInstance( value ) ) { - // first try LockMode name - LockMode lockMode = LockMode.fromExternalForm( (String) value ); - if ( lockMode == null ) { - try { - lockMode = getLockMode( LockModeType.valueOf( (String) value ) ); - } - catch (Exception ignore) { - } - } - if ( lockMode != null ) { - return lockMode; - } + return LockMode.fromExternalForm( (String) value ); } - throw new IllegalArgumentException( "Unknown lock mode source : " + value ); + throw new IllegalArgumentException( "Unknown lock mode source: '" + value + "'; can't convert from value of type " + value.getClass() ); } } From 6008264711a828f5b798157db068a3126422534e Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Mon, 18 Oct 2021 10:33:22 +0100 Subject: [PATCH 356/644] HHH-14816 Optimise LockMode#fromExternalForm for common case --- hibernate-core/src/main/java/org/hibernate/LockMode.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hibernate-core/src/main/java/org/hibernate/LockMode.java b/hibernate-core/src/main/java/org/hibernate/LockMode.java index 18e5498df538..72a42843f9ad 100644 --- a/hibernate-core/src/main/java/org/hibernate/LockMode.java +++ b/hibernate-core/src/main/java/org/hibernate/LockMode.java @@ -147,6 +147,12 @@ public static LockMode fromExternalForm(String externalForm) { return NONE; } + for ( LockMode lockMode : LockMode.values() ) { + if ( lockMode.externalForm.equals( externalForm ) ) { + return lockMode; + } + } + for ( LockMode lockMode : LockMode.values() ) { if ( lockMode.externalForm.equalsIgnoreCase( externalForm ) ) { return lockMode; From ef3fe11ae673558e278d8c30902253365950da78 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Thu, 14 Oct 2021 12:56:27 +0100 Subject: [PATCH 357/644] HHH-14882 Minor implementation optimisations in internal StandardStack The current StandardStack implementation is based on a LinkedList, which is well known to be a suboptimal choice; this should be switched to a lazily allocated ArrayDeque. --- .../util/collections/StandardStack.java | 32 +++++++++++++++---- 1 file changed, 25 insertions(+), 7 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/internal/util/collections/StandardStack.java b/hibernate-core/src/main/java/org/hibernate/internal/util/collections/StandardStack.java index db11ba4e5ef4..91cf3f025734 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/util/collections/StandardStack.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/util/collections/StandardStack.java @@ -6,9 +6,8 @@ */ package org.hibernate.internal.util.collections; -import java.util.LinkedList; -import java.util.function.Consumer; -import java.util.function.Function; +import java.util.ArrayDeque; +import java.util.Deque; /** * A general-purpose stack impl. @@ -19,39 +18,58 @@ */ public final class StandardStack implements Stack { - private final LinkedList internalStack = new LinkedList<>(); + private ArrayDeque internalStack; public StandardStack() { } @Override public void push(T newCurrent) { - internalStack.addFirst( newCurrent ); + stackInstanceExpected().addFirst( newCurrent ); + } + + private Deque stackInstanceExpected() { + if ( internalStack == null ) { + //"7" picked to use 8, but skipping the odd initialCapacity method + internalStack = new ArrayDeque<>(7); + } + return internalStack; } @Override public T pop() { - return internalStack.removeFirst(); + return stackInstanceExpected().removeFirst(); } @Override public T getCurrent() { + if ( internalStack == null ) { + return null; + } return internalStack.peek(); } @Override public int depth() { + if ( internalStack == null ) { + return 0; + } return internalStack.size(); } @Override public boolean isEmpty() { + if ( internalStack == null ) { + return true; + } return internalStack.isEmpty(); } @Override public void clear() { - internalStack.clear(); + if ( internalStack != null ) { + internalStack.clear(); + } } } From 9dd6cd06c9c8d5d4c23232663845d9d02176bc8f Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Mon, 18 Oct 2021 11:35:45 +0100 Subject: [PATCH 358/644] HHH-14882 StandardStack needs to support null entries --- .../util/collections/StandardStack.java | 25 ++++++++++++++----- 1 file changed, 19 insertions(+), 6 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/internal/util/collections/StandardStack.java b/hibernate-core/src/main/java/org/hibernate/internal/util/collections/StandardStack.java index 91cf3f025734..1696eca5dae3 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/util/collections/StandardStack.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/util/collections/StandardStack.java @@ -10,25 +10,31 @@ import java.util.Deque; /** - * A general-purpose stack impl. + * A general-purpose stack impl supporting null values. * * @param The type of things stored in the stack * * @author Steve Ebersole + * @author Sanne Grinovero */ public final class StandardStack implements Stack { - private ArrayDeque internalStack; + private ArrayDeque internalStack; + private static final Object NULL_TOKEN = new Object(); public StandardStack() { } @Override public void push(T newCurrent) { - stackInstanceExpected().addFirst( newCurrent ); + Object toStore = newCurrent; + if ( newCurrent == null ) { + toStore = NULL_TOKEN; + } + stackInstanceExpected().addFirst( toStore ); } - private Deque stackInstanceExpected() { + private Deque stackInstanceExpected() { if ( internalStack == null ) { //"7" picked to use 8, but skipping the odd initialCapacity method internalStack = new ArrayDeque<>(7); @@ -38,7 +44,14 @@ private Deque stackInstanceExpected() { @Override public T pop() { - return stackInstanceExpected().removeFirst(); + return convert( stackInstanceExpected().removeFirst() ); + } + + private T convert(final Object internalStoredObject) { + if ( internalStoredObject == NULL_TOKEN ) { + return null; + } + return (T) internalStoredObject; } @Override @@ -46,7 +59,7 @@ public T getCurrent() { if ( internalStack == null ) { return null; } - return internalStack.peek(); + return convert( internalStack.peek() ); } @Override From ead2447524bd65cd452486940c31770a5fc8ba30 Mon Sep 17 00:00:00 2001 From: "nathan.xu" Date: Tue, 19 Oct 2021 23:28:36 -0400 Subject: [PATCH 359/644] HHH-14891 update JTS package name in user guide (Hibernate Spatial BasicTypes table in 'Domain Model' chapter) --- .../main/asciidoc/userguide/chapters/domain/basic_types.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/src/main/asciidoc/userguide/chapters/domain/basic_types.adoc b/documentation/src/main/asciidoc/userguide/chapters/domain/basic_types.adoc index a5544a778ddd..d12289de1575 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/domain/basic_types.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/domain/basic_types.adoc @@ -87,7 +87,7 @@ Internally Hibernate uses a registry of basic types when it needs to resolve a s [cols="<.^,<.^,<.^,<.^",options="header",] |================================================================================================= |Hibernate type (org.hibernate.spatial package) |JDBC type |Java type |BasicTypeRegistry key(s) -|JTSGeometryType |depends on the dialect | com.vividsolutions.jts.geom.Geometry |jts_geometry, and the class names of Geometry and its subclasses +|JTSGeometryType |depends on the dialect | org.locationtech.jts.geom.Geometry |jts_geometry, and the class names of Geometry and its subclasses |GeolatteGeometryType |depends on the dialect | org.geolatte.geom.Geometry |geolatte_geometry, and the class names of Geometry and its subclasses |================================================================================================= From 2f52c8024c14a66cd3e83406f0c5b8180f986efa Mon Sep 17 00:00:00 2001 From: Higor Tavares <42852956+higortavares@users.noreply.github.com> Date: Tue, 19 Oct 2021 18:35:12 -0300 Subject: [PATCH 360/644] remove the commented code --- .../java/org/hibernate/cfg/BinderHelper.java | 129 ------------------ 1 file changed, 129 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/BinderHelper.java b/hibernate-core/src/main/java/org/hibernate/cfg/BinderHelper.java index a7f61dc18ce7..4dd9882d5a17 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/BinderHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/BinderHelper.java @@ -111,135 +111,6 @@ public static Property shallowCopy(Property property) { return clone; } -// This is sooooooooo close in terms of not generating a synthetic property if we do not have to (where property ref -// refers to a single property). The sticking point is cases where the `referencedPropertyName` come from subclasses -// or secondary tables. Part of the problem is in PersistentClass itself during attempts to resolve the referenced -// property; currently it only considers non-subclass and non-joined properties. Part of the problem is in terms -// of SQL generation. -// public static void createSyntheticPropertyReference( -// Ejb3JoinColumn[] columns, -// PersistentClass ownerEntity, -// PersistentClass associatedEntity, -// Value value, -// boolean inverse, -// Mappings mappings) { -// //associated entity only used for more precise exception, yuk! -// if ( columns[0].isImplicit() || StringHelper.isNotEmpty( columns[0].getMappedBy() ) ) return; -// int fkEnum = Ejb3JoinColumn.checkReferencedColumnsType( columns, ownerEntity, mappings ); -// PersistentClass associatedClass = columns[0].getPropertyHolder() != null ? -// columns[0].getPropertyHolder().getPersistentClass() : -// null; -// if ( Ejb3JoinColumn.NON_PK_REFERENCE == fkEnum ) { -// //find properties associated to a certain column -// Object columnOwner = findColumnOwner( ownerEntity, columns[0].getReferencedColumn(), mappings ); -// List properties = findPropertiesByColumns( columnOwner, columns, mappings ); -// -// if ( properties == null ) { -// //TODO use a ToOne type doing a second select -// StringBuilder columnsList = new StringBuilder(); -// columnsList.append( "referencedColumnNames(" ); -// for (Ejb3JoinColumn column : columns) { -// columnsList.append( column.getReferencedColumn() ).append( ", " ); -// } -// columnsList.setLength( columnsList.length() - 2 ); -// columnsList.append( ") " ); -// -// if ( associatedEntity != null ) { -// //overidden destination -// columnsList.append( "of " ) -// .append( associatedEntity.getEntityName() ) -// .append( "." ) -// .append( columns[0].getPropertyName() ) -// .append( " " ); -// } -// else { -// if ( columns[0].getPropertyHolder() != null ) { -// columnsList.append( "of " ) -// .append( columns[0].getPropertyHolder().getEntityName() ) -// .append( "." ) -// .append( columns[0].getPropertyName() ) -// .append( " " ); -// } -// } -// columnsList.append( "referencing " ) -// .append( ownerEntity.getEntityName() ) -// .append( " not mapped to a single property" ); -// throw new AnnotationException( columnsList.toString() ); -// } -// -// final String referencedPropertyName; -// -// if ( properties.size() == 1 ) { -// referencedPropertyName = properties.get(0).getName(); -// } -// else { -// // Create a synthetic (embedded composite) property to use as the referenced property which -// // contains all the properties mapped to the referenced columns. We need to make a shallow copy -// // of the properties to mark them as non-insertable/updatable. -// -// // todo : what if the columns all match with an existing component? -// -// StringBuilder propertyNameBuffer = new StringBuilder( "_" ); -// propertyNameBuffer.append( associatedClass.getEntityName().replace( '.', '_' ) ); -// propertyNameBuffer.append( "_" ).append( columns[0].getPropertyName() ); -// String syntheticPropertyName = propertyNameBuffer.toString(); -// //create an embeddable component -// -// //todo how about properties.size() == 1, this should be much simpler -// Component embeddedComp = columnOwner instanceof PersistentClass ? -// new Component( mappings, (PersistentClass) columnOwner ) : -// new Component( mappings, (Join) columnOwner ); -// embeddedComp.setEmbedded( true ); -// embeddedComp.setNodeName( syntheticPropertyName ); -// embeddedComp.setComponentClassName( embeddedComp.getOwner().getClassName() ); -// for (Property property : properties) { -// Property clone = BinderHelper.shallowCopy( property ); -// clone.setInsertable( false ); -// clone.setUpdateable( false ); -// clone.setNaturalIdentifier( false ); -// clone.setGeneration( property.getGeneration() ); -// embeddedComp.addProperty( clone ); -// } -// SyntheticProperty synthProp = new SyntheticProperty(); -// synthProp.setName( syntheticPropertyName ); -// synthProp.setNodeName( syntheticPropertyName ); -// synthProp.setPersistentClass( ownerEntity ); -// synthProp.setUpdateable( false ); -// synthProp.setInsertable( false ); -// synthProp.setValue( embeddedComp ); -// synthProp.setPropertyAccessorName( "embedded" ); -// ownerEntity.addProperty( synthProp ); -// //make it unique -// TableBinder.createUniqueConstraint( embeddedComp ); -// -// referencedPropertyName = syntheticPropertyName; -// } -// -// /** -// * creating the property ref to the new synthetic property -// */ -// if ( value instanceof ToOne ) { -// ( (ToOne) value ).setReferencedPropertyName( referencedPropertyName ); -// mappings.addUniquePropertyReference( ownerEntity.getEntityName(), referencedPropertyName ); -// } -// else if ( value instanceof Collection ) { -// ( (Collection) value ).setReferencedPropertyName( referencedPropertyName ); -// //not unique because we could create a mtm wo association table -// mappings.addPropertyReference( ownerEntity.getEntityName(), referencedPropertyName ); -// } -// else { -// throw new AssertionFailure( -// "Do a property ref on an unexpected Value type: " -// + value.getClass().getName() -// ); -// } -// mappings.addPropertyReferencedAssociation( -// ( inverse ? "inverse__" : "" ) + associatedClass.getEntityName(), -// columns[0].getPropertyName(), -// referencedPropertyName -// ); -// } -// } public static void createSyntheticPropertyReference( Ejb3JoinColumn[] columns, From 54ea27a4d586477ade662441b616dc11c2545c51 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Thu, 21 Oct 2021 12:25:25 -0500 Subject: [PATCH 361/644] improve hibernate-core-jakarta build --- .../hibernate-core-jakarta.gradle | 231 +++++++++++++----- hibernate-core/hibernate-core.gradle | 15 +- 2 files changed, 177 insertions(+), 69 deletions(-) diff --git a/hibernate-core-jakarta/hibernate-core-jakarta.gradle b/hibernate-core-jakarta/hibernate-core-jakarta.gradle index e9b091c0c98a..f2b1cf528ec4 100644 --- a/hibernate-core-jakarta/hibernate-core-jakarta.gradle +++ b/hibernate-core-jakarta/hibernate-core-jakarta.gradle @@ -5,8 +5,6 @@ * See the lgpl.txt file in the root directory or . */ -import org.apache.tools.ant.filters.ReplaceTokens - description = 'Hibernate O/RM implementation of the Jakarta Persistence specification' apply from: rootProject.file( 'gradle/published-java-module.gradle' ) @@ -88,86 +86,195 @@ dependencies { testCompile libraries.jboss_annotation_spec_jar } -jar { - mustRunAfter project(':hibernate-core').tasks.jar - mustRunAfter project(':hibernate-core').tasks.testJar +// we do not want the much of the normal java plugin's behavior +compileJava.enabled false +processResources.enabled false +compileTestJava.enabled false +processTestResources.enabled false +jar.enabled false + +ext { + transformedJarName = project(':hibernate-core').tasks.jar.archiveFileName.get().replaceAll( 'hibernate-core', 'hibernate-core-jakarta' ) + + unpackedTestDirRelative = 'tmp/unpack/test' + transformedTestDirRelative = 'classes/java/test' + + unpackedTestDir = "${buildDir}/${unpackedTestDirRelative}" + transformedTestDir = "${buildDir}/${transformedTestDirRelative}" + + baseTransformerArgs = [ + // "quiet" output + '-q', + '-tr', new File(getProjectDir().getParentFile(), 'rules/jakarta-renames.properties').path, + '-tv', new File(getProjectDir().getParentFile(), 'rules/jakarta-versions.properties').path, + '-td', new File(getProjectDir().getParentFile(), 'rules/jakarta-direct.properties').path, + ] +} + +task transformJar { + description 'Transforms the hibernate-core jar using the JakartaTransformer tool' + dependsOn project(':hibernate-core').tasks.jar - dependsOn project(':hibernate-core').tasks.testJar - def baseDir = project(':hibernate-core').buildDir - def baseJars = fileTree(baseDir).matching {include 'libs/*.jar' } - inputs.files(baseJars).skipWhenEmpty() - outputs.dir project.buildDir + mustRunAfter project(':hibernate-core').tasks.jar + + inputs.file project(':hibernate-core').tasks.jar.archiveFile + outputs.file "${buildDir}/libs/${transformedJarName}" + doLast { - new File(project.buildDir, "libs").mkdirs() - fileTree(project.buildDir).matching { include 'libs/*.jar' }.each { delete it } - - baseJars.each { bundleJar -> - def sourceJarPath = baseDir.path + '/libs/' + bundleJar.name - println 'Initial bundle jar name [ ' + sourceJarPath + ' ]' - - def finalBundleJarName = project.buildDir.path + '/libs/' + bundleJar.name.replaceAll( 'hibernate-core', 'hibernate-core-jakarta' ) - println 'Default jakarta final bundle jar name [ ' + finalBundleJarName + ' ]' - - def transformerArgs = [ - sourceJarPath, finalBundleJarName, - '-q', // quiet output - '-tr', new File(getProjectDir().getParentFile(), 'rules/jakarta-renames.properties').path, - '-tv', new File(getProjectDir().getParentFile(), 'rules/jakarta-versions.properties').path, - '-td', new File(getProjectDir().getParentFile(), 'rules/jakarta-direct.properties').path, - ] - - println 'Transformer options:' - transformerArgs.each { - println ' [ ' + it + ' ]' - } - - javaexec { - classpath configurations.jakartaeeTransformJars - main = 'org.eclipse.transformer.jakarta.JakartaTransformer' - args = transformerArgs - } + def transformerArgs = [ + // source jar + project(':hibernate-core').tasks.jar.archiveFile.get(), + // target jar + file( "${buildDir}/libs/${transformedJarName}" ) + ] + ( project.baseTransformerArgs as ArrayList ) + + println 'Transformer options (main) :' + transformerArgs.each { + println ' [ ' + it + ' ]' + } + + javaexec { + classpath configurations.jakartaeeTransformJars + main = 'org.eclipse.transformer.jakarta.JakartaTransformer' + args = transformerArgs } } } task unpackTestJar(type: Copy) { - dependsOn jar - fileTree(project.buildDir).matching { include 'libs/*-test.jar' }.each { - def outputDir = file("${buildDir}/unpacked/" + it.name) - from zipTree(it) - into outputDir + description 'Unpacks the hibernate-core test jar into a directory so we can transform it and replace token(s) in the test resources' + + dependsOn project(':hibernate-core').tasks.testJar + mustRunAfter project(':hibernate-core').tasks.testJar + + inputs.file project(':hibernate-core').tasks.testJar.archiveFile + outputs.dir project.unpackedTestDir + + from zipTree( project( ":hibernate-core" ).tasks.testJar.archiveFile ) + into project.unpackedTestDir + + // There are persistence.xml files referencing jar files through their absolute path so we + // have to replace 'hibernate-core' references in the path with 'hibernate-core-jakarta' + + filesMatching('**/*.xml') { + filter { line -> + line.replaceAll( 'hibernate-core/target', 'hibernate-core-jakarta/target' ) + } } + +// - commented out atm because this causes problems for the JakartaTransformer (doesn't everything?) +// filter { line -> +// line.replaceAll( 'hibernate-core/target', 'hibernate-core-jakarta/target' ) +// } + +// doLast { +// // replacing this text in the unpack dir causes problems for the JakartaTransformer (doesn't everything?) +// // - so we only do it in the transformed dir after the transformation happens. +// ant.replaceregexp(match:'hibernate-core', replace:'hibernate-core-jakarta', flags:'g', byline:true) { +// fileset(dir: "${project.unpackedTestDir}/bundles", includes: '**/*.xml') +// } +// } + } -task copyBundleResources (type: Copy) { +task transformTests { + description 'Transforms the hibernate-core tests using the JakartaTransformer tool' + dependsOn unpackTestJar - File unpackedDir = new File(project.buildDir, "libs/hibernate-core-jakarta-${project.version}-test.jar") - ext { - bundlesTargetDir = file( "${buildDir}/bundles" ) - bundleTokens = dbBundle[db] - ext.bundleTokens['buildDirName'] = buildDir.absolutePath - } + mustRunAfter unpackTestJar + + inputs.dir project.unpackedTestDir + outputs.dir project.transformedTestDir + + def transformedTestDirFile = file(project.transformedTestDir) - from file("${buildDir}/unpacked/${unpackedDir.name}/templates") - into ext.bundlesTargetDir - filter( ReplaceTokens, tokens: ext.bundleTokens) doFirst { - ext.bundlesTargetDir.mkdirs() + println ":transformTests#doFirst : ${project.transformedTestDir} (exists? : ${transformedTestDirFile.exists()})" + + // JakartaTransformer expects that the output directory does not exist and + // also expects that the parent of the output directory does + if ( transformedTestDirFile.exists() ) { + def wasDeleteSuccessful = transformedTestDirFile.delete() + println ":unpackTestJar#doLast : deleting ${project.transformedTestDir} (successful? : ${wasDeleteSuccessful})" + + def wasMakeDirsSuccessful = transformedTestDirFile.parentFile.mkdirs() + println ":unpackTestJar#doLast : created ${transformedTestDirFile.parentFile.absolutePath} (successful? : ${wasMakeDirsSuccessful})" + } + } + +// doLast { +// // replacing this text in the unpack dir causes problems for the JakartaTransformer (doesn't everything?) +// // - so we only do it in the transformed dir after the transformation happens. +// ant.replaceregexp(match:'hibernate-core', replace:'hibernate-core-jakarta', flags:'g', byline:true) { +// fileset(dir: "${project.transformedTestDir}/bundles", includes: '**/*.xml') +// } +// } + + doLast { + def transformerArgs = [ + // source dir + project.unpackedTestDir, + // target dir + project.transformedTestDir + ] + ( project.baseTransformerArgs as ArrayList ) + + println 'Transformer options (tests) :' + transformerArgs.each { + println ' [ ' + it + ' ]' + } + + javaexec { + classpath configurations.jakartaeeTransformJars + main = 'org.eclipse.transformer.jakarta.JakartaTransformer' + args = transformerArgs + } } } -processTestResources.dependsOn copyBundleResources +/** + * Allow the transformation task to process these bundles and then move them + */ +task stagePackagingTestBundles(type:Copy) { + dependsOn tasks.transformTests + mustRunAfter tasks.transformTests + + from project.file( project.transformedTestDir ) + into project.file( "${buildDir}" ) +} + +task testJar(type: Jar) { + description 'Jars the transformed tests' + + dependsOn tasks.transformTests + dependsOn tasks.stagePackagingTestBundles + mustRunAfter tasks.transformTests + mustRunAfter tasks.stagePackagingTestBundles + + from project.transformedTestDir + + duplicatesStrategy = DuplicatesStrategy.EXCLUDE + archiveClassifier.set( 'test' ) +} artifacts { - tests new File(project.buildDir, "libs/hibernate-core-jakarta-${project.version}-test.jar") + tests tasks.testJar } test { - fileTree(project.buildDir).matching { include 'libs/*-test.jar' }.each { - def outputDir = file("${buildDir}/unpacked/" + it.name) - testClassesDirs += files(outputDir) - classpath += files(outputDir) - } + dependsOn tasks.transformJar + dependsOn tasks.transformTests + dependsOn tasks.stagePackagingTestBundles + + mustRunAfter tasks.transformJar + mustRunAfter tasks.transformTests + mustRunAfter tasks.stagePackagingTestBundles + + classpath += files( + "${buildDir}/libs/${project.transformedJarName}", + "${buildDir}/${project.transformedTestDirRelative}" + ) + testClassesDirs += files( project.layout.buildDirectory.dir( project.transformedTestDirRelative ) ) + systemProperty 'file.encoding', 'utf-8' if ( gradle.ext.javaVersions.test.launcher.asInt() >= 9 ) { @@ -177,4 +284,6 @@ test { jvmArgs( ['--add-opens', 'java.base/java.security=ALL-UNNAMED'] ) jvmArgs( ['--add-opens', 'java.base/java.lang=ALL-UNNAMED'] ) } + + maxHeapSize = '3G' } \ No newline at end of file diff --git a/hibernate-core/hibernate-core.gradle b/hibernate-core/hibernate-core.gradle index f2a1c3c0f862..10db463bf1a3 100644 --- a/hibernate-core/hibernate-core.gradle +++ b/hibernate-core/hibernate-core.gradle @@ -25,7 +25,7 @@ sourceSets { // resources inherently exclude sources test { resources { - setSrcDirs( ['src/test/java','src/test/resources','src/test/bundles'] ) + srcDir 'src/test/java' } } } @@ -196,18 +196,13 @@ tasks.compile.dependsOn generateGrammarSource task copyBundleResources (type: Copy) { ext { - bundlesTargetDir = file( "${buildDir}/bundles" ) bundleTokens = dbBundle[db] ext.bundleTokens['buildDirName'] = buildDir.absolutePath } - from file('src/test/bundles/templates') - into ext.bundlesTargetDir + from 'src/test/bundles/templates' + into "${buildDir}/bundles" filter( ReplaceTokens, tokens: ext.bundleTokens) - - doFirst { - ext.bundlesTargetDir.mkdirs() - } } processTestResources.dependsOn copyBundleResources @@ -219,6 +214,9 @@ task testJar(type: Jar, dependsOn: testClasses) { duplicatesStrategy = DuplicatesStrategy.EXCLUDE archiveClassifier.set( 'test' ) from sourceSets.test.output + from( "${buildDir}/bundles" ) { + into 'bundles' + } } artifacts { @@ -239,6 +237,7 @@ test { beforeTest { descriptor -> //println "Starting test: " + descriptor } + // Allow to exclude specific tests if (project.hasProperty('excludeTests')) { filter { From e4b56b927169b318231770af1b0854b02a6b286c Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Thu, 21 Oct 2021 13:52:33 -0500 Subject: [PATCH 362/644] HHH-14857 - Deprecations in preparation for 6 --- .../main/java/org/hibernate/EntityMode.java | 26 ++++++++++++++++++- .../SessionFactoryOptionsBuilder.java | 12 +++++---- .../hbm/internal/EntityModeConverter.java | 21 ++++++++++++--- .../hbm/AbstractEntitySourceImpl.java | 12 +++++++++ .../org/hibernate/cfg/AvailableSettings.java | 3 +++ .../internal/log/DeprecationLogger.java | 6 +++++ 6 files changed, 71 insertions(+), 9 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/EntityMode.java b/hibernate-core/src/main/java/org/hibernate/EntityMode.java index 1f07ca88d487..522a333e34f9 100644 --- a/hibernate-core/src/main/java/org/hibernate/EntityMode.java +++ b/hibernate-core/src/main/java/org/hibernate/EntityMode.java @@ -8,11 +8,16 @@ import java.util.Locale; +import static org.hibernate.cfg.AvailableSettings.DEFAULT_ENTITY_MODE; +import static org.hibernate.internal.log.DeprecationLogger.DEPRECATION_LOGGER; + /** * Defines the representation modes available for entities. * - * @author Steve Ebersole + * @deprecated To be removed in 6.0 in favor of `ManagedTypeRepresentationStrategy` + * and `RepresentationMode` */ +@Deprecated public enum EntityMode { /** * The {@code pojo} entity mode describes an entity model made up of entity classes (loosely) following @@ -58,4 +63,23 @@ public static EntityMode parse(String entityMode) { return valueOf( entityMode.toUpperCase( Locale.ENGLISH ) ); } + public static EntityMode fromSetting(Object setting) { + if ( setting != null ) { + DEPRECATION_LOGGER.deprecatedSetting( DEFAULT_ENTITY_MODE ); + } + + if ( setting == null || setting == POJO ) { + return POJO; + } + + if ( setting instanceof EntityMode ) { + return ( (EntityMode) setting ); + } + + if ( setting instanceof String ) { + return parse( (String) setting ); + } + + return POJO; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java index ac6163fdfad6..d0b4376af53b 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java @@ -130,6 +130,7 @@ import static org.hibernate.cfg.AvailableSettings.DISCARD_PC_ON_CLOSE; import static org.hibernate.engine.config.spi.StandardConverters.BOOLEAN; import static org.hibernate.internal.CoreLogging.messageLogger; +import static org.hibernate.internal.log.DeprecationLogger.DEPRECATION_LOGGER; /** * In-flight state of {@link org.hibernate.boot.spi.SessionFactoryOptions} @@ -330,10 +331,11 @@ public SessionFactoryOptionsBuilder(StandardServiceRegistry serviceRegistry, Boo this.entityNotFoundDelegate = StandardEntityNotFoundDelegate.INSTANCE; this.identifierRollbackEnabled = cfgService.getSetting( USE_IDENTIFIER_ROLLBACK, BOOLEAN, false ); - this.defaultEntityMode = EntityMode.parse( (String) configurationSettings.get( DEFAULT_ENTITY_MODE ) ); this.checkNullability = cfgService.getSetting( CHECK_NULLABILITY, BOOLEAN, true ); this.initializeLazyStateOutsideTransactions = cfgService.getSetting( ENABLE_LAZY_LOAD_NO_TRANS, BOOLEAN, false ); + this.defaultEntityMode = EntityMode.fromSetting( configurationSettings.get( DEFAULT_ENTITY_MODE ) ); + this.multiTenancyStrategy = MultiTenancyStrategy.determineMultiTenancyStrategy( configurationSettings ); this.currentTenantIdentifierResolver = strategySelector.resolveStrategy( CurrentTenantIdentifierResolver.class, @@ -475,7 +477,7 @@ public SessionFactoryOptionsBuilder(StandardServiceRegistry serviceRegistry, Boo null ); if ( oldSetting != null ) { - DeprecationLogger.DEPRECATION_LOGGER.deprecatedSetting( + DEPRECATION_LOGGER.deprecatedSetting( org.hibernate.jpa.AvailableSettings.DISCARD_PC_ON_CLOSE, DISCARD_PC_ON_CLOSE ); @@ -562,7 +564,7 @@ private static Interceptor determineInterceptor(Map configurationSettings, Strat () -> { final Object oldSetting = configurationSettings.get( org.hibernate.jpa.AvailableSettings.INTERCEPTOR ); if ( oldSetting != null ) { - DeprecationLogger.DEPRECATION_LOGGER.deprecatedSetting( + DEPRECATION_LOGGER.deprecatedSetting( org.hibernate.jpa.AvailableSettings.INTERCEPTOR, INTERCEPTOR ); @@ -583,7 +585,7 @@ private static Supplier determineStatelessInterceptor( () -> { final Object oldSetting = configurationSettings.get( org.hibernate.jpa.AvailableSettings.SESSION_INTERCEPTOR ); if ( oldSetting != null ) { - DeprecationLogger.DEPRECATION_LOGGER.deprecatedSetting( + DEPRECATION_LOGGER.deprecatedSetting( org.hibernate.jpa.AvailableSettings.SESSION_INTERCEPTOR, SESSION_SCOPED_INTERCEPTOR ); @@ -659,7 +661,7 @@ private PhysicalConnectionHandlingMode interpretConnectionHandlingMode( ConnectionReleaseMode specifiedReleaseMode, Map configurationSettings, TransactionCoordinatorBuilder transactionCoordinatorBuilder) { - DeprecationLogger.DEPRECATION_LOGGER.logUseOfDeprecatedConnectionHandlingSettings(); + DEPRECATION_LOGGER.logUseOfDeprecatedConnectionHandlingSettings(); final ConnectionAcquisitionMode effectiveAcquisitionMode = specifiedAcquisitionMode == null ? ConnectionAcquisitionMode.AS_NEEDED diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/internal/EntityModeConverter.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/internal/EntityModeConverter.java index d9548064fad2..6c5aa1ad1ba0 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/internal/EntityModeConverter.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/internal/EntityModeConverter.java @@ -7,16 +7,31 @@ package org.hibernate.boot.jaxb.hbm.internal; import org.hibernate.EntityMode; +import org.hibernate.internal.log.DeprecationLogger; +import org.hibernate.internal.util.StringHelper; /** - * @author Steve Ebersole + * @deprecated for removal in 6.0 */ +@Deprecated public class EntityModeConverter { public static EntityMode fromXml(String name) { - return EntityMode.parse( name ); + final EntityMode entityMode = EntityMode.parse( name ); + if ( StringHelper.isNotEmpty( name ) ) { + DeprecationLogger.DEPRECATION_LOGGER.info( + "XML mapping specified an entity-mode - `%s`. Starting in 6.0 this is simply inferred from the entity/composite mapping" + ); + } + return entityMode; } public static String toXml(EntityMode entityMode) { - return ( null == entityMode ) ? null : entityMode.getExternalName(); + if ( entityMode == null ) { + return null; + } + DeprecationLogger.DEPRECATION_LOGGER.info( + "XML mapping specified an entity-mode - `%s`. Starting in 6.0 this is simply inferred from the entity/composite mapping" + ); + return entityMode.getExternalName(); } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/AbstractEntitySourceImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/AbstractEntitySourceImpl.java index cfb2826243b1..230856c2126c 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/AbstractEntitySourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/AbstractEntitySourceImpl.java @@ -324,10 +324,22 @@ public boolean isSelectBeforeUpdate() { return jaxbEntityMapping.isSelectBeforeUpdate(); } + /** + * @deprecated to be removed in 6.0. Starting in 6.0 the mode is inferred + * from the entity-type mapping + */ + @Deprecated protected EntityMode determineEntityMode() { return StringHelper.isNotEmpty( entityNamingSource.getClassName() ) ? EntityMode.POJO : EntityMode.MAP; } + /** + * @deprecated to be removed in 6.0. Starting in 6.0 the mode is inferred + * from the entity-type mapping + * + * See `ManagedTypeRepresentationStrategy` and `RepresentationMode` in 6.0 + */ + @Deprecated @Override public Map getTuplizerClassMap() { return tuplizerClassMap; diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java index f4da85d6817a..59d79cb7156d 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java @@ -1409,7 +1409,10 @@ public interface AvailableSettings extends org.hibernate.jpa.AvailableSettings { /** * The EntityMode in which set the Session opened from the SessionFactory. + * + * @deprecated An entity-type has one "mode" relative to any SessionFactory. */ + @Deprecated String DEFAULT_ENTITY_MODE = "hibernate.default_entity_mode"; /** diff --git a/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java b/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java index 9ecfe081bf67..9f709d59a333 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java @@ -297,4 +297,10 @@ void connectionProviderClassDeprecated( ) void deprecatedJmxBeanRegistration(String name); + @LogMessage(level = WARN) + @Message( + id = 90000031, + value = "Encountered deprecated setting [%s] which is planned for removal" + ) + void deprecatedSetting(String setting); } From 85cd748de58dd090b04212ad0770f479187a29f5 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Thu, 21 Oct 2021 14:15:57 -0500 Subject: [PATCH 363/644] improve hibernate-core-jakarta build --- hibernate-core-jakarta/hibernate-core-jakarta.gradle | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/hibernate-core-jakarta/hibernate-core-jakarta.gradle b/hibernate-core-jakarta/hibernate-core-jakarta.gradle index f2b1cf528ec4..ce20340feffd 100644 --- a/hibernate-core-jakarta/hibernate-core-jakarta.gradle +++ b/hibernate-core-jakarta/hibernate-core-jakarta.gradle @@ -118,7 +118,7 @@ task transformJar { mustRunAfter project(':hibernate-core').tasks.jar inputs.file project(':hibernate-core').tasks.jar.archiveFile - outputs.file "${buildDir}/libs/${transformedJarName}" + outputs.file tasks.jar.archiveFile.get().asFile doLast { def transformerArgs = [ @@ -141,6 +141,15 @@ task transformJar { } } +configurations { + [apiElements, runtimeElements].each { + it.outgoing.artifacts.removeIf { + it.buildDependencies.getDependencies(null).contains(jar) + } + it.outgoing.artifact(tasks.jar.archiveFile.get().asFile) + } +} + task unpackTestJar(type: Copy) { description 'Unpacks the hibernate-core test jar into a directory so we can transform it and replace token(s) in the test resources' From 1fdd0a6df12dbc9ec18e79a012390e910fd73698 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Thu, 21 Oct 2021 14:34:26 -0500 Subject: [PATCH 364/644] improve hibernate-core-jakarta build --- .../hibernate-core-jakarta.gradle | 89 +++++++++++++------ 1 file changed, 62 insertions(+), 27 deletions(-) diff --git a/hibernate-core-jakarta/hibernate-core-jakarta.gradle b/hibernate-core-jakarta/hibernate-core-jakarta.gradle index ce20340feffd..b83db4750440 100644 --- a/hibernate-core-jakarta/hibernate-core-jakarta.gradle +++ b/hibernate-core-jakarta/hibernate-core-jakarta.gradle @@ -1,3 +1,5 @@ +import javax.inject.Inject + /* * Hibernate, Relational Persistence for Idiomatic Java * @@ -13,7 +15,7 @@ configurations { tests { description = 'Configuration for the produced test jar' } - jakartaeeTransformJars + jakartaeeTransformTool } dependencies { @@ -37,7 +39,7 @@ dependencies { compile( libraries.jakarta_jaxb_api ) compile( libraries.jakarta_jaxb_runtime ) - jakartaeeTransformJars 'biz.aQute.bnd:biz.aQute.bnd.transform:5.1.1', + jakartaeeTransformTool 'biz.aQute.bnd:biz.aQute.bnd.transform:5.1.1', 'commons-cli:commons-cli:1.4', 'org.slf4j:slf4j-simple:1.7.30', 'org.slf4j:slf4j-api:1.7.26', @@ -111,34 +113,14 @@ ext { ] } -task transformJar { +task transformJar(type: JakartaJarTransformation) { description 'Transforms the hibernate-core jar using the JakartaTransformer tool' dependsOn project(':hibernate-core').tasks.jar mustRunAfter project(':hibernate-core').tasks.jar - inputs.file project(':hibernate-core').tasks.jar.archiveFile - outputs.file tasks.jar.archiveFile.get().asFile - - doLast { - def transformerArgs = [ - // source jar - project(':hibernate-core').tasks.jar.archiveFile.get(), - // target jar - file( "${buildDir}/libs/${transformedJarName}" ) - ] + ( project.baseTransformerArgs as ArrayList ) - - println 'Transformer options (main) :' - transformerArgs.each { - println ' [ ' + it + ' ]' - } - - javaexec { - classpath configurations.jakartaeeTransformJars - main = 'org.eclipse.transformer.jakarta.JakartaTransformer' - args = transformerArgs - } - } + sourceJar project(':hibernate-core').tasks.jar.archiveFile + targetJar tasks.jar.archiveFile.get().asFile } configurations { @@ -146,7 +128,9 @@ configurations { it.outgoing.artifacts.removeIf { it.buildDependencies.getDependencies(null).contains(jar) } - it.outgoing.artifact(tasks.jar.archiveFile.get().asFile) + it.outgoing.artifact(tasks.transformJar.targetJar) { + builtBy tasks.transformJar + } } } @@ -233,7 +217,7 @@ task transformTests { } javaexec { - classpath configurations.jakartaeeTransformJars + classpath configurations.jakartaeeTransformTool main = 'org.eclipse.transformer.jakarta.JakartaTransformer' args = transformerArgs } @@ -295,4 +279,55 @@ test { } maxHeapSize = '3G' +} + + +@CacheableTask +abstract class JakartaJarTransformation extends DefaultTask { + private final RegularFileProperty sourceJar; + private final RegularFileProperty targetJar; + + @Inject + JakartaJarTransformation(ObjectFactory objectFactory) { + sourceJar = objectFactory.fileProperty(); + targetJar = objectFactory.fileProperty(); + } + + @InputFile + @PathSensitive( PathSensitivity.RELATIVE ) + RegularFileProperty getSourceJar() { + return sourceJar; + } + + void sourceJar(Object fileReference) { + sourceJar.set( project.file( fileReference ) ) + } + + @OutputFile + RegularFileProperty getTargetJar() { + return targetJar; + } + + void targetJar(Object fileReference) { + targetJar.set( project.file( fileReference ) ) + } + + @TaskAction + void transform() { + project.javaexec( new Action() { + @Override + void execute(JavaExecSpec javaExecSpec) { + javaExecSpec.classpath( getProject().getConfigurations().getByName( "jakartaeeTransformTool" ) ); + javaExecSpec.setMain( "org.eclipse.transformer.jakarta.JakartaTransformer" ); + javaExecSpec.args( + sourceJar.get().getAsFile().getAbsolutePath(), + targetJar.get().getAsFile().getAbsolutePath(), + "-q", + "-tr", getProject().getRootProject().file( "rules/jakarta-renames.properties" ).getAbsolutePath(), + "-tv", getProject().getRootProject().file( "rules/jakarta-versions.properties" ).getAbsolutePath(), + "-td", getProject().getRootProject().file( "rules/jakarta-direct.properties" ).getAbsolutePath() + ); + } + }); + } } \ No newline at end of file From 91e29358be0a73d77ac00de45ddf56dd989fefd2 Mon Sep 17 00:00:00 2001 From: Steve Ebersole Date: Thu, 21 Oct 2021 16:13:55 -0500 Subject: [PATCH 365/644] HHH-14857 - Deprecations in preparation for 6 --- .../src/main/java/org/hibernate/tuple/Tuplizer.java | 4 ++++ .../java/org/hibernate/tuple/component/ComponentTuplizer.java | 4 ++++ .../main/java/org/hibernate/tuple/entity/EntityTuplizer.java | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/Tuplizer.java b/hibernate-core/src/main/java/org/hibernate/tuple/Tuplizer.java index 9c0120b185e4..16ec664d3232 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/Tuplizer.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/Tuplizer.java @@ -31,8 +31,12 @@ * @see org.hibernate.tuple.entity.EntityTuplizer * @see org.hibernate.tuple.component.ComponentTuplizer * + * @deprecated for removal in 6.0. See instead `ManagedTypeRepresentationStrategy` + * and `RepresentationMode` in 6.0 + * * @author Steve Ebersole */ +@Deprecated public interface Tuplizer { /** * Extract the current values contained on the given entity. diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/component/ComponentTuplizer.java b/hibernate-core/src/main/java/org/hibernate/tuple/component/ComponentTuplizer.java index 916e02b6d57a..75eaa2572e07 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/component/ComponentTuplizer.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/component/ComponentTuplizer.java @@ -20,7 +20,11 @@ * * @author Gavin King * @author Steve Ebersole + * + * @deprecated for removal in 6.0. See instead `ManagedTypeRepresentationStrategy` + * and `RepresentationMode` in 6.0 */ +@Deprecated public interface ComponentTuplizer extends Tuplizer, Serializable { /** * Retrieve the current value of the parent property. diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityTuplizer.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityTuplizer.java index 68b8b9d22fa2..2f7e932b4e4e 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityTuplizer.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityTuplizer.java @@ -28,7 +28,11 @@ * * @author Gavin King * @author Steve Ebersole + * + * @deprecated for removal in 6.0. See instead `ManagedTypeRepresentationStrategy` + * and `RepresentationMode` in 6.0 */ +@Deprecated public interface EntityTuplizer extends Tuplizer { /** * Return the entity-mode handled by this tuplizer instance. From 8a2869a09ae642a7539fcc085c52e616f86c9f93 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Mon, 25 Oct 2021 16:55:57 +0100 Subject: [PATCH 366/644] HHH-14900 Remove dead logger --- .../hibernate/engine/jdbc/batch/internal/BatchBuilderImpl.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BatchBuilderImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BatchBuilderImpl.java index 1dbd70962844..b15c4f5594b9 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BatchBuilderImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BatchBuilderImpl.java @@ -13,8 +13,6 @@ import org.hibernate.engine.jdbc.batch.spi.BatchBuilder; import org.hibernate.engine.jdbc.batch.spi.BatchKey; import org.hibernate.engine.jdbc.spi.JdbcCoordinator; -import org.hibernate.internal.CoreLogging; -import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.config.ConfigurationHelper; import org.hibernate.service.spi.Configurable; import org.hibernate.service.spi.Manageable; @@ -25,7 +23,6 @@ * @author Steve Ebersole */ public class BatchBuilderImpl implements BatchBuilder, Configurable, Manageable, BatchBuilderMXBean { - private static final CoreMessageLogger LOG = CoreLogging.messageLogger( BatchBuilderImpl.class ); private int jdbcBatchSize; From 9ecd1799a0f408b86d2e9398a41fdb7f310938a6 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Mon, 25 Oct 2021 17:00:50 +0100 Subject: [PATCH 367/644] HHH-14900 Since the BatchBuilderImpl Service is shared, mutable field jdbcBatchSize should be marked volatile --- .../hibernate/engine/jdbc/batch/internal/BatchBuilderImpl.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BatchBuilderImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BatchBuilderImpl.java index b15c4f5594b9..5e993eb0cd53 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BatchBuilderImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BatchBuilderImpl.java @@ -24,7 +24,7 @@ */ public class BatchBuilderImpl implements BatchBuilder, Configurable, Manageable, BatchBuilderMXBean { - private int jdbcBatchSize; + private volatile int jdbcBatchSize; /** * Constructs a BatchBuilderImpl From aba67cfe6eef2da0534dadf62c8916a65a34a45e Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Mon, 25 Oct 2021 17:03:03 +0100 Subject: [PATCH 368/644] HHH-14900 BatchBuilderImpl doesn't need to be Configurable --- .../engine/jdbc/batch/internal/BatchBuilderImpl.java | 12 +----------- 1 file changed, 1 insertion(+), 11 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BatchBuilderImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BatchBuilderImpl.java index 5e993eb0cd53..de2563be084d 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BatchBuilderImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BatchBuilderImpl.java @@ -6,15 +6,10 @@ */ package org.hibernate.engine.jdbc.batch.internal; -import java.util.Map; - -import org.hibernate.cfg.Environment; import org.hibernate.engine.jdbc.batch.spi.Batch; import org.hibernate.engine.jdbc.batch.spi.BatchBuilder; import org.hibernate.engine.jdbc.batch.spi.BatchKey; import org.hibernate.engine.jdbc.spi.JdbcCoordinator; -import org.hibernate.internal.util.config.ConfigurationHelper; -import org.hibernate.service.spi.Configurable; import org.hibernate.service.spi.Manageable; /** @@ -22,7 +17,7 @@ * * @author Steve Ebersole */ -public class BatchBuilderImpl implements BatchBuilder, Configurable, Manageable, BatchBuilderMXBean { +public class BatchBuilderImpl implements BatchBuilder, Manageable, BatchBuilderMXBean { private volatile int jdbcBatchSize; @@ -41,11 +36,6 @@ public BatchBuilderImpl(int jdbcBatchSize) { this.jdbcBatchSize = jdbcBatchSize; } - @Override - public void configure(Map configurationValues) { - jdbcBatchSize = ConfigurationHelper.getInt( Environment.STATEMENT_BATCH_SIZE, configurationValues, jdbcBatchSize ); - } - @Override public int getJdbcBatchSize() { return jdbcBatchSize; From 5ad60c4b6151fd7eaddef0a112787ebfacb91a86 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Mon, 25 Oct 2021 17:09:04 +0100 Subject: [PATCH 369/644] HHH-14900 No need in tests to shadow the jdbcBatchSize field of BatchBuilderImpl extensions --- .../test/transaction/batch/JtaWithFailingBatchTest.java | 8 +------- .../transaction/batch/JtaWithStatementsBatchTest.java | 8 +------- .../hibernate/test/insertordering/InsertOrderingTest.java | 8 +------- 3 files changed, 3 insertions(+), 21 deletions(-) diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/transaction/batch/JtaWithFailingBatchTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/transaction/batch/JtaWithFailingBatchTest.java index 71fb84cd75fd..3aa6a9ca72b5 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/transaction/batch/JtaWithFailingBatchTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/transaction/batch/JtaWithFailingBatchTest.java @@ -151,16 +151,10 @@ protected String getBatchBuilderClassName() { } public static class TestBatchBuilder extends BatchBuilderImpl { - private int jdbcBatchSize; - - @Override - public void setJdbcBatchSize(int jdbcBatchSize) { - this.jdbcBatchSize = jdbcBatchSize; - } @Override public Batch buildBatch(BatchKey key, JdbcCoordinator jdbcCoordinator) { - return buildBatchTest( key, jdbcCoordinator, jdbcBatchSize ); + return buildBatchTest( key, jdbcCoordinator, getJdbcBatchSize() ); } protected BatchingBatch buildBatchTest(BatchKey key, JdbcCoordinator jdbcCoordinator, int jdbcBatchSize) { diff --git a/hibernate-core/src/test/java/org/hibernate/jpa/test/transaction/batch/JtaWithStatementsBatchTest.java b/hibernate-core/src/test/java/org/hibernate/jpa/test/transaction/batch/JtaWithStatementsBatchTest.java index da0459e800a6..e406e4a29091 100644 --- a/hibernate-core/src/test/java/org/hibernate/jpa/test/transaction/batch/JtaWithStatementsBatchTest.java +++ b/hibernate-core/src/test/java/org/hibernate/jpa/test/transaction/batch/JtaWithStatementsBatchTest.java @@ -127,16 +127,10 @@ protected String getBatchBuilderClassName() { } public static class TestBatchBuilder extends BatchBuilderImpl { - private int jdbcBatchSize; - - @Override - public void setJdbcBatchSize(int jdbcBatchSize) { - this.jdbcBatchSize = jdbcBatchSize; - } @Override public Batch buildBatch(BatchKey key, JdbcCoordinator jdbcCoordinator) { - return buildBatchTest( key, jdbcCoordinator, jdbcBatchSize ); + return buildBatchTest( key, jdbcCoordinator, getJdbcBatchSize() ); } protected BatchingBatch buildBatchTest(BatchKey key, JdbcCoordinator jdbcCoordinator, int jdbcBatchSize) { diff --git a/hibernate-core/src/test/java/org/hibernate/test/insertordering/InsertOrderingTest.java b/hibernate-core/src/test/java/org/hibernate/test/insertordering/InsertOrderingTest.java index 82585b95acab..19488ce81c56 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/insertordering/InsertOrderingTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/insertordering/InsertOrderingTest.java @@ -109,16 +109,10 @@ public void addToBatch() { } public static class StatsBatchBuilder extends BatchBuilderImpl { - private int jdbcBatchSize; - - @Override - public void setJdbcBatchSize(int jdbcBatchSize) { - this.jdbcBatchSize = jdbcBatchSize; - } @Override public Batch buildBatch(BatchKey key, JdbcCoordinator jdbcCoordinator) { - return new StatsBatch( key, jdbcCoordinator, jdbcBatchSize ); + return new StatsBatch( key, jdbcCoordinator, getJdbcBatchSize() ); } } } From 959dfea66fae35dc28353bab5c6a12c30e2f26af Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Mon, 25 Oct 2021 17:37:00 +0100 Subject: [PATCH 370/644] HHH-14899 Have SessionImpl override the default method getConfiguredJdbcBatchSize --- .../hibernate/internal/FastSessionServices.java | 2 ++ .../java/org/hibernate/internal/SessionImpl.java | 14 ++++++++++++++ 2 files changed, 16 insertions(+) diff --git a/hibernate-core/src/main/java/org/hibernate/internal/FastSessionServices.java b/hibernate-core/src/main/java/org/hibernate/internal/FastSessionServices.java index 69dae836c9de..bef97b2fecf6 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/FastSessionServices.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/FastSessionServices.java @@ -160,6 +160,7 @@ public final class FastSessionServices { final boolean discardOnClose; final BaselineSessionEventsListenerBuilder defaultSessionEventListeners; final LockOptions defaultLockOptions; + final int defaultJdbcBatchSize; //Private fields: private final Dialect dialect; @@ -217,6 +218,7 @@ public final class FastSessionServices { this.disallowOutOfTransactionUpdateOperations = !sessionFactoryOptions.isAllowOutOfTransactionUpdateOperations(); this.useStreamForLobBinding = Environment.useStreamsForBinary() || dialect.useInputStreamToInsertBlob(); this.requiresMultiTenantConnectionProvider = sf.getSettings().getMultiTenancyStrategy().requiresMultiTenantConnectionProvider(); + this.defaultJdbcBatchSize = sessionFactoryOptions.getJdbcBatchSize(); //Some "hot" services: this.connectionProvider = requiresMultiTenantConnectionProvider ? null : sr.getService( ConnectionProvider.class ); diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java index 6489891016e6..53e8015dfc1f 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java @@ -300,6 +300,20 @@ protected ActionQueue createActionQueue() { return new ActionQueue( this ); } + /** + * Override the implementation provided on SharedSessionContractImplementor + * which is not very efficient: this method is hot in Hibernate Reactive, and could + * be hot in some ORM contexts as well. + * @return + */ + @Override + public Integer getConfiguredJdbcBatchSize() { + final Integer sessionJdbcBatchSize = getJdbcBatchSize(); + return sessionJdbcBatchSize == null ? + fastSessionServices.defaultJdbcBatchSize : + sessionJdbcBatchSize; + } + private LockOptions getLockOptionsForRead() { return this.lockOptions == null ? fastSessionServices.defaultLockOptions : this.lockOptions; } From 7ff73d178f4ae6c0add8ada23a45b979a18591ad Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Mon, 25 Oct 2021 17:49:52 +0100 Subject: [PATCH 371/644] HHH-14899 Inconsistent default value for STATEMENT_BATCH_SIZE --- .../hibernate/boot/internal/SessionFactoryOptionsBuilder.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java index d0b4376af53b..1f4875e9bbea 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java @@ -428,7 +428,7 @@ public SessionFactoryOptionsBuilder(StandardServiceRegistry serviceRegistry, Boo } } - this.jdbcBatchSize = ConfigurationHelper.getInt( STATEMENT_BATCH_SIZE, configurationSettings, 0 ); + this.jdbcBatchSize = ConfigurationHelper.getInt( STATEMENT_BATCH_SIZE, configurationSettings, 1 ); if ( !meta.supportsBatchUpdates() ) { this.jdbcBatchSize = 0; } From 634c257d93729e1a645eded974a190d13cf6b74b Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Tue, 26 Oct 2021 10:06:11 +0100 Subject: [PATCH 372/644] HHH-14899 Rename test class to fix typo: StateObjectStateExceptionHandlingTest to StaleObjectStateExceptionHandlingTest --- ...ngTest.java => StaleObjectStateExceptionHandlingTest.java} | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) rename hibernate-core/src/test/java/org/hibernate/test/exceptionhandling/{StateObjectStateExceptionHandlingTest.java => StaleObjectStateExceptionHandlingTest.java} (95%) diff --git a/hibernate-core/src/test/java/org/hibernate/test/exceptionhandling/StateObjectStateExceptionHandlingTest.java b/hibernate-core/src/test/java/org/hibernate/test/exceptionhandling/StaleObjectStateExceptionHandlingTest.java similarity index 95% rename from hibernate-core/src/test/java/org/hibernate/test/exceptionhandling/StateObjectStateExceptionHandlingTest.java rename to hibernate-core/src/test/java/org/hibernate/test/exceptionhandling/StaleObjectStateExceptionHandlingTest.java index c0c50be6ef55..e7b38a0b74cf 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/exceptionhandling/StateObjectStateExceptionHandlingTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/exceptionhandling/StaleObjectStateExceptionHandlingTest.java @@ -21,9 +21,9 @@ @TestForIssue(jiraKey = "HHH-12666") @RequiresDialect(H2Dialect.class) -public class StateObjectStateExceptionHandlingTest extends BaseExceptionHandlingTest { +public class StaleObjectStateExceptionHandlingTest extends BaseExceptionHandlingTest { - public StateObjectStateExceptionHandlingTest( + public StaleObjectStateExceptionHandlingTest( BootstrapMethod bootstrapMethod, ExceptionHandlingSetting exceptionHandlingSetting, ExceptionExpectations exceptionExpectations) { From 7f71dca1aee845bd8bfe5055ed6b31c3d912de52 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Tue, 26 Oct 2021 10:30:01 +0100 Subject: [PATCH 373/644] HHH-14899 StaleObjectStateExceptionHandlingTest should expect a StaleStateException --- .../test/exceptionhandling/ExceptionExpectations.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/hibernate-core/src/test/java/org/hibernate/test/exceptionhandling/ExceptionExpectations.java b/hibernate-core/src/test/java/org/hibernate/test/exceptionhandling/ExceptionExpectations.java index 7c8dbc608192..7e81d16b30de 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/exceptionhandling/ExceptionExpectations.java +++ b/hibernate-core/src/test/java/org/hibernate/test/exceptionhandling/ExceptionExpectations.java @@ -12,7 +12,7 @@ import javax.persistence.PersistenceException; import javax.persistence.RollbackException; -import org.hibernate.StaleObjectStateException; +import org.hibernate.StaleStateException; import org.hibernate.TransactionException; import org.hibernate.TransientObjectException; import org.hibernate.exception.ConstraintViolationException; @@ -68,7 +68,7 @@ public void onGetSingleResultWithNoResults(RuntimeException e) { @Override public void onStaleObjectMergeAndUpdateFlush(RuntimeException e) { assertThat( e, instanceOf( OptimisticLockException.class ) ); - assertThat( e.getCause(), instanceOf( StaleObjectStateException.class ) ); + assertThat( e.getCause(), instanceOf( StaleStateException.class ) ); } @Override @@ -145,7 +145,7 @@ public void onGetSingleResultWithNoResults(RuntimeException e) { @Override public void onStaleObjectMergeAndUpdateFlush(RuntimeException e) { - assertThat( e, instanceOf( StaleObjectStateException.class ) ); + assertThat( e, instanceOf( StaleStateException.class ) ); } @Override @@ -221,7 +221,7 @@ public void onGetSingleResultWithNoResults(RuntimeException e) { @Override public void onStaleObjectMergeAndUpdateFlush(RuntimeException e) { assertThat( e, instanceOf( OptimisticLockException.class ) ); - assertThat( e.getCause(), instanceOf( StaleObjectStateException.class ) ); + assertThat( e.getCause(), instanceOf( StaleStateException.class ) ); } @Override From cc7498cf3ce621b929197db7b83914a101cae774 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Tue, 26 Oct 2021 16:58:32 +0100 Subject: [PATCH 374/644] HHH-14901 Introduce a new BatchBuilder implementation, suitable for immutable code deployments --- .../UnmodifiableBatchBuilderImpl.java | 39 ++++++++++++++ .../UnmodifiableBatchBuilderInitiator.java | 52 +++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/UnmodifiableBatchBuilderImpl.java create mode 100644 hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/UnmodifiableBatchBuilderInitiator.java diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/UnmodifiableBatchBuilderImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/UnmodifiableBatchBuilderImpl.java new file mode 100644 index 000000000000..c60764ee4b08 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/UnmodifiableBatchBuilderImpl.java @@ -0,0 +1,39 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.engine.jdbc.batch.internal; + +import org.hibernate.engine.jdbc.batch.spi.Batch; +import org.hibernate.engine.jdbc.batch.spi.BatchBuilder; +import org.hibernate.engine.jdbc.batch.spi.BatchKey; +import org.hibernate.engine.jdbc.spi.JdbcCoordinator; + +/** + * Simplified version of BatchBuilderImpl which does not support + * changing the configured jdbc Batch size at runtime and is + * not exposed via JMX. + * @author Sanne Grinovero + */ +final class UnmodifiableBatchBuilderImpl implements BatchBuilder { + + private final int jdbcBatchSize; + + public UnmodifiableBatchBuilderImpl(int jdbcBatchSize) { + this.jdbcBatchSize = jdbcBatchSize; + } + + @Override + public Batch buildBatch(BatchKey key, JdbcCoordinator jdbcCoordinator) { + final Integer sessionJdbcBatchSize = jdbcCoordinator.getJdbcSessionOwner() + .getJdbcBatchSize(); + final int jdbcBatchSizeToUse = sessionJdbcBatchSize == null ? + this.jdbcBatchSize : + sessionJdbcBatchSize; + return jdbcBatchSizeToUse > 1 + ? new BatchingBatch( key, jdbcCoordinator, jdbcBatchSizeToUse ) + : new NonBatchingBatch( key, jdbcCoordinator ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/UnmodifiableBatchBuilderInitiator.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/UnmodifiableBatchBuilderInitiator.java new file mode 100644 index 000000000000..7c972aebee9b --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/UnmodifiableBatchBuilderInitiator.java @@ -0,0 +1,52 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.engine.jdbc.batch.internal; + +import java.util.Map; + +import org.hibernate.boot.registry.StandardServiceInitiator; +import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; +import org.hibernate.cfg.Environment; +import org.hibernate.engine.jdbc.batch.spi.BatchBuilder; +import org.hibernate.internal.util.config.ConfigurationHelper; +import org.hibernate.service.spi.ServiceException; +import org.hibernate.service.spi.ServiceRegistryImplementor; + +/** + * Initiator for the {@link UnmodifiableBatchBuilderImpl} service using + * {@link UnmodifiableBatchBuilderImpl}. + * This is not the default implementation, but it's a useful alternative to have + * in some environments. + * + * @author Sanne Grinovero + */ +public final class UnmodifiableBatchBuilderInitiator implements StandardServiceInitiator { + /** + * Singleton access + */ + public static final UnmodifiableBatchBuilderInitiator INSTANCE = new UnmodifiableBatchBuilderInitiator(); + + @Override + public Class getServiceInitiated() { + return BatchBuilder.class; + } + + @Override + public BatchBuilder initiateService(Map configurationValues, ServiceRegistryImplementor registry) { + final Object builder = configurationValues.get( BatchBuilderInitiator.BUILDER ); + if ( builder == null ) { + return new UnmodifiableBatchBuilderImpl( + ConfigurationHelper.getInt( Environment.STATEMENT_BATCH_SIZE, configurationValues, 1 ) + ); + } + else { + throw new ServiceException( "This Hibernate ORM serviceregistry has been configured explicitly to use " + this.getClass() + + " to create BatchBuilder instances; the property '" + BatchBuilderInitiator.BUILDER + + "' is not supported." ); + } + } +} From a2cbe10e0799af2ea77dc64c57ceeb493f16b203 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Tue, 26 Oct 2021 17:07:23 +0100 Subject: [PATCH 375/644] HHH-14901 Refactor shared code into a single reused method --- .../jdbc/batch/internal/BatchBuilderImpl.java | 10 ++----- .../internal/SharedBatchBuildingCode.java | 28 +++++++++++++++++++ .../UnmodifiableBatchBuilderImpl.java | 10 ++----- 3 files changed, 32 insertions(+), 16 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/SharedBatchBuildingCode.java diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BatchBuilderImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BatchBuilderImpl.java index de2563be084d..dd1ac78b0a92 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BatchBuilderImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/BatchBuilderImpl.java @@ -48,13 +48,7 @@ public void setJdbcBatchSize(int jdbcBatchSize) { @Override public Batch buildBatch(BatchKey key, JdbcCoordinator jdbcCoordinator) { - final Integer sessionJdbcBatchSize = jdbcCoordinator.getJdbcSessionOwner() - .getJdbcBatchSize(); - final int jdbcBatchSizeToUse = sessionJdbcBatchSize == null ? - this.jdbcBatchSize : - sessionJdbcBatchSize; - return jdbcBatchSizeToUse > 1 - ? new BatchingBatch( key, jdbcCoordinator, jdbcBatchSizeToUse ) - : new NonBatchingBatch( key, jdbcCoordinator ); + return SharedBatchBuildingCode.buildBatch( jdbcBatchSize, key, jdbcCoordinator ); } + } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/SharedBatchBuildingCode.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/SharedBatchBuildingCode.java new file mode 100644 index 000000000000..d122128c886d --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/SharedBatchBuildingCode.java @@ -0,0 +1,28 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.engine.jdbc.batch.internal; + +import org.hibernate.engine.jdbc.batch.spi.Batch; +import org.hibernate.engine.jdbc.batch.spi.BatchKey; +import org.hibernate.engine.jdbc.spi.JdbcCoordinator; + +/** + * Common code across BatchBuilder service implementors + */ +final class SharedBatchBuildingCode { + + static Batch buildBatch(final int defaultJdbcBatchSize, final BatchKey key, final JdbcCoordinator jdbcCoordinator) { + final Integer sessionJdbcBatchSize = jdbcCoordinator.getJdbcSessionOwner() + .getJdbcBatchSize(); + final int jdbcBatchSizeToUse = sessionJdbcBatchSize == null ? + defaultJdbcBatchSize : + sessionJdbcBatchSize; + return jdbcBatchSizeToUse > 1 + ? new BatchingBatch( key, jdbcCoordinator, jdbcBatchSizeToUse ) + : new NonBatchingBatch( key, jdbcCoordinator ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/UnmodifiableBatchBuilderImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/UnmodifiableBatchBuilderImpl.java index c60764ee4b08..dd3553f5ca8b 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/UnmodifiableBatchBuilderImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/batch/internal/UnmodifiableBatchBuilderImpl.java @@ -27,13 +27,7 @@ public UnmodifiableBatchBuilderImpl(int jdbcBatchSize) { @Override public Batch buildBatch(BatchKey key, JdbcCoordinator jdbcCoordinator) { - final Integer sessionJdbcBatchSize = jdbcCoordinator.getJdbcSessionOwner() - .getJdbcBatchSize(); - final int jdbcBatchSizeToUse = sessionJdbcBatchSize == null ? - this.jdbcBatchSize : - sessionJdbcBatchSize; - return jdbcBatchSizeToUse > 1 - ? new BatchingBatch( key, jdbcCoordinator, jdbcBatchSizeToUse ) - : new NonBatchingBatch( key, jdbcCoordinator ); + return SharedBatchBuildingCode.buildBatch( jdbcBatchSize, key, jdbcCoordinator ); } + } From 2c3b3cb3d789f05b6457661268a327ecc4caa2d0 Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Wed, 27 Oct 2021 11:08:47 +0000 Subject: [PATCH 376/644] 5.6.1.Final --- changelog.txt | 23 +++++++++++++++++++++++ gradle/version.properties | 2 +- 2 files changed, 24 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 73d54a5aa0c7..35e957f9c6f1 100644 --- a/changelog.txt +++ b/changelog.txt @@ -3,6 +3,29 @@ Hibernate 5 Changelog Note: Please refer to JIRA to learn more about each issue. +Changes in 5.6.1.Final (October 27, 2021) +------------------------------------------------------------------------------------------------------------------------ + +https://hibernate.atlassian.net/projects/HHH/versions/31993 + +** Bug + * [HHH-14899] - Dialect no longer controlling the default jdbc batch size to use + * [HHH-14891] - JTS package not updated in "spatial basic types table" in user guide + * [HHH-14881] - Converters defined through orm.xml are never retrieved from the CDI context + * [HHH-14880] - in orm.xml ignores the element + * [HHH-14816] - Can not set lock mode with QueryHint due to type case problem + * [HHH-13766] - Attribute with AttributeConverter not updated when inline dirty checking is enabled + +** Improvement + * [HHH-14901] - Introduce a new BatchBuilder implementation, suitable for immutable code deployments + * [HHH-14883] - Fix an AsciiDoc rendering error in 'spatial' user guide + * [HHH-14882] - Minor implementation optimisations in internal StandardStack + * [HHH-14869] - Extract JPA listener definitions when building metadata rather than when creating the SessionFactory + +** Task + * [HHH-14900] - Minor code cleanup in BatchBuilderImpl + + Changes in 5.6.0.Final (October 11, 2021) ------------------------------------------------------------------------------------------------------------------------ diff --git a/gradle/version.properties b/gradle/version.properties index 390986338952..6a9b5d42684f 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -hibernateVersion=5.6.1-SNAPSHOT \ No newline at end of file +hibernateVersion=5.6.1.Final \ No newline at end of file From f9bc1a279a22f54dd92eee02a00d3fd6b79f3610 Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Wed, 27 Oct 2021 11:13:33 +0000 Subject: [PATCH 377/644] 5.6.2-SNAPSHOT --- gradle/version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/version.properties b/gradle/version.properties index 6a9b5d42684f..5c72c9b3ea00 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -hibernateVersion=5.6.1.Final \ No newline at end of file +hibernateVersion=5.6.2-SNAPSHOT \ No newline at end of file From 6c53a9d1abf1bb2e38cfbb986a8bb33188aacfb9 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Fri, 29 Oct 2021 14:01:54 +0100 Subject: [PATCH 378/644] HHH-14903 The new getConfiguredJdbcBatchSize method optimisation should apply to StatelessSession as well --- .../internal/AbstractSharedSessionContract.java | 14 ++++++++++++++ .../java/org/hibernate/internal/SessionImpl.java | 14 -------------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java b/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java index aeaf0634d181..62d59cad1494 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/AbstractSharedSessionContract.java @@ -233,6 +233,20 @@ public AbstractSharedSessionContract(SessionFactoryImpl factory, SessionCreation } } + /** + * Override the implementation provided on SharedSessionContractImplementor + * which is not very efficient: this method is hot in Hibernate Reactive, and could + * be hot in some ORM contexts as well. + * @return + */ + @Override + public Integer getConfiguredJdbcBatchSize() { + final Integer sessionJdbcBatchSize = this.jdbcBatchSize; + return sessionJdbcBatchSize == null ? + fastSessionServices.defaultJdbcBatchSize : + sessionJdbcBatchSize; + } + protected void addSharedSessionTransactionObserver(TransactionCoordinator transactionCoordinator) { } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java index 53e8015dfc1f..6489891016e6 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionImpl.java @@ -300,20 +300,6 @@ protected ActionQueue createActionQueue() { return new ActionQueue( this ); } - /** - * Override the implementation provided on SharedSessionContractImplementor - * which is not very efficient: this method is hot in Hibernate Reactive, and could - * be hot in some ORM contexts as well. - * @return - */ - @Override - public Integer getConfiguredJdbcBatchSize() { - final Integer sessionJdbcBatchSize = getJdbcBatchSize(); - return sessionJdbcBatchSize == null ? - fastSessionServices.defaultJdbcBatchSize : - sessionJdbcBatchSize; - } - private LockOptions getLockOptionsForRead() { return this.lockOptions == null ? fastSessionServices.defaultLockOptions : this.lockOptions; } From ccd58ee499eefca66664ef0305679ae85367c655 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Mon, 8 Nov 2021 13:28:44 +0100 Subject: [PATCH 379/644] HHH-14918 Always process components containing an ID copy as we would any other FK --- .../InFlightMetadataCollectorImpl.java | 57 ------------------- .../CopyIdentifierComponentSecondPass.java | 21 ++++--- 2 files changed, 14 insertions(+), 64 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java index b362de7fc5b7..568ef9649817 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java @@ -57,7 +57,6 @@ import org.hibernate.boot.spi.NaturalIdUniqueKeyBinder; import org.hibernate.cfg.AnnotatedClassType; import org.hibernate.cfg.AvailableSettings; -import org.hibernate.cfg.CopyIdentifierComponentSecondPass; import org.hibernate.cfg.CreateKeySecondPass; import org.hibernate.cfg.FkSecondPass; import org.hibernate.cfg.IdGeneratorResolverSecondPass; @@ -1504,7 +1503,6 @@ public Join locateJoin(Identifier tableName) { private ArrayList idGeneratorResolverSecondPassList; private ArrayList setSimpleValueTypeSecondPassList; - private ArrayList copyIdentifierComponentSecondPasList; private ArrayList fkSecondPassList; private ArrayList createKeySecondPasList; private ArrayList secondaryTableSecondPassList; @@ -1526,9 +1524,6 @@ public void addSecondPass(SecondPass secondPass, boolean onTopOfTheQueue) { else if ( secondPass instanceof SetSimpleValueTypeSecondPass ) { addSetSimpleValueTypeSecondPass( (SetSimpleValueTypeSecondPass) secondPass, onTopOfTheQueue ); } - else if ( secondPass instanceof CopyIdentifierComponentSecondPass ) { - addCopyIdentifierComponentSecondPass( (CopyIdentifierComponentSecondPass) secondPass, onTopOfTheQueue ); - } else if ( secondPass instanceof FkSecondPass ) { addFkSecondPass( (FkSecondPass) secondPass, onTopOfTheQueue ); } @@ -1576,15 +1571,6 @@ private void addIdGeneratorResolverSecondPass(IdGeneratorResolverSecondPass seco addSecondPass( secondPass, idGeneratorResolverSecondPassList, onTopOfTheQueue ); } - private void addCopyIdentifierComponentSecondPass( - CopyIdentifierComponentSecondPass secondPass, - boolean onTopOfTheQueue) { - if ( copyIdentifierComponentSecondPasList == null ) { - copyIdentifierComponentSecondPasList = new ArrayList<>(); - } - addSecondPass( secondPass, copyIdentifierComponentSecondPasList, onTopOfTheQueue ); - } - private void addFkSecondPass(FkSecondPass secondPass, boolean onTopOfTheQueue) { if ( fkSecondPassList == null ) { fkSecondPassList = new ArrayList<>(); @@ -1635,8 +1621,6 @@ public void processSecondPasses(MetadataBuildingContext buildingContext) { processSecondPasses( implicitColumnNamingSecondPassList ); processSecondPasses( setSimpleValueTypeSecondPassList ); - processCopyIdentifierSecondPassesInOrder(); - processFkSecondPassesInOrder(); processSecondPasses( createKeySecondPasList ); @@ -1661,14 +1645,6 @@ public void processSecondPasses(MetadataBuildingContext buildingContext) { } } - private void processCopyIdentifierSecondPassesInOrder() { - if ( copyIdentifierComponentSecondPasList == null ) { - return; - } - sortCopyIdentifierComponentSecondPasses(); - processSecondPasses( copyIdentifierComponentSecondPasList ); - } - private void processSecondPasses(ArrayList secondPasses) { if ( secondPasses == null ) { return; @@ -1681,39 +1657,6 @@ private void processSecondPasses(ArrayList secondPasses) { secondPasses.clear(); } - private void sortCopyIdentifierComponentSecondPasses() { - - ArrayList sorted = - new ArrayList<>( copyIdentifierComponentSecondPasList.size() ); - Set toSort = new HashSet<>( copyIdentifierComponentSecondPasList ); - topologicalSort( sorted, toSort ); - copyIdentifierComponentSecondPasList = sorted; - } - - /* naive O(n^3) topological sort */ - private void topologicalSort( List sorted, Set toSort ) { - while (!toSort.isEmpty()) { - CopyIdentifierComponentSecondPass independent = null; - - searchForIndependent: - for ( CopyIdentifierComponentSecondPass secondPass : toSort ) { - for ( CopyIdentifierComponentSecondPass other : toSort ) { - if (secondPass.dependentUpon( other )) { - continue searchForIndependent; - } - } - independent = secondPass; - break; - } - if (independent == null) { - throw new MappingException( "cyclic dependency in derived identities" ); - } - toSort.remove( independent ); - sorted.add( independent ); - } - } - - private void processFkSecondPassesInOrder() { if ( fkSecondPassList == null || fkSecondPassList.isEmpty() ) { return; diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/CopyIdentifierComponentSecondPass.java b/hibernate-core/src/main/java/org/hibernate/cfg/CopyIdentifierComponentSecondPass.java index 3ad1b8345113..8d19a35ae317 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/CopyIdentifierComponentSecondPass.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/CopyIdentifierComponentSecondPass.java @@ -16,8 +16,6 @@ import org.hibernate.AssertionFailure; import org.hibernate.MappingException; import org.hibernate.boot.model.naming.Identifier; -import org.hibernate.boot.model.naming.ImplicitNamingStrategy; -import org.hibernate.boot.model.naming.ObjectNameNormalizer; import org.hibernate.boot.model.naming.PhysicalNamingStrategy; import org.hibernate.boot.model.relational.Database; import org.hibernate.boot.spi.MetadataBuildingContext; @@ -33,7 +31,7 @@ /** * @author Emmanuel Bernard */ -public class CopyIdentifierComponentSecondPass implements SecondPass { +public class CopyIdentifierComponentSecondPass extends FkSecondPass { private static final Logger log = Logger.getLogger( CopyIdentifierComponentSecondPass.class ); private final String referencedEntityName; @@ -46,12 +44,25 @@ public CopyIdentifierComponentSecondPass( String referencedEntityName, Ejb3JoinColumn[] joinColumns, MetadataBuildingContext buildingContext) { + super( comp, joinColumns ); this.component = comp; this.referencedEntityName = referencedEntityName; this.buildingContext = buildingContext; this.joinColumns = joinColumns; } + @Override + public String getReferencedEntityName() { + return referencedEntityName; + } + + @Override + public boolean isInPrimaryKey() { + // This second pass is apparently only ever used to initialize composite identifiers + return true; + } + + @Override @SuppressWarnings({ "unchecked" }) public void doSecondPass(Map persistentClasses) throws MappingException { PersistentClass referencedPersistentClass = (PersistentClass) persistentClasses.get( referencedEntityName ); @@ -219,8 +230,4 @@ private void applyComponentColumnSizeValueToJoinColumn(Column column, Ejb3JoinCo mappingColumn.setPrecision( column.getPrecision() ); mappingColumn.setScale( column.getScale() ); } - - public boolean dependentUpon( CopyIdentifierComponentSecondPass other ) { - return this.referencedEntityName.equals( other.component.getOwner().getEntityName() ); - } } From 2e1f7b5d89dffca6cd2502ebb3f4e487078d7934 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Mon, 8 Nov 2021 13:16:40 +0100 Subject: [PATCH 380/644] HHH-14918 Test entity with composite ID containing an association to another entity which itself has a composite ID containing an association to another entity --- ...IdClassForNestedIdWithAssociationTest.java | 196 ++++++++++++++++++ 1 file changed, 196 insertions(+) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/idclass/IdClassForNestedIdWithAssociationTest.java diff --git a/hibernate-core/src/test/java/org/hibernate/test/idclass/IdClassForNestedIdWithAssociationTest.java b/hibernate-core/src/test/java/org/hibernate/test/idclass/IdClassForNestedIdWithAssociationTest.java new file mode 100644 index 000000000000..73597437db64 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/idclass/IdClassForNestedIdWithAssociationTest.java @@ -0,0 +1,196 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.test.idclass; + +import static org.assertj.core.api.Assertions.assertThat; +import static org.hibernate.test.util.SchemaUtil.getColumnNames; + +import java.io.Serializable; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.IdClass; +import javax.persistence.ManyToOne; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; +import org.junit.Test; + +/** + * Test that bootstrap doesn't throw an exception + * when an entity has a composite ID containing an association to another entity, + * which itself has a composite ID containing an association to another entity. + *

    + * This test used to fail on bootstrap with the following error: + *

    + * org.hibernate.MappingException: identifier mapping has wrong number of columns: org.hibernate.test.idclass.IdClassForNestedIdWithAssociationTest$NestedIdClassEntity type: component[idClassEntity,key3] + * at org.hibernate.mapping.RootClass.validate(RootClass.java:273) + * at org.hibernate.boot.internal.MetadataImpl.validate(MetadataImpl.java:359) + * at org.hibernate.internal.SessionFactoryImpl.(SessionFactoryImpl.java:307) + * at org.hibernate.boot.internal.SessionFactoryBuilderImpl.build(SessionFactoryBuilderImpl.java:471) + * at org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase.buildResources(BaseNonConfigCoreFunctionalTestCase.java:165) + * at org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase.startUp(BaseNonConfigCoreFunctionalTestCase.java:141) + * at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) + * at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) + * at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) + * at java.base/java.lang.reflect.Method.invoke(Method.java:566) + * at org.hibernate.testing.junit4.TestClassMetadata.performCallbackInvocation(TestClassMetadata.java:205) + */ +@TestForIssue(jiraKey = "HHH-14918") +public class IdClassForNestedIdWithAssociationTest extends BaseNonConfigCoreFunctionalTestCase { + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { BasicEntity.class, IdClassEntity.class, NestedIdClassEntity.class }; + } + + @Test + public void metadataTest() { + assertThat( getColumnNames( "NestedIdClassEntity", metadata() ) ) + // Just check we're using copied IDs; otherwise the test wouldn't be able to reproduce HHH-14918. + .containsExactlyInAnyOrder( "idClassEntity_basicEntity_key1", "idClassEntity_key2", "key3" ); + } + + // The main goal of the test is to check that bootstrap doesn't throw an exception, + // but it feels wrong to have a test class with just an empty test method, + // so just check that persisting/loading works correctly. + @Test + public void smokeTest() { + inTransaction( s -> { + BasicEntity basic = new BasicEntity( 1L ); + s.persist( basic ); + IdClassEntity idClass = new IdClassEntity( basic, 2L ); + s.persist( idClass ); + NestedIdClassEntity nestedIdClass = new NestedIdClassEntity( idClass, 3L ); + s.persist( nestedIdClass ); + } ); + + inTransaction( s -> { + NestedIdClassEntity nestedIdClass = s.get( + NestedIdClassEntity.class, + new NestedIdClassEntity.NestedIdClassEntityId( 1L, 2L, 3L ) + ); + assertThat( nestedIdClass ) + .extracting( NestedIdClassEntity::getKey3 ) + .isEqualTo( 3L ); + IdClassEntity idClass = nestedIdClass.getIdClassEntity(); + assertThat( idClass ) + .extracting( IdClassEntity::getKey2 ) + .isEqualTo( 2L ); + BasicEntity basic = idClass.basicEntity; + assertThat( basic ) + .extracting( BasicEntity::getKey1 ) + .isEqualTo( 1L ); + } ); + } + + @Entity(name = "BasicEntity") + public static class BasicEntity { + @Id + Long key1; + + protected BasicEntity() { + } + + public BasicEntity(long key1) { + this.key1 = key1; + } + + public Long getKey1() { + return key1; + } + } + + @Entity(name = "IdClassEntity") + @IdClass(IdClassEntity.IdClassEntityId.class) + public static class IdClassEntity { + @Id + @ManyToOne + BasicEntity basicEntity; + @Id + Long key2; + + protected IdClassEntity() { + } + + public IdClassEntity(BasicEntity basicEntity, long key2) { + this.basicEntity = basicEntity; + this.key2 = key2; + } + + public BasicEntity getBasicEntity() { + return basicEntity; + } + + public Long getKey2() { + return key2; + } + + public static class IdClassEntityId implements Serializable { + long basicEntity; + long key2; + + protected IdClassEntityId() { + } + + public IdClassEntityId(long basicEntity, long key2) { + this.basicEntity = basicEntity; + this.key2 = key2; + } + + public long getBasicEntity() { + return basicEntity; + } + + public long getKey2() { + return key2; + } + } + } + + @Entity(name = "NestedIdClassEntity") + @IdClass(NestedIdClassEntity.NestedIdClassEntityId.class) + public static class NestedIdClassEntity { + @Id + @ManyToOne + IdClassEntity idClassEntity; + @Id + Long key3; + + protected NestedIdClassEntity() { + } + + public NestedIdClassEntity(IdClassEntity idClassEntity, long key3) { + this.idClassEntity = idClassEntity; + this.key3 = key3; + } + + public IdClassEntity getIdClassEntity() { + return idClassEntity; + } + + public Long getKey3() { + return key3; + } + + public static class NestedIdClassEntityId implements Serializable { + IdClassEntity.IdClassEntityId idClassEntity; + long key3; + + protected NestedIdClassEntityId() { + } + + public NestedIdClassEntityId(IdClassEntity.IdClassEntityId idClassEntity, long key3) { + this.idClassEntity = idClassEntity; + this.key3 = key3; + } + + public NestedIdClassEntityId(long basicEntity, long key2, long key3) { + this( new IdClassEntity.IdClassEntityId( basicEntity, key2 ), key3 ); + } + } + } +} From e5a78f0ee507f146d04d7c1b59fef57f75ed20a8 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Tue, 9 Nov 2021 13:41:41 +0100 Subject: [PATCH 381/644] Add test exclusion property handling to jakarta module --- hibernate-core-jakarta/hibernate-core-jakarta.gradle | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hibernate-core-jakarta/hibernate-core-jakarta.gradle b/hibernate-core-jakarta/hibernate-core-jakarta.gradle index b83db4750440..09e3e1bd5dc8 100644 --- a/hibernate-core-jakarta/hibernate-core-jakarta.gradle +++ b/hibernate-core-jakarta/hibernate-core-jakarta.gradle @@ -279,6 +279,12 @@ test { } maxHeapSize = '3G' + // Allow to exclude specific tests + if (project.hasProperty('excludeTests')) { + filter { + excludeTestsMatching project.property('excludeTests').toString() + } + } } From 76eeb6fb5e5421bca80a908ced6eca944f750474 Mon Sep 17 00:00:00 2001 From: "nathan.xu" Date: Fri, 12 Nov 2021 21:04:15 -0500 Subject: [PATCH 382/644] HHH-14926 fix ascii error in 'test-case-guide.adoc' --- test-case-guide.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test-case-guide.adoc b/test-case-guide.adoc index 1f4a8b61851b..eb46249163c1 100644 --- a/test-case-guide.adoc +++ b/test-case-guide.adoc @@ -9,7 +9,7 @@ This is meant as a guide for writing test cases to be attached to bug reports in There are a number of tenants that make up a good test case as opposed to a poor one. In fact there are a few guides for this across the web including (http://stackoverflow.com/help/mcve[MCVE]) and (http://sscce.org/[SSCCE]). These guides all assert the same ideas albeit using different terms. Given the ubiquity of StackOverflow and the fact that the MCVE guidelines were written specifically for StackOverflow, we will use those terms here as we assume most developers have seen them before: * (M)inimal - Provide just the minimal information needed. If second level caching is irrelevant to the bug report then the test should not use second level caching. If entity inheritance is irrelevant then do not use it in the test. If your application uses Spring Data, remove Spring Data from the test. -* (C)omplete - Provide all information needed to reproduce the problem. If a bug only occurs when using bytecode enhancement, then the test should include bytecode enhancement. In other words the test should be self-contained. +* \(C)omplete - Provide all information needed to reproduce the problem. If a bug only occurs when using bytecode enhancement, then the test should include bytecode enhancement. In other words the test should be self-contained. * (V)erifiable - The test should actually reproduce the problem being reported. From 1a641695fa48ae1eb4b545a6eac36152f50e4038 Mon Sep 17 00:00:00 2001 From: Ratul sharker Date: Sun, 14 Nov 2021 17:43:21 +0600 Subject: [PATCH 383/644] HHH-14916 : inside `renderFetches`, `renderJoins` called if the `fetch` is `instanceof` `Form` interface. --- .../hibernate/query/criteria/internal/QueryStructure.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hibernate-core/src/main/java/org/hibernate/query/criteria/internal/QueryStructure.java b/hibernate-core/src/main/java/org/hibernate/query/criteria/internal/QueryStructure.java index e4bddf4a5441..e0a88f871eab 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/criteria/internal/QueryStructure.java +++ b/hibernate-core/src/main/java/org/hibernate/query/criteria/internal/QueryStructure.java @@ -19,6 +19,7 @@ import javax.persistence.criteria.AbstractQuery; import javax.persistence.criteria.Expression; import javax.persistence.criteria.Fetch; +import javax.persistence.criteria.From; import javax.persistence.criteria.Join; import javax.persistence.criteria.JoinType; import javax.persistence.criteria.ParameterExpression; @@ -483,6 +484,11 @@ private void renderFetches( .append( ( (FromImplementor) fetch ).renderTableExpression( renderingContext ) ); renderFetches( jpaqlQuery, renderingContext, fetch.getFetches() ); + + if (fetch instanceof From) { + From from = (From) fetch; + renderJoins(jpaqlQuery, renderingContext, from.getJoins()); + } } } } From b125d13edea4c330bfcfa2681360aebb59aeabd0 Mon Sep 17 00:00:00 2001 From: Ratul sharker Date: Sun, 14 Nov 2021 17:48:19 +0600 Subject: [PATCH 384/644] HHH-14916 : test case written. --- .../criteria/internal/hhh14916/Author.java | 25 +++++++ .../criteria/internal/hhh14916/Book.java | 32 ++++++++ .../criteria/internal/hhh14916/Chapter.java | 22 ++++++ .../internal/hhh14916/HHH14916Test.java | 74 +++++++++++++++++++ 4 files changed, 153 insertions(+) create mode 100644 hibernate-core/src/test/java/org/hibernate/query/criteria/internal/hhh14916/Author.java create mode 100644 hibernate-core/src/test/java/org/hibernate/query/criteria/internal/hhh14916/Book.java create mode 100644 hibernate-core/src/test/java/org/hibernate/query/criteria/internal/hhh14916/Chapter.java create mode 100644 hibernate-core/src/test/java/org/hibernate/query/criteria/internal/hhh14916/HHH14916Test.java diff --git a/hibernate-core/src/test/java/org/hibernate/query/criteria/internal/hhh14916/Author.java b/hibernate-core/src/test/java/org/hibernate/query/criteria/internal/hhh14916/Author.java new file mode 100644 index 000000000000..a37b0910a2cc --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/query/criteria/internal/hhh14916/Author.java @@ -0,0 +1,25 @@ +package org.hibernate.query.criteria.internal.hhh14916; + +import java.util.ArrayList; +import java.util.List; +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.OneToMany; + +@Entity +public class Author { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + public Long authorId; + + @Column + public String name; + + @OneToMany(fetch = FetchType.LAZY, mappedBy = "author", orphanRemoval = true, cascade = CascadeType.ALL) + public List books = new ArrayList<>(); +} diff --git a/hibernate-core/src/test/java/org/hibernate/query/criteria/internal/hhh14916/Book.java b/hibernate-core/src/test/java/org/hibernate/query/criteria/internal/hhh14916/Book.java new file mode 100644 index 000000000000..23ec689a034c --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/query/criteria/internal/hhh14916/Book.java @@ -0,0 +1,32 @@ +package org.hibernate.query.criteria.internal.hhh14916; + +import java.util.ArrayList; +import java.util.List; +import javax.persistence.CascadeType; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; +import javax.persistence.OneToMany; + +@Entity +public class Book { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + public Long bookId; + + @Column + public String name; + + @ManyToOne(fetch = FetchType.LAZY, optional = false) + @JoinColumn(name = "author_id", nullable = false) + public Author author; + + @OneToMany(fetch = FetchType.LAZY, mappedBy = "book", orphanRemoval = true, cascade = CascadeType.ALL) + public List chapters = new ArrayList<>(); +} diff --git a/hibernate-core/src/test/java/org/hibernate/query/criteria/internal/hhh14916/Chapter.java b/hibernate-core/src/test/java/org/hibernate/query/criteria/internal/hhh14916/Chapter.java new file mode 100644 index 000000000000..a97d6da843be --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/query/criteria/internal/hhh14916/Chapter.java @@ -0,0 +1,22 @@ +package org.hibernate.query.criteria.internal.hhh14916; + +import javax.persistence.Entity; +import javax.persistence.FetchType; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.JoinColumn; +import javax.persistence.ManyToOne; + +@Entity +public class Chapter { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + public Long chapterId; + + public String name; + + @ManyToOne(fetch = FetchType.LAZY, optional = false) + @JoinColumn(name = "book_id", nullable = false) + public Book book; +} diff --git a/hibernate-core/src/test/java/org/hibernate/query/criteria/internal/hhh14916/HHH14916Test.java b/hibernate-core/src/test/java/org/hibernate/query/criteria/internal/hhh14916/HHH14916Test.java new file mode 100644 index 000000000000..3583194b832b --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/query/criteria/internal/hhh14916/HHH14916Test.java @@ -0,0 +1,74 @@ +package org.hibernate.query.criteria.internal.hhh14916; + +import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; +import org.hibernate.testing.TestForIssue; +import static org.junit.Assert.assertEquals; +import org.junit.Before; +import org.junit.Test; + +import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; +import javax.persistence.criteria.CriteriaBuilder; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.JoinType; +import javax.persistence.criteria.ListJoin; +import javax.persistence.criteria.Predicate; +import javax.persistence.criteria.Root; + +@TestForIssue( jiraKey = "HHH-14916" ) +public class HHH14916Test extends BaseEntityManagerFunctionalTestCase { + + @Before + public void before() { + populateData(); + } + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { Author.class, Book.class, Chapter.class }; + } + + @Test + public void testJoinOnFetchNoExceptionThrow() { + doInJPA( this::entityManagerFactory, entityManager -> { + + final CriteriaBuilder builder = entityManager.getCriteriaBuilder(); + final CriteriaQuery query = builder.createQuery(Author.class); + + final Root root = query.from(Author.class); + final ListJoin authorBookJoin = (ListJoin)root.fetch("books", JoinType.LEFT); + + final ListJoin bookChapterJoin = authorBookJoin.joinList("chapters", JoinType.LEFT); + + final Predicate finalPredicate = builder.equal(bookChapterJoin.get("name"), "Overview of HTTP"); + query.where(finalPredicate); + + Author author = entityManager.createQuery(query).getSingleResult(); + + assertEquals(author.name, "David Gourley"); + assertEquals(author.books.get(0).name, "HTTP Definitive guide"); + assertEquals(author.books.get(0).chapters.get(0).name, "Overview of HTTP"); + } ); + } + + public void populateData() { + doInJPA(this::entityManagerFactory, entityManager -> { + // Insert data + Chapter chapter = new Chapter(); + chapter.name = "Overview of HTTP"; + + Book book = new Book(); + book.name = "HTTP Definitive guide"; + + Author author = new Author(); + author.name = "David Gourley"; + + book.chapters.add(chapter); + author.books.add(book); + + chapter.book = book; + book.author = author; + + entityManager.persist(author); + }); + } +} From fa3a364b7948f8e2b739e96afe76a3d1cf748e90 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Kautler?= Date: Wed, 3 Nov 2021 14:50:59 +0100 Subject: [PATCH 385/644] Fix dead link in documentation --- .../main/asciidoc/userguide/chapters/bootstrap/Bootstrap.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/src/main/asciidoc/userguide/chapters/bootstrap/Bootstrap.adoc b/documentation/src/main/asciidoc/userguide/chapters/bootstrap/Bootstrap.adoc index fb4c994fc2eb..6fdc91bfaeec 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/bootstrap/Bootstrap.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/bootstrap/Bootstrap.adoc @@ -315,7 +315,7 @@ In the `persistence.xml` configuration file above, the `orm.xml` XML file contai As previously seen, the Hibernate native bootstrap mechanism allows you to customize a great variety of configurations which are passed via the `Metadata` object. -When using Hibernate as a JPA provider, the `EntityManagerFactory` is backed by a `SessionFactory`. For this reason, you might still want to use the `Metadata` object to pass various settings which cannot be supplied via the standard Hibernate <>. +When using Hibernate as a JPA provider, the `EntityManagerFactory` is backed by a `SessionFactory`. For this reason, you might still want to use the `Metadata` object to pass various settings which cannot be supplied via the standard Hibernate <>. For this reason, you can use the https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/boot/spi/MetadataBuilderContributor.html[`MetadataBuilderContributor`] class as you can see in the following examples. From 3845d2f97f91f6fbab3c295ea43a39e8da1f0c2a Mon Sep 17 00:00:00 2001 From: Maciej Walkowiak Date: Wed, 10 Nov 2021 21:47:41 +0100 Subject: [PATCH 386/644] Refer correct entity in "Composite identifiers with associations" section Code sample uses `Book` entity instead of `PersonAddress`. --- .../main/asciidoc/userguide/chapters/domain/identifiers.adoc | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/documentation/src/main/asciidoc/userguide/chapters/domain/identifiers.adoc b/documentation/src/main/asciidoc/userguide/chapters/domain/identifiers.adoc index 1f1fe9718d1c..cb6551329111 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/domain/identifiers.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/domain/identifiers.adoc @@ -186,7 +186,7 @@ Use of this feature may or may not be portable from a JPA perspective. ==== Composite identifiers with associations Hibernate allows defining a composite identifier out of entity associations. -In the following example, the `PersonAddress` entity identifier is formed of two `@ManyToOne` associations. +In the following example, the `Book` entity identifier is formed of two `@ManyToOne` associations. [[identifiers-composite-id-mapping-example]] .Composite identifiers with associations From e155fc551e3a61cd98062c3fd17e59758f310766 Mon Sep 17 00:00:00 2001 From: Chris Cranford Date: Tue, 9 Nov 2021 12:54:44 -0500 Subject: [PATCH 387/644] HHH-14540 Don't share session-scoped interceptors with temp session --- .../internal/SessionFactoryImpl.java | 15 +++- .../synchronization/AuditProcess.java | 1 + ...sionFactoryInterceptorTransactionTest.java | 76 +++++++++++++++++++ .../tm/SessionInterceptorTransactionTest.java | 73 ++++++++++++++++++ .../test/integration/tm/TestInterceptor.java | 43 +++++++++++ 5 files changed, 205 insertions(+), 3 deletions(-) create mode 100644 hibernate-envers/src/test/java/org/hibernate/envers/test/integration/tm/SessionFactoryInterceptorTransactionTest.java create mode 100644 hibernate-envers/src/test/java/org/hibernate/envers/test/integration/tm/SessionInterceptorTransactionTest.java create mode 100644 hibernate-envers/src/test/java/org/hibernate/envers/test/integration/tm/TestInterceptor.java diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java index ef50a2b8ec00..c99724a10aab 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java @@ -1123,7 +1123,7 @@ public Type resolveParameterBindType(Class clazz){ } } - public static Interceptor configuredInterceptor(Interceptor interceptor, SessionFactoryOptions options) { + public static Interceptor configuredInterceptor(Interceptor interceptor, boolean explicitNoInterceptor, SessionFactoryOptions options) { // NOTE : DO NOT return EmptyInterceptor.INSTANCE from here as a "default for the Session" // we "filter" that one out here. The return from here should represent the // explicitly configured Interceptor (if one). Return null from here instead; Session @@ -1139,6 +1139,12 @@ public static Interceptor configuredInterceptor(Interceptor interceptor, Session return optionsInterceptor; } + // If explicitly asking for no interceptor and there is no SessionFactory-scoped interceptors, then + // no need to inherit from the configured stateless session ones. + if ( explicitNoInterceptor ) { + return null; + } + // then check the Session-scoped interceptor prototype final Class statelessInterceptorImplementor = options.getStatelessInterceptorImplementor(); final Supplier statelessInterceptorImplementorSupplier = options.getStatelessInterceptorImplementorSupplier(); @@ -1181,6 +1187,7 @@ public static class SessionBuilderImpl implements Sess private String tenantIdentifier; private TimeZone jdbcTimeZone; private boolean queryParametersValidationEnabled; + private boolean explicitNoInterceptor; // Lazy: defaults can be built by invoking the builder in fastSessionServices.defaultSessionEventListeners // (Need a fresh build for each Session as the listener instances can't be reused across sessions) @@ -1269,7 +1276,7 @@ public Connection getConnection() { @Override public Interceptor getInterceptor() { - return configuredInterceptor( interceptor, sessionFactory.getSessionFactoryOptions() ); + return configuredInterceptor( interceptor, explicitNoInterceptor, sessionFactory.getSessionFactoryOptions() ); } @Override @@ -1316,6 +1323,7 @@ public T owner(SessionOwner sessionOwner) { @SuppressWarnings("unchecked") public T interceptor(Interceptor interceptor) { this.interceptor = interceptor; + this.explicitNoInterceptor = false; return (T) this; } @@ -1323,6 +1331,7 @@ public T interceptor(Interceptor interceptor) { @SuppressWarnings("unchecked") public T noInterceptor() { this.interceptor = EmptyInterceptor.INSTANCE; + this.explicitNoInterceptor = true; return (T) this; } @@ -1494,7 +1503,7 @@ public Connection getConnection() { @Override public Interceptor getInterceptor() { - return configuredInterceptor( EmptyInterceptor.INSTANCE, sessionFactory.getSessionFactoryOptions() ); + return configuredInterceptor( EmptyInterceptor.INSTANCE, false, sessionFactory.getSessionFactoryOptions() ); } diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/internal/synchronization/AuditProcess.java b/hibernate-envers/src/main/java/org/hibernate/envers/internal/synchronization/AuditProcess.java index ac47d29ee8c2..def0caab20fe 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/internal/synchronization/AuditProcess.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/internal/synchronization/AuditProcess.java @@ -160,6 +160,7 @@ public void doBeforeTransactionCompletion(SessionImplementor session) { .connection() .autoClose( false ) .connectionHandlingMode( PhysicalConnectionHandlingMode.DELAYED_ACQUISITION_AND_RELEASE_AFTER_TRANSACTION ) + .noInterceptor() .openSession(); executeInSession( temporarySession ); temporarySession.flush(); diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/tm/SessionFactoryInterceptorTransactionTest.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/tm/SessionFactoryInterceptorTransactionTest.java new file mode 100644 index 000000000000..1f6fd564642f --- /dev/null +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/tm/SessionFactoryInterceptorTransactionTest.java @@ -0,0 +1,76 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.envers.test.integration.tm; + +import static org.junit.Assert.assertEquals; + +import java.util.Map; + +import javax.persistence.EntityManager; +import javax.transaction.TransactionManager; + +import org.hibernate.FlushMode; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.envers.test.BaseEnversJPAFunctionalTestCase; +import org.hibernate.envers.test.Priority; +import org.hibernate.envers.test.entities.StrTestEntity; +import org.hibernate.internal.SessionImpl; +import org.junit.Test; + +import org.hibernate.testing.jta.TestingJtaBootstrap; +import org.hibernate.testing.jta.TestingJtaPlatformImpl; + +/** + * @author Chris Cranford + */ +public class SessionFactoryInterceptorTransactionTest extends BaseEnversJPAFunctionalTestCase { + + private TestInterceptor interceptor; + private TransactionManager tm; + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { StrTestEntity.class }; + } + + @Override + protected void addConfigOptions(Map options) { + super.addConfigOptions( options ); + + TestInterceptor.reset(); + + this.interceptor = new TestInterceptor(); + options.put( AvailableSettings.INTERCEPTOR, interceptor ); + options.put( AvailableSettings.ALLOW_JTA_TRANSACTION_ACCESS, true ); + + TestingJtaBootstrap.prepare( options ); + tm = TestingJtaPlatformImpl.INSTANCE.getTransactionManager(); + } + + @Test + @Priority(10) + public void initData() throws Exception { + // Revision 1 + EntityManager em = getEntityManager(); + // Explicitly use manual flush to trigger separate temporary session write via Envers + em.unwrap( SessionImpl.class ).setHibernateFlushMode( FlushMode.MANUAL ); + tm.begin(); + StrTestEntity entity = new StrTestEntity( "Test" ); + em.persist( entity ); + em.flush(); + tm.commit(); + } + + @Test + public void testInterceptorInvocations() throws Exception { + // Expect the interceptor to have been created once and invoked twice, once for the original session + // and follow-up for the Envers temporary session. + final Map invocationMap = TestInterceptor.getBeforeCompletionCallbacks(); + assertEquals( 1, invocationMap.size() ); + assertEquals( invocationMap.values().stream().filter( v -> v == 2 ).count(), 1 ); + } +} diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/tm/SessionInterceptorTransactionTest.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/tm/SessionInterceptorTransactionTest.java new file mode 100644 index 000000000000..921fb08c2e21 --- /dev/null +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/tm/SessionInterceptorTransactionTest.java @@ -0,0 +1,73 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.envers.test.integration.tm; + +import static org.junit.Assert.assertEquals; + +import java.util.Map; + +import javax.persistence.EntityManager; +import javax.transaction.TransactionManager; + +import org.hibernate.FlushMode; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.envers.test.BaseEnversJPAFunctionalTestCase; +import org.hibernate.envers.test.Priority; +import org.hibernate.envers.test.entities.StrTestEntity; +import org.hibernate.internal.SessionImpl; +import org.junit.Test; + +import org.hibernate.testing.jta.TestingJtaBootstrap; +import org.hibernate.testing.jta.TestingJtaPlatformImpl; + +/** + * @author Chris Cranford + */ +public class SessionInterceptorTransactionTest extends BaseEnversJPAFunctionalTestCase { + + private TransactionManager tm; + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { StrTestEntity.class }; + } + + @Override + protected void addConfigOptions(Map options) { + super.addConfigOptions( options ); + + TestInterceptor.reset(); + + options.put( AvailableSettings.SESSION_SCOPED_INTERCEPTOR, TestInterceptor.class.getName() ); + options.put( AvailableSettings.ALLOW_JTA_TRANSACTION_ACCESS, "true" ); + + TestingJtaBootstrap.prepare( options ); + tm = TestingJtaPlatformImpl.INSTANCE.getTransactionManager(); + } + + @Test + @Priority(10) + public void initData() throws Exception { + // Revision 1 + EntityManager em = getEntityManager(); + // Explicitly use manual flush to trigger separate temporary session write via Envers + em.unwrap( SessionImpl.class ).setHibernateFlushMode( FlushMode.MANUAL ); + tm.begin(); + StrTestEntity entity = new StrTestEntity( "Test" ); + em.persist( entity ); + em.flush(); + tm.commit(); + } + + @Test + public void testInterceptorInvocations() throws Exception { + // The interceptor should only be created once and should only be invoked once. + final Map invocationMap = TestInterceptor.getBeforeCompletionCallbacks(); + assertEquals( 1, invocationMap.size() ); + assertEquals( invocationMap.values().stream().filter( v -> v == 1 ).count(), 1 ); + } +} diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/tm/TestInterceptor.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/tm/TestInterceptor.java new file mode 100644 index 000000000000..b8e7a2740474 --- /dev/null +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/tm/TestInterceptor.java @@ -0,0 +1,43 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.envers.test.integration.tm; + +import java.util.HashMap; +import java.util.Map; + +import org.hibernate.EmptyInterceptor; +import org.hibernate.Transaction; + +import org.jboss.logging.Logger; + +/** + * @author Chris Cranford + */ +public class TestInterceptor extends EmptyInterceptor { + + private static final Logger LOGGER = Logger.getLogger( TestInterceptor.class ); + private static Map interceptorInvocations = new HashMap<>(); + + public TestInterceptor() { + interceptorInvocations.put( this, 0 ); + } + + @Override + public void beforeTransactionCompletion(Transaction tx) { + super.beforeTransactionCompletion(tx); + interceptorInvocations.put( this, interceptorInvocations.get( this ) + 1 ); + LOGGER.info( "Interceptor beforeTransactionCompletion invoked" ); + } + + public static Map getBeforeCompletionCallbacks() { + return interceptorInvocations; + } + + public static void reset() { + interceptorInvocations.clear(); + } +} From 1dc49271c18afa355d5ea331cd7c91123cfd0361 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Tue, 16 Nov 2021 15:26:48 +0000 Subject: [PATCH 388/644] HHH-14540 Maintain strict API backwards compatibility --- .../java/org/hibernate/internal/SessionFactoryImpl.java | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java index c99724a10aab..87d51e7c514c 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java @@ -1123,6 +1123,14 @@ public Type resolveParameterBindType(Class clazz){ } } + /** + * @deprecated use {@link #configuredInterceptor(Interceptor, boolean, SessionFactoryOptions)} + */ + @Deprecated + public static Interceptor configuredInterceptor(Interceptor interceptor, SessionFactoryOptions options) { + return configuredInterceptor( interceptor, false, options ); + } + public static Interceptor configuredInterceptor(Interceptor interceptor, boolean explicitNoInterceptor, SessionFactoryOptions options) { // NOTE : DO NOT return EmptyInterceptor.INSTANCE from here as a "default for the Session" // we "filter" that one out here. The return from here should represent the From f54f6bdf4e2536e283112cf8ae181fa059e19c36 Mon Sep 17 00:00:00 2001 From: "nathan.xu" Date: Tue, 16 Nov 2021 15:45:35 -0500 Subject: [PATCH 389/644] HHH-14927 bump current hibernate version from 5.5 to 5.6 in user guide --- documentation/src/main/style/asciidoctor/js/toc.js | 1 + 1 file changed, 1 insertion(+) diff --git a/documentation/src/main/style/asciidoctor/js/toc.js b/documentation/src/main/style/asciidoctor/js/toc.js index 4ffda4a4f75c..a4f8ede62f72 100644 --- a/documentation/src/main/style/asciidoctor/js/toc.js +++ b/documentation/src/main/style/asciidoctor/js/toc.js @@ -1,5 +1,6 @@ var versions = { 'current' : '/current/userguide/html_single/Hibernate_User_Guide.html', + '5.5' : '/5.5/userguide/html_single/Hibernate_User_Guide.html', '5.4' : '/5.4/userguide/html_single/Hibernate_User_Guide.html', '5.3' : '/5.3/userguide/html_single/Hibernate_User_Guide.html', '5.2' : '/5.2/userguide/html_single/Hibernate_User_Guide.html', From c3631970a5d1d445adafc07b0632181c18c1ae8d Mon Sep 17 00:00:00 2001 From: "nathan.xu" Date: Wed, 17 Nov 2021 01:55:32 -0500 Subject: [PATCH 390/644] HHH-14927 fix other obvious defects in user guide --- documentation/src/main/asciidoc/userguide/Bibliography.adoc | 4 ++-- .../main/asciidoc/userguide/chapters/domain/basic_types.adoc | 2 +- .../src/main/asciidoc/userguide/chapters/domain/naming.adoc | 4 ++-- .../src/main/asciidoc/userguide/chapters/osgi/OSGi.adoc | 2 +- .../org/hibernate/userguide/mapping/basic/BitSetUserType.java | 2 +- 5 files changed, 7 insertions(+), 7 deletions(-) diff --git a/documentation/src/main/asciidoc/userguide/Bibliography.adoc b/documentation/src/main/asciidoc/userguide/Bibliography.adoc index c5fa06b93821..60f6f59f6842 100644 --- a/documentation/src/main/asciidoc/userguide/Bibliography.adoc +++ b/documentation/src/main/asciidoc/userguide/Bibliography.adoc @@ -2,5 +2,5 @@ [bibliography] - [[[PoEAA]]] Martin Fowler. https://www.martinfowler.com/books/eaa.html[Patterns of Enterprise Application Architecture]. - Addison-Wesley Publishing Company. 2003. -- [[[JPwH]]] Christian Bauer & Gavin King. https://www.manning.com/books/java-persistence-with-hibernate-second-edition[Java Persistence with Hibernate, Second Edition]. Manning Publications Co. 2015. + Addison-Wesley Professional. 2002. +- [[[JPwH]]] Christian Bauer & Gavin King. https://www.manning.com/books/java-persistence-with-hibernate-second-edition[Java Persistence with Hibernate, Second Edition]. Manning. 2015. diff --git a/documentation/src/main/asciidoc/userguide/chapters/domain/basic_types.adoc b/documentation/src/main/asciidoc/userguide/chapters/domain/basic_types.adoc index d12289de1575..7f3b46156570 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/domain/basic_types.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/domain/basic_types.adoc @@ -187,7 +187,7 @@ The `@Column` annotation defines other mapping information as well. See its Java We said before that a Hibernate type is not a Java type, nor an SQL type, but that it understands both and performs the marshalling between them. But looking at the basic type mappings from the previous examples, -how did Hibernate know to use its `org.hibernate.type.StringType` for mapping for `java.lang.String` attributes, +how did Hibernate know to use its `org.hibernate.type.StringType` for mapping `java.lang.String` attributes, or its `org.hibernate.type.IntegerType` for mapping `java.lang.Integer` attributes? The answer lies in a service inside Hibernate called the `org.hibernate.type.BasicTypeRegistry`, which essentially maintains a map of `org.hibernate.type.BasicType` (an `org.hibernate.type.Type` specialization) instances keyed by a name. diff --git a/documentation/src/main/asciidoc/userguide/chapters/domain/naming.adoc b/documentation/src/main/asciidoc/userguide/chapters/domain/naming.adoc index 97255bf216c8..4dbfe886a807 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/domain/naming.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/domain/naming.adoc @@ -25,7 +25,7 @@ Also, the NamingStrategy contract was often not flexible enough to properly appl "rule", either because the API lacked the information to decide or because the API was honestly not well defined as it grew. -Due to these limitation, `org.hibernate.cfg.NamingStrategy` has been deprecated +Due to these limitations, `org.hibernate.cfg.NamingStrategy` has been deprecated in favor of ImplicitNamingStrategy and PhysicalNamingStrategy. ==== @@ -89,7 +89,7 @@ into the mapping via explicit names. While the purpose of an ImplicitNamingStrategy is to determine that an attribute named `accountNumber` maps to a logical column name of `accountNumber` when not explicitly specified, the purpose of a PhysicalNamingStrategy -would be, for example, to say that the physical column name should instead be abbreviated `acct_num`. +would be, for example, to say that the physical column name should instead be abbreviated to `acct_num`. [NOTE] ==== diff --git a/documentation/src/main/asciidoc/userguide/chapters/osgi/OSGi.adoc b/documentation/src/main/asciidoc/userguide/chapters/osgi/OSGi.adoc index bd8dec29e8f4..58551fb84def 100644 --- a/documentation/src/main/asciidoc/userguide/chapters/osgi/OSGi.adoc +++ b/documentation/src/main/asciidoc/userguide/chapters/osgi/OSGi.adoc @@ -33,7 +33,7 @@ Also, note that the features are heavily tested against Karaf 3.0.3 as a part of However, they'll likely work on other versions as well. hibernate-osgi, theoretically, supports a variety of OSGi containers, such as Equinox. -In that case, please use `features.xm` as a reference for necessary bundles to activate and their correct ordering. +In that case, please use `features.xml` as a reference for necessary bundles to activate and their correct ordering. However, note that Karaf starts a number of bundles automatically, several of which would need to be installed manually on alternatives. === QuickStarts/Demos diff --git a/documentation/src/test/java/org/hibernate/userguide/mapping/basic/BitSetUserType.java b/documentation/src/test/java/org/hibernate/userguide/mapping/basic/BitSetUserType.java index f70cdaf47efa..9bf847edf8ed 100644 --- a/documentation/src/test/java/org/hibernate/userguide/mapping/basic/BitSetUserType.java +++ b/documentation/src/test/java/org/hibernate/userguide/mapping/basic/BitSetUserType.java @@ -21,7 +21,7 @@ //tag::basic-custom-type-BitSetUserType-example[] public class BitSetUserType implements UserType { - public static final BitSetUserType INSTANCE = new BitSetUserType(); + public static final BitSetUserType INSTANCE = new BitSetUserType(); private static final Logger log = Logger.getLogger( BitSetUserType.class ); From 35f374aac736de2e6fb7553f04b8944ff1589e42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Mon, 22 Nov 2021 08:59:05 +0100 Subject: [PATCH 391/644] HHH-14936 Avoid NPE in JdbcConnectionContext's static init --- .../hibernate/testing/cleaner/JdbcConnectionContext.java | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/hibernate-testing/src/main/java/org/hibernate/testing/cleaner/JdbcConnectionContext.java b/hibernate-testing/src/main/java/org/hibernate/testing/cleaner/JdbcConnectionContext.java index 365a6c6f8f97..b61fdd70d661 100644 --- a/hibernate-testing/src/main/java/org/hibernate/testing/cleaner/JdbcConnectionContext.java +++ b/hibernate-testing/src/main/java/org/hibernate/testing/cleaner/JdbcConnectionContext.java @@ -38,8 +38,12 @@ public final class JdbcConnectionContext { password = connectionProperties.getProperty( AvailableSettings.PASS ); Properties p = new Properties(); - p.put( "user", user ); - p.put( "password", password ); + if ( user != null ) { + p.put( "user", user ); + } + if ( password != null ) { + p.put( "password", password ); + } properties = p; } catch (Exception e) { From f604e8fa33acc79bdb00d4ec61a9926c5c127460 Mon Sep 17 00:00:00 2001 From: Marius Klein Date: Tue, 23 Nov 2021 11:09:42 +0100 Subject: [PATCH 392/644] HHH-14937 SybaseASE15 supports schemas and catalogs --- .../main/java/org/hibernate/dialect/SybaseASE15Dialect.java | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/SybaseASE15Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/SybaseASE15Dialect.java index 242212b61884..98d39b3780d1 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SybaseASE15Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SybaseASE15Dialect.java @@ -12,6 +12,7 @@ import org.hibernate.dialect.function.NoArgSQLFunction; import org.hibernate.dialect.function.SQLFunctionTemplate; import org.hibernate.dialect.function.VarArgsSQLFunction; +import org.hibernate.engine.jdbc.env.spi.NameQualifierSupport; import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; import org.hibernate.type.descriptor.sql.TinyIntTypeDescriptor; @@ -436,4 +437,9 @@ public boolean supportsLockTimeouts() { public boolean supportsPartitionBy() { return false; } + + @Override + public NameQualifierSupport getNameQualifierSupport() { + return NameQualifierSupport.BOTH; + } } From 69cd716e379c724ea39b173bee6c437651c8548c Mon Sep 17 00:00:00 2001 From: Jan Schatteman Date: Thu, 2 Dec 2021 22:06:01 +0100 Subject: [PATCH 393/644] Revert deprecations on main (#4412) * Revert "HHH-14857 - Deprecations in preparation for 6" This reverts commit 91e29358be0a73d77ac00de45ddf56dd989fefd2. * Revert "HHH-14857 - Deprecations in preparation for 6" This reverts commit e4b56b927169b318231770af1b0854b02a6b286c. --- .../main/java/org/hibernate/EntityMode.java | 26 +------------------ .../SessionFactoryOptionsBuilder.java | 12 ++++----- .../hbm/internal/EntityModeConverter.java | 21 +++------------ .../hbm/AbstractEntitySourceImpl.java | 12 --------- .../org/hibernate/cfg/AvailableSettings.java | 3 --- .../internal/log/DeprecationLogger.java | 6 ----- .../java/org/hibernate/tuple/Tuplizer.java | 4 --- .../tuple/component/ComponentTuplizer.java | 4 --- .../tuple/entity/EntityTuplizer.java | 4 --- 9 files changed, 9 insertions(+), 83 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/EntityMode.java b/hibernate-core/src/main/java/org/hibernate/EntityMode.java index 522a333e34f9..1f07ca88d487 100644 --- a/hibernate-core/src/main/java/org/hibernate/EntityMode.java +++ b/hibernate-core/src/main/java/org/hibernate/EntityMode.java @@ -8,16 +8,11 @@ import java.util.Locale; -import static org.hibernate.cfg.AvailableSettings.DEFAULT_ENTITY_MODE; -import static org.hibernate.internal.log.DeprecationLogger.DEPRECATION_LOGGER; - /** * Defines the representation modes available for entities. * - * @deprecated To be removed in 6.0 in favor of `ManagedTypeRepresentationStrategy` - * and `RepresentationMode` + * @author Steve Ebersole */ -@Deprecated public enum EntityMode { /** * The {@code pojo} entity mode describes an entity model made up of entity classes (loosely) following @@ -63,23 +58,4 @@ public static EntityMode parse(String entityMode) { return valueOf( entityMode.toUpperCase( Locale.ENGLISH ) ); } - public static EntityMode fromSetting(Object setting) { - if ( setting != null ) { - DEPRECATION_LOGGER.deprecatedSetting( DEFAULT_ENTITY_MODE ); - } - - if ( setting == null || setting == POJO ) { - return POJO; - } - - if ( setting instanceof EntityMode ) { - return ( (EntityMode) setting ); - } - - if ( setting instanceof String ) { - return parse( (String) setting ); - } - - return POJO; - } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java index 1f4875e9bbea..704437008fc9 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java @@ -130,7 +130,6 @@ import static org.hibernate.cfg.AvailableSettings.DISCARD_PC_ON_CLOSE; import static org.hibernate.engine.config.spi.StandardConverters.BOOLEAN; import static org.hibernate.internal.CoreLogging.messageLogger; -import static org.hibernate.internal.log.DeprecationLogger.DEPRECATION_LOGGER; /** * In-flight state of {@link org.hibernate.boot.spi.SessionFactoryOptions} @@ -331,11 +330,10 @@ public SessionFactoryOptionsBuilder(StandardServiceRegistry serviceRegistry, Boo this.entityNotFoundDelegate = StandardEntityNotFoundDelegate.INSTANCE; this.identifierRollbackEnabled = cfgService.getSetting( USE_IDENTIFIER_ROLLBACK, BOOLEAN, false ); + this.defaultEntityMode = EntityMode.parse( (String) configurationSettings.get( DEFAULT_ENTITY_MODE ) ); this.checkNullability = cfgService.getSetting( CHECK_NULLABILITY, BOOLEAN, true ); this.initializeLazyStateOutsideTransactions = cfgService.getSetting( ENABLE_LAZY_LOAD_NO_TRANS, BOOLEAN, false ); - this.defaultEntityMode = EntityMode.fromSetting( configurationSettings.get( DEFAULT_ENTITY_MODE ) ); - this.multiTenancyStrategy = MultiTenancyStrategy.determineMultiTenancyStrategy( configurationSettings ); this.currentTenantIdentifierResolver = strategySelector.resolveStrategy( CurrentTenantIdentifierResolver.class, @@ -477,7 +475,7 @@ public SessionFactoryOptionsBuilder(StandardServiceRegistry serviceRegistry, Boo null ); if ( oldSetting != null ) { - DEPRECATION_LOGGER.deprecatedSetting( + DeprecationLogger.DEPRECATION_LOGGER.deprecatedSetting( org.hibernate.jpa.AvailableSettings.DISCARD_PC_ON_CLOSE, DISCARD_PC_ON_CLOSE ); @@ -564,7 +562,7 @@ private static Interceptor determineInterceptor(Map configurationSettings, Strat () -> { final Object oldSetting = configurationSettings.get( org.hibernate.jpa.AvailableSettings.INTERCEPTOR ); if ( oldSetting != null ) { - DEPRECATION_LOGGER.deprecatedSetting( + DeprecationLogger.DEPRECATION_LOGGER.deprecatedSetting( org.hibernate.jpa.AvailableSettings.INTERCEPTOR, INTERCEPTOR ); @@ -585,7 +583,7 @@ private static Supplier determineStatelessInterceptor( () -> { final Object oldSetting = configurationSettings.get( org.hibernate.jpa.AvailableSettings.SESSION_INTERCEPTOR ); if ( oldSetting != null ) { - DEPRECATION_LOGGER.deprecatedSetting( + DeprecationLogger.DEPRECATION_LOGGER.deprecatedSetting( org.hibernate.jpa.AvailableSettings.SESSION_INTERCEPTOR, SESSION_SCOPED_INTERCEPTOR ); @@ -661,7 +659,7 @@ private PhysicalConnectionHandlingMode interpretConnectionHandlingMode( ConnectionReleaseMode specifiedReleaseMode, Map configurationSettings, TransactionCoordinatorBuilder transactionCoordinatorBuilder) { - DEPRECATION_LOGGER.logUseOfDeprecatedConnectionHandlingSettings(); + DeprecationLogger.DEPRECATION_LOGGER.logUseOfDeprecatedConnectionHandlingSettings(); final ConnectionAcquisitionMode effectiveAcquisitionMode = specifiedAcquisitionMode == null ? ConnectionAcquisitionMode.AS_NEEDED diff --git a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/internal/EntityModeConverter.java b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/internal/EntityModeConverter.java index 6c5aa1ad1ba0..d9548064fad2 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/internal/EntityModeConverter.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/jaxb/hbm/internal/EntityModeConverter.java @@ -7,31 +7,16 @@ package org.hibernate.boot.jaxb.hbm.internal; import org.hibernate.EntityMode; -import org.hibernate.internal.log.DeprecationLogger; -import org.hibernate.internal.util.StringHelper; /** - * @deprecated for removal in 6.0 + * @author Steve Ebersole */ -@Deprecated public class EntityModeConverter { public static EntityMode fromXml(String name) { - final EntityMode entityMode = EntityMode.parse( name ); - if ( StringHelper.isNotEmpty( name ) ) { - DeprecationLogger.DEPRECATION_LOGGER.info( - "XML mapping specified an entity-mode - `%s`. Starting in 6.0 this is simply inferred from the entity/composite mapping" - ); - } - return entityMode; + return EntityMode.parse( name ); } public static String toXml(EntityMode entityMode) { - if ( entityMode == null ) { - return null; - } - DeprecationLogger.DEPRECATION_LOGGER.info( - "XML mapping specified an entity-mode - `%s`. Starting in 6.0 this is simply inferred from the entity/composite mapping" - ); - return entityMode.getExternalName(); + return ( null == entityMode ) ? null : entityMode.getExternalName(); } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/AbstractEntitySourceImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/AbstractEntitySourceImpl.java index 230856c2126c..cfb2826243b1 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/AbstractEntitySourceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/AbstractEntitySourceImpl.java @@ -324,22 +324,10 @@ public boolean isSelectBeforeUpdate() { return jaxbEntityMapping.isSelectBeforeUpdate(); } - /** - * @deprecated to be removed in 6.0. Starting in 6.0 the mode is inferred - * from the entity-type mapping - */ - @Deprecated protected EntityMode determineEntityMode() { return StringHelper.isNotEmpty( entityNamingSource.getClassName() ) ? EntityMode.POJO : EntityMode.MAP; } - /** - * @deprecated to be removed in 6.0. Starting in 6.0 the mode is inferred - * from the entity-type mapping - * - * See `ManagedTypeRepresentationStrategy` and `RepresentationMode` in 6.0 - */ - @Deprecated @Override public Map getTuplizerClassMap() { return tuplizerClassMap; diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java index 59d79cb7156d..f4da85d6817a 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/AvailableSettings.java @@ -1409,10 +1409,7 @@ public interface AvailableSettings extends org.hibernate.jpa.AvailableSettings { /** * The EntityMode in which set the Session opened from the SessionFactory. - * - * @deprecated An entity-type has one "mode" relative to any SessionFactory. */ - @Deprecated String DEFAULT_ENTITY_MODE = "hibernate.default_entity_mode"; /** diff --git a/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java b/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java index 9f709d59a333..9ecfe081bf67 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/log/DeprecationLogger.java @@ -297,10 +297,4 @@ void connectionProviderClassDeprecated( ) void deprecatedJmxBeanRegistration(String name); - @LogMessage(level = WARN) - @Message( - id = 90000031, - value = "Encountered deprecated setting [%s] which is planned for removal" - ) - void deprecatedSetting(String setting); } diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/Tuplizer.java b/hibernate-core/src/main/java/org/hibernate/tuple/Tuplizer.java index 16ec664d3232..9c0120b185e4 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/Tuplizer.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/Tuplizer.java @@ -31,12 +31,8 @@ * @see org.hibernate.tuple.entity.EntityTuplizer * @see org.hibernate.tuple.component.ComponentTuplizer * - * @deprecated for removal in 6.0. See instead `ManagedTypeRepresentationStrategy` - * and `RepresentationMode` in 6.0 - * * @author Steve Ebersole */ -@Deprecated public interface Tuplizer { /** * Extract the current values contained on the given entity. diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/component/ComponentTuplizer.java b/hibernate-core/src/main/java/org/hibernate/tuple/component/ComponentTuplizer.java index 75eaa2572e07..916e02b6d57a 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/component/ComponentTuplizer.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/component/ComponentTuplizer.java @@ -20,11 +20,7 @@ * * @author Gavin King * @author Steve Ebersole - * - * @deprecated for removal in 6.0. See instead `ManagedTypeRepresentationStrategy` - * and `RepresentationMode` in 6.0 */ -@Deprecated public interface ComponentTuplizer extends Tuplizer, Serializable { /** * Retrieve the current value of the parent property. diff --git a/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityTuplizer.java b/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityTuplizer.java index 2f7e932b4e4e..68b8b9d22fa2 100644 --- a/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityTuplizer.java +++ b/hibernate-core/src/main/java/org/hibernate/tuple/entity/EntityTuplizer.java @@ -28,11 +28,7 @@ * * @author Gavin King * @author Steve Ebersole - * - * @deprecated for removal in 6.0. See instead `ManagedTypeRepresentationStrategy` - * and `RepresentationMode` in 6.0 */ -@Deprecated public interface EntityTuplizer extends Tuplizer { /** * Return the entity-mode handled by this tuplizer instance. From 2d871d64f272d99a1da806a7328fef4f2a09f91f Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Mon, 6 Dec 2021 11:40:47 +0100 Subject: [PATCH 394/644] HHH-14897 Allow ordering with nulls first/last in JPA Criteria --- .../criteria/HibernateCriteriaBuilder.java | 17 ++++ .../internal/CriteriaBuilderImpl.java | 10 ++- .../criteria/internal/CriteriaQueryImpl.java | 11 +++ .../query/criteria/internal/OrderImpl.java | 12 ++- .../criteria/internal/NullPrecedenceTest.java | 90 +++++++++++++++++++ 5 files changed, 138 insertions(+), 2 deletions(-) create mode 100644 hibernate-core/src/test/java/org/hibernate/query/criteria/internal/NullPrecedenceTest.java diff --git a/hibernate-core/src/main/java/org/hibernate/query/criteria/HibernateCriteriaBuilder.java b/hibernate-core/src/main/java/org/hibernate/query/criteria/HibernateCriteriaBuilder.java index ac787039b1e3..a4784a9f8c4d 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/criteria/HibernateCriteriaBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/query/criteria/HibernateCriteriaBuilder.java @@ -9,6 +9,7 @@ import java.util.Map; import javax.persistence.criteria.CriteriaBuilder; import javax.persistence.criteria.Expression; +import javax.persistence.criteria.Order; import javax.persistence.criteria.Predicate; /** @@ -67,4 +68,20 @@ public interface HibernateCriteriaBuilder extends CriteriaBuilder { */ > Expression mapSize(M map); + /** + * Create an ordering by the ascending value of the expression. + * @param x expression used to define the ordering + * @param nullsFirst Whether null should be sorted first + * @return ascending ordering corresponding to the expression + */ + Order asc(Expression x, boolean nullsFirst); + + /** + * Create an ordering by the descending value of the expression. + * @param x expression used to define the ordering + * @param nullsFirst Whether null should be sorted first + * @return descending ordering corresponding to the expression + */ + Order desc(Expression x, boolean nullsFirst); + } diff --git a/hibernate-core/src/main/java/org/hibernate/query/criteria/internal/CriteriaBuilderImpl.java b/hibernate-core/src/main/java/org/hibernate/query/criteria/internal/CriteriaBuilderImpl.java index 79e049a6ae21..82e48fdf7aba 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/criteria/internal/CriteriaBuilderImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/criteria/internal/CriteriaBuilderImpl.java @@ -250,8 +250,16 @@ public Order desc(Expression x) { return new OrderImpl( x, false ); } + @Override + public Order asc(Expression x, boolean nullsFirst) { + return new OrderImpl( x, true, nullsFirst ); + } - // predicates ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + @Override + public Order desc(Expression x, boolean nullsFirst) { + return new OrderImpl( x, false, nullsFirst ); + } +// predicates ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ public Predicate wrap(Expression expression) { if ( Predicate.class.isInstance( expression ) ) { diff --git a/hibernate-core/src/main/java/org/hibernate/query/criteria/internal/CriteriaQueryImpl.java b/hibernate-core/src/main/java/org/hibernate/query/criteria/internal/CriteriaQueryImpl.java index 6ec5ddd1d66d..84ebb81c404b 100755 --- a/hibernate-core/src/main/java/org/hibernate/query/criteria/internal/CriteriaQueryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/criteria/internal/CriteriaQueryImpl.java @@ -395,6 +395,17 @@ protected void renderOrderByClause(RenderingContext renderingContext, StringBuil jpaqlBuffer.append( sep ) .append( ( (Renderable) orderSpec.getExpression() ).render( renderingContext ) ) .append( orderSpec.isAscending() ? " asc" : " desc" ); + if ( orderSpec instanceof OrderImpl ) { + Boolean nullsFirst = ( (OrderImpl) orderSpec ).getNullsFirst(); + if ( nullsFirst != null ) { + if ( nullsFirst ) { + jpaqlBuffer.append( " nulls first" ); + } + else { + jpaqlBuffer.append( " nulls last" ); + } + } + } sep = ", "; } } diff --git a/hibernate-core/src/main/java/org/hibernate/query/criteria/internal/OrderImpl.java b/hibernate-core/src/main/java/org/hibernate/query/criteria/internal/OrderImpl.java index 2078da416636..ca12796a5048 100644 --- a/hibernate-core/src/main/java/org/hibernate/query/criteria/internal/OrderImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/query/criteria/internal/OrderImpl.java @@ -19,14 +19,20 @@ public class OrderImpl implements Order, Serializable { private final Expression expression; private final boolean ascending; + private final Boolean nullsFirst; public OrderImpl(Expression expression) { - this( expression, true ); + this( expression, true, null ); } public OrderImpl(Expression expression, boolean ascending) { + this(expression, ascending, null); + } + + public OrderImpl(Expression expression, boolean ascending, Boolean nullsFirst) { this.expression = expression; this.ascending = ascending; + this.nullsFirst = nullsFirst; } public Order reverse() { @@ -40,4 +46,8 @@ public boolean isAscending() { public Expression getExpression() { return expression; } + + public Boolean getNullsFirst() { + return nullsFirst; + } } diff --git a/hibernate-core/src/test/java/org/hibernate/query/criteria/internal/NullPrecedenceTest.java b/hibernate-core/src/test/java/org/hibernate/query/criteria/internal/NullPrecedenceTest.java new file mode 100644 index 000000000000..7e5178766687 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/query/criteria/internal/NullPrecedenceTest.java @@ -0,0 +1,90 @@ +package org.hibernate.query.criteria.internal; + +import java.util.List; +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.TypedQuery; +import javax.persistence.criteria.CriteriaQuery; +import javax.persistence.criteria.Root; + +import org.hibernate.jpa.test.BaseEntityManagerFunctionalTestCase; +import org.hibernate.query.criteria.HibernateCriteriaBuilder; + +import org.hibernate.testing.TestForIssue; +import org.junit.Assert; +import org.junit.Test; + +import static org.hibernate.testing.transaction.TransactionUtil.doInJPA; + +/** + * @author Christian Beikov + */ +@TestForIssue( jiraKey = "HHH-14897" ) +public class NullPrecedenceTest extends BaseEntityManagerFunctionalTestCase { + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { Foo.class }; + } + + @Test + public void testNullPrecedence() { + doInJPA( this::entityManagerFactory, entityManager -> { + entityManager.persist( new Foo( 1L, null ) ); + entityManager.persist( new Foo( 2L, "ABC" ) ); + entityManager.persist( new Foo( 3L, "DEF" ) ); + entityManager.persist( new Foo( 4L, "DEF" ) ); + final HibernateCriteriaBuilder cb = (HibernateCriteriaBuilder) entityManager.getCriteriaBuilder(); + + final CriteriaQuery cq = cb.createQuery( Foo.class ); + final Root foo = cq.from( Foo.class ); + + cq.orderBy( + cb.desc( foo.get( "bar" ), true ), + cb.desc( foo.get( "id" ) ) + ); + + final TypedQuery tq = entityManager.createQuery( cq ); + + final List resultList = tq.getResultList(); + Assert.assertEquals( 4, resultList.size() ); + Assert.assertEquals( 1L, resultList.get( 0 ).getId() ); + Assert.assertEquals( 4L, resultList.get( 1 ).getId() ); + Assert.assertEquals( 3L, resultList.get( 2 ).getId() ); + Assert.assertEquals( 2L, resultList.get( 3 ).getId() ); + } ); + } + + @Entity(name = "Foo") + public static class Foo { + + private long id; + private String bar; + + public Foo() { + } + + public Foo(long id, String bar) { + this.id = id; + this.bar = bar; + } + + @Id + @Column(nullable = false) + public long getId() { + return this.id; + } + public void setId(final long id) { + this.id = id; + } + + public String getBar() { + return bar; + } + + public void setBar(String bar) { + this.bar = bar; + } + } +} From b8046d1a809ae1ac7fe2c2c305c67f61ea21c039 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Wed, 24 Nov 2021 12:47:34 +0000 Subject: [PATCH 395/644] HHH-14938 Upgrade to MySQL Connector/J 8.0.27 --- gradle/libraries.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libraries.gradle b/gradle/libraries.gradle index 1b74f018c203..7ddc2ff28f03 100644 --- a/gradle/libraries.gradle +++ b/gradle/libraries.gradle @@ -125,7 +125,7 @@ ext { hsqldb: "org.hsqldb:hsqldb:2.3.2", derby: "org.apache.derby:derby:10.14.2.0", postgresql: 'org.postgresql:postgresql:42.2.16', - mysql: 'mysql:mysql-connector-java:8.0.17', + mysql: 'mysql:mysql-connector-java:8.0.27', mariadb: 'org.mariadb.jdbc:mariadb-java-client:2.2.3', cockroachdb: 'org.postgresql:postgresql:42.2.8', From fa8b78d345e01d980a6046f226664f28799c73e0 Mon Sep 17 00:00:00 2001 From: Neon Ngo Date: Mon, 6 Dec 2021 09:51:37 -0500 Subject: [PATCH 396/644] HHH-14956 Fix link to MetadataBuilderContributor javadocs - Under Appendix > Configurations > Bootstrap properties - hibernate.metadata_builder_contributor --- .../main/asciidoc/userguide/appendices/Configurations.adoc | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc b/documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc index 625dfe10095c..65887a2710b7 100644 --- a/documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc +++ b/documentation/src/main/asciidoc/userguide/appendices/Configurations.adoc @@ -1101,8 +1101,8 @@ Like a `PersisterClassResolver`, the `PersisterFactory` can be used to customize `*hibernate.service.allow_crawling*` (e.g. `true` (default value) or `false`):: Crawl all available service bindings for an alternate registration of a given Hibernate `Service`. -`*hibernate.metadata_builder_contributor*` (e.g. The instance, the class or the fully qualified class name of a https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/jpa/boot/spi/MetadataBuilderContributor.html[`MetadataBuilderContributor`]):: -Used to define an instance, the class or the fully qualified class name of a https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/jpa/boot/spi/MetadataBuilderContributor.html[`MetadataBuilderContributor`] which can be used to configure the `MetadataBuilder` when bootstrapping via the JPA `EntityManagerFactory`. +`*hibernate.metadata_builder_contributor*` (e.g. The instance, the class or the fully qualified class name of a https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/boot/spi/MetadataBuilderContributor.html[`MetadataBuilderContributor`]):: +Used to define an instance, the class or the fully qualified class name of a https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/boot/spi/MetadataBuilderContributor.html[`MetadataBuilderContributor`] which can be used to configure the `MetadataBuilder` when bootstrapping via the JPA `EntityManagerFactory`. [[configurations-misc]] === Miscellaneous properties From 9a9653689e464f01ef9bd5c7cf3181485b333217 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Mon, 6 Dec 2021 18:57:42 +0100 Subject: [PATCH 397/644] Change branch name in GitHub actions workflow to 5.6 --- .github/workflows/contributor-build.yml | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/.github/workflows/contributor-build.yml b/.github/workflows/contributor-build.yml index dbdb5d6e2d9e..e6ccfdb63ed3 100644 --- a/.github/workflows/contributor-build.yml +++ b/.github/workflows/contributor-build.yml @@ -9,12 +9,10 @@ name: Hibernate ORM build on: push: branches: - - 'main' - - 'wip/6.0' + - '5.6' pull_request: branches: - - 'main' - - 'wip/6.0' + - '5.6' jobs: build: name: Java 8 From 77776a6af170c30bcde5eb52dd95e7160f350907 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Tue, 9 Nov 2021 11:43:53 +0100 Subject: [PATCH 398/644] HHH-14211 Switch to using oid for CLOB in PostgreSQL to avoid losing data after vacuumlo --- .../dialect/PostgreSQL81Dialect.java | 2 +- .../test/lob/PostgreSqlLobStringTest.java | 86 ++++++++++--------- migration-guide.adoc | 62 +++++++++++++ 3 files changed, 109 insertions(+), 41 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL81Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL81Dialect.java index ad4ee3a3eef4..09b8df5cb52a 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL81Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQL81Dialect.java @@ -114,7 +114,7 @@ public PostgreSQL81Dialect() { registerColumnType( Types.BINARY, "bytea" ); registerColumnType( Types.LONGVARCHAR, "text" ); registerColumnType( Types.LONGVARBINARY, "bytea" ); - registerColumnType( Types.CLOB, "text" ); + registerColumnType( Types.CLOB, "oid" ); registerColumnType( Types.BLOB, "oid" ); registerColumnType( Types.NUMERIC, "numeric($p, $s)" ); registerColumnType( Types.OTHER, "uuid" ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/lob/PostgreSqlLobStringTest.java b/hibernate-core/src/test/java/org/hibernate/test/lob/PostgreSqlLobStringTest.java index 1ba2ce15d1b4..c521dbdcf269 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/lob/PostgreSqlLobStringTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/lob/PostgreSqlLobStringTest.java @@ -65,9 +65,9 @@ protected void prepareTest() " (?, ?, ?, -1)" )) { int index = 1; - statement.setString(index++, value1); - statement.setString(index++, value2); - statement.setString(index++, value3); + statement.setClob( index++, session.getLobHelper().createClob( value1 ) ); + statement.setClob( index++, session.getLobHelper().createClob( value2 ) ); + statement.setClob( index++, session.getLobHelper().createClob( value3 ) ); assertEquals( 1, statement.executeUpdate() ); } @@ -77,57 +77,63 @@ protected void prepareTest() @Test public void testBadClobDataSavedAsStringFails() { - try { - doInHibernate( this::sessionFactory, session -> { - final Query query = session.createQuery( "from TestEntity" ); + doInHibernate( this::sessionFactory, session -> { + final Query query = session.createQuery( "from TestEntity" ); - final List results = query.list(); + final List results = query.list(); - fail("Exception thrown expected"); - } ); - } - catch (Exception e) { - Exception rootException = (Exception) ExceptionUtil.rootCause( e ); - assertTrue( rootException.getMessage().startsWith( "Bad value for type long" ) ); - } + assertThat( results.size(), is( 1 ) ); + + final TestEntity testEntity = results.get( 0 ); + assertThat( testEntity.getFirstLobField(), is( value1 ) ); + assertThat( testEntity.getSecondLobField(), is( value2 ) ); + final Clob clobField = testEntity.getClobField(); + try { + + assertThat( clobField.getSubString( 1, (int) clobField.length() ), is( value3 ) ); + } + catch (SQLException e) { + fail( e.getMessage() ); + } + } ); } @Test public void testBadClobDataSavedAsStringworksAfterUpdate() { doInHibernate( this::sessionFactory, session -> { - session.doWork( connection -> { - try(Statement statement = connection.createStatement()) { - statement.executeUpdate( - "update test_entity\n" + - "set \n" + - " clobfield = lo_from_bytea(0, cast(clobfield as bytea)),\n" + - " firstlobfield = lo_from_bytea(0, cast(firstlobfield as bytea)),\n" + - " secondlobfield = lo_from_bytea(0, cast(secondlobfield as bytea))" - ); - } - } ); - } ); + session.doWork( connection -> { + try (Statement statement = connection.createStatement()) { + statement.executeUpdate( + "update test_entity\n" + + "set \n" + + " clobfield = lo_from_bytea(0, lo_get(clobfield)),\n" + + " firstlobfield = lo_from_bytea(0, lo_get(firstlobfield)),\n" + + " secondlobfield = lo_from_bytea(0, lo_get(secondlobfield))" + ); + } + } ); + } ); doInHibernate( this::sessionFactory, session -> { - final Query query = session.createQuery( "from TestEntity" ); + final Query query = session.createQuery( "from TestEntity" ); - final List results = query.list(); + final List results = query.list(); - assertThat( results.size(), is( 1 ) ); + assertThat( results.size(), is( 1 ) ); - final TestEntity testEntity = results.get( 0 ); - assertThat( testEntity.getFirstLobField(), is( value1 ) ); - assertThat( testEntity.getSecondLobField(), is( value2 ) ); - final Clob clobField = testEntity.getClobField(); - try { + final TestEntity testEntity = results.get( 0 ); + assertThat( testEntity.getFirstLobField(), is( value1 ) ); + assertThat( testEntity.getSecondLobField(), is( value2 ) ); + final Clob clobField = testEntity.getClobField(); + try { - assertThat( clobField.getSubString( 1, (int) clobField.length() ), is( value3 ) ); - } - catch (SQLException e) { - fail( e.getMessage() ); - } - } ); + assertThat( clobField.getSubString( 1, (int) clobField.length() ), is( value3 ) ); + } + catch (SQLException e) { + fail( e.getMessage() ); + } + } ); } @Entity(name = "TestEntity") diff --git a/migration-guide.adoc b/migration-guide.adoc index fe220a2b9b41..c9bb6396d733 100644 --- a/migration-guide.adoc +++ b/migration-guide.adoc @@ -19,3 +19,65 @@ configure `hibernate.bytecode.provider=javassist`: remove the property if you're A side effect is that Hibenate ORM no longer lists javassist among its dependencies. +=== Changes to the DDL type for CLOB in PostgreSQL81Dialect and its subclasses + +As of 5.6.2, the default PostgreSQL DDL type for CLOB columns i.e. fields annotated with `@Lob` or with the type `java.sql.Clob` +will be the `oid` type whereas before, the type `text` was used. The `text` type does not support streaming data +and is, even if TOASTed, materialized eagerly by the server, which is not what one would expect for LOB types. + +All PostgreSQL JDBC drivers unfortunately just store the `oid` it created for a `java.sql.Clob` into the `text` column. +Although reading back the value with the CLOB API works, PostgreSQL has no knowledge of the reference to the LOB, +because the `oid` is not known to PostgreSQL, leading to data loss when `vacuumlo` (the utility to clean up unused LOBs) runs. +To avoid the data loss, it is required to use the `oid` type so that `vacuumlo` can see the reference. + +Updating to 5.6.2 does not require any schema or application changes by default, but we highly recommend +that you migrate existing `text` columns for LOBs to `oid` to prevent data loss due to the activity of `vacuumlo`. + +[source,sql] +---- +alter table test_entity +alter column clobfield +set data type oid using clobfield::oid +---- + +If you are overriding the `JdbcTypeDescriptor` for `CLOB` to use e.g. `VarcharTypeDescriptor` in a custom PostgreSQL dialect, +beware that you will also have to override the column type in the custom dialect, as with "pgjdbc", +it is not possible to read/write an `oid` column with the JDBC `ResultSet#getString/Statement#setString` methods. + +[source,java] +---- +registerColumnType( Types.CLOB, "text" ); +---- + +Alternatively, you can remove the `JdbcTypeDescriptor` override and migrate to `oid` with + +[source,sql] +---- +alter table test_entity +alter column clobfield +set data type oid using lo_from_bytea(0, cast(clobfield as bytea)) +---- + +The switch to `oid` might have a negative impact on performance for small values that are fetched often, +because the value is stored in a different file system page than the row, even for small values +The benefit of the `oid` type is that it allows streaming the content and reduces the row size. + +Users that just want a large text type but don't care about streaming should use the Hibernate type `text`: + +[source,java] +---- +@Entity +public class TestEntity { + + @org.hibernate.annotations.Type( type = "text" ) + String clobField; + + //... +} +---- + +This will map to `java.sql.Types.LONGVARCHAR` for which Hibernate dialects register a DDL type that supports access +via the `ResultSet#getString/Statement#setString` methods i.e. in case of PostgreSQL the type `text`. + +The `@Lob` annotation should only be used to force the use of the `ResultSet#getClob/Statement#setClob` JDBC driver methods, +which is in turn necessary for streaming data. From 696db954160a13c8aa1317b698badd36d9398fa0 Mon Sep 17 00:00:00 2001 From: "jaehun.lee" Date: Sun, 22 Nov 2020 20:38:39 +0900 Subject: [PATCH 399/644] polishing --- .../persister/entity/AbstractEntityPersister.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index fbd6be954474..8ed6a7e6f52c 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -3297,7 +3297,7 @@ public String getSelectByUniqueKeyString(String propertyName) { .toStatementString(); } - private BasicBatchKey inserBatchKey; + private BasicBatchKey insertBatchKey; /** * Perform an SQL INSERT. @@ -3338,8 +3338,8 @@ public void insert( jdbcBatchSizeToUse > 1 && getIdentifierGenerator().supportsJdbcBatchInserts(); - if ( useBatch && inserBatchKey == null ) { - inserBatchKey = new BasicBatchKey( + if ( useBatch && insertBatchKey == null ) { + insertBatchKey = new BasicBatchKey( getEntityName() + "#INSERT", expectation ); @@ -3352,7 +3352,7 @@ public void insert( if ( useBatch ) { insert = session .getJdbcCoordinator() - .getBatch( inserBatchKey ) + .getBatch(insertBatchKey) .getBatchStatement( sql, callable ); } else { @@ -3372,7 +3372,7 @@ public void insert( dehydrate( id, fields, null, notNull, propertyColumnInsertable, j, insert, session, index, false ); if ( useBatch ) { - session.getJdbcCoordinator().getBatch( inserBatchKey ).addToBatch(); + session.getJdbcCoordinator().getBatch(insertBatchKey).addToBatch(); } else { expectation.verifyOutcome( From 49d2fccbcbb59b13c3224d1a10c4f30e332b8072 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Mon, 6 Dec 2021 19:46:44 +0100 Subject: [PATCH 400/644] Fixup code formatting --- .../hibernate/persister/entity/AbstractEntityPersister.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index 8ed6a7e6f52c..afe36eaf65bd 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -3352,7 +3352,7 @@ public void insert( if ( useBatch ) { insert = session .getJdbcCoordinator() - .getBatch(insertBatchKey) + .getBatch( insertBatchKey ) .getBatchStatement( sql, callable ); } else { @@ -3372,7 +3372,7 @@ public void insert( dehydrate( id, fields, null, notNull, propertyColumnInsertable, j, insert, session, index, false ); if ( useBatch ) { - session.getJdbcCoordinator().getBatch(insertBatchKey).addToBatch(); + session.getJdbcCoordinator().getBatch( insertBatchKey ).addToBatch(); } else { expectation.verifyOutcome( From 9d3b3d1c8a71c989fe2168ec7998811939fc56f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Thu, 4 Nov 2021 10:38:47 +0100 Subject: [PATCH 401/644] HHH-14921 Clarify the ability of IdentifierGenerator to be configured and to register exportables --- .../InFlightMetadataCollectorImpl.java | 5 +-- .../main/java/org/hibernate/id/Assigned.java | 2 +- .../java/org/hibernate/id/Configurable.java | 3 ++ .../org/hibernate/id/ForeignGenerator.java | 2 +- .../org/hibernate/id/IdentifierGenerator.java | 35 +++++++++++++++++-- .../org/hibernate/id/IncrementGenerator.java | 2 +- .../id/MultipleHiLoPerTableGenerator.java | 3 +- .../id/PersistentIdentifierGenerator.java | 12 ++++--- .../org/hibernate/id/SelectGenerator.java | 2 +- .../org/hibernate/id/SequenceGenerator.java | 2 +- .../java/org/hibernate/id/UUIDGenerator.java | 2 +- .../org/hibernate/id/UUIDHexGenerator.java | 2 +- .../id/enhanced/SequenceStyleGenerator.java | 3 +- .../hibernate/id/enhanced/TableGenerator.java | 3 +- .../DefaultIdentifierGeneratorFactory.java | 5 +-- .../java/org/hibernate/mapping/Component.java | 5 +-- 16 files changed, 57 insertions(+), 31 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java index 568ef9649817..5b780c15eef0 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java @@ -45,7 +45,6 @@ import org.hibernate.boot.model.naming.ImplicitUniqueKeyNameSource; import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject; import org.hibernate.boot.model.relational.Database; -import org.hibernate.boot.model.relational.ExportableProducer; import org.hibernate.boot.model.relational.Namespace; import org.hibernate.boot.model.relational.QualifiedTableName; import org.hibernate.boot.model.source.internal.ImplicitColumnNamingSecondPass; @@ -2249,9 +2248,7 @@ private void handleIdentifierValueBinding( entityBinding ); - if ( ig instanceof ExportableProducer ) { - ( (ExportableProducer) ig ).registerExportables( getDatabase() ); - } + ig.registerExportables( getDatabase() ); } catch (MappingException e) { // ignore this for now. The reasoning being "non-reflective" binding as needed diff --git a/hibernate-core/src/main/java/org/hibernate/id/Assigned.java b/hibernate-core/src/main/java/org/hibernate/id/Assigned.java index e22faa0f7df7..cfffdcc2107f 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/Assigned.java +++ b/hibernate-core/src/main/java/org/hibernate/id/Assigned.java @@ -23,7 +23,7 @@ * * @author Gavin King */ -public class Assigned implements IdentifierGenerator, Configurable { +public class Assigned implements IdentifierGenerator { private String entityName; public Serializable generate(SharedSessionContractImplementor session, Object obj) throws HibernateException { diff --git a/hibernate-core/src/main/java/org/hibernate/id/Configurable.java b/hibernate-core/src/main/java/org/hibernate/id/Configurable.java index 7ffdcc970063..87d53fba0dd0 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/Configurable.java +++ b/hibernate-core/src/main/java/org/hibernate/id/Configurable.java @@ -15,11 +15,14 @@ /** * An {@link IdentifierGenerator} that supports "configuration". * + * @deprecated All methods are already defined in {@link IdentifierGenerator}. + * Just implement {@link IdentifierGenerator}. * @see IdentifierGenerator * * @author Gavin King * @author Steve Ebersole */ +@Deprecated public interface Configurable { /** * Configure this instance, given the value of parameters diff --git a/hibernate-core/src/main/java/org/hibernate/id/ForeignGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/ForeignGenerator.java index d7a00d37a9d1..6528d81c133a 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/ForeignGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/ForeignGenerator.java @@ -34,7 +34,7 @@ * * @author Gavin King */ -public class ForeignGenerator implements IdentifierGenerator, Configurable { +public class ForeignGenerator implements IdentifierGenerator { private static final CoreMessageLogger LOG = messageLogger( ForeignGenerator.class ); private String entityName; diff --git a/hibernate-core/src/main/java/org/hibernate/id/IdentifierGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/IdentifierGenerator.java index 51bc8a355e5b..ca3da8b32783 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/IdentifierGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/IdentifierGenerator.java @@ -7,10 +7,16 @@ package org.hibernate.id; import java.io.Serializable; +import java.util.Properties; import javax.persistence.GeneratedValue; import org.hibernate.HibernateException; +import org.hibernate.MappingException; +import org.hibernate.boot.model.relational.Database; +import org.hibernate.boot.model.relational.ExportableProducer; import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.service.ServiceRegistry; +import org.hibernate.type.Type; /** * The general contract between a class that generates unique @@ -29,9 +35,8 @@ * @author Gavin King * * @see PersistentIdentifierGenerator - * @see Configurable */ -public interface IdentifierGenerator { +public interface IdentifierGenerator extends Configurable, ExportableProducer { /** * The configuration parameter holding the entity name */ @@ -48,6 +53,32 @@ public interface IdentifierGenerator { */ String GENERATOR_NAME = "GENERATOR_NAME"; + /** + * Configure this instance, given the value of parameters + * specified by the user as <param> elements. + *

    + * This method is called just once, following instantiation, and before {@link #registerExportables(Database)}. + * + * @param type The id property type descriptor + * @param params param values, keyed by parameter name + * @param serviceRegistry Access to service that may be needed. + * @throws MappingException If configuration fails. + */ + @Override + default void configure(Type type, Properties params, ServiceRegistry serviceRegistry) throws MappingException { + } + + /** + * Register database objects used by this identifier generator, e.g. sequences, tables, etc. + *

    + * This method is called just once, after {@link #configure(Type, Properties, ServiceRegistry)}. + * + * @param database The database instance + */ + @Override + default void registerExportables(Database database) { + } + /** * Generate a new identifier. * diff --git a/hibernate-core/src/main/java/org/hibernate/id/IncrementGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/IncrementGenerator.java index 68ab1517aae9..6f2261a4deaf 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/IncrementGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/IncrementGenerator.java @@ -38,7 +38,7 @@ * @author Steve Ebersole * @author Brett Meyer */ -public class IncrementGenerator implements IdentifierGenerator, Configurable { +public class IncrementGenerator implements IdentifierGenerator { private static final CoreMessageLogger LOG = CoreLogging.messageLogger( IncrementGenerator.class ); private Class returnClass; diff --git a/hibernate-core/src/main/java/org/hibernate/id/MultipleHiLoPerTableGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/MultipleHiLoPerTableGenerator.java index 6c7c1000d808..eb891e5ae35c 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/MultipleHiLoPerTableGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/MultipleHiLoPerTableGenerator.java @@ -78,7 +78,7 @@ * @deprecated Use {@link org.hibernate.id.enhanced.TableGenerator} instead. */ @Deprecated -public class MultipleHiLoPerTableGenerator implements PersistentIdentifierGenerator, Configurable { +public class MultipleHiLoPerTableGenerator implements PersistentIdentifierGenerator { private static final CoreMessageLogger LOG = CoreLogging.messageLogger( MultipleHiLoPerTableGenerator.class ); public static final String ID_TABLE = "table"; @@ -253,6 +253,7 @@ private ResultSet executeQuery(PreparedStatement ps, SessionEventListenerManager } } + @Override @SuppressWarnings({"StatementWithEmptyBody", "deprecation"}) public void configure(Type type, Properties params, ServiceRegistry serviceRegistry) throws MappingException { returnClass = type.getReturnedClass(); diff --git a/hibernate-core/src/main/java/org/hibernate/id/PersistentIdentifierGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/PersistentIdentifierGenerator.java index 6529124f98a3..cc81847f5178 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/PersistentIdentifierGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/PersistentIdentifierGenerator.java @@ -6,23 +6,25 @@ */ package org.hibernate.id; +import java.util.Properties; + import org.hibernate.HibernateException; -import org.hibernate.boot.model.relational.ExportableProducer; import org.hibernate.dialect.Dialect; +import org.hibernate.service.ServiceRegistry; +import org.hibernate.type.Type; /** * An IdentifierGenerator that requires creation of database objects. *

    - * All PersistentIdentifierGenerators that also implement - * Configurable have access to a special mapping parameter: schema + * All PersistentIdentifierGenerators have access to a special mapping parameter + * in their {@link #configure(Type, Properties, ServiceRegistry)} method: schema * * @author Gavin King * @author Steve Ebersole * * @see IdentifierGenerator - * @see Configurable */ -public interface PersistentIdentifierGenerator extends IdentifierGenerator, ExportableProducer { +public interface PersistentIdentifierGenerator extends IdentifierGenerator { /** * The configuration parameter holding the schema name diff --git a/hibernate-core/src/main/java/org/hibernate/id/SelectGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/SelectGenerator.java index eb7521309e1b..40c0b0eb667d 100755 --- a/hibernate-core/src/main/java/org/hibernate/id/SelectGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/SelectGenerator.java @@ -31,7 +31,7 @@ * * @author Gavin King */ -public class SelectGenerator extends AbstractPostInsertGenerator implements Configurable { +public class SelectGenerator extends AbstractPostInsertGenerator { private String uniqueKeyPropertyName; @Override diff --git a/hibernate-core/src/main/java/org/hibernate/id/SequenceGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/SequenceGenerator.java index cf82f58765e9..1f68fa056e54 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/SequenceGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/SequenceGenerator.java @@ -45,7 +45,7 @@ */ @Deprecated public class SequenceGenerator - implements PersistentIdentifierGenerator, BulkInsertionCapableIdentifierGenerator, Configurable { + implements PersistentIdentifierGenerator, BulkInsertionCapableIdentifierGenerator { private static final Logger LOG = Logger.getLogger( SequenceGenerator.class.getName() ); diff --git a/hibernate-core/src/main/java/org/hibernate/id/UUIDGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/UUIDGenerator.java index 0b86ee15cea0..a18597b1fd04 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/UUIDGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/UUIDGenerator.java @@ -39,7 +39,7 @@ * * @author Steve Ebersole */ -public class UUIDGenerator implements IdentifierGenerator, Configurable { +public class UUIDGenerator implements IdentifierGenerator { public static final String UUID_GEN_STRATEGY = "uuid_gen_strategy"; public static final String UUID_GEN_STRATEGY_CLASS = "uuid_gen_strategy_class"; diff --git a/hibernate-core/src/main/java/org/hibernate/id/UUIDHexGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/UUIDHexGenerator.java index a51c6fd9af18..a0370886de30 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/UUIDHexGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/UUIDHexGenerator.java @@ -29,7 +29,7 @@ * * @author Gavin King */ -public class UUIDHexGenerator extends AbstractUUIDGenerator implements Configurable { +public class UUIDHexGenerator extends AbstractUUIDGenerator { private static final CoreMessageLogger LOG = CoreLogging.messageLogger( UUIDHexGenerator.class ); private static boolean WARNED; diff --git a/hibernate-core/src/main/java/org/hibernate/id/enhanced/SequenceStyleGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/enhanced/SequenceStyleGenerator.java index d3d7de7e5c1e..27b89170adec 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/enhanced/SequenceStyleGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/enhanced/SequenceStyleGenerator.java @@ -24,7 +24,6 @@ import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.id.BulkInsertionCapableIdentifierGenerator; -import org.hibernate.id.Configurable; import org.hibernate.id.IdentifierGenerator; import org.hibernate.id.PersistentIdentifierGenerator; import org.hibernate.id.SequenceMismatchStrategy; @@ -101,7 +100,7 @@ * @author Lukasz Antoniak (lukasz dot antoniak at gmail dot com) */ public class SequenceStyleGenerator - implements PersistentIdentifierGenerator, BulkInsertionCapableIdentifierGenerator, Configurable { + implements PersistentIdentifierGenerator, BulkInsertionCapableIdentifierGenerator { private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, diff --git a/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableGenerator.java index 5a961091953e..d817777b55f8 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableGenerator.java @@ -36,7 +36,6 @@ import org.hibernate.engine.jdbc.spi.SqlStatementLogger; import org.hibernate.engine.spi.SessionEventListenerManager; import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.id.Configurable; import org.hibernate.id.ExportableColumn; import org.hibernate.id.IdentifierGenerator; import org.hibernate.id.IdentifierGeneratorHelper; @@ -129,7 +128,7 @@ * * @author Steve Ebersole */ -public class TableGenerator implements PersistentIdentifierGenerator, Configurable { +public class TableGenerator implements PersistentIdentifierGenerator { private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, TableGenerator.class.getName() diff --git a/hibernate-core/src/main/java/org/hibernate/id/factory/internal/DefaultIdentifierGeneratorFactory.java b/hibernate-core/src/main/java/org/hibernate/id/factory/internal/DefaultIdentifierGeneratorFactory.java index 5d433606e632..b08e65021142 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/factory/internal/DefaultIdentifierGeneratorFactory.java +++ b/hibernate-core/src/main/java/org/hibernate/id/factory/internal/DefaultIdentifierGeneratorFactory.java @@ -19,7 +19,6 @@ import org.hibernate.engine.config.spi.StandardConverters; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.id.Assigned; -import org.hibernate.id.Configurable; import org.hibernate.id.ForeignGenerator; import org.hibernate.id.GUIDGenerator; import org.hibernate.id.IdentifierGenerator; @@ -140,9 +139,7 @@ public boolean useJpaCompliantCreation() { FallbackBeanInstanceProducer.INSTANCE ).getBeanInstance(); } - if ( identifierGenerator instanceof Configurable ) { - ( ( Configurable ) identifierGenerator ).configure( type, config, serviceRegistry ); - } + identifierGenerator.configure( type, config, serviceRegistry ); return identifierGenerator; } catch ( Exception e ) { diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Component.java b/hibernate-core/src/main/java/org/hibernate/mapping/Component.java index af85ad6fbbc5..105d59f50b84 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Component.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Component.java @@ -16,7 +16,6 @@ import org.hibernate.EntityMode; import org.hibernate.MappingException; import org.hibernate.boot.model.relational.Database; -import org.hibernate.boot.model.relational.ExportableProducer; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; import org.hibernate.boot.spi.MetadataBuildingContext; @@ -512,9 +511,7 @@ public void execute(SharedSessionContractImplementor session, Object incomingObj @Override public void registerExportables(Database database) { - if ( ExportableProducer.class.isInstance( subGenerator ) ) { - ( (ExportableProducer) subGenerator ).registerExportables( database ); - } + subGenerator.registerExportables( database ); } } From af5afa988dc02d422d8e1591658dfa3112a50dce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Thu, 4 Nov 2021 13:23:37 +0100 Subject: [PATCH 402/644] HHH-14921 Clarify that org.hibernate.mapping.AuxiliaryDatabaseObject has been replaced with org.hibernate.boot.model.relational.AuxiliaryDatabaseObject --- .../boot/model/relational/AbstractAuxiliaryDatabaseObject.java | 2 +- .../boot/model/source/spi/MetadataSourceProcessor.java | 2 +- .../java/org/hibernate/mapping/AuxiliaryDatabaseObject.java | 3 +++ 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/relational/AbstractAuxiliaryDatabaseObject.java b/hibernate-core/src/main/java/org/hibernate/boot/model/relational/AbstractAuxiliaryDatabaseObject.java index 95230353ed09..cf3eb2bb32b9 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/relational/AbstractAuxiliaryDatabaseObject.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/relational/AbstractAuxiliaryDatabaseObject.java @@ -13,7 +13,7 @@ import org.hibernate.dialect.Dialect; /** - * Convenience base class for {@link org.hibernate.mapping.AuxiliaryDatabaseObject}s. + * Convenience base class for {@link AuxiliaryDatabaseObject}s. *

    * This implementation performs dialect scoping checks strictly based on * dialect name comparisons. Custom implementations might want to do diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/source/spi/MetadataSourceProcessor.java b/hibernate-core/src/main/java/org/hibernate/boot/model/source/spi/MetadataSourceProcessor.java index 4a857b8a7848..d5e651d2ff06 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/source/spi/MetadataSourceProcessor.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/source/spi/MetadataSourceProcessor.java @@ -47,7 +47,7 @@ public interface MetadataSourceProcessor { void processNamedQueries(); /** - * Process all {@link org.hibernate.mapping.AuxiliaryDatabaseObject} definitions. + * Process all {@link org.hibernate.boot.model.relational.AuxiliaryDatabaseObject} definitions. *

    * This step has no prerequisites. */ diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/AuxiliaryDatabaseObject.java b/hibernate-core/src/main/java/org/hibernate/mapping/AuxiliaryDatabaseObject.java index 22ef534bbdcb..f902bd8bac76 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/AuxiliaryDatabaseObject.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/AuxiliaryDatabaseObject.java @@ -15,7 +15,10 @@ * creating/dropping the schema. * * @author Steve Ebersole + * + * @deprecated Use {@link org.hibernate.boot.model.relational.AuxiliaryDatabaseObject} instead. */ +@Deprecated public interface AuxiliaryDatabaseObject extends RelationalModel, Serializable { /** * Add the given dialect name to the scope of dialects to which From 0bd228a64017293e04ff73f163892ee16e2695ab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Thu, 4 Nov 2021 14:01:12 +0100 Subject: [PATCH 403/644] HHH-14921 Remove a few unused SQL generation methods in identifier generators They are getting in the way of changes related to the default schema --- .../id/MultipleHiLoPerTableGenerator.java | 16 ------------ .../id/PersistentIdentifierGenerator.java | 26 ------------------- .../org/hibernate/id/SequenceGenerator.java | 11 -------- .../id/enhanced/DatabaseStructure.java | 15 ----------- .../id/enhanced/SequenceStructure.java | 12 --------- .../id/enhanced/SequenceStyleGenerator.java | 11 -------- .../hibernate/id/enhanced/TableGenerator.java | 16 ------------ .../hibernate/id/enhanced/TableStructure.java | 15 ----------- hibernate-envers/hibernate-envers.gradle | 1 + .../enhanced/OrderedSequenceStructure.java | 13 ---------- .../MonotonicRevisionNumberTest.java | 16 ++++++++++-- 11 files changed, 15 insertions(+), 137 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/id/MultipleHiLoPerTableGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/MultipleHiLoPerTableGenerator.java index eb891e5ae35c..074f6084f6e5 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/MultipleHiLoPerTableGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/MultipleHiLoPerTableGenerator.java @@ -14,7 +14,6 @@ import java.sql.Types; import java.util.Properties; -import org.hibernate.HibernateException; import org.hibernate.LockMode; import org.hibernate.MappingException; import org.hibernate.boot.model.naming.Identifier; @@ -22,7 +21,6 @@ import org.hibernate.boot.model.relational.Namespace; import org.hibernate.boot.model.relational.QualifiedName; import org.hibernate.boot.model.relational.QualifiedNameParser; -import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.engine.jdbc.internal.FormatStyle; import org.hibernate.engine.jdbc.spi.JdbcServices; @@ -377,20 +375,6 @@ public void registerExportables(Database database) { } - public String[] sqlCreateStrings(Dialect dialect) throws HibernateException { - return new String[] { - dialect.getCreateTableString() - + ' ' + tableName + " ( " - + segmentColumnName + ' ' + dialect.getTypeName( Types.VARCHAR, keySize, 0, 0 ) + ", " - + valueColumnName + ' ' + dialect.getTypeName( Types.INTEGER ) - + " )" + dialect.getTableTypeString() - }; - } - - public String[] sqlDropStrings(Dialect dialect) throws HibernateException { - return new String[] {dialect.getDropTableString( tableName )}; - } - public Object generatorKey() { return tableName; } diff --git a/hibernate-core/src/main/java/org/hibernate/id/PersistentIdentifierGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/PersistentIdentifierGenerator.java index cc81847f5178..fa61f015c4a1 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/PersistentIdentifierGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/PersistentIdentifierGenerator.java @@ -59,32 +59,6 @@ public interface PersistentIdentifierGenerator extends IdentifierGenerator { */ String IDENTIFIER_NORMALIZER = "identifier_normalizer"; - /** - * The SQL required to create the underlying database objects. - * - * @param dialect The dialect against which to generate the create command(s) - * - * @return The create command(s) - * - * @throws HibernateException problem creating the create command(s) - * @deprecated Utilize the ExportableProducer contract instead - */ - @Deprecated - String[] sqlCreateStrings(Dialect dialect) throws HibernateException; - - /** - * The SQL required to remove the underlying database objects. - * - * @param dialect The dialect against which to generate the drop command(s) - * - * @return The drop command(s) - * - * @throws HibernateException problem creating the drop command(s) - * @deprecated Utilize the ExportableProducer contract instead - */ - @Deprecated - String[] sqlDropStrings(Dialect dialect) throws HibernateException; - /** * Return a key unique to the underlying database objects. Prevents us from * trying to create/remove them multiple times. diff --git a/hibernate-core/src/main/java/org/hibernate/id/SequenceGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/SequenceGenerator.java index 1f68fa056e54..a968f1b2f984 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/SequenceGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/SequenceGenerator.java @@ -144,17 +144,6 @@ protected IntegralDataTypeHolder buildHolder() { return IdentifierGeneratorHelper.getIntegralDataTypeHolder( identifierType.getReturnedClass() ); } - @Override - @SuppressWarnings( {"deprecation"}) - public String[] sqlCreateStrings(Dialect dialect) throws HibernateException { - return dialect.getCreateSequenceStrings( sequenceName, 1, 1 ); - } - - @Override - public String[] sqlDropStrings(Dialect dialect) throws HibernateException { - return dialect.getDropSequenceStrings( sequenceName ); - } - @Override public boolean supportsBulkInsertionIdentifierGeneration() { return true; diff --git a/hibernate-core/src/main/java/org/hibernate/id/enhanced/DatabaseStructure.java b/hibernate-core/src/main/java/org/hibernate/id/enhanced/DatabaseStructure.java index 2e256864c94f..dcb907e14fde 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/enhanced/DatabaseStructure.java +++ b/hibernate-core/src/main/java/org/hibernate/id/enhanced/DatabaseStructure.java @@ -7,7 +7,6 @@ package org.hibernate.id.enhanced; import org.hibernate.boot.model.relational.ExportableProducer; -import org.hibernate.dialect.Dialect; import org.hibernate.engine.spi.SharedSessionContractImplementor; /** @@ -58,20 +57,6 @@ public interface DatabaseStructure extends ExportableProducer { */ void prepare(Optimizer optimizer); - /** - * Commands needed to create the underlying structures. - * @param dialect The database dialect being used. - * @return The creation commands. - */ - String[] sqlCreateStrings(Dialect dialect); - - /** - * Commands needed to drop the underlying structures. - * @param dialect The database dialect being used. - * @return The drop commands. - */ - String[] sqlDropStrings(Dialect dialect); - /** * Is the structure physically a sequence? * diff --git a/hibernate-core/src/main/java/org/hibernate/id/enhanced/SequenceStructure.java b/hibernate-core/src/main/java/org/hibernate/id/enhanced/SequenceStructure.java index b32ce3d9682d..ed0e9be86c40 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/enhanced/SequenceStructure.java +++ b/hibernate-core/src/main/java/org/hibernate/id/enhanced/SequenceStructure.java @@ -11,12 +11,10 @@ import java.sql.SQLException; import org.hibernate.AssertionFailure; -import org.hibernate.HibernateException; import org.hibernate.boot.model.relational.Database; import org.hibernate.boot.model.relational.Namespace; import org.hibernate.boot.model.relational.QualifiedName; import org.hibernate.boot.model.relational.Sequence; -import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.id.IdentifierGeneratorHelper; @@ -144,16 +142,6 @@ public void registerExportables(Database database) { this.sql = database.getJdbcEnvironment().getDialect().getSequenceNextValString( sequenceName ); } - @Override - public String[] sqlCreateStrings(Dialect dialect) throws HibernateException { - return dialect.getCreateSequenceStrings( sequenceName, initialValue, getSourceIncrementSize() ); - } - - @Override - public String[] sqlDropStrings(Dialect dialect) throws HibernateException { - return dialect.getDropSequenceStrings( sequenceName ); - } - @Override public boolean isPhysicalSequence() { return true; diff --git a/hibernate-core/src/main/java/org/hibernate/id/enhanced/SequenceStyleGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/enhanced/SequenceStyleGenerator.java index 27b89170adec..ae7bccc19ebc 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/enhanced/SequenceStyleGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/enhanced/SequenceStyleGenerator.java @@ -12,7 +12,6 @@ import org.hibernate.HibernateException; import org.hibernate.MappingException; -import org.hibernate.boot.SchemaAutoTooling; import org.hibernate.boot.model.naming.Identifier; import org.hibernate.boot.model.relational.Database; import org.hibernate.boot.model.relational.QualifiedName; @@ -532,16 +531,6 @@ public Object generatorKey() { return databaseStructure.getName(); } - @Override - public String[] sqlCreateStrings(Dialect dialect) throws HibernateException { - return databaseStructure.sqlCreateStrings( dialect ); - } - - @Override - public String[] sqlDropStrings(Dialect dialect) throws HibernateException { - return databaseStructure.sqlDropStrings( dialect ); - } - // BulkInsertionCapableIdentifierGenerator implementation ~~~~~~~~~~~~~~~~~ diff --git a/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableGenerator.java index d817777b55f8..c557d209a973 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableGenerator.java @@ -16,7 +16,6 @@ import java.util.Map; import java.util.Properties; -import org.hibernate.HibernateException; import org.hibernate.LockMode; import org.hibernate.LockOptions; import org.hibernate.MappingException; @@ -708,21 +707,6 @@ private ResultSet executeQuery(PreparedStatement ps, SessionEventListenerManager } } - @Override - public String[] sqlCreateStrings(Dialect dialect) throws HibernateException { - return new String[] { - dialect.getCreateTableString() + ' ' + renderedTableName + " ( " - + segmentColumnName + ' ' + dialect.getTypeName( Types.VARCHAR, segmentValueLength, 0, 0 ) + " not null " - + ", " + valueColumnName + ' ' + dialect.getTypeName( Types.BIGINT ) - + ", primary key ( " + segmentColumnName + " ) )" + dialect.getTableTypeString() - }; - } - - @Override - public String[] sqlDropStrings(Dialect dialect) throws HibernateException { - return new String[] { dialect.getDropTableString( renderedTableName ) }; - } - @Override public void registerExportables(Database database) { final Dialect dialect = database.getJdbcEnvironment().getDialect(); diff --git a/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableStructure.java b/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableStructure.java index 5a2d5420df90..38a82558adf7 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableStructure.java +++ b/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableStructure.java @@ -10,10 +10,8 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; -import java.sql.Types; import org.hibernate.AssertionFailure; -import org.hibernate.HibernateException; import org.hibernate.LockMode; import org.hibernate.boot.model.naming.Identifier; import org.hibernate.boot.model.relational.Database; @@ -220,19 +218,6 @@ private ResultSet executeQuery(PreparedStatement ps, SessionEventListenerManager } } - @Override - public String[] sqlCreateStrings(Dialect dialect) throws HibernateException { - return new String[] { - dialect.getCreateTableString() + " " + tableNameText + " ( " + valueColumnNameText + " " + dialect.getTypeName( Types.BIGINT ) + " )", - "insert into " + tableNameText + " values ( " + initialValue + " )" - }; - } - - @Override - public String[] sqlDropStrings(Dialect dialect) throws HibernateException { - return new String[] { dialect.getDropTableString( tableNameText ) }; - } - @Override public boolean isPhysicalSequence() { return false; diff --git a/hibernate-envers/hibernate-envers.gradle b/hibernate-envers/hibernate-envers.gradle index f168ec015af4..9c6f594d2c42 100644 --- a/hibernate-envers/hibernate-envers.gradle +++ b/hibernate-envers/hibernate-envers.gradle @@ -21,6 +21,7 @@ dependencies { testCompile( project( ':hibernate-testing' ) ) testCompile( project( path: ':hibernate-core', configuration: 'tests' ) ) + testCompile( libraries.assertj ) } sourceSets { diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/enhanced/OrderedSequenceStructure.java b/hibernate-envers/src/main/java/org/hibernate/envers/enhanced/OrderedSequenceStructure.java index 4cdfa70e55e0..82c3d26c91a5 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/enhanced/OrderedSequenceStructure.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/enhanced/OrderedSequenceStructure.java @@ -6,7 +6,6 @@ */ package org.hibernate.envers.enhanced; -import org.hibernate.HibernateException; import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject; import org.hibernate.boot.model.relational.Database; import org.hibernate.boot.model.relational.QualifiedName; @@ -36,18 +35,6 @@ public OrderedSequenceStructure( this.sequenceObject = new OrderedSequence(); } - @Override - public String[] sqlCreateStrings(Dialect dialect) throws HibernateException { - // delegate to auxiliary object - return sequenceObject.sqlCreateStrings( dialect ); - } - - @Override - public String[] sqlDropStrings(Dialect dialect) throws HibernateException { - // delegate to auxiliary object - return sequenceObject.sqlDropStrings( dialect ); - } - @Override protected void buildSequence(Database database) { database.addAuxiliaryDatabaseObject( sequenceObject ); diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/reventity/MonotonicRevisionNumberTest.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/reventity/MonotonicRevisionNumberTest.java index 6b9274973d96..e04e094183a5 100644 --- a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/reventity/MonotonicRevisionNumberTest.java +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/reventity/MonotonicRevisionNumberTest.java @@ -6,6 +6,12 @@ */ package org.hibernate.envers.test.integration.reventity; +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.Optional; + +import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject; +import org.hibernate.boot.model.relational.Database; import org.hibernate.dialect.Oracle8iDialect; import org.hibernate.envers.enhanced.OrderedSequenceGenerator; import org.hibernate.envers.enhanced.SequenceIdRevisionEntity; @@ -35,10 +41,16 @@ public void testOracleSequenceOrder() { EntityPersister persister = sessionFactory().getEntityPersister( SequenceIdRevisionEntity.class.getName() ); IdentifierGenerator generator = persister.getIdentifierGenerator(); Assert.assertTrue( OrderedSequenceGenerator.class.isInstance( generator ) ); - OrderedSequenceGenerator seqGenerator = (OrderedSequenceGenerator) generator; + + Database database = metadata().getDatabase(); + Optional sequenceOptional = database.getAuxiliaryDatabaseObjects().stream() + .filter( o -> "REVISION_GENERATOR".equals( o.getExportIdentifier() ) ) + .findFirst(); + assertThat( sequenceOptional ).isPresent(); + String[] sqlCreateStrings = sequenceOptional.get().sqlCreateStrings( database.getDialect() ); Assert.assertTrue( "Oracle sequence needs to be ordered in RAC environment.", - seqGenerator.sqlCreateStrings( getDialect() )[0].toLowerCase().endsWith( " order" ) + sqlCreateStrings[0].toLowerCase().endsWith( " order" ) ); } } From 9a14200ca2028f005cd129989004bfef1e52c843 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Thu, 4 Nov 2021 14:31:04 +0100 Subject: [PATCH 404/644] HHH-14921 Remove unused method PersistentIdentifierGenerator#generatorKey --- .../org/hibernate/id/MultipleHiLoPerTableGenerator.java | 3 --- .../org/hibernate/id/PersistentIdentifierGenerator.java | 8 -------- .../main/java/org/hibernate/id/SequenceGenerator.java | 4 ---- .../hibernate/id/enhanced/SequenceStyleGenerator.java | 9 --------- .../java/org/hibernate/id/enhanced/TableGenerator.java | 5 ----- 5 files changed, 29 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/id/MultipleHiLoPerTableGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/MultipleHiLoPerTableGenerator.java index 074f6084f6e5..3b09e2ce92cc 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/MultipleHiLoPerTableGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/MultipleHiLoPerTableGenerator.java @@ -375,7 +375,4 @@ public void registerExportables(Database database) { } - public Object generatorKey() { - return tableName; - } } diff --git a/hibernate-core/src/main/java/org/hibernate/id/PersistentIdentifierGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/PersistentIdentifierGenerator.java index fa61f015c4a1..4a129711e4ab 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/PersistentIdentifierGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/PersistentIdentifierGenerator.java @@ -58,12 +58,4 @@ public interface PersistentIdentifierGenerator extends IdentifierGenerator { * The key under which to find the {@link org.hibernate.boot.model.naming.ObjectNameNormalizer} in the config param map. */ String IDENTIFIER_NORMALIZER = "identifier_normalizer"; - - /** - * Return a key unique to the underlying database objects. Prevents us from - * trying to create/remove them multiple times. - * - * @return Object an identifying key for this generator - */ - Object generatorKey(); } diff --git a/hibernate-core/src/main/java/org/hibernate/id/SequenceGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/SequenceGenerator.java index a968f1b2f984..636ee383f0c2 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/SequenceGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/SequenceGenerator.java @@ -73,10 +73,6 @@ protected Type getIdentifierType() { return identifierType; } - public Object generatorKey() { - return getSequenceName(); - } - public String getSequenceName() { return sequenceName; } diff --git a/hibernate-core/src/main/java/org/hibernate/id/enhanced/SequenceStyleGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/enhanced/SequenceStyleGenerator.java index ae7bccc19ebc..75fe27ae5ea4 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/enhanced/SequenceStyleGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/enhanced/SequenceStyleGenerator.java @@ -523,15 +523,6 @@ public Serializable generate(SharedSessionContractImplementor session, Object ob return optimizer.generate( databaseStructure.buildCallback( session ) ); } - - // PersistentIdentifierGenerator implementation ~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - @Override - public Object generatorKey() { - return databaseStructure.getName(); - } - - // BulkInsertionCapableIdentifierGenerator implementation ~~~~~~~~~~~~~~~~~ @Override diff --git a/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableGenerator.java index c557d209a973..a80f334037da 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableGenerator.java @@ -248,11 +248,6 @@ public class TableGenerator implements PersistentIdentifierGenerator { private Optimizer optimizer; private long accessCount; - @Override - public Object generatorKey() { - return qualifiedTableName.render(); - } - /** * Type mapping for the identifier. * From 5b83edfd49f8df348b2356978837d44342df5f8f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Thu, 4 Nov 2021 17:55:55 +0100 Subject: [PATCH 405/644] HHH-14921 Delay generation of SQL strings by identifier generators until schema export or session factory creation --- .../relational/AuxiliaryDatabaseObject.java | 34 +++++++- .../SqlStringGenerationContext.java | 48 ++++++++++ .../SqlStringGenerationContextImpl.java | 52 +++++++++++ .../identity/GetGeneratedKeysDelegate.java | 3 +- .../spi/SessionFactoryDelegatingImpl.java | 6 ++ .../engine/spi/SessionFactoryImplementor.java | 3 + .../hql/internal/ast/HqlSqlWalker.java | 2 +- .../id/AbstractPostInsertGenerator.java | 3 +- ...lkInsertionCapableIdentifierGenerator.java | 4 +- ...ompositeNestedGeneratedValueGenerator.java | 21 +++++ .../org/hibernate/id/IdentifierGenerator.java | 11 +++ .../org/hibernate/id/IdentityGenerator.java | 5 +- .../org/hibernate/id/IncrementGenerator.java | 49 ++++++++--- .../id/MultipleHiLoPerTableGenerator.java | 25 +++--- .../id/PostInsertIdentifierGenerator.java | 1 + .../org/hibernate/id/SelectGenerator.java | 5 +- .../org/hibernate/id/SequenceGenerator.java | 28 +++--- .../id/SequenceIdentityGenerator.java | 17 ++-- .../id/enhanced/DatabaseStructure.java | 50 ++++++++++- .../id/enhanced/SequenceStructure.java | 20 +++-- .../id/enhanced/SequenceStyleGenerator.java | 22 +++-- .../hibernate/id/enhanced/TableGenerator.java | 39 +++++---- .../hibernate/id/enhanced/TableStructure.java | 48 +++++----- .../InsertGeneratedIdentifierDelegate.java | 4 +- .../internal/SessionFactoryImpl.java | 11 ++- .../java/org/hibernate/mapping/Component.java | 6 ++ .../java/org/hibernate/mapping/Table.java | 26 ++++-- .../AbstractCollectionPersister.java | 1 + .../entity/AbstractEntityPersister.java | 7 +- .../schema/internal/SchemaDropperImpl.java | 7 +- ...andardAuxiliaryDatabaseObjectExporter.java | 5 +- .../internal/StandardTableExporter.java | 10 ++- .../hibernate/tool/schema/spi/Exporter.java | 1 + .../SequenceHiLoGeneratorNoIncrementTest.java | 1 + .../id/SequenceHiLoGeneratorTest.java | 1 + ...HiloGeneratorWitZeroIncrementSizeTest.java | 1 + .../enhanced/SequenceStyleConfigUnitTest.java | 87 ++++++++++--------- .../NewGeneratorMappingsTest.java | 10 ++- .../id/sequences/HibernateSequenceTest.java | 3 +- .../enhanced/auto/NewGeneratorsTests.java | 4 +- .../enhanced/sequence/BasicSequenceTest.java | 3 +- .../HiLoSequenceMismatchStrategyTest.java | 5 +- .../tck2_2/GeneratedValueTests.java | 22 +++-- .../SchemaUpdateTableBackedSequenceTest.java | 6 +- .../enhanced/OrderedSequenceStructure.java | 18 ++-- 45 files changed, 527 insertions(+), 208 deletions(-) create mode 100644 hibernate-core/src/main/java/org/hibernate/boot/model/relational/SqlStringGenerationContext.java create mode 100644 hibernate-core/src/main/java/org/hibernate/boot/model/relational/internal/SqlStringGenerationContextImpl.java diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/relational/AuxiliaryDatabaseObject.java b/hibernate-core/src/main/java/org/hibernate/boot/model/relational/AuxiliaryDatabaseObject.java index 7434c0772afd..60c54fcb334b 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/relational/AuxiliaryDatabaseObject.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/relational/AuxiliaryDatabaseObject.java @@ -39,14 +39,40 @@ public interface AuxiliaryDatabaseObject extends Exportable, Serializable { */ public boolean beforeTablesOnCreation(); + /** + * Gets the SQL strings for creating the database object. + * + * @param context A context to help generate the SQL creation strings + * + * @return the SQL strings for creating the database object. + */ + default String[] sqlCreateStrings(SqlStringGenerationContext context) { + return sqlCreateStrings( context.getDialect() ); + } + /** * Gets the SQL strings for creating the database object. * * @param dialect The dialect for which to generate the SQL creation strings * * @return the SQL strings for creating the database object. + * @deprecated Implement {@link #sqlCreateStrings(SqlStringGenerationContext)} instead. + */ + @Deprecated + default String[] sqlCreateStrings(Dialect dialect) { + throw new IllegalStateException( this + " does not implement sqlCreateStrings(...)" ); + } + + /** + * Gets the SQL strings for dropping the database object. + * + * @param context A context to help generate the SQL drop strings + * + * @return the SQL strings for dropping the database object. */ - public String[] sqlCreateStrings(Dialect dialect); + default String[] sqlDropStrings(SqlStringGenerationContext context) { + return sqlDropStrings( context.getDialect() ); + } /** * Gets the SQL strings for dropping the database object. @@ -54,8 +80,12 @@ public interface AuxiliaryDatabaseObject extends Exportable, Serializable { * @param dialect The dialect for which to generate the SQL drop strings * * @return the SQL strings for dropping the database object. + * @deprecated Implement {@link #sqlDropStrings(SqlStringGenerationContext)} instead. */ - public String[] sqlDropStrings(Dialect dialect); + @Deprecated + default String[] sqlDropStrings(Dialect dialect) { + throw new IllegalStateException( this + " does not implement sqlDropStrings(...)" ); + } /** * Additional, optional interface for AuxiliaryDatabaseObject that want to allow diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/relational/SqlStringGenerationContext.java b/hibernate-core/src/main/java/org/hibernate/boot/model/relational/SqlStringGenerationContext.java new file mode 100644 index 000000000000..9daa2271a94b --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/relational/SqlStringGenerationContext.java @@ -0,0 +1,48 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.boot.model.relational; + +import org.hibernate.dialect.Dialect; + +/** + * A context provided to methods responsible for generating SQL strings on startup. + */ +public interface SqlStringGenerationContext { + + /** + * @return The database dialect, to generate SQL fragments that are specific to each vendor. + */ + Dialect getDialect(); + + /** + * Render a formatted a table name + * + * @param qualifiedName The table name + * + * @return The formatted name, + */ + String format(QualifiedTableName qualifiedName); + + /** + * Render a formatted sequence name + * + * @param qualifiedName The sequence name + * + * @return The formatted name + */ + String format(QualifiedSequenceName qualifiedName); + + /** + * Render a formatted non-table and non-sequence qualified name + * + * @param qualifiedName The name + * + * @return The formatted name + */ + String format(QualifiedName qualifiedName); + +} diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/relational/internal/SqlStringGenerationContextImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/model/relational/internal/SqlStringGenerationContextImpl.java new file mode 100644 index 000000000000..83b39a0efaee --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/relational/internal/SqlStringGenerationContextImpl.java @@ -0,0 +1,52 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.boot.model.relational.internal; + +import org.hibernate.boot.model.relational.QualifiedName; +import org.hibernate.boot.model.relational.QualifiedSequenceName; +import org.hibernate.boot.model.relational.QualifiedTableName; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; +import org.hibernate.dialect.Dialect; +import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; +import org.hibernate.engine.jdbc.env.spi.QualifiedObjectNameFormatter; + +public class SqlStringGenerationContextImpl + implements SqlStringGenerationContext { + + public static SqlStringGenerationContext forTests(JdbcEnvironment jdbcEnvironment) { + return new SqlStringGenerationContextImpl( jdbcEnvironment ); + } + + private final Dialect dialect; + private final QualifiedObjectNameFormatter qualifiedObjectNameFormatter; + + public SqlStringGenerationContextImpl(JdbcEnvironment jdbcEnvironment) { + this.dialect = jdbcEnvironment.getDialect(); + this.qualifiedObjectNameFormatter = jdbcEnvironment.getQualifiedObjectNameFormatter(); + } + + @Override + public Dialect getDialect() { + return dialect; + } + + @Override + public String format(QualifiedTableName qualifiedName) { + return qualifiedObjectNameFormatter.format( qualifiedName, dialect ); + } + + @Override + public String format(QualifiedSequenceName qualifiedName) { + return qualifiedObjectNameFormatter.format( qualifiedName, dialect ); + } + + @Override + public String format(QualifiedName qualifiedName) { + return qualifiedObjectNameFormatter.format( qualifiedName, dialect ); + } + +} diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/identity/GetGeneratedKeysDelegate.java b/hibernate-core/src/main/java/org/hibernate/dialect/identity/GetGeneratedKeysDelegate.java index 38cc8e323c47..ef4c6e389640 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/identity/GetGeneratedKeysDelegate.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/identity/GetGeneratedKeysDelegate.java @@ -11,6 +11,7 @@ import java.sql.ResultSet; import java.sql.SQLException; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.dialect.Dialect; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.id.IdentifierGeneratorHelper; @@ -37,7 +38,7 @@ public GetGeneratedKeysDelegate(PostInsertIdentityPersister persister, Dialect d } @Override - public IdentifierGeneratingInsert prepareIdentifierGeneratingInsert() { + public IdentifierGeneratingInsert prepareIdentifierGeneratingInsert(SqlStringGenerationContext context) { IdentifierGeneratingInsert insert = new IdentifierGeneratingInsert( dialect ); insert.addIdentityColumn( persister.getRootTableKeyColumnNames()[0] ); return insert; diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryDelegatingImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryDelegatingImpl.java index 349e28f9fce8..e5269956c261 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryDelegatingImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryDelegatingImpl.java @@ -30,6 +30,7 @@ import org.hibernate.StatelessSession; import org.hibernate.StatelessSessionBuilder; import org.hibernate.TypeHelper; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.boot.spi.SessionFactoryOptions; import org.hibernate.cache.spi.CacheImplementor; import org.hibernate.cfg.Settings; @@ -244,6 +245,11 @@ public JdbcServices getJdbcServices() { return delegate.getJdbcServices(); } + @Override + public SqlStringGenerationContext getSqlStringGenerationContext() { + return delegate.getSqlStringGenerationContext(); + } + @Override public Dialect getDialect() { return delegate.getDialect(); diff --git a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryImplementor.java b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryImplementor.java index 0a78018a4f1d..ddbab41b53e1 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/spi/SessionFactoryImplementor.java @@ -21,6 +21,7 @@ import org.hibernate.Session; import org.hibernate.SessionFactory; import org.hibernate.SessionFactoryObserver; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.boot.spi.SessionFactoryOptions; import org.hibernate.cache.spi.CacheImplementor; import org.hibernate.cfg.Settings; @@ -298,6 +299,8 @@ default Dialect getDialect() { return getJdbcServices().getDialect(); } + SqlStringGenerationContext getSqlStringGenerationContext(); + /** * Retrieves the SQLExceptionConverter in effect for this SessionFactory. * diff --git a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/HqlSqlWalker.java b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/HqlSqlWalker.java index 73b7d6afecba..4174070e6fb4 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/HqlSqlWalker.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/internal/ast/HqlSqlWalker.java @@ -897,7 +897,7 @@ protected void postProcessInsert(AST insert) throws SemanticException, QueryExce } final String fragment = capableGenerator.determineBulkInsertionIdentifierGenerationSelectFragment( - sessionFactoryHelper.getFactory().getDialect() + sessionFactoryHelper.getFactory().getSqlStringGenerationContext() ); if ( fragment != null ) { // we got a fragment from the generator, so alter the sql tree... diff --git a/hibernate-core/src/main/java/org/hibernate/id/AbstractPostInsertGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/AbstractPostInsertGenerator.java index ca57bc0dd3c9..1e0ba78e2af1 100755 --- a/hibernate-core/src/main/java/org/hibernate/id/AbstractPostInsertGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/AbstractPostInsertGenerator.java @@ -8,6 +8,7 @@ import java.io.Serializable; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.dialect.Dialect; import org.hibernate.engine.spi.SharedSessionContractImplementor; @@ -29,7 +30,7 @@ public boolean supportsBulkInsertionIdentifierGeneration() { } @Override - public String determineBulkInsertionIdentifierGenerationSelectFragment(Dialect dialect) { + public String determineBulkInsertionIdentifierGenerationSelectFragment(SqlStringGenerationContext context) { return null; } } diff --git a/hibernate-core/src/main/java/org/hibernate/id/BulkInsertionCapableIdentifierGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/BulkInsertionCapableIdentifierGenerator.java index c3baa8b84460..371b8d0f7735 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/BulkInsertionCapableIdentifierGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/BulkInsertionCapableIdentifierGenerator.java @@ -6,7 +6,7 @@ */ package org.hibernate.id; -import org.hibernate.dialect.Dialect; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; /** * Specialized contract for {@link IdentifierGenerator} implementations capable of being used in conjunction @@ -32,5 +32,5 @@ public interface BulkInsertionCapableIdentifierGenerator extends IdentifierGener * * @return The identifier value generation fragment (SQL). {@code null} indicates that no fragment is needed. */ - public String determineBulkInsertionIdentifierGenerationSelectFragment(Dialect dialect); + public String determineBulkInsertionIdentifierGenerationSelectFragment(SqlStringGenerationContext context); } diff --git a/hibernate-core/src/main/java/org/hibernate/id/CompositeNestedGeneratedValueGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/CompositeNestedGeneratedValueGenerator.java index 4b45876a8e73..dd730989aea5 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/CompositeNestedGeneratedValueGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/CompositeNestedGeneratedValueGenerator.java @@ -9,11 +9,15 @@ import java.io.Serializable; import java.util.ArrayList; import java.util.List; +import java.util.Properties; import org.hibernate.HibernateException; import org.hibernate.boot.model.relational.Database; import org.hibernate.boot.model.relational.ExportableProducer; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.engine.spi.SharedSessionContractImplementor; +import org.hibernate.service.ServiceRegistry; +import org.hibernate.type.Type; /** * For composite identifiers, defines a number of "nested" generations that @@ -67,6 +71,16 @@ public interface GenerationContextLocator { * determined {@link GenerationContextLocator#locateGenerationContext context} */ public interface GenerationPlan extends ExportableProducer { + + /** + * Initializes this instance, in particular pre-generates SQL as necessary. + *

    + * This method is called after {@link #registerExportables(Database)}, before first use. + * + * @param context A context to help generate SQL strings + */ + void initialize(SqlStringGenerationContext context); + /** * Execute the value generation. * @@ -106,4 +120,11 @@ public void registerExportables(Database database) { plan.registerExportables( database ); } } + + @Override + public void initialize(SqlStringGenerationContext context) { + for (GenerationPlan plan : generationPlans) { + plan.initialize( context ); + } + } } diff --git a/hibernate-core/src/main/java/org/hibernate/id/IdentifierGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/IdentifierGenerator.java index ca3da8b32783..41207aab4e7f 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/IdentifierGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/IdentifierGenerator.java @@ -14,6 +14,7 @@ import org.hibernate.MappingException; import org.hibernate.boot.model.relational.Database; import org.hibernate.boot.model.relational.ExportableProducer; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.service.ServiceRegistry; import org.hibernate.type.Type; @@ -79,6 +80,16 @@ default void configure(Type type, Properties params, ServiceRegistry serviceRegi default void registerExportables(Database database) { } + /** + * Initializes this instance, in particular pre-generates SQL as necessary. + *

    + * This method is called after {@link #registerExportables(Database)}, before first use. + * + * @param context A context to help generate SQL strings + */ + default void initialize(SqlStringGenerationContext context) { + } + /** * Generate a new identifier. * diff --git a/hibernate-core/src/main/java/org/hibernate/id/IdentityGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/IdentityGenerator.java index cb42f197b7d5..5b3e307c8135 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/IdentityGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/IdentityGenerator.java @@ -13,6 +13,7 @@ import org.hibernate.AssertionFailure; import org.hibernate.HibernateException; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.dialect.Dialect; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.id.insert.AbstractReturningDelegate; @@ -67,7 +68,7 @@ public InsertSelectDelegate(PostInsertIdentityPersister persister, Dialect diale } @Override - public IdentifierGeneratingInsert prepareIdentifierGeneratingInsert() { + public IdentifierGeneratingInsert prepareIdentifierGeneratingInsert(SqlStringGenerationContext context) { InsertSelectIdentityInsert insert = new InsertSelectIdentityInsert( dialect ); insert.addIdentityColumn( persister.getRootTableKeyColumnNames()[0] ); return insert; @@ -120,7 +121,7 @@ public BasicDelegate(PostInsertIdentityPersister persister, Dialect dialect) { } @Override - public IdentifierGeneratingInsert prepareIdentifierGeneratingInsert() { + public IdentifierGeneratingInsert prepareIdentifierGeneratingInsert(SqlStringGenerationContext context) { IdentifierGeneratingInsert insert = new IdentifierGeneratingInsert( dialect ); insert.addIdentityColumn( persister.getRootTableKeyColumnNames()[0] ); return insert; diff --git a/hibernate-core/src/main/java/org/hibernate/id/IncrementGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/IncrementGenerator.java index 6f2261a4deaf..4a3ca87b6549 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/IncrementGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/IncrementGenerator.java @@ -10,11 +10,17 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; +import java.util.ArrayList; +import java.util.List; import java.util.Properties; import org.hibernate.HibernateException; import org.hibernate.MappingException; +import org.hibernate.boot.model.naming.Identifier; import org.hibernate.boot.model.naming.ObjectNameNormalizer; +import org.hibernate.boot.model.relational.QualifiedTableName; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; +import org.hibernate.engine.jdbc.env.spi.IdentifierHelper; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.internal.CoreLogging; @@ -42,6 +48,8 @@ public class IncrementGenerator implements IdentifierGenerator { private static final CoreMessageLogger LOG = CoreLogging.messageLogger( IncrementGenerator.class ); private Class returnClass; + private String column; + private List physicalTableNames; private String sql; private IntegralDataTypeHolder previousValueHolder; @@ -62,17 +70,13 @@ public void configure(Type type, Properties params, ServiceRegistry serviceRegis final ObjectNameNormalizer normalizer = (ObjectNameNormalizer) params.get( PersistentIdentifierGenerator.IDENTIFIER_NORMALIZER ); - String column = params.getProperty( "column" ); + column = params.getProperty( "column" ); if ( column == null ) { column = params.getProperty( PersistentIdentifierGenerator.PK ); } column = normalizer.normalizeIdentifierQuoting( column ).render( jdbcEnvironment.getDialect() ); - String tableList = params.getProperty( "tables" ); - if ( tableList == null ) { - tableList = params.getProperty( PersistentIdentifierGenerator.TABLES ); - } - String[] tables = StringHelper.split( ", ", tableList ); + IdentifierHelper identifierHelper = jdbcEnvironment.getIdentifierHelper(); final String schema = normalizer.toDatabaseIdentifierText( params.getProperty( PersistentIdentifierGenerator.SCHEMA ) @@ -81,23 +85,40 @@ public void configure(Type type, Properties params, ServiceRegistry serviceRegis params.getProperty( PersistentIdentifierGenerator.CATALOG ) ); + String tableList = params.getProperty( "tables" ); + if ( tableList == null ) { + tableList = params.getProperty( PersistentIdentifierGenerator.TABLES ); + } + physicalTableNames = new ArrayList<>(); + for ( String tableName : StringHelper.split( ", ", tableList ) ) { + physicalTableNames.add( new QualifiedTableName( identifierHelper.toIdentifier( catalog ), + identifierHelper.toIdentifier( schema ), identifierHelper.toIdentifier( tableName ) ) ); + } + } + + @Override + public void initialize(SqlStringGenerationContext context) { StringBuilder buf = new StringBuilder(); - for ( int i = 0; i < tables.length; i++ ) { - final String tableName = normalizer.toDatabaseIdentifierText( tables[i] ); - if ( tables.length > 1 ) { + for ( int i = 0; i < physicalTableNames.size(); i++ ) { + final String tableName = context.format( physicalTableNames.get( i ) ); + if ( physicalTableNames.size() > 1 ) { buf.append( "select max(" ).append( column ).append( ") as mx from " ); } - buf.append( Table.qualify( catalog, schema, tableName ) ); - if ( i < tables.length - 1 ) { + buf.append( tableName ); + if ( i < physicalTableNames.size() - 1 ) { buf.append( " union " ); } } - if ( tables.length > 1 ) { + String maxColumn; + if ( physicalTableNames.size() > 1 ) { buf.insert( 0, "( " ).append( " ) ids_" ); - column = "ids_.mx"; + maxColumn = "ids_.mx"; + } + else { + maxColumn = column; } - sql = "select max(" + column + ") from " + buf.toString(); + sql = "select max(" + maxColumn + ") from " + buf.toString(); } private void initializePreviousValueHolder(SharedSessionContractImplementor session) { diff --git a/hibernate-core/src/main/java/org/hibernate/id/MultipleHiLoPerTableGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/MultipleHiLoPerTableGenerator.java index 3b09e2ce92cc..ea617988cfdb 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/MultipleHiLoPerTableGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/MultipleHiLoPerTableGenerator.java @@ -21,6 +21,7 @@ import org.hibernate.boot.model.relational.Namespace; import org.hibernate.boot.model.relational.QualifiedName; import org.hibernate.boot.model.relational.QualifiedNameParser; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.engine.jdbc.internal.FormatStyle; import org.hibernate.engine.jdbc.spi.JdbcServices; @@ -91,7 +92,7 @@ public class MultipleHiLoPerTableGenerator implements PersistentIdentifierGenera private static final String DEFAULT_VALUE_COLUMN = "sequence_next_hi_value"; private QualifiedName qualifiedTableName; - private String tableName; + private QualifiedName physicalTableName; private String segmentColumnName; private String segmentName; private String valueColumnName; @@ -175,7 +176,7 @@ public IntegralDataTypeHolder execute(Connection connection) throws SQLException rows = executeUpdate( updatePreparedStatement, statsCollector ); } catch (SQLException sqle) { - LOG.error( LOG.unableToUpdateHiValue( tableName ), sqle ); + LOG.error( LOG.unableToUpdateHiValue( physicalTableName.render() ), sqle ); throw sqle; } finally { @@ -340,23 +341,23 @@ public void registerExportables(Database database) { table.addColumn( valueColumn ); } - final JdbcEnvironment jdbcEnvironment = database.getJdbcEnvironment(); - // allow physical naming strategies a chance to kick in - tableName = jdbcEnvironment.getQualifiedObjectNameFormatter().format( - table.getQualifiedTableName(), - jdbcEnvironment.getDialect() - ); + physicalTableName = table.getQualifiedTableName(); + } + + @Override + public void initialize(SqlStringGenerationContext context) { + String formattedPhysicalTableName = context.format( physicalTableName ); query = "select " + valueColumnName + " from " + - jdbcEnvironment.getDialect().appendLockHint( LockMode.PESSIMISTIC_WRITE, tableName ) + + context.getDialect().appendLockHint( LockMode.PESSIMISTIC_WRITE, formattedPhysicalTableName ) + " where " + segmentColumnName + " = '" + segmentName + "'" + - jdbcEnvironment.getDialect().getForUpdateString(); + context.getDialect().getForUpdateString(); update = "update " + - tableName + + formattedPhysicalTableName + " set " + valueColumnName + " = ? where " + @@ -367,7 +368,7 @@ public void registerExportables(Database database) { segmentName + "'"; - insert = "insert into " + tableName + + insert = "insert into " + formattedPhysicalTableName + "(" + segmentColumnName + ", " + valueColumnName + ") " + "values('" + segmentName + "', ?)"; diff --git a/hibernate-core/src/main/java/org/hibernate/id/PostInsertIdentifierGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/PostInsertIdentifierGenerator.java index d23d86f2386f..8fc44924aafa 100755 --- a/hibernate-core/src/main/java/org/hibernate/id/PostInsertIdentifierGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/PostInsertIdentifierGenerator.java @@ -7,6 +7,7 @@ package org.hibernate.id; import org.hibernate.HibernateException; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.dialect.Dialect; import org.hibernate.id.insert.InsertGeneratedIdentifierDelegate; diff --git a/hibernate-core/src/main/java/org/hibernate/id/SelectGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/SelectGenerator.java index 40c0b0eb667d..76925c9d2efa 100755 --- a/hibernate-core/src/main/java/org/hibernate/id/SelectGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/SelectGenerator.java @@ -14,6 +14,7 @@ import org.hibernate.HibernateException; import org.hibernate.MappingException; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.dialect.Dialect; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.id.insert.AbstractSelectingDelegate; @@ -39,6 +40,7 @@ public void configure(Type type, Properties params, ServiceRegistry serviceRegis uniqueKeyPropertyName = params.getProperty( "key" ); } + @Override public InsertGeneratedIdentifierDelegate getInsertGeneratedIdentifierDelegate( PostInsertIdentityPersister persister, Dialect dialect, @@ -102,7 +104,8 @@ private SelectGeneratorDelegate( idType = persister.getIdentifierType(); } - public IdentifierGeneratingInsert prepareIdentifierGeneratingInsert() { + @Override + public IdentifierGeneratingInsert prepareIdentifierGeneratingInsert(SqlStringGenerationContext context) { return new IdentifierGeneratingInsert( dialect ); } diff --git a/hibernate-core/src/main/java/org/hibernate/id/SequenceGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/SequenceGenerator.java index 636ee383f0c2..4058c906f2b4 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/SequenceGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/SequenceGenerator.java @@ -12,7 +12,6 @@ import java.sql.SQLException; import java.util.Properties; -import org.hibernate.HibernateException; import org.hibernate.MappingException; import org.hibernate.boot.model.naming.ObjectNameNormalizer; import org.hibernate.boot.model.relational.Database; @@ -20,8 +19,7 @@ import org.hibernate.boot.model.relational.QualifiedName; import org.hibernate.boot.model.relational.QualifiedNameParser; import org.hibernate.boot.model.relational.Sequence; -import org.hibernate.dialect.Dialect; -import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.internal.log.DeprecationLogger; import org.hibernate.internal.util.config.ConfigurationHelper; @@ -65,7 +63,7 @@ public class SequenceGenerator public static final String PARAMETERS = "parameters"; private QualifiedName logicalQualifiedSequenceName; - private String sequenceName; + private QualifiedName physicalSequenceName; private Type identifierType; private String sql; @@ -73,8 +71,8 @@ protected Type getIdentifierType() { return identifierType; } - public String getSequenceName() { - return sequenceName; + public QualifiedName getPhysicalSequenceName() { + return physicalSequenceName; } @Override @@ -146,8 +144,8 @@ public boolean supportsBulkInsertionIdentifierGeneration() { } @Override - public String determineBulkInsertionIdentifierGenerationSelectFragment(Dialect dialect) { - return dialect.getSelectSequenceNextValString( getSequenceName() ); + public String determineBulkInsertionIdentifierGenerationSelectFragment(SqlStringGenerationContext context) { + return context.getDialect().getSelectSequenceNextValString( context.format( getPhysicalSequenceName() ) ); } @Override @@ -167,14 +165,12 @@ public void registerExportables(Database database) { 1 ); } + this.physicalSequenceName = sequence.getName(); + } - final JdbcEnvironment jdbcEnvironment = database.getJdbcEnvironment(); - final Dialect dialect = jdbcEnvironment.getDialect(); - - this.sequenceName = jdbcEnvironment.getQualifiedObjectNameFormatter().format( - sequence.getName(), - dialect - ); - this.sql = jdbcEnvironment.getDialect().getSequenceNextValString( sequenceName ); + @Override + public void initialize(SqlStringGenerationContext context) { + String formattedPhysicalSequenceName = context.format( physicalSequenceName ); + this.sql = context.getDialect().getSequenceNextValString( formattedPhysicalSequenceName ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/id/SequenceIdentityGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/SequenceIdentityGenerator.java index b6ff0c2e3c7b..86d48a4a729e 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/SequenceIdentityGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/SequenceIdentityGenerator.java @@ -13,6 +13,8 @@ import org.hibernate.HibernateException; import org.hibernate.MappingException; +import org.hibernate.boot.model.relational.QualifiedName; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.dialect.Dialect; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.id.insert.AbstractReturningDelegate; @@ -55,7 +57,7 @@ public InsertGeneratedIdentifierDelegate getInsertGeneratedIdentifierDelegate( PostInsertIdentityPersister persister, Dialect dialect, boolean isGetGeneratedKeysEnabled) throws HibernateException { - return new Delegate( persister, dialect, getSequenceName() ); + return new Delegate( persister, getPhysicalSequenceName() ); } @Override @@ -64,22 +66,23 @@ public void configure(Type type, Properties params, ServiceRegistry serviceRegis } public static class Delegate extends AbstractReturningDelegate { - private final Dialect dialect; - private final String sequenceNextValFragment; + private final QualifiedName physicalSequenceName; private final String[] keyColumns; - public Delegate(PostInsertIdentityPersister persister, Dialect dialect, String sequenceName) { + public Delegate(PostInsertIdentityPersister persister, QualifiedName physicalSequenceName) { super( persister ); - this.dialect = dialect; - this.sequenceNextValFragment = dialect.getSelectSequenceNextValString( sequenceName ); + this.physicalSequenceName = physicalSequenceName; this.keyColumns = getPersister().getRootTableKeyColumnNames(); if ( keyColumns.length > 1 ) { throw new HibernateException( "sequence-identity generator cannot be used with with multi-column keys" ); } } - public IdentifierGeneratingInsert prepareIdentifierGeneratingInsert() { + @Override + public IdentifierGeneratingInsert prepareIdentifierGeneratingInsert(SqlStringGenerationContext context) { + Dialect dialect = context.getDialect(); NoCommentsInsert insert = new NoCommentsInsert( dialect ); + String sequenceNextValFragment = dialect.getSelectSequenceNextValString( context.format( physicalSequenceName ) ); insert.addColumn( getPersister().getRootTableKeyColumnNames()[0], sequenceNextValFragment ); return insert; } diff --git a/hibernate-core/src/main/java/org/hibernate/id/enhanced/DatabaseStructure.java b/hibernate-core/src/main/java/org/hibernate/id/enhanced/DatabaseStructure.java index dcb907e14fde..edbf54eb08db 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/enhanced/DatabaseStructure.java +++ b/hibernate-core/src/main/java/org/hibernate/id/enhanced/DatabaseStructure.java @@ -6,7 +6,10 @@ */ package org.hibernate.id.enhanced; +import org.hibernate.boot.model.relational.Database; import org.hibernate.boot.model.relational.ExportableProducer; +import org.hibernate.boot.model.relational.QualifiedName; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.engine.spi.SharedSessionContractImplementor; /** @@ -17,10 +20,14 @@ */ public interface DatabaseStructure extends ExportableProducer { /** - * The name of the database structure (table or sequence). + * The physical name of the database structure (table or sequence). + *

    + * Only available after {@link #registerExportables(Database)} + * has been called. + * * @return The structure name. */ - String getName(); + QualifiedName getPhysicalName(); /** * How many times has this structure been accessed through this reference? @@ -54,8 +61,45 @@ public interface DatabaseStructure extends ExportableProducer { * but before first use. * * @param optimizer The optimizer being applied to the generator. + * + * @deprecated Use {@link #configure(Optimizer)} instead. + */ + @Deprecated + default void prepare(Optimizer optimizer) { + } + + /** + * Configures this structure with the given arguments. + *

    + * Called just after instantiation, before {@link #initialize(SqlStringGenerationContext)} + * + * @param optimizer The optimizer being applied to the generator. + */ + default void configure(Optimizer optimizer) { + prepare( optimizer ); + } + + /** + * Register database objects involved in this structure, e.g. sequences, tables, etc. + *

    + * This method is called just once, after {@link #configure(Optimizer)}, + * but before {@link #initialize(SqlStringGenerationContext)}. + * + * @param database The database instance + */ + @Override + void registerExportables(Database database); + + /** + * Initializes this structure, in particular pre-generates SQL as necessary. + *

    + * This method is called just once, after {@link #registerExportables(Database)}, + * before first use. + * + * @param context A context to help generate SQL strings */ - void prepare(Optimizer optimizer); + default void initialize(SqlStringGenerationContext context) { + } /** * Is the structure physically a sequence? diff --git a/hibernate-core/src/main/java/org/hibernate/id/enhanced/SequenceStructure.java b/hibernate-core/src/main/java/org/hibernate/id/enhanced/SequenceStructure.java index ed0e9be86c40..330f6a6577ec 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/enhanced/SequenceStructure.java +++ b/hibernate-core/src/main/java/org/hibernate/id/enhanced/SequenceStructure.java @@ -15,6 +15,7 @@ import org.hibernate.boot.model.relational.Namespace; import org.hibernate.boot.model.relational.QualifiedName; import org.hibernate.boot.model.relational.Sequence; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.engine.spi.SharedSessionContractImplementor; import org.hibernate.id.IdentifierGeneratorHelper; @@ -42,7 +43,7 @@ public class SequenceStructure implements DatabaseStructure { private String sql; private boolean applyIncrementSizeToSourceValues; private int accessCounter; - protected String sequenceName; + protected QualifiedName physicalSequenceName; public SequenceStructure( JdbcEnvironment jdbcEnvironment, @@ -58,8 +59,8 @@ public SequenceStructure( } @Override - public String getName() { - return sequenceName; + public QualifiedName getPhysicalName() { + return physicalSequenceName; } @Override @@ -132,14 +133,18 @@ public String getTenantIdentifier() { } @Override - public void prepare(Optimizer optimizer) { + public void configure(Optimizer optimizer) { applyIncrementSizeToSourceValues = optimizer.applyIncrementSizeToSourceValues(); } @Override public void registerExportables(Database database) { buildSequence( database ); - this.sql = database.getJdbcEnvironment().getDialect().getSequenceNextValString( sequenceName ); + } + + @Override + public void initialize(SqlStringGenerationContext context) { + this.sql = context.getDialect().getSequenceNextValString( context.format( physicalSequenceName ) ); } @Override @@ -170,9 +175,6 @@ protected void buildSequence(Database database) { sequence = namespace.createSequence( logicalQualifiedSequenceName.getObjectName(), initialValue, sourceIncrementSize ); } - this.sequenceName = database.getJdbcEnvironment().getQualifiedObjectNameFormatter().format( - sequence.getName(), - database.getJdbcEnvironment().getDialect() - ); + this.physicalSequenceName = sequence.getName(); } } diff --git a/hibernate-core/src/main/java/org/hibernate/id/enhanced/SequenceStyleGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/enhanced/SequenceStyleGenerator.java index 75fe27ae5ea4..5f15d73fad06 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/enhanced/SequenceStyleGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/enhanced/SequenceStyleGenerator.java @@ -16,6 +16,7 @@ import org.hibernate.boot.model.relational.Database; import org.hibernate.boot.model.relational.QualifiedName; import org.hibernate.boot.model.relational.QualifiedNameParser; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.cfg.AvailableSettings; import org.hibernate.dialect.Dialect; import org.hibernate.engine.config.spi.ConfigurationService; @@ -297,7 +298,17 @@ public void configure(Type type, Properties params, ServiceRegistry serviceRegis incrementSize, ConfigurationHelper.getInt( INITIAL_PARAM, params, -1 ) ); - this.databaseStructure.prepare( optimizer ); + this.databaseStructure.configure( optimizer ); + } + + @Override + public void registerExportables(Database database) { + databaseStructure.registerExportables( database ); + } + + @Override + public void initialize(SqlStringGenerationContext context) { + this.databaseStructure.initialize( context ); } /** @@ -535,13 +546,8 @@ public boolean supportsBulkInsertionIdentifierGeneration() { } @Override - public String determineBulkInsertionIdentifierGenerationSelectFragment(Dialect dialect) { - return dialect.getSelectSequenceNextValString( getDatabaseStructure().getName() ); - } - - @Override - public void registerExportables(Database database) { - databaseStructure.registerExportables( database ); + public String determineBulkInsertionIdentifierGenerationSelectFragment(SqlStringGenerationContext context) { + return context.getDialect().getSelectSequenceNextValString( context.format( getDatabaseStructure().getPhysicalName() ) ); } /** diff --git a/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableGenerator.java index a80f334037da..509fc4cc5cd1 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableGenerator.java @@ -25,6 +25,7 @@ import org.hibernate.boot.model.relational.Namespace; import org.hibernate.boot.model.relational.QualifiedName; import org.hibernate.boot.model.relational.QualifiedNameParser; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.cfg.AvailableSettings; import org.hibernate.dialect.Dialect; import org.hibernate.engine.config.spi.ConfigurationService; @@ -231,7 +232,7 @@ public class TableGenerator implements PersistentIdentifierGenerator { private Type identifierType; private QualifiedName qualifiedTableName; - private String renderedTableName; + private QualifiedName physicalTableName; private String segmentColumnName; private String segmentValue; @@ -518,30 +519,31 @@ protected int determineIncrementSize(Properties params) { } @SuppressWarnings({"unchecked", "WeakerAccess"}) - protected String buildSelectQuery(Dialect dialect) { + protected String buildSelectQuery(String formattedPhysicalTableName, SqlStringGenerationContext context) { final String alias = "tbl"; final String query = "select " + StringHelper.qualify( alias, valueColumnName ) + - " from " + renderedTableName + ' ' + alias + + " from " + formattedPhysicalTableName + ' ' + alias + " where " + StringHelper.qualify( alias, segmentColumnName ) + "=?"; final LockOptions lockOptions = new LockOptions( LockMode.PESSIMISTIC_WRITE ); lockOptions.setAliasSpecificLockMode( alias, LockMode.PESSIMISTIC_WRITE ); final Map updateTargetColumnsMap = Collections.singletonMap( alias, new String[] { valueColumnName } ); - return dialect.applyLocksToSql( query, lockOptions, updateTargetColumnsMap ); + return context.getDialect().applyLocksToSql( query, lockOptions, updateTargetColumnsMap ); } @SuppressWarnings("WeakerAccess") - protected String buildUpdateQuery() { - return "update " + renderedTableName + + protected String buildUpdateQuery(String formattedPhysicalTableName, SqlStringGenerationContext context) { + return "update " + formattedPhysicalTableName + " set " + valueColumnName + "=? " + " where " + valueColumnName + "=? and " + segmentColumnName + "=?"; } @SuppressWarnings("WeakerAccess") - protected String buildInsertQuery() { - return "insert into " + renderedTableName + " (" + segmentColumnName + ", " + valueColumnName + ") " + " values (?,?)"; + protected String buildInsertQuery(String formattedPhysicalTableName, SqlStringGenerationContext context) { + return "insert into " + formattedPhysicalTableName + " (" + segmentColumnName + ", " + valueColumnName + ") " + " values (?,?)"; } - protected InitCommand generateInsertInitCommand() { + protected InitCommand generateInsertInitCommand(SqlStringGenerationContext context) { + String renderedTableName = context.format( physicalTableName ); int value = initialValue; if ( storeLastUsedValue ) { value = initialValue - 1; @@ -639,7 +641,7 @@ public IntegralDataTypeHolder execute(Connection connection) throws SQLException rows = executeUpdate( updatePS, statsCollector ); } catch (SQLException e) { - LOG.unableToUpdateQueryHiValue( renderedTableName, e ); + LOG.unableToUpdateQueryHiValue( physicalTableName.render(), e ); throw e; } } @@ -740,14 +742,15 @@ public void registerExportables(Database database) { } // allow physical naming strategies a chance to kick in - this.renderedTableName = database.getJdbcEnvironment().getQualifiedObjectNameFormatter().format( - table.getQualifiedTableName(), - dialect - ); - table.addInitCommand( generateInsertInitCommand() ); + this.physicalTableName = table.getQualifiedTableName(); + table.addInitCommand( this::generateInsertInitCommand ); + } - this.selectQuery = buildSelectQuery( dialect ); - this.updateQuery = buildUpdateQuery(); - this.insertQuery = buildInsertQuery(); + @Override + public void initialize(SqlStringGenerationContext context) { + String formattedPhysicalTableName = context.format( physicalTableName ); + this.selectQuery = buildSelectQuery( formattedPhysicalTableName, context ); + this.updateQuery = buildUpdateQuery( formattedPhysicalTableName, context ); + this.insertQuery = buildInsertQuery( formattedPhysicalTableName, context ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableStructure.java b/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableStructure.java index 38a82558adf7..17c44e9002b4 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableStructure.java +++ b/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableStructure.java @@ -18,6 +18,7 @@ import org.hibernate.boot.model.relational.InitCommand; import org.hibernate.boot.model.relational.Namespace; import org.hibernate.boot.model.relational.QualifiedName; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.engine.jdbc.internal.FormatStyle; @@ -53,7 +54,7 @@ public class TableStructure implements DatabaseStructure { private final int incrementSize; private final Class numberType; - private String tableNameText; + private QualifiedName physicalTableName; private String valueColumnNameText; private String selectQuery; @@ -78,8 +79,8 @@ public TableStructure( } @Override - public String getName() { - return tableNameText; + public QualifiedName getPhysicalName() { + return physicalTableName; } @Override @@ -135,7 +136,7 @@ public IntegralDataTypeHolder execute(Connection connection) throws SQLException )) { final ResultSet selectRS = executeQuery( selectStatement, statsCollector ); if ( !selectRS.next() ) { - final String err = "could not read a hi value - you need to populate the table: " + tableNameText; + final String err = "could not read a hi value - you need to populate the table: " + physicalTableName; LOG.error( err ); throw new IdentifierGenerationException( err ); } @@ -161,7 +162,7 @@ public IntegralDataTypeHolder execute(Connection connection) throws SQLException rows = executeUpdate( updatePS, statsCollector ); } catch (SQLException e) { - LOG.unableToUpdateQueryHiValue( tableNameText, e ); + LOG.unableToUpdateQueryHiValue( physicalTableName.render(), e ); throw e; } } while ( rows == 0 ); @@ -239,22 +240,9 @@ public void registerExportables(Database database) { table = namespace.createTable( logicalQualifiedTableName.getObjectName(), false ); tableCreated = true; } + this.physicalTableName = table.getQualifiedTableName(); - this.tableNameText = jdbcEnvironment.getQualifiedObjectNameFormatter().format( - table.getQualifiedTableName(), - dialect - ); - - this.valueColumnNameText = logicalValueColumnNameIdentifier.render( dialect ); - - - this.selectQuery = "select " + valueColumnNameText + " as id_val" + - " from " + dialect.appendLockHint( LockMode.PESSIMISTIC_WRITE, tableNameText ) + - dialect.getForUpdateString(); - - this.updateQuery = "update " + tableNameText + - " set " + valueColumnNameText + "= ?" + - " where " + valueColumnNameText + "=?"; + valueColumnNameText = logicalValueColumnNameIdentifier.render( dialect ); if ( tableCreated ) { ExportableColumn valueColumn = new ExportableColumn( database, @@ -265,9 +253,23 @@ public void registerExportables(Database database) { table.addColumn( valueColumn ); - table.addInitCommand( - new InitCommand( "insert into " + tableNameText + " values ( " + initialValue + " )" ) - ); + table.addInitCommand( context -> new InitCommand( "insert into " + + context.format( physicalTableName ) + " values ( " + initialValue + " )" ) ); } } + + @Override + public void initialize(SqlStringGenerationContext context) { + Dialect dialect = context.getDialect(); + + String formattedPhysicalTableName = context.format( physicalTableName ); + + this.selectQuery = "select " + valueColumnNameText + " as id_val" + + " from " + dialect.appendLockHint( LockMode.PESSIMISTIC_WRITE, formattedPhysicalTableName ) + + dialect.getForUpdateString(); + + this.updateQuery = "update " + formattedPhysicalTableName + + " set " + valueColumnNameText + "= ?" + + " where " + valueColumnNameText + "=?"; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/id/insert/InsertGeneratedIdentifierDelegate.java b/hibernate-core/src/main/java/org/hibernate/id/insert/InsertGeneratedIdentifierDelegate.java index 98da2c2b370b..564a7cad92f3 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/insert/InsertGeneratedIdentifierDelegate.java +++ b/hibernate-core/src/main/java/org/hibernate/id/insert/InsertGeneratedIdentifierDelegate.java @@ -8,6 +8,7 @@ import java.io.Serializable; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.engine.spi.SharedSessionContractImplementor; /** @@ -25,9 +26,10 @@ public interface InsertGeneratedIdentifierDelegate { * Build a {@link org.hibernate.sql.Insert} specific to the delegate's mode * of handling generated key values. * + * @param context A context to help generate SQL strings * @return The insert object. */ - IdentifierGeneratingInsert prepareIdentifierGeneratingInsert(); + IdentifierGeneratingInsert prepareIdentifierGeneratingInsert(SqlStringGenerationContext context); /** * Perform the indicated insert SQL statement and determine the identifier value diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java index 87d51e7c514c..b404b1c7e022 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java @@ -18,7 +18,6 @@ import java.util.Map; import java.util.Set; import java.util.TimeZone; -import java.util.function.Function; import java.util.function.Supplier; import javax.naming.Reference; import javax.naming.StringRefAddr; @@ -49,6 +48,8 @@ import org.hibernate.TypeHelper; import org.hibernate.boot.cfgxml.spi.CfgXmlAccessService; import org.hibernate.boot.cfgxml.spi.LoadedConfig; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; +import org.hibernate.boot.model.relational.internal.SqlStringGenerationContextImpl; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.spi.MetadataImplementor; import org.hibernate.boot.spi.SessionFactoryOptions; @@ -171,6 +172,7 @@ public class SessionFactoryImpl implements SessionFactoryImplementor { private final transient SessionFactoryServiceRegistry serviceRegistry; private final transient EventEngine eventEngine; private final transient JdbcServices jdbcServices; + private final transient SqlStringGenerationContext sqlStringGenerationContext; private final transient SQLFunctionRegistry sqlFunctionRegistry; @@ -231,6 +233,7 @@ public SessionFactoryImpl( this.uuid = options.getUuid(); jdbcServices = serviceRegistry.getService( JdbcServices.class ); + sqlStringGenerationContext = new SqlStringGenerationContextImpl( jdbcServices.getJdbcEnvironment() ); this.properties = new HashMap<>(); this.properties.putAll( serviceRegistry.getService( ConfigurationService.class ).getSettings() ); @@ -302,6 +305,7 @@ public void sessionFactoryClosed(SessionFactory factory) { settings.getDefaultSchemaName(), (RootClass) model ); + generator.initialize( sqlStringGenerationContext ); identifierGenerators.put( model.getEntityName(), generator ); } ); metadata.validate(); @@ -560,6 +564,11 @@ public JdbcServices getJdbcServices() { return jdbcServices; } + @Override + public SqlStringGenerationContext getSqlStringGenerationContext() { + return sqlStringGenerationContext; + } + public IdentifierGeneratorFactory getIdentifierGeneratorFactory() { return null; } diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Component.java b/hibernate-core/src/main/java/org/hibernate/mapping/Component.java index 105d59f50b84..70e8d878afb7 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Component.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Component.java @@ -16,6 +16,7 @@ import org.hibernate.EntityMode; import org.hibernate.MappingException; import org.hibernate.boot.model.relational.Database; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; import org.hibernate.boot.spi.MetadataBuildingContext; @@ -513,6 +514,11 @@ public void execute(SharedSessionContractImplementor session, Object incomingObj public void registerExportables(Database database) { subGenerator.registerExportables( database ); } + + @Override + public void initialize(SqlStringGenerationContext context) { + subGenerator.initialize( context ); + } } } diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Table.java b/hibernate-core/src/main/java/org/hibernate/mapping/Table.java index afe61a784ffb..2c5ae2f33f42 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Table.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Table.java @@ -16,6 +16,7 @@ import java.util.Locale; import java.util.Map; import java.util.Objects; +import java.util.function.Function; import org.hibernate.HibernateException; import org.hibernate.MappingException; @@ -25,6 +26,7 @@ import org.hibernate.boot.model.relational.InitCommand; import org.hibernate.boot.model.relational.Namespace; import org.hibernate.boot.model.relational.QualifiedTableName; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.engine.jdbc.env.spi.QualifiedObjectNameFormatter; @@ -67,7 +69,7 @@ public class Table implements RelationalModel, Serializable, Exportable { private boolean hasDenormalizedTables; private String comment; - private List initCommands; + private List> initCommandProducers; public Table() { } @@ -897,18 +899,30 @@ public String toString() { } } + /** + * @deprecated Use {@link #addInitCommand(Function)} instead. + */ + @Deprecated public void addInitCommand(InitCommand command) { - if ( initCommands == null ) { - initCommands = new ArrayList<>(); + addInitCommand( ignored -> command ); + } + + public void addInitCommand(Function commandProducer) { + if ( initCommandProducers == null ) { + initCommandProducers = new ArrayList<>(); } - initCommands.add( command ); + initCommandProducers.add( commandProducer ); } - public List getInitCommands() { - if ( initCommands == null ) { + public List getInitCommands(SqlStringGenerationContext context) { + if ( initCommandProducers == null ) { return Collections.emptyList(); } else { + List initCommands = new ArrayList<>(); + for ( Function producer : initCommandProducers ) { + initCommands.add( producer.apply( context ) ); + } return Collections.unmodifiableList( initCommands ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java index 9c5ba874c7cd..2d95b4bdddb3 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java @@ -459,6 +459,7 @@ public AbstractCollectionPersister( factory.getSettings().getDefaultSchemaName(), null ); + identifierGenerator.initialize( creationContext.getSessionFactory().getSqlStringGenerationContext() ); } else { identifierType = null; diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index afe36eaf65bd..da6dcb72e859 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -37,6 +37,7 @@ import org.hibernate.Session; import org.hibernate.StaleObjectStateException; import org.hibernate.StaleStateException; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.boot.spi.MetadataImplementor; import org.hibernate.boot.spi.SessionFactoryOptions; import org.hibernate.bytecode.enhance.spi.LazyPropertyInitializer; @@ -2957,8 +2958,8 @@ else if ( includeProperty[i] ) { * * @return The insert SQL statement string */ - public String generateIdentityInsertString(boolean[] includeProperty) { - Insert insert = identityDelegate.prepareIdentifierGeneratingInsert(); + public String generateIdentityInsertString(SqlStringGenerationContext context, boolean[] includeProperty) { + Insert insert = identityDelegate.prepareIdentifierGeneratingInsert( context ); insert.setTableName( getTableName( 0 ) ); // add normal properties except lobs @@ -4396,7 +4397,7 @@ private void doLateInit() { identityDelegate = ( (PostInsertIdentifierGenerator) getIdentifierGenerator() ) .getInsertGeneratedIdentifierDelegate( this, getFactory().getDialect(), useGetGeneratedKeys() ); sqlIdentityInsertString = customSQLInsert[0] == null - ? generateIdentityInsertString( getPropertyInsertability() ) + ? generateIdentityInsertString( factory.getSqlStringGenerationContext(), getPropertyInsertability() ) : substituteBrackets( customSQLInsert[0] ); } else { diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/SchemaDropperImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/SchemaDropperImpl.java index 5ea8918308fa..eefebb38b9c7 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/SchemaDropperImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/SchemaDropperImpl.java @@ -22,6 +22,8 @@ import org.hibernate.boot.model.relational.Exportable; import org.hibernate.boot.model.relational.Namespace; import org.hibernate.boot.model.relational.Sequence; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; +import org.hibernate.boot.model.relational.internal.SqlStringGenerationContextImpl; import org.hibernate.boot.spi.MetadataImplementor; import org.hibernate.dialect.Dialect; import org.hibernate.engine.config.spi.ConfigurationService; @@ -187,7 +189,8 @@ private void dropFromMetadata( Formatter formatter, GenerationTarget... targets) { final Database database = metadata.getDatabase(); - final JdbcEnvironment jdbcEnvironment = database.getJdbcEnvironment(); + SqlStringGenerationContext sqlStringGenerationContext = + new SqlStringGenerationContextImpl( metadata.getDatabase().getJdbcEnvironment() ); boolean tryToDropCatalogs = false; boolean tryToDropSchemas = false; @@ -259,7 +262,7 @@ private void dropFromMetadata( } applySqlStrings( - auxiliaryDatabaseObject.sqlDropStrings( jdbcEnvironment.getDialect() ), + auxiliaryDatabaseObject.sqlDropStrings( sqlStringGenerationContext ), formatter, options, targets diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardAuxiliaryDatabaseObjectExporter.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardAuxiliaryDatabaseObjectExporter.java index abd43db6eaf4..09a67f5af44a 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardAuxiliaryDatabaseObjectExporter.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardAuxiliaryDatabaseObjectExporter.java @@ -8,6 +8,7 @@ import org.hibernate.boot.Metadata; import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject; +import org.hibernate.boot.model.relational.internal.SqlStringGenerationContextImpl; import org.hibernate.dialect.Dialect; import org.hibernate.tool.schema.spi.Exporter; @@ -23,11 +24,11 @@ public StandardAuxiliaryDatabaseObjectExporter(Dialect dialect) { @Override public String[] getSqlCreateStrings(AuxiliaryDatabaseObject object, Metadata metadata) { - return object.sqlCreateStrings( dialect ); + return object.sqlCreateStrings( new SqlStringGenerationContextImpl( metadata.getDatabase().getJdbcEnvironment() ) ); } @Override public String[] getSqlDropStrings(AuxiliaryDatabaseObject object, Metadata metadata) { - return object.sqlDropStrings( dialect ); + return object.sqlDropStrings( new SqlStringGenerationContextImpl( metadata.getDatabase().getJdbcEnvironment() ) ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardTableExporter.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardTableExporter.java index 4b5534203ef4..54ebf07bf603 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardTableExporter.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardTableExporter.java @@ -16,6 +16,8 @@ import org.hibernate.boot.model.relational.InitCommand; import org.hibernate.boot.model.relational.QualifiedName; import org.hibernate.boot.model.relational.QualifiedNameParser; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; +import org.hibernate.boot.model.relational.internal.SqlStringGenerationContextImpl; import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.mapping.Column; @@ -152,7 +154,9 @@ public String[] getSqlCreateStrings(Table table, Metadata metadata) { applyComments( table, tableName, sqlStrings ); - applyInitCommands( table, sqlStrings ); + SqlStringGenerationContext context = + new SqlStringGenerationContextImpl( metadata.getDatabase().getJdbcEnvironment() ); + applyInitCommands( table, sqlStrings, context ); return sqlStrings.toArray( new String[ sqlStrings.size() ] ); } @@ -173,8 +177,8 @@ protected void applyComments(Table table, QualifiedName tableName, List } } - protected void applyInitCommands(Table table, List sqlStrings) { - for ( InitCommand initCommand : table.getInitCommands() ) { + protected void applyInitCommands(Table table, List sqlStrings, SqlStringGenerationContext context) { + for ( InitCommand initCommand : table.getInitCommands( context ) ) { Collections.addAll( sqlStrings, initCommand.getInitCommands() ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/Exporter.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/Exporter.java index 19e81d291371..f7a5a00a23ba 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/Exporter.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/Exporter.java @@ -9,6 +9,7 @@ import org.hibernate.boot.Metadata; import org.hibernate.boot.model.relational.Exportable; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; /** * Defines a contract for exporting of database objects (tables, sequences, etc) for use in SQL {@code CREATE} and diff --git a/hibernate-core/src/test/java/org/hibernate/id/SequenceHiLoGeneratorNoIncrementTest.java b/hibernate-core/src/test/java/org/hibernate/id/SequenceHiLoGeneratorNoIncrementTest.java index 433cef1cb090..fca2b880956a 100644 --- a/hibernate-core/src/test/java/org/hibernate/id/SequenceHiLoGeneratorNoIncrementTest.java +++ b/hibernate-core/src/test/java/org/hibernate/id/SequenceHiLoGeneratorNoIncrementTest.java @@ -76,6 +76,7 @@ public void setUp() throws Exception { generator.registerExportables( metadata.getDatabase() ); sessionFactory = (SessionFactoryImplementor) metadata.buildSessionFactory(); + generator.initialize( sessionFactory.getSqlStringGenerationContext() ); sequenceValueExtractor = new SequenceValueExtractor( sessionFactory.getDialect(), TEST_SEQUENCE ); } diff --git a/hibernate-core/src/test/java/org/hibernate/id/SequenceHiLoGeneratorTest.java b/hibernate-core/src/test/java/org/hibernate/id/SequenceHiLoGeneratorTest.java index 6f8532764270..ce65ba2dea8a 100644 --- a/hibernate-core/src/test/java/org/hibernate/id/SequenceHiLoGeneratorTest.java +++ b/hibernate-core/src/test/java/org/hibernate/id/SequenceHiLoGeneratorTest.java @@ -71,6 +71,7 @@ public void setUp() throws Exception { generator.registerExportables( metadata.getDatabase() ); sessionFactory = (SessionFactoryImplementor) metadata.buildSessionFactory(); + generator.initialize( sessionFactory.getSqlStringGenerationContext() ); sequenceValueExtractor = new SequenceValueExtractor( sessionFactory.getDialect(), TEST_SEQUENCE ); } diff --git a/hibernate-core/src/test/java/org/hibernate/id/SequenceStyleGeneratorBehavesLikeSequeceHiloGeneratorWitZeroIncrementSizeTest.java b/hibernate-core/src/test/java/org/hibernate/id/SequenceStyleGeneratorBehavesLikeSequeceHiloGeneratorWitZeroIncrementSizeTest.java index a818fa483a7e..f1c627e1af56 100644 --- a/hibernate-core/src/test/java/org/hibernate/id/SequenceStyleGeneratorBehavesLikeSequeceHiloGeneratorWitZeroIncrementSizeTest.java +++ b/hibernate-core/src/test/java/org/hibernate/id/SequenceStyleGeneratorBehavesLikeSequeceHiloGeneratorWitZeroIncrementSizeTest.java @@ -74,6 +74,7 @@ protected MetadataBuildingContext getBuildingContext() { generator.registerExportables( metadata.getDatabase() ); sessionFactory = (SessionFactoryImplementor) metadata.buildSessionFactory(); + generator.initialize( sessionFactory.getSqlStringGenerationContext() ); sequenceValueExtractor = new SequenceValueExtractor( sessionFactory.getDialect(), TEST_SEQUENCE ); } diff --git a/hibernate-core/src/test/java/org/hibernate/id/enhanced/SequenceStyleConfigUnitTest.java b/hibernate-core/src/test/java/org/hibernate/id/enhanced/SequenceStyleConfigUnitTest.java index c3eaf912a74f..4c00816b3eb2 100644 --- a/hibernate-core/src/test/java/org/hibernate/id/enhanced/SequenceStyleConfigUnitTest.java +++ b/hibernate-core/src/test/java/org/hibernate/id/enhanced/SequenceStyleConfigUnitTest.java @@ -11,6 +11,7 @@ import org.hibernate.MappingException; import org.hibernate.boot.internal.MetadataBuilderImpl; import org.hibernate.boot.model.relational.Database; +import org.hibernate.boot.model.relational.internal.SqlStringGenerationContextImpl; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cfg.AvailableSettings; @@ -45,13 +46,14 @@ public void testDefaultedSequenceBackedConfiguration() { SequenceStyleGenerator generator = new SequenceStyleGenerator(); generator.configure( StandardBasicTypes.LONG, props, serviceRegistry ); - generator.registerExportables( - new Database( new MetadataBuilderImpl.MetadataBuildingOptionsImpl( serviceRegistry ) ) - ); + Database database = new Database( new MetadataBuilderImpl.MetadataBuildingOptionsImpl( serviceRegistry ) ); + generator.registerExportables( database ); + generator.initialize( SqlStringGenerationContextImpl.forTests( database.getJdbcEnvironment() ) ); assertClassAssignability( SequenceStructure.class, generator.getDatabaseStructure().getClass() ); assertClassAssignability( NoopOptimizer.class, generator.getOptimizer().getClass() ); - assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME, generator.getDatabaseStructure().getName() ); + assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME, + generator.getDatabaseStructure().getPhysicalName().render() ); } } @@ -76,13 +78,14 @@ public void testDefaultedTableBackedConfiguration() { SequenceStyleGenerator generator = new SequenceStyleGenerator(); generator.configure( StandardBasicTypes.LONG, props, serviceRegistry ); - generator.registerExportables( - new Database( new MetadataBuilderImpl.MetadataBuildingOptionsImpl( serviceRegistry ) ) - ); + Database database = new Database( new MetadataBuilderImpl.MetadataBuildingOptionsImpl( serviceRegistry ) ); + generator.registerExportables( database ); + generator.initialize( SqlStringGenerationContextImpl.forTests( database.getJdbcEnvironment() ) ); assertClassAssignability( TableStructure.class, generator.getDatabaseStructure().getClass() ); assertClassAssignability( NoopOptimizer.class, generator.getOptimizer().getClass() ); - assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME, generator.getDatabaseStructure().getName() ); + assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME, + generator.getDatabaseStructure().getPhysicalName().render() ); } } @@ -103,13 +106,14 @@ public void testDefaultOptimizerBasedOnIncrementBackedBySequence() { SequenceStyleGenerator generator = new SequenceStyleGenerator(); generator.configure( StandardBasicTypes.LONG, props, serviceRegistry ); - generator.registerExportables( - new Database( new MetadataBuilderImpl.MetadataBuildingOptionsImpl( serviceRegistry ) ) - ); + Database database = new Database( new MetadataBuilderImpl.MetadataBuildingOptionsImpl( serviceRegistry ) ); + generator.registerExportables( database ); + generator.initialize( SqlStringGenerationContextImpl.forTests( database.getJdbcEnvironment() ) ); assertClassAssignability( TableStructure.class, generator.getDatabaseStructure().getClass() ); assertClassAssignability( PooledOptimizer.class, generator.getOptimizer().getClass() ); - assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME, generator.getDatabaseStructure().getName() ); + assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME, + generator.getDatabaseStructure().getPhysicalName().render() ); } // for dialects which do support pooled sequences, we default to pooled+sequence @@ -121,13 +125,14 @@ public void testDefaultOptimizerBasedOnIncrementBackedBySequence() { SequenceStyleGenerator generator = new SequenceStyleGenerator(); generator.configure( StandardBasicTypes.LONG, props, serviceRegistry ); - generator.registerExportables( - new Database( new MetadataBuilderImpl.MetadataBuildingOptionsImpl( serviceRegistry ) ) - ); + Database database = new Database( new MetadataBuilderImpl.MetadataBuildingOptionsImpl( serviceRegistry ) ); + generator.registerExportables( database ); + generator.initialize( SqlStringGenerationContextImpl.forTests( database.getJdbcEnvironment() ) ); assertClassAssignability( SequenceStructure.class, generator.getDatabaseStructure().getClass() ); assertClassAssignability( PooledOptimizer.class, generator.getOptimizer().getClass() ); - assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME, generator.getDatabaseStructure().getName() ); + assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME, + generator.getDatabaseStructure().getPhysicalName().render() ); } } @@ -146,13 +151,14 @@ public void testDefaultOptimizerBasedOnIncrementBackedByTable() { SequenceStyleGenerator generator = new SequenceStyleGenerator(); generator.configure( StandardBasicTypes.LONG, props, serviceRegistry ); - generator.registerExportables( - new Database( new MetadataBuilderImpl.MetadataBuildingOptionsImpl( serviceRegistry ) ) - ); + Database database = new Database( new MetadataBuilderImpl.MetadataBuildingOptionsImpl( serviceRegistry ) ); + generator.registerExportables( database ); + generator.initialize( SqlStringGenerationContextImpl.forTests( database.getJdbcEnvironment() ) ); assertClassAssignability( TableStructure.class, generator.getDatabaseStructure().getClass() ); assertClassAssignability( PooledOptimizer.class, generator.getOptimizer().getClass() ); - assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME, generator.getDatabaseStructure().getName() ); + assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME, + generator.getDatabaseStructure().getPhysicalName().render() ); } } @@ -169,13 +175,14 @@ public void testForceTableUse() { SequenceStyleGenerator generator = new SequenceStyleGenerator(); generator.configure( StandardBasicTypes.LONG, props, serviceRegistry ); - generator.registerExportables( - new Database( new MetadataBuilderImpl.MetadataBuildingOptionsImpl( serviceRegistry ) ) - ); + Database database = new Database( new MetadataBuilderImpl.MetadataBuildingOptionsImpl( serviceRegistry ) ); + generator.registerExportables( database ); + generator.initialize( SqlStringGenerationContextImpl.forTests( database.getJdbcEnvironment() ) ); assertClassAssignability( TableStructure.class, generator.getDatabaseStructure().getClass() ); assertClassAssignability( NoopOptimizer.class, generator.getOptimizer().getClass() ); - assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME, generator.getDatabaseStructure().getName() ); + assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME, + generator.getDatabaseStructure().getPhysicalName().render() ); } } @@ -193,9 +200,9 @@ public void testExplicitOptimizerWithExplicitIncrementSize() { props.setProperty( SequenceStyleGenerator.INCREMENT_PARAM, "20" ); SequenceStyleGenerator generator = new SequenceStyleGenerator(); generator.configure( StandardBasicTypes.LONG, props, serviceRegistry ); - generator.registerExportables( - new Database( new MetadataBuilderImpl.MetadataBuildingOptionsImpl( serviceRegistry ) ) - ); + Database database = new Database( new MetadataBuilderImpl.MetadataBuildingOptionsImpl( serviceRegistry ) ); + generator.registerExportables( database ); + generator.initialize( SqlStringGenerationContextImpl.forTests( database.getJdbcEnvironment() ) ); assertClassAssignability( SequenceStructure.class, generator.getDatabaseStructure().getClass() ); assertClassAssignability( NoopOptimizer.class, generator.getOptimizer().getClass() ); @@ -208,9 +215,8 @@ public void testExplicitOptimizerWithExplicitIncrementSize() { props.setProperty( SequenceStyleGenerator.INCREMENT_PARAM, "20" ); generator = new SequenceStyleGenerator(); generator.configure( StandardBasicTypes.LONG, props, serviceRegistry ); - generator.registerExportables( - new Database( new MetadataBuilderImpl.MetadataBuildingOptionsImpl( serviceRegistry ) ) - ); + generator.registerExportables( database ); + generator.initialize( SqlStringGenerationContextImpl.forTests( database.getJdbcEnvironment() ) ); assertClassAssignability( SequenceStructure.class, generator.getDatabaseStructure().getClass() ); assertClassAssignability( HiLoOptimizer.class, generator.getOptimizer().getClass() ); assertEquals( 20, generator.getOptimizer().getIncrementSize() ); @@ -222,9 +228,8 @@ public void testExplicitOptimizerWithExplicitIncrementSize() { props.setProperty( SequenceStyleGenerator.INCREMENT_PARAM, "20" ); generator = new SequenceStyleGenerator(); generator.configure( StandardBasicTypes.LONG, props, serviceRegistry ); - generator.registerExportables( - new Database( new MetadataBuilderImpl.MetadataBuildingOptionsImpl( serviceRegistry ) ) - ); + generator.registerExportables( database ); + generator.initialize( SqlStringGenerationContextImpl.forTests( database.getJdbcEnvironment() ) ); // because the dialect reports to not support pooled seqyences, the expectation is that we will // use a table for the backing structure... assertClassAssignability( TableStructure.class, generator.getDatabaseStructure().getClass() ); @@ -243,27 +248,25 @@ public void testPreferredPooledOptimizerSetting() { props.setProperty( SequenceStyleGenerator.INCREMENT_PARAM, "20" ); SequenceStyleGenerator generator = new SequenceStyleGenerator(); generator.configure( StandardBasicTypes.LONG, props, serviceRegistry ); - generator.registerExportables( - new Database( new MetadataBuilderImpl.MetadataBuildingOptionsImpl( serviceRegistry ) ) - ); + Database database = new Database( new MetadataBuilderImpl.MetadataBuildingOptionsImpl( serviceRegistry ) ); + generator.registerExportables( database ); + generator.initialize( SqlStringGenerationContextImpl.forTests( database.getJdbcEnvironment() ) ); assertClassAssignability( SequenceStructure.class, generator.getDatabaseStructure().getClass() ); assertClassAssignability( PooledOptimizer.class, generator.getOptimizer().getClass() ); props.setProperty( Environment.PREFER_POOLED_VALUES_LO, "true" ); generator = new SequenceStyleGenerator(); generator.configure( StandardBasicTypes.LONG, props, serviceRegistry ); - generator.registerExportables( - new Database( new MetadataBuilderImpl.MetadataBuildingOptionsImpl( serviceRegistry ) ) - ); + generator.registerExportables( database ); + generator.initialize( SqlStringGenerationContextImpl.forTests( database.getJdbcEnvironment() ) ); assertClassAssignability( SequenceStructure.class, generator.getDatabaseStructure().getClass() ); assertClassAssignability( PooledLoOptimizer.class, generator.getOptimizer().getClass() ); props.setProperty( Environment.PREFERRED_POOLED_OPTIMIZER, StandardOptimizerDescriptor.POOLED_LOTL.getExternalName() ); generator = new SequenceStyleGenerator(); generator.configure( StandardBasicTypes.LONG, props, serviceRegistry ); - generator.registerExportables( - new Database( new MetadataBuilderImpl.MetadataBuildingOptionsImpl( serviceRegistry ) ) - ); + generator.registerExportables( database ); + generator.initialize( SqlStringGenerationContextImpl.forTests( database.getJdbcEnvironment() ) ); assertClassAssignability( SequenceStructure.class, generator.getDatabaseStructure().getClass() ); assertClassAssignability( PooledLoThreadLocalOptimizer.class, generator.getOptimizer().getClass() ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/id/generationmappings/NewGeneratorMappingsTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/id/generationmappings/NewGeneratorMappingsTest.java index 9a778187a522..06c65b110819 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/id/generationmappings/NewGeneratorMappingsTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/id/generationmappings/NewGeneratorMappingsTest.java @@ -66,7 +66,8 @@ public void testMinimalSequenceEntity() { IdentifierGenerator generator = persister.getIdentifierGenerator(); assertTrue( SequenceStyleGenerator.class.isInstance( generator ) ); SequenceStyleGenerator seqGenerator = (SequenceStyleGenerator) generator; - assertEquals( MinimalSequenceEntity.SEQ_NAME, seqGenerator.getDatabaseStructure().getName() ); + assertEquals( MinimalSequenceEntity.SEQ_NAME, + seqGenerator.getDatabaseStructure().getPhysicalName().render() ); // 1 is the annotation default assertEquals( 1, seqGenerator.getDatabaseStructure().getInitialValue() ); // 50 is the annotation default @@ -91,7 +92,8 @@ public void testAutoEntity() { IdentifierGenerator generator = persister.getIdentifierGenerator(); assertTrue( SequenceStyleGenerator.class.isInstance( generator ) ); SequenceStyleGenerator seqGenerator = (SequenceStyleGenerator) generator; - assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME, seqGenerator.getDatabaseStructure().getName() ); + assertEquals( SequenceStyleGenerator.DEF_SEQUENCE_NAME, + seqGenerator.getDatabaseStructure().getPhysicalName().render() ); assertEquals( SequenceStyleGenerator.DEFAULT_INITIAL_VALUE, seqGenerator.getDatabaseStructure().getInitialValue() ); assertEquals( SequenceStyleGenerator.DEFAULT_INCREMENT_SIZE, seqGenerator.getDatabaseStructure().getIncrementSize() ); } @@ -123,7 +125,7 @@ public void testSequencePerEntity() { SequenceStyleGenerator seqGenerator = (SequenceStyleGenerator) generator; assertEquals( StringHelper.unqualifyEntityName( DedicatedSequenceEntity1.class.getName() ) + DedicatedSequenceEntity1.SEQUENCE_SUFFIX, - seqGenerator.getDatabaseStructure().getName() + seqGenerator.getDatabaseStructure().getPhysicalName().render() ); // Checking second entity. @@ -133,7 +135,7 @@ public void testSequencePerEntity() { seqGenerator = (SequenceStyleGenerator) generator; assertEquals( DedicatedSequenceEntity2.ENTITY_NAME + DedicatedSequenceEntity1.SEQUENCE_SUFFIX, - seqGenerator.getDatabaseStructure().getName() + seqGenerator.getDatabaseStructure().getPhysicalName().render() ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/id/sequences/HibernateSequenceTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/id/sequences/HibernateSequenceTest.java index 2117b99b5f46..d26a56c115a7 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/id/sequences/HibernateSequenceTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/id/sequences/HibernateSequenceTest.java @@ -12,7 +12,6 @@ import org.hibernate.Session; import org.hibernate.Transaction; import org.hibernate.cfg.Configuration; -import org.hibernate.cfg.Environment; import org.hibernate.dialect.H2Dialect; import org.hibernate.id.IdentifierGenerator; import org.hibernate.id.enhanced.SequenceStyleGenerator; @@ -57,7 +56,7 @@ public void testHibernateSequenceSchema() { SequenceStyleGenerator seqGenerator = (SequenceStyleGenerator) generator; Assert.assertEquals( Table.qualify( null, SCHEMA_NAME, SequenceStyleGenerator.DEF_SEQUENCE_NAME ), - seqGenerator.getDatabaseStructure().getName() + seqGenerator.getDatabaseStructure().getPhysicalName().render() ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/idgen/enhanced/auto/NewGeneratorsTests.java b/hibernate-core/src/test/java/org/hibernate/test/idgen/enhanced/auto/NewGeneratorsTests.java index 5d73e16074e3..88f1965e05cb 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/idgen/enhanced/auto/NewGeneratorsTests.java +++ b/hibernate-core/src/test/java/org/hibernate/test/idgen/enhanced/auto/NewGeneratorsTests.java @@ -70,9 +70,9 @@ public void testAutoDefaults() { final DatabaseStructure databaseStructure = generator.getDatabaseStructure(); // HHH-14491 - what we want to happen - assertThat( databaseStructure.getName(), is( "Entity1_SEQ" ) ); + assertThat( databaseStructure.getPhysicalName().render(), is( "Entity1_SEQ" ) ); // or this depending on the discussion (Jira) about using entity name v. table name as the base - assertThat( databaseStructure.getName(), is( "tbl_1_SEQ" ) ); + assertThat( databaseStructure.getPhysicalName().render(), is( "tbl_1_SEQ" ) ); // HHH-14491 - this is what we want to have happen assertThat( databaseStructure.getIncrementSize(), is( 50 ) ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/idgen/enhanced/sequence/BasicSequenceTest.java b/hibernate-core/src/test/java/org/hibernate/test/idgen/enhanced/sequence/BasicSequenceTest.java index ec1e00f8a778..e91c214c8432 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/idgen/enhanced/sequence/BasicSequenceTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/idgen/enhanced/sequence/BasicSequenceTest.java @@ -64,7 +64,8 @@ public void testSequencePerEntity() { EntityPersister persister = sessionFactory().getEntityPersister( overriddenEntityName ); assertClassAssignability( SequenceStyleGenerator.class, persister.getIdentifierGenerator().getClass() ); SequenceStyleGenerator generator = (SequenceStyleGenerator) persister.getIdentifierGenerator(); - assertEquals( overriddenEntityName + SequenceStyleGenerator.DEF_SEQUENCE_SUFFIX, generator.getDatabaseStructure().getName() ); + assertEquals( overriddenEntityName + SequenceStyleGenerator.DEF_SEQUENCE_SUFFIX, + generator.getDatabaseStructure().getPhysicalName().getObjectName().getText() ); Session s = openSession(); s.beginTransaction(); diff --git a/hibernate-core/src/test/java/org/hibernate/test/idgen/enhanced/sequence/HiLoSequenceMismatchStrategyTest.java b/hibernate-core/src/test/java/org/hibernate/test/idgen/enhanced/sequence/HiLoSequenceMismatchStrategyTest.java index 759392532538..f9e43a4355b3 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/idgen/enhanced/sequence/HiLoSequenceMismatchStrategyTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/idgen/enhanced/sequence/HiLoSequenceMismatchStrategyTest.java @@ -16,6 +16,7 @@ import org.hibernate.annotations.GenericGenerator; import org.hibernate.annotations.Parameter; +import org.hibernate.boot.model.relational.QualifiedName; import org.hibernate.cfg.AvailableSettings; import org.hibernate.cfg.Configuration; import org.hibernate.cfg.Environment; @@ -93,8 +94,8 @@ public void testSequenceMismatchStrategyNotApplied() { SequenceStyleGenerator generator = (SequenceStyleGenerator) persister.getIdentifierGenerator(); assertClassAssignability( HiLoOptimizer.class, generator.getOptimizer().getClass() ); - String sequenceName = generator.getDatabaseStructure().getName(); - Assert.assertEquals( this.sequenceName, sequenceName ); + QualifiedName sequenceName = generator.getDatabaseStructure().getPhysicalName(); + Assert.assertEquals( this.sequenceName, sequenceName.render() ); int incrementSize = generator.getOptimizer().getIncrementSize(); Assert.assertNotEquals( 1, incrementSize ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/jpa/compliance/tck2_2/GeneratedValueTests.java b/hibernate-core/src/test/java/org/hibernate/test/jpa/compliance/tck2_2/GeneratedValueTests.java index 3fd7d89eb86b..85a650740e6a 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/jpa/compliance/tck2_2/GeneratedValueTests.java +++ b/hibernate-core/src/test/java/org/hibernate/test/jpa/compliance/tck2_2/GeneratedValueTests.java @@ -17,6 +17,7 @@ import org.hibernate.boot.MetadataSources; import org.hibernate.boot.model.naming.Identifier; import org.hibernate.boot.model.relational.Sequence; +import org.hibernate.boot.model.relational.internal.SqlStringGenerationContextImpl; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cfg.AvailableSettings; @@ -61,13 +62,13 @@ public void baseline() { null, (RootClass) entityMapping ); + generator.initialize( SqlStringGenerationContextImpl.forTests( bootModel.getDatabase().getJdbcEnvironment() ) ); final SequenceStyleGenerator sequenceStyleGenerator = assertTyping( SequenceStyleGenerator.class, generator ); - - assertThat( sequenceStyleGenerator.getDatabaseStructure().getName(), is( "my_real_db_sequence" ) ); + assertThat( sequenceStyleGenerator.getDatabaseStructure().getPhysicalName().render(), is( "my_real_db_sequence" ) ); // all the JPA defaults since they were not defined assertThat( sequenceStyleGenerator.getDatabaseStructure().getInitialValue(), is( 100 ) ); @@ -91,6 +92,7 @@ public void testImplicitSequenceGenerator() { null, (RootClass) entityMapping ); + generator.initialize( SqlStringGenerationContextImpl.forTests( bootModel.getDatabase().getJdbcEnvironment() ) ); final SequenceStyleGenerator sequenceStyleGenerator = assertTyping( SequenceStyleGenerator.class, @@ -99,7 +101,7 @@ public void testImplicitSequenceGenerator() { // PREFER_GENERATOR_NAME_AS_DEFAULT_SEQUENCE_NAME == false indicates that the legacy // default (hibernate_sequence) should be used - assertThat( sequenceStyleGenerator.getDatabaseStructure().getName(), is( "hibernate_sequence" ) ); + assertThat( sequenceStyleGenerator.getDatabaseStructure().getPhysicalName().render(), is( "hibernate_sequence" ) ); // the JPA defaults since they were not defined assertThat( sequenceStyleGenerator.getDatabaseStructure().getInitialValue(), is( 1 ) ); @@ -121,6 +123,7 @@ public void testImplicitSequenceGeneratorGeneratorName() { null, (RootClass) entityMapping ); + generator.initialize( SqlStringGenerationContextImpl.forTests( bootModel.getDatabase().getJdbcEnvironment() ) ); final SequenceStyleGenerator sequenceStyleGenerator = assertTyping( SequenceStyleGenerator.class, @@ -129,7 +132,7 @@ public void testImplicitSequenceGeneratorGeneratorName() { // PREFER_GENERATOR_NAME_AS_DEFAULT_SEQUENCE_NAME == true (the default) indicates that the generator-name // should be used as the default instead. - assertThat( sequenceStyleGenerator.getDatabaseStructure().getName(), is( "my_db_sequence" ) ); + assertThat( sequenceStyleGenerator.getDatabaseStructure().getPhysicalName().render(), is( "my_db_sequence" ) ); // the JPA defaults since they were not defined assertThat( sequenceStyleGenerator.getDatabaseStructure().getInitialValue(), is( 1 ) ); @@ -153,10 +156,11 @@ public void testExplicitSequenceGeneratorImplicitName() { null, (RootClass) entityMapping ); + generator.initialize( SqlStringGenerationContextImpl.forTests( bootModel.getDatabase().getJdbcEnvironment() ) ); final SequenceStyleGenerator sequenceStyleGenerator = assertTyping( SequenceStyleGenerator.class, generator ); // all the JPA defaults since they were not defined - assertThat( sequenceStyleGenerator.getDatabaseStructure().getName(), is( SequenceStyleGenerator.DEF_SEQUENCE_NAME ) ); + assertThat( sequenceStyleGenerator.getDatabaseStructure().getPhysicalName().render(), is( SequenceStyleGenerator.DEF_SEQUENCE_NAME ) ); assertThat( sequenceStyleGenerator.getDatabaseStructure().getInitialValue(), is( 100 ) ); assertThat( sequenceStyleGenerator.getDatabaseStructure().getIncrementSize(), is( 500 ) ); } @@ -177,13 +181,14 @@ public void testExplicitSequenceGeneratorImplicitNamePreferGeneratorName() { null, (RootClass) entityMapping ); + generator.initialize( SqlStringGenerationContextImpl.forTests( bootModel.getDatabase().getJdbcEnvironment() ) ); final SequenceStyleGenerator sequenceStyleGenerator = assertTyping( SequenceStyleGenerator.class, generator ); // all the JPA defaults since they were not defined - assertThat( sequenceStyleGenerator.getDatabaseStructure().getName(), is( "my_db_sequence" ) ); + assertThat( sequenceStyleGenerator.getDatabaseStructure().getPhysicalName().render(), is( "my_db_sequence" ) ); assertThat( sequenceStyleGenerator.getDatabaseStructure().getInitialValue(), is( 100 ) ); assertThat( sequenceStyleGenerator.getDatabaseStructure().getIncrementSize(), is( 500 ) ); @@ -215,6 +220,7 @@ public void testImplicitTableGenerator() { null, (RootClass) entityMapping ); + generator.initialize( SqlStringGenerationContextImpl.forTests( bootModel.getDatabase().getJdbcEnvironment() ) ); final TableGenerator tableGenerator = assertTyping( TableGenerator.class, generator ); @@ -240,6 +246,7 @@ public void testExplicitTableGeneratorImplicitName() { null, (RootClass) entityMapping ); + generator.initialize( SqlStringGenerationContextImpl.forTests( bootModel.getDatabase().getJdbcEnvironment() ) ); final TableGenerator tableGenerator = assertTyping( TableGenerator.class, generator ); @@ -265,6 +272,7 @@ public void testExplicitTableGenerator() { null, (RootClass) entityMapping ); + generator.initialize( SqlStringGenerationContextImpl.forTests( bootModel.getDatabase().getJdbcEnvironment() ) ); final TableGenerator tableGenerator = assertTyping( TableGenerator.class, generator ); @@ -292,6 +300,7 @@ public void testExplicitIncrementGenerator() { null, (RootClass) entityMapping ); + generator.initialize( SqlStringGenerationContextImpl.forTests( bootModel.getDatabase().getJdbcEnvironment() ) ); assertTyping( IncrementGenerator.class, generator ); } @@ -311,6 +320,7 @@ public void testImplicitIncrementGenerator() { null, (RootClass) entityMapping ); + generator.initialize( SqlStringGenerationContextImpl.forTests( bootModel.getDatabase().getJdbcEnvironment() ) ); assertTyping( IncrementGenerator.class, generator ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaUpdateTableBackedSequenceTest.java b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaUpdateTableBackedSequenceTest.java index 67a7d427da28..1d4f1ee5e2d3 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaUpdateTableBackedSequenceTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaUpdateTableBackedSequenceTest.java @@ -16,6 +16,8 @@ import org.hibernate.boot.model.naming.Identifier; import org.hibernate.boot.model.relational.Database; import org.hibernate.boot.model.relational.QualifiedTableName; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; +import org.hibernate.boot.model.relational.internal.SqlStringGenerationContextImpl; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cfg.AvailableSettings; @@ -34,7 +36,6 @@ import org.hibernate.testing.junit4.BaseUnitTestCase; import org.junit.After; import org.junit.Before; -import org.junit.Ignore; import org.junit.Test; import static org.junit.Assert.assertEquals; @@ -77,7 +78,8 @@ public void testCreateTableOnUpdate() throws SQLException { // lets make sure the InitCommand is there assertEquals( 1, database.getDefaultNamespace().getTables().size() ); Table table = database.getDefaultNamespace().getTables().iterator().next(); - assertEquals( 1, table.getInitCommands().size() ); + SqlStringGenerationContext context = SqlStringGenerationContextImpl.forTests( database.getJdbcEnvironment() ); + assertEquals( 1, table.getInitCommands( context ).size() ); final TargetImpl target = new TargetImpl(); diff --git a/hibernate-envers/src/main/java/org/hibernate/envers/enhanced/OrderedSequenceStructure.java b/hibernate-envers/src/main/java/org/hibernate/envers/enhanced/OrderedSequenceStructure.java index 82c3d26c91a5..fbb57577b2f3 100644 --- a/hibernate-envers/src/main/java/org/hibernate/envers/enhanced/OrderedSequenceStructure.java +++ b/hibernate-envers/src/main/java/org/hibernate/envers/enhanced/OrderedSequenceStructure.java @@ -9,6 +9,7 @@ import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject; import org.hibernate.boot.model.relational.Database; import org.hibernate.boot.model.relational.QualifiedName; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.dialect.Dialect; import org.hibernate.dialect.Oracle8iDialect; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; @@ -38,16 +39,13 @@ public OrderedSequenceStructure( @Override protected void buildSequence(Database database) { database.addAuxiliaryDatabaseObject( sequenceObject ); - this.sequenceName = database.getJdbcEnvironment().getQualifiedObjectNameFormatter().format( - getQualifiedName(), - database.getJdbcEnvironment().getDialect() - ); + this.physicalSequenceName = getQualifiedName(); } private class OrderedSequence implements AuxiliaryDatabaseObject { @Override public String getExportIdentifier() { - return getName(); + return getQualifiedName().render(); } @Override @@ -63,9 +61,10 @@ public boolean beforeTablesOnCreation() { } @Override - public String[] sqlCreateStrings(Dialect dialect) { + public String[] sqlCreateStrings(SqlStringGenerationContext context) { + Dialect dialect = context.getDialect(); final String[] createStrings = dialect.getCreateSequenceStrings( - getName(), + context.format( getPhysicalName() ), getInitialValue(), getSourceIncrementSize() ); @@ -80,8 +79,9 @@ public String[] sqlCreateStrings(Dialect dialect) { } @Override - public String[] sqlDropStrings(Dialect dialect) { - return dialect.getDropSequenceStrings( getName() ); + public String[] sqlDropStrings(SqlStringGenerationContext context) { + Dialect dialect = context.getDialect(); + return dialect.getDropSequenceStrings( context.format( getPhysicalName() ) ); } } } From 36b001221b8b61f20a5bb81b7e90fff931c4b528 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Mon, 8 Nov 2021 11:12:32 +0100 Subject: [PATCH 406/644] HHH-14921 Always use SqlStringGenerationContext for generation of SQL strings involving table/sequence names --- .../boot/model/relational/QualifiedName.java | 4 +- .../SqlStringGenerationContext.java | 20 ++++- .../SqlStringGenerationContextImpl.java | 22 ++++++ .../dialect/AbstractHANADialect.java | 12 ++- .../dialect/SQLServer2012Dialect.java | 16 ++-- .../hibernate/dialect/Teradata14Dialect.java | 14 ++-- .../dialect/unique/DB2UniqueDelegate.java | 18 ++--- .../dialect/unique/DefaultUniqueDelegate.java | 30 +++---- .../unique/InformixUniqueDelegate.java | 9 +-- .../dialect/unique/UniqueDelegate.java | 21 +++-- .../engine/jdbc/env/spi/JdbcEnvironment.java | 2 + .../AbstractMultiTableBulkIdStrategyImpl.java | 31 ++++---- .../hql/spi/id/MultiTableBulkIdStrategy.java | 7 +- .../AbstractCteValuesListBulkIdHandler.java | 5 +- .../id/cte/CteValuesListBulkIdStrategy.java | 4 +- .../GlobalTemporaryTableBulkIdStrategy.java | 13 ++- .../InlineIdsInClauseBulkIdStrategy.java | 4 +- .../InlineIdsOrClauseBulkIdStrategy.java | 4 +- ...neIdsSubSelectValueListBulkIdStrategy.java | 4 +- .../LocalTemporaryTableBulkIdStrategy.java | 13 ++- .../PersistentTableBulkIdStrategy.java | 15 ++-- .../internal/FilterConfiguration.java | 2 +- .../internal/SessionFactoryImpl.java | 3 +- .../org/hibernate/mapping/Constraint.java | 19 +++-- .../org/hibernate/mapping/ForeignKey.java | 14 +++- .../java/org/hibernate/mapping/Index.java | 56 +++++-------- .../org/hibernate/mapping/PrimaryKey.java | 5 +- .../hibernate/mapping/RelationalModel.java | 6 +- .../java/org/hibernate/mapping/Table.java | 79 +++++++------------ .../java/org/hibernate/mapping/UniqueKey.java | 9 +-- .../AbstractCollectionPersister.java | 10 +-- .../entity/AbstractEntityPersister.java | 8 +- .../entity/JoinedSubclassEntityPersister.java | 21 +++-- .../entity/SingleTableEntityPersister.java | 7 +- .../entity/UnionSubclassEntityPersister.java | 13 +-- .../internal/ExtractionContextImpl.java | 9 +++ ...tionExtractorJdbcDatabaseMetaDataImpl.java | 5 +- .../schema/extract/spi/ExtractionContext.java | 7 ++ .../internal/AbstractSchemaMigrator.java | 40 +++++++--- .../internal/GroupedSchemaMigratorImpl.java | 16 ++-- .../IndividuallySchemaMigratorImpl.java | 13 ++- .../schema/internal/SchemaCreatorImpl.java | 28 +++++-- .../schema/internal/SchemaDropperImpl.java | 19 +++-- ...andardAuxiliaryDatabaseObjectExporter.java | 12 +-- .../internal/StandardForeignKeyExporter.java | 22 ++---- .../internal/StandardIndexExporter.java | 21 ++--- .../internal/StandardSequenceExporter.java | 19 ++--- .../internal/StandardTableExporter.java | 24 ++---- .../internal/StandardUniqueKeyExporter.java | 13 ++- .../exec/ImprovedExtractionContextImpl.java | 9 +++ .../hibernate/tool/schema/spi/Exporter.java | 4 +- .../jpa/PersistenceUnitOverridesTests.java | 4 +- .../id/sequences/HibernateSequenceTest.java | 2 +- .../test/hbm/uk/UniqueDelegateTest.java | 21 +++-- .../enhanced/table/Db2GenerationTest.java | 21 ++++- .../tck2_2/GeneratedValueTests.java | 13 ++- .../CheckForExistingForeignKeyTest.java | 11 ++- .../internal/AbstractSchemaMigratorTest.java | 8 +- .../MonotonicRevisionNumberTest.java | 6 +- 59 files changed, 486 insertions(+), 381 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/relational/QualifiedName.java b/hibernate-core/src/main/java/org/hibernate/boot/model/relational/QualifiedName.java index 92139e89c224..b7af552a2b2d 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/relational/QualifiedName.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/relational/QualifiedName.java @@ -31,8 +31,8 @@ public interface QualifiedName { * Returns a String-form of the qualified name. *

    * Depending on intention, may not be appropriate. May want - * {@link org.hibernate.engine.jdbc.env.spi.QualifiedObjectNameFormatter#format} - * instead. See {@link org.hibernate.engine.jdbc.env.spi.JdbcEnvironment#getQualifiedObjectNameFormatter} + * {@link SqlStringGenerationContext#format} + * instead. * * @return The string form */ diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/relational/SqlStringGenerationContext.java b/hibernate-core/src/main/java/org/hibernate/boot/model/relational/SqlStringGenerationContext.java index 9daa2271a94b..522fbb0bb480 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/relational/SqlStringGenerationContext.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/relational/SqlStringGenerationContext.java @@ -7,6 +7,7 @@ package org.hibernate.boot.model.relational; import org.hibernate.dialect.Dialect; +import org.hibernate.engine.jdbc.env.spi.IdentifierHelper; /** * A context provided to methods responsible for generating SQL strings on startup. @@ -14,10 +15,18 @@ public interface SqlStringGenerationContext { /** - * @return The database dialect, to generate SQL fragments that are specific to each vendor. + * @return The database dialect of the current JDBC environment, + * to generate SQL fragments that are specific to each vendor. */ Dialect getDialect(); + /** + * @return The helper for dealing with identifiers in the current JDBC environment. + *

    + * Note that the Identifiers returned from this helper already account for auto-quoting. + */ + IdentifierHelper getIdentifierHelper(); + /** * Render a formatted a table name * @@ -45,4 +54,13 @@ public interface SqlStringGenerationContext { */ String format(QualifiedName qualifiedName); + /** + * Render a formatted sequence name, without the catalog (even the default one). + * + * @param qualifiedName The sequence name + * + * @return The formatted name + */ + String formatWithoutCatalog(QualifiedSequenceName qualifiedName); + } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/relational/internal/SqlStringGenerationContextImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/model/relational/internal/SqlStringGenerationContextImpl.java index 83b39a0efaee..6311ddc2779e 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/relational/internal/SqlStringGenerationContextImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/relational/internal/SqlStringGenerationContextImpl.java @@ -11,6 +11,7 @@ import org.hibernate.boot.model.relational.QualifiedTableName; import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.dialect.Dialect; +import org.hibernate.engine.jdbc.env.spi.IdentifierHelper; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.engine.jdbc.env.spi.QualifiedObjectNameFormatter; @@ -22,10 +23,13 @@ public static SqlStringGenerationContext forTests(JdbcEnvironment jdbcEnvironmen } private final Dialect dialect; + private final IdentifierHelper identifierHelper; private final QualifiedObjectNameFormatter qualifiedObjectNameFormatter; + @SuppressWarnings("deprecation") public SqlStringGenerationContextImpl(JdbcEnvironment jdbcEnvironment) { this.dialect = jdbcEnvironment.getDialect(); + this.identifierHelper = jdbcEnvironment.getIdentifierHelper(); this.qualifiedObjectNameFormatter = jdbcEnvironment.getQualifiedObjectNameFormatter(); } @@ -34,6 +38,11 @@ public Dialect getDialect() { return dialect; } + @Override + public IdentifierHelper getIdentifierHelper() { + return identifierHelper; + } + @Override public String format(QualifiedTableName qualifiedName) { return qualifiedObjectNameFormatter.format( qualifiedName, dialect ); @@ -49,4 +58,17 @@ public String format(QualifiedName qualifiedName) { return qualifiedObjectNameFormatter.format( qualifiedName, dialect ); } + @Override + public String formatWithoutCatalog(QualifiedSequenceName qualifiedName) { + QualifiedSequenceName nameToFormat; + if ( qualifiedName.getCatalogName() != null + || qualifiedName.getSchemaName() == null && defaultSchema != null ) { + nameToFormat = new QualifiedSequenceName( null, + schemaWithDefault( qualifiedName.getSchemaName() ), qualifiedName.getSequenceName() ); + } + else { + nameToFormat = qualifiedName; + } + return qualifiedObjectNameFormatter.format( nameToFormat, dialect ); + } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/AbstractHANADialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/AbstractHANADialect.java index 2c087e2ca3eb..61670a4fa4e5 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/AbstractHANADialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/AbstractHANADialect.java @@ -40,8 +40,10 @@ import org.hibernate.LockOptions; import org.hibernate.MappingException; import org.hibernate.ScrollMode; +import org.hibernate.boot.Metadata; import org.hibernate.boot.model.TypeContributions; import org.hibernate.boot.model.naming.Identifier; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.cfg.AvailableSettings; import org.hibernate.dialect.function.AnsiTrimFunction; import org.hibernate.dialect.function.NoArgSQLFunction; @@ -728,14 +730,16 @@ public int getMaxLobPrefetchSize() { private final StandardTableExporter hanaTableExporter = new StandardTableExporter( this ) { @Override - public String[] getSqlCreateStrings(org.hibernate.mapping.Table table, org.hibernate.boot.Metadata metadata) { - String[] sqlCreateStrings = super.getSqlCreateStrings( table, metadata ); + public String[] getSqlCreateStrings(Table table, Metadata metadata, + SqlStringGenerationContext context) { + String[] sqlCreateStrings = super.getSqlCreateStrings( table, metadata, context ); return quoteTypeIfNecessary( table, sqlCreateStrings, getCreateTableString() ); } @Override - public String[] getSqlDropStrings(Table table, org.hibernate.boot.Metadata metadata) { - String[] sqlDropStrings = super.getSqlDropStrings( table, metadata ); + public String[] getSqlDropStrings(Table table, Metadata metadata, + SqlStringGenerationContext context) { + String[] sqlDropStrings = super.getSqlDropStrings( table, metadata, context ); return quoteTypeIfNecessary( table, sqlDropStrings, "drop table" ); } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServer2012Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServer2012Dialect.java index b25672486650..1818f5042ba9 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/SQLServer2012Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/SQLServer2012Dialect.java @@ -9,9 +9,9 @@ import org.hibernate.boot.Metadata; import org.hibernate.boot.model.relational.QualifiedSequenceName; import org.hibernate.boot.model.relational.Sequence; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.dialect.pagination.LimitHandler; import org.hibernate.dialect.pagination.SQLServer2012LimitHandler; -import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.tool.schema.internal.StandardSequenceExporter; import org.hibernate.tool.schema.spi.Exporter; @@ -118,14 +118,12 @@ public SqlServerSequenceExporter(Dialect dialect) { } @Override - protected String getFormattedSequenceName(QualifiedSequenceName name, Metadata metadata) { - if ( name.getCatalogName() != null ) { - // SQL Server does not allow the catalog in the sequence name. - // See https://docs.microsoft.com/en-us/sql/t-sql/statements/create-sequence-transact-sql?view=sql-server-ver15&viewFallbackFrom=sql-server-ver12 - // Keeping the catalog in the name does not break on ORM, but it fails using Vert.X for Reactive. - name = new QualifiedSequenceName( null, name.getSchemaName(), name.getObjectName() ); - } - return super.getFormattedSequenceName( name, metadata ); + protected String getFormattedSequenceName(QualifiedSequenceName name, Metadata metadata, + SqlStringGenerationContext context) { + // SQL Server does not allow the catalog in the sequence name. + // See https://docs.microsoft.com/en-us/sql/t-sql/statements/create-sequence-transact-sql?view=sql-server-ver15&viewFallbackFrom=sql-server-ver12 + // Keeping the catalog in the name does not break on ORM, but it fails using Vert.X for Reactive. + return context.formatWithoutCatalog( name ); } } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/Teradata14Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/Teradata14Dialect.java index 9744036649a6..1526bbb975e5 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/Teradata14Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/Teradata14Dialect.java @@ -17,6 +17,7 @@ import org.hibernate.LockOptions; import org.hibernate.boot.Metadata; import org.hibernate.boot.model.relational.QualifiedNameImpl; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.cfg.Environment; import org.hibernate.dialect.function.SQLFunctionTemplate; import org.hibernate.dialect.identity.IdentityColumnSupport; @@ -214,22 +215,19 @@ public TeradataIndexExporter(Dialect dialect) { } @Override - public String[] getSqlCreateStrings(Index index, Metadata metadata) { + public String[] getSqlCreateStrings(Index index, Metadata metadata, + SqlStringGenerationContext context) { final JdbcEnvironment jdbcEnvironment = metadata.getDatabase().getJdbcEnvironment(); - final String tableName = jdbcEnvironment.getQualifiedObjectNameFormatter().format( - index.getTable().getQualifiedTableName(), - jdbcEnvironment.getDialect() - ); + final String tableName = context.format( index.getTable().getQualifiedTableName() ); final String indexNameForCreation; if ( getDialect().qualifyIndexName() ) { - indexNameForCreation = jdbcEnvironment.getQualifiedObjectNameFormatter().format( + indexNameForCreation = context.format( new QualifiedNameImpl( index.getTable().getQualifiedTableName().getCatalogName(), index.getTable().getQualifiedTableName().getSchemaName(), jdbcEnvironment.getIdentifierHelper().toIdentifier( index.getName() ) - ), - jdbcEnvironment.getDialect() + ) ); } else { diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/unique/DB2UniqueDelegate.java b/hibernate-core/src/main/java/org/hibernate/dialect/unique/DB2UniqueDelegate.java index b866eb762b95..1770053ab807 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/unique/DB2UniqueDelegate.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/unique/DB2UniqueDelegate.java @@ -9,6 +9,7 @@ import java.util.Iterator; import org.hibernate.boot.Metadata; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.dialect.Dialect; import org.hibernate.mapping.UniqueKey; @@ -29,10 +30,11 @@ public DB2UniqueDelegate( Dialect dialect ) { } @Override - public String getAlterTableToAddUniqueKeyCommand(UniqueKey uniqueKey, Metadata metadata) { + public String getAlterTableToAddUniqueKeyCommand(UniqueKey uniqueKey, Metadata metadata, + SqlStringGenerationContext context) { if ( hasNullable( uniqueKey ) ) { return org.hibernate.mapping.Index.buildSqlCreateIndexString( - dialect, + context, uniqueKey.getName(), uniqueKey.getTable(), uniqueKey.columnIterator(), @@ -42,23 +44,21 @@ public String getAlterTableToAddUniqueKeyCommand(UniqueKey uniqueKey, Metadata m ); } else { - return super.getAlterTableToAddUniqueKeyCommand( uniqueKey, metadata ); + return super.getAlterTableToAddUniqueKeyCommand( uniqueKey, metadata, context ); } } @Override - public String getAlterTableToDropUniqueKeyCommand(UniqueKey uniqueKey, Metadata metadata) { + public String getAlterTableToDropUniqueKeyCommand(UniqueKey uniqueKey, Metadata metadata, + SqlStringGenerationContext context) { if ( hasNullable( uniqueKey ) ) { return org.hibernate.mapping.Index.buildSqlDropIndexString( uniqueKey.getName(), - metadata.getDatabase().getJdbcEnvironment().getQualifiedObjectNameFormatter().format( - uniqueKey.getTable().getQualifiedTableName(), - metadata.getDatabase().getJdbcEnvironment().getDialect() - ) + context.format( uniqueKey.getTable().getQualifiedTableName() ) ); } else { - return super.getAlterTableToDropUniqueKeyCommand( uniqueKey, metadata ); + return super.getAlterTableToDropUniqueKeyCommand( uniqueKey, metadata, context ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/unique/DefaultUniqueDelegate.java b/hibernate-core/src/main/java/org/hibernate/dialect/unique/DefaultUniqueDelegate.java index eec4fbd62f1f..f73d3ca30db3 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/unique/DefaultUniqueDelegate.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/unique/DefaultUniqueDelegate.java @@ -9,8 +9,10 @@ import java.util.Iterator; import org.hibernate.boot.Metadata; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.dialect.Dialect; -import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; +import org.hibernate.mapping.Column; +import org.hibernate.mapping.Table; import org.hibernate.mapping.UniqueKey; /** @@ -34,23 +36,21 @@ public DefaultUniqueDelegate( Dialect dialect ) { // legacy model ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @Override - public String getColumnDefinitionUniquenessFragment(org.hibernate.mapping.Column column) { + public String getColumnDefinitionUniquenessFragment(Column column, + SqlStringGenerationContext context) { return ""; } @Override - public String getTableCreationUniqueConstraintsFragment(org.hibernate.mapping.Table table) { + public String getTableCreationUniqueConstraintsFragment(Table table, + SqlStringGenerationContext context) { return ""; } @Override - public String getAlterTableToAddUniqueKeyCommand(UniqueKey uniqueKey, Metadata metadata) { - final JdbcEnvironment jdbcEnvironment = metadata.getDatabase().getJdbcEnvironment(); - - final String tableName = jdbcEnvironment.getQualifiedObjectNameFormatter().format( - uniqueKey.getTable().getQualifiedTableName(), - dialect - ); + public String getAlterTableToAddUniqueKeyCommand(UniqueKey uniqueKey, Metadata metadata, + SqlStringGenerationContext context) { + final String tableName = context.format( uniqueKey.getTable().getQualifiedTableName() ); final String constraintName = dialect.quote( uniqueKey.getName() ); return dialect.getAlterTableString( tableName ) @@ -76,13 +76,9 @@ protected String uniqueConstraintSql(UniqueKey uniqueKey) { } @Override - public String getAlterTableToDropUniqueKeyCommand(UniqueKey uniqueKey, Metadata metadata) { - final JdbcEnvironment jdbcEnvironment = metadata.getDatabase().getJdbcEnvironment(); - - final String tableName = jdbcEnvironment.getQualifiedObjectNameFormatter().format( - uniqueKey.getTable().getQualifiedTableName(), - dialect - ); + public String getAlterTableToDropUniqueKeyCommand(UniqueKey uniqueKey, Metadata metadata, + SqlStringGenerationContext context) { + final String tableName = context.format( uniqueKey.getTable().getQualifiedTableName() ); final StringBuilder buf = new StringBuilder( dialect.getAlterTableString(tableName) ); buf.append( getDropUnique() ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/unique/InformixUniqueDelegate.java b/hibernate-core/src/main/java/org/hibernate/dialect/unique/InformixUniqueDelegate.java index ae8fc4204cac..cffa7b5ffe82 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/unique/InformixUniqueDelegate.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/unique/InformixUniqueDelegate.java @@ -7,6 +7,7 @@ package org.hibernate.dialect.unique; import org.hibernate.boot.Metadata; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.dialect.Dialect; import org.hibernate.mapping.UniqueKey; @@ -24,13 +25,11 @@ public InformixUniqueDelegate( Dialect dialect ) { // legacy model ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @Override - public String getAlterTableToAddUniqueKeyCommand(UniqueKey uniqueKey, Metadata metadata) { + public String getAlterTableToAddUniqueKeyCommand(UniqueKey uniqueKey, Metadata metadata, + SqlStringGenerationContext context) { // Do this here, rather than allowing UniqueKey/Constraint to do it. // We need full, simplified control over whether or not it happens. - final String tableName = metadata.getDatabase().getJdbcEnvironment().getQualifiedObjectNameFormatter().format( - uniqueKey.getTable().getQualifiedTableName(), - metadata.getDatabase().getJdbcEnvironment().getDialect() - ); + final String tableName = context.format( uniqueKey.getTable().getQualifiedTableName() ); final String constraintName = dialect.quote( uniqueKey.getName() ); return dialect.getAlterTableString( tableName ) + " add constraint " + uniqueConstraintSql( uniqueKey ) + " constraint " + constraintName; diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/unique/UniqueDelegate.java b/hibernate-core/src/main/java/org/hibernate/dialect/unique/UniqueDelegate.java index 89ef372eba2c..6fdc173af796 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/unique/UniqueDelegate.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/unique/UniqueDelegate.java @@ -7,6 +7,9 @@ package org.hibernate.dialect.unique; import org.hibernate.boot.Metadata; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; +import org.hibernate.mapping.Column; +import org.hibernate.mapping.Table; import org.hibernate.mapping.UniqueKey; /** @@ -38,11 +41,11 @@ public interface UniqueDelegate { * This is intended for dialects which do not support unique constraints * * @param column The column to which to apply the unique - * + * @param context A context for SQL string generation * @return The fragment (usually "unique"), empty string indicates the uniqueness will be indicated using a * different approach */ - public String getColumnDefinitionUniquenessFragment(org.hibernate.mapping.Column column); + public String getColumnDefinitionUniquenessFragment(Column column, SqlStringGenerationContext context); /** * Get the fragment that can be used to apply unique constraints as part of table creation. The implementation @@ -53,30 +56,32 @@ public interface UniqueDelegate { * Intended for Dialects which support unique constraint definitions, but just not in separate ALTER statements. * * @param table The table for which to generate the unique constraints fragment - * + * @param context A context for SQL string generation * @return The fragment, typically in the form {@code ", unique(col1, col2), unique( col20)"}. NOTE: The leading * comma is important! */ - public String getTableCreationUniqueConstraintsFragment(org.hibernate.mapping.Table table); + public String getTableCreationUniqueConstraintsFragment(Table table, SqlStringGenerationContext context); /** * Get the SQL ALTER TABLE command to be used to create the given UniqueKey. * * @param uniqueKey The UniqueKey instance. Contains all information about the columns * @param metadata Access to the bootstrap mapping information - * + * @param context A context for SQL string generation * @return The ALTER TABLE command */ - public String getAlterTableToAddUniqueKeyCommand(UniqueKey uniqueKey, Metadata metadata); + public String getAlterTableToAddUniqueKeyCommand(UniqueKey uniqueKey, Metadata metadata, + SqlStringGenerationContext context); /** * Get the SQL ALTER TABLE command to be used to drop the given UniqueKey. * * @param uniqueKey The UniqueKey instance. Contains all information about the columns * @param metadata Access to the bootstrap mapping information - * + * @param context A context for SQL string generation * @return The ALTER TABLE command */ - public String getAlterTableToDropUniqueKeyCommand(UniqueKey uniqueKey, Metadata metadata); + public String getAlterTableToDropUniqueKeyCommand(UniqueKey uniqueKey, Metadata metadata, + SqlStringGenerationContext context); } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/JdbcEnvironment.java b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/JdbcEnvironment.java index 2a9fa57f0b6a..a0b48b68d699 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/JdbcEnvironment.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jdbc/env/spi/JdbcEnvironment.java @@ -55,7 +55,9 @@ public interface JdbcEnvironment extends Service { * Obtain support for formatting qualified object names. * * @return Qualified name support. + * @deprecated Use a provided {@link org.hibernate.boot.model.relational.SqlStringGenerationContext} instead. */ + @Deprecated QualifiedObjectNameFormatter getQualifiedObjectNameFormatter(); /** diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/AbstractMultiTableBulkIdStrategyImpl.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/AbstractMultiTableBulkIdStrategyImpl.java index 71f4e763953b..7be9641f62ab 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/AbstractMultiTableBulkIdStrategyImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/AbstractMultiTableBulkIdStrategyImpl.java @@ -12,6 +12,7 @@ import org.hibernate.QueryException; import org.hibernate.boot.model.relational.QualifiedTableName; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.boot.spi.MetadataBuildingOptions; import org.hibernate.boot.spi.MetadataImplementor; import org.hibernate.boot.spi.SessionFactoryOptions; @@ -48,7 +49,8 @@ public final void prepare( JdbcServices jdbcServices, JdbcConnectionAccess connectionAccess, MetadataImplementor metadata, - SessionFactoryOptions sessionFactoryOptions) { + SessionFactoryOptions sessionFactoryOptions, + SqlStringGenerationContext sqlStringGenerationContext) { // build/get Table representation of the bulk-id tables - subclasses need hooks // for each: // handle DDL @@ -66,9 +68,8 @@ public final void prepare( continue; } - final String idTableName = jdbcEnvironment.getQualifiedObjectNameFormatter().format( - determineIdTableName( jdbcEnvironment, entityBinding ), - jdbcEnvironment.getDialect() + final String idTableName = sqlStringGenerationContext.format( + determineIdTableName( jdbcEnvironment, entityBinding ) ); final Table idTable = new Table(); idTable.setName( idTableName ); @@ -81,7 +82,9 @@ public final void prepare( } augmentIdTableDefinition( idTable ); - final TT idTableInfo = buildIdTableInfo( entityBinding, idTable, jdbcServices, metadata, context ); + final TT idTableInfo = buildIdTableInfo( entityBinding, idTable, jdbcServices, metadata, context, + sqlStringGenerationContext + ); idTableInfoMap.put( entityBinding.getEntityName(), idTableInfo ); } @@ -125,16 +128,17 @@ protected abstract TT buildIdTableInfo( Table idTable, JdbcServices jdbcServices, MetadataImplementor metadata, - CT context); + CT context, + SqlStringGenerationContext sqlStringGenerationContext); - protected String buildIdTableCreateStatement(Table idTable, JdbcServices jdbcServices, MetadataImplementor metadata) { - final JdbcEnvironment jdbcEnvironment = jdbcServices.getJdbcEnvironment(); - final Dialect dialect = jdbcEnvironment.getDialect(); + protected String buildIdTableCreateStatement(Table idTable, MetadataImplementor metadata, + SqlStringGenerationContext sqlStringGenerationContext) { + final Dialect dialect = sqlStringGenerationContext.getDialect(); StringBuilder buffer = new StringBuilder( getIdTableSupport().getCreateIdTableCommand() ) .append( ' ' ) - .append( jdbcEnvironment.getQualifiedObjectNameFormatter().format( idTable.getQualifiedTableName(), dialect ) ) + .append( sqlStringGenerationContext.format( idTable.getQualifiedTableName() ) ) .append( " (" ); Iterator itr = idTable.getColumnIterator(); @@ -169,12 +173,9 @@ protected String buildIdTableCreateStatement(Table idTable, JdbcServices jdbcSer return buffer.toString(); } - protected String buildIdTableDropStatement(Table idTable, JdbcServices jdbcServices) { - final JdbcEnvironment jdbcEnvironment = jdbcServices.getJdbcEnvironment(); - final Dialect dialect = jdbcEnvironment.getDialect(); - + protected String buildIdTableDropStatement(Table idTable, SqlStringGenerationContext sqlStringGenerationContext) { return getIdTableSupport().getDropIdTableCommand() + " " - + jdbcEnvironment.getQualifiedObjectNameFormatter().format( idTable.getQualifiedTableName(), dialect ); + + sqlStringGenerationContext.format( idTable.getQualifiedTableName() ); } protected void finishPreparation( diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/MultiTableBulkIdStrategy.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/MultiTableBulkIdStrategy.java index 76854f0ecd78..48553f3b128a 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/MultiTableBulkIdStrategy.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/MultiTableBulkIdStrategy.java @@ -6,6 +6,7 @@ */ package org.hibernate.hql.spi.id; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.boot.spi.MetadataImplementor; import org.hibernate.boot.spi.SessionFactoryOptions; import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess; @@ -27,16 +28,18 @@ public interface MultiTableBulkIdStrategy { *

  • Adding tables to the passed Mappings, to be picked by by "schema management tools"
  • *
  • Manually creating the tables immediately through the passed JDBC Connection access
  • * - * @param jdbcServices The JdbcService object + * @param jdbcServices The JdbcService object * @param connectionAccess Access to the JDBC Connection * @param metadata Access to the O/RM mapping information * @param sessionFactoryOptions + * @param sqlStringGenerationContext */ void prepare( JdbcServices jdbcServices, JdbcConnectionAccess connectionAccess, MetadataImplementor metadata, - SessionFactoryOptions sessionFactoryOptions); + SessionFactoryOptions sessionFactoryOptions, + SqlStringGenerationContext sqlStringGenerationContext); /** * Release the strategy. Called as the SessionFactory is being shut down. diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/cte/AbstractCteValuesListBulkIdHandler.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/cte/AbstractCteValuesListBulkIdHandler.java index 2f4b75e7fee0..c8c118cf15a6 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/cte/AbstractCteValuesListBulkIdHandler.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/cte/AbstractCteValuesListBulkIdHandler.java @@ -72,13 +72,12 @@ protected String determineIdTableName(Queryable persister) { "HT_" + StringHelper.unquote( persister.getTableName(), jdbcEnvironment.getDialect() ) ).render(); - return jdbcEnvironment.getQualifiedObjectNameFormatter().format( + return persister.getFactory().getSqlStringGenerationContext().format( new QualifiedTableName( Identifier.toIdentifier( catalog ), Identifier.toIdentifier( schema ), Identifier.toIdentifier( qualifiedTableName ) - ), - jdbcEnvironment.getDialect() + ) ); } diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/cte/CteValuesListBulkIdStrategy.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/cte/CteValuesListBulkIdStrategy.java index 7a83da863b45..15848ee673b1 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/cte/CteValuesListBulkIdStrategy.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/cte/CteValuesListBulkIdStrategy.java @@ -6,6 +6,7 @@ */ package org.hibernate.hql.spi.id.cte; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.boot.spi.MetadataImplementor; import org.hibernate.boot.spi.SessionFactoryOptions; import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess; @@ -55,7 +56,8 @@ public void prepare( JdbcServices jdbcServices, JdbcConnectionAccess jdbcConnectionAccess, MetadataImplementor metadataImplementor, - SessionFactoryOptions sessionFactoryOptions) { + SessionFactoryOptions sessionFactoryOptions, + SqlStringGenerationContext sqlStringGenerationContext) { // nothing to do } diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/global/GlobalTemporaryTableBulkIdStrategy.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/global/GlobalTemporaryTableBulkIdStrategy.java index c1cbed9c660b..17dbd9de3107 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/global/GlobalTemporaryTableBulkIdStrategy.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/global/GlobalTemporaryTableBulkIdStrategy.java @@ -8,6 +8,7 @@ import java.sql.PreparedStatement; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.spi.MetadataBuildingOptions; import org.hibernate.boot.spi.MetadataImplementor; @@ -104,16 +105,14 @@ protected IdTableInfoImpl buildIdTableInfo( Table idTable, JdbcServices jdbcServices, MetadataImplementor metadata, - PreparationContextImpl context) { - context.creationStatements.add( buildIdTableCreateStatement( idTable, jdbcServices, metadata ) ); + PreparationContextImpl context, + SqlStringGenerationContext sqlStringGenerationContext) { + context.creationStatements.add( buildIdTableCreateStatement( idTable, metadata, sqlStringGenerationContext ) ); if ( dropIdTables ) { - context.dropStatements.add( buildIdTableDropStatement( idTable, jdbcServices ) ); + context.dropStatements.add( buildIdTableDropStatement( idTable, sqlStringGenerationContext ) ); } - final String renderedName = jdbcServices.getJdbcEnvironment().getQualifiedObjectNameFormatter().format( - idTable.getQualifiedTableName(), - jdbcServices.getJdbcEnvironment().getDialect() - ); + final String renderedName = sqlStringGenerationContext.format( idTable.getQualifiedTableName() ); return new IdTableInfoImpl( renderedName ); } diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/inline/InlineIdsInClauseBulkIdStrategy.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/inline/InlineIdsInClauseBulkIdStrategy.java index 90b95a1e8947..be03521fb2a0 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/inline/InlineIdsInClauseBulkIdStrategy.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/inline/InlineIdsInClauseBulkIdStrategy.java @@ -6,6 +6,7 @@ */ package org.hibernate.hql.spi.id.inline; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.boot.spi.MetadataImplementor; import org.hibernate.boot.spi.SessionFactoryOptions; import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess; @@ -43,7 +44,8 @@ public void prepare( JdbcServices jdbcServices, JdbcConnectionAccess jdbcConnectionAccess, MetadataImplementor metadataImplementor, - SessionFactoryOptions sessionFactoryOptions) { + SessionFactoryOptions sessionFactoryOptions, + SqlStringGenerationContext sqlStringGenerationContext) { // nothing to do } diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/inline/InlineIdsOrClauseBulkIdStrategy.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/inline/InlineIdsOrClauseBulkIdStrategy.java index 0ec0204f1fca..1c479e1d9d29 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/inline/InlineIdsOrClauseBulkIdStrategy.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/inline/InlineIdsOrClauseBulkIdStrategy.java @@ -6,6 +6,7 @@ */ package org.hibernate.hql.spi.id.inline; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.boot.spi.MetadataImplementor; import org.hibernate.boot.spi.SessionFactoryOptions; import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess; @@ -45,7 +46,8 @@ public void prepare( JdbcServices jdbcServices, JdbcConnectionAccess jdbcConnectionAccess, MetadataImplementor metadataImplementor, - SessionFactoryOptions sessionFactoryOptions) { + SessionFactoryOptions sessionFactoryOptions, + SqlStringGenerationContext sqlStringGenerationContext) { // nothing to do } diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/inline/InlineIdsSubSelectValueListBulkIdStrategy.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/inline/InlineIdsSubSelectValueListBulkIdStrategy.java index 09c15d520f11..7e6578357fb9 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/inline/InlineIdsSubSelectValueListBulkIdStrategy.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/inline/InlineIdsSubSelectValueListBulkIdStrategy.java @@ -6,6 +6,7 @@ */ package org.hibernate.hql.spi.id.inline; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.boot.spi.MetadataImplementor; import org.hibernate.boot.spi.SessionFactoryOptions; import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess; @@ -48,7 +49,8 @@ public void prepare( JdbcServices jdbcServices, JdbcConnectionAccess jdbcConnectionAccess, MetadataImplementor metadataImplementor, - SessionFactoryOptions sessionFactoryOptions) { + SessionFactoryOptions sessionFactoryOptions, + SqlStringGenerationContext sqlStringGenerationContext) { // nothing to do } diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/local/LocalTemporaryTableBulkIdStrategy.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/local/LocalTemporaryTableBulkIdStrategy.java index 68c2088932ba..715cb7fc9361 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/local/LocalTemporaryTableBulkIdStrategy.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/local/LocalTemporaryTableBulkIdStrategy.java @@ -7,6 +7,7 @@ package org.hibernate.hql.spi.id.local; import org.hibernate.boot.TempTableDdlTransactionHandling; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.spi.MetadataBuildingOptions; import org.hibernate.boot.spi.MetadataImplementor; @@ -111,17 +112,15 @@ protected IdTableInfoImpl buildIdTableInfo( Table idTable, JdbcServices jdbcServices, MetadataImplementor metadata, - PreparationContextImpl context) { - String dropStatement = buildIdTableDropStatement( idTable, jdbcServices ); + PreparationContextImpl context, + SqlStringGenerationContext sqlStringGenerationContext) { + String dropStatement = buildIdTableDropStatement( idTable, sqlStringGenerationContext ); if ( dropIdTables ) { context.dropStatements.add( dropStatement ); } return new IdTableInfoImpl( - jdbcServices.getJdbcEnvironment().getQualifiedObjectNameFormatter().format( - idTable.getQualifiedTableName(), - jdbcServices.getJdbcEnvironment().getDialect() - ), - buildIdTableCreateStatement( idTable, jdbcServices, metadata ), + sqlStringGenerationContext.format( idTable.getQualifiedTableName() ), + buildIdTableCreateStatement( idTable, metadata, sqlStringGenerationContext ), dropStatement ); } diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/persistent/PersistentTableBulkIdStrategy.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/persistent/PersistentTableBulkIdStrategy.java index 04c2cf0c04e0..dec96832e55d 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/persistent/PersistentTableBulkIdStrategy.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/persistent/PersistentTableBulkIdStrategy.java @@ -10,6 +10,7 @@ import org.hibernate.boot.model.naming.Identifier; import org.hibernate.boot.model.relational.QualifiedTableName; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.spi.MetadataBuildingOptions; import org.hibernate.boot.spi.MetadataImplementor; @@ -124,15 +125,15 @@ protected IdTableInfoImpl buildIdTableInfo( Table idTable, JdbcServices jdbcServices, MetadataImplementor metadata, - PreparationContextImpl context) { - final String renderedName = jdbcServices.getJdbcEnvironment().getQualifiedObjectNameFormatter().format( - idTable.getQualifiedTableName(), - jdbcServices.getJdbcEnvironment().getDialect() - ); + PreparationContextImpl context, + SqlStringGenerationContext sqlStringGenerationContext) { + final String renderedName = sqlStringGenerationContext.format( idTable.getQualifiedTableName() ); - context.creationStatements.add( buildIdTableCreateStatement( idTable, jdbcServices, metadata ) ); + context.creationStatements.add( buildIdTableCreateStatement( idTable, metadata, + sqlStringGenerationContext + ) ); if ( dropIdTables ) { - context.dropStatements.add( buildIdTableDropStatement( idTable, jdbcServices ) ); + context.dropStatements.add( buildIdTableDropStatement( idTable, sqlStringGenerationContext ) ); } return new IdTableInfoImpl( renderedName ); diff --git a/hibernate-core/src/main/java/org/hibernate/internal/FilterConfiguration.java b/hibernate-core/src/main/java/org/hibernate/internal/FilterConfiguration.java index 84461d642af3..c494da3c2029 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/FilterConfiguration.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/FilterConfiguration.java @@ -59,7 +59,7 @@ public Map getAliasTableMap(SessionFactoryImplementor factory) { } else if ( persistentClass != null ) { String table = persistentClass.getTable().getQualifiedName( - factory.getDialect(), + factory.getSqlStringGenerationContext(), factory.getSettings().getDefaultCatalogName(), factory.getSettings().getDefaultSchemaName() ); diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java index b404b1c7e022..099de0dcb53c 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java @@ -325,7 +325,8 @@ public void sessionFactoryClosed(SessionFactory factory) { jdbcServices, buildLocalConnectionAccess(), metadata, - sessionFactoryOptions + sessionFactoryOptions, + sqlStringGenerationContext ); SchemaManagementToolCoordinator.process( diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Constraint.java b/hibernate-core/src/main/java/org/hibernate/mapping/Constraint.java index a15aa2a3a656..85ab53899aff 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Constraint.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Constraint.java @@ -18,6 +18,7 @@ import org.hibernate.HibernateException; import org.hibernate.boot.model.relational.Exportable; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.dialect.Dialect; import org.hibernate.engine.spi.Mapping; import org.hibernate.internal.util.StringHelper; @@ -179,9 +180,12 @@ public boolean isGenerated(Dialect dialect) { return true; } - public String sqlDropString(Dialect dialect, String defaultCatalog, String defaultSchema) { + @Override + public String sqlDropString(SqlStringGenerationContext context, + String defaultCatalog, String defaultSchema) { + Dialect dialect = context.getDialect(); if ( isGenerated( dialect ) ) { - final String tableName = getTable().getQualifiedName( dialect, defaultCatalog, defaultSchema ); + final String tableName = getTable().getQualifiedName( context, defaultCatalog, defaultSchema ); return String.format( Locale.ROOT, "%s evictData constraint %s", @@ -194,14 +198,17 @@ public String sqlDropString(Dialect dialect, String defaultCatalog, String defau } } - public String sqlCreateString(Dialect dialect, Mapping p, String defaultCatalog, String defaultSchema) { + @Override + public String sqlCreateString(Mapping p, SqlStringGenerationContext context, String defaultCatalog, + String defaultSchema) { + Dialect dialect = context.getDialect(); if ( isGenerated( dialect ) ) { // Certain dialects (ex: HANA) don't support FKs as expected, but other constraints can still be created. // If that's the case, hasAlterTable() will be true, but getAddForeignKeyConstraintString will return // empty string. Prevent blank "alter table" statements. - String constraintString = sqlConstraintString( dialect, getName(), defaultCatalog, defaultSchema ); + String constraintString = sqlConstraintString( context, getName(), defaultCatalog, defaultSchema ); if ( !StringHelper.isEmpty( constraintString ) ) { - final String tableName = getTable().getQualifiedName( dialect, defaultCatalog, defaultSchema ); + final String tableName = getTable().getQualifiedName( context, defaultCatalog, defaultSchema ); return dialect.getAlterTableString( tableName ) + " " + constraintString; } } @@ -213,7 +220,7 @@ public List getColumns() { } public abstract String sqlConstraintString( - Dialect d, + SqlStringGenerationContext context, String constraintName, String defaultCatalog, String defaultSchema); diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/ForeignKey.java b/hibernate-core/src/main/java/org/hibernate/mapping/ForeignKey.java index 73d891f1a647..3f309d1d4f9e 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/ForeignKey.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/ForeignKey.java @@ -11,6 +11,7 @@ import java.util.List; import org.hibernate.MappingException; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.dialect.Dialect; import org.hibernate.internal.util.StringHelper; @@ -54,11 +55,13 @@ public void setName(String name) { } } + @Override public String sqlConstraintString( - Dialect dialect, + SqlStringGenerationContext context, String constraintName, String defaultCatalog, String defaultSchema) { + Dialect dialect = context.getDialect(); String[] columnNames = new String[getColumnSpan()]; String[] referencedColumnNames = new String[getColumnSpan()]; @@ -87,7 +90,7 @@ public String sqlConstraintString( constraintName, columnNames, referencedTable.getQualifiedName( - dialect, + context, defaultCatalog, defaultSchema ), @@ -172,8 +175,11 @@ public void setKeyDefinition(String keyDefinition) { this.keyDefinition = keyDefinition; } - public String sqlDropString(Dialect dialect, String defaultCatalog, String defaultSchema) { - String tableName = getTable().getQualifiedName( dialect, defaultCatalog, defaultSchema ); + @Override + public String sqlDropString(SqlStringGenerationContext context, + String defaultCatalog, String defaultSchema) { + Dialect dialect = context.getDialect(); + String tableName = getTable().getQualifiedName( context, defaultCatalog, defaultSchema ); final StringBuilder buf = new StringBuilder( dialect.getAlterTableString( tableName ) ); buf.append( dialect.getDropForeignKeyString() ); if ( dialect.supportsIfExistsBeforeConstraintName() ) { diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Index.java b/hibernate-core/src/main/java/org/hibernate/mapping/Index.java index 4d7da83ec7cc..cbc96c2ea023 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Index.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Index.java @@ -16,8 +16,8 @@ import org.hibernate.boot.Metadata; import org.hibernate.boot.model.naming.Identifier; import org.hibernate.boot.model.relational.Exportable; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.dialect.Dialect; -import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.engine.spi.Mapping; import org.hibernate.internal.util.StringHelper; @@ -32,10 +32,13 @@ public class Index implements RelationalModel, Exportable, Serializable { private java.util.Map columnOrderMap = new HashMap( ); private Identifier name; - public String sqlCreateString(Dialect dialect, Mapping mapping, String defaultCatalog, String defaultSchema) + @Override + public String sqlCreateString(Mapping mapping, SqlStringGenerationContext context, String defaultCatalog, + String defaultSchema) throws HibernateException { + Dialect dialect = context.getDialect(); return buildSqlCreateIndexString( - dialect, + context, getQuotedName( dialect ), getTable(), getColumnIterator(), @@ -47,12 +50,12 @@ public String sqlCreateString(Dialect dialect, Mapping mapping, String defaultCa } public static String buildSqlDropIndexString( - Dialect dialect, + SqlStringGenerationContext context, Table table, String name, String defaultCatalog, String defaultSchema) { - return buildSqlDropIndexString( name, table.getQualifiedName( dialect, defaultCatalog, defaultSchema ) ); + return buildSqlDropIndexString( name, table.getQualifiedName( context, defaultCatalog, defaultSchema ) ); } public static String buildSqlDropIndexString( @@ -62,7 +65,7 @@ public static String buildSqlDropIndexString( } public static String buildSqlCreateIndexString( - Dialect dialect, + SqlStringGenerationContext context, String name, Table table, Iterator columns, @@ -71,9 +74,9 @@ public static String buildSqlCreateIndexString( String defaultCatalog, String defaultSchema) { return buildSqlCreateIndexString( - dialect, + context.getDialect(), name, - table.getQualifiedName( dialect, defaultCatalog, defaultSchema ), + table.getQualifiedName( context, defaultCatalog, defaultSchema ), columns, columnOrderMap, unique @@ -109,42 +112,17 @@ public static String buildSqlCreateIndexString( } public static String buildSqlCreateIndexString( - Dialect dialect, - String name, - Table table, - Iterator columns, - boolean unique, - String defaultCatalog, - String defaultSchema) { - return buildSqlCreateIndexString( - dialect, - name, - table, - columns, - Collections.EMPTY_MAP, - unique, - defaultCatalog, - defaultSchema - ); - } - - public static String buildSqlCreateIndexString( - Dialect dialect, + SqlStringGenerationContext context, String name, Table table, Iterator columns, java.util.Map columnOrderMap, boolean unique, Metadata metadata) { - final JdbcEnvironment jdbcEnvironment = metadata.getDatabase().getJdbcEnvironment(); - - final String tableName = jdbcEnvironment.getQualifiedObjectNameFormatter().format( - table.getQualifiedTableName(), - dialect - ); + final String tableName = context.format( table.getQualifiedTableName() ); return buildSqlCreateIndexString( - dialect, + context.getDialect(), name, tableName, columns, @@ -168,10 +146,12 @@ public String sqlConstraintString(Dialect dialect) { } @Override - public String sqlDropString(Dialect dialect, String defaultCatalog, String defaultSchema) { + public String sqlDropString(SqlStringGenerationContext context, + String defaultCatalog, String defaultSchema) { + Dialect dialect = context.getDialect(); return "drop index " + StringHelper.qualify( - table.getQualifiedName( dialect, defaultCatalog, defaultSchema ), + table.getQualifiedName( context, defaultCatalog, defaultSchema ), getQuotedName( dialect ) ); } diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/PrimaryKey.java b/hibernate-core/src/main/java/org/hibernate/mapping/PrimaryKey.java index 3c5e9a03b127..162c37f19855 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/PrimaryKey.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/PrimaryKey.java @@ -7,6 +7,7 @@ package org.hibernate.mapping; import java.util.Iterator; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.dialect.Dialect; import org.hibernate.internal.util.StringHelper; @@ -69,7 +70,9 @@ public String sqlConstraintString(Dialect dialect) { return buf.append(')').toString(); } - public String sqlConstraintString(Dialect dialect, String constraintName, String defaultCatalog, String defaultSchema) { + @Override + public String sqlConstraintString(SqlStringGenerationContext context, String constraintName, String defaultCatalog, String defaultSchema) { + Dialect dialect = context.getDialect(); StringBuilder buf = new StringBuilder( dialect.getAddPrimaryKeyConstraintString(constraintName) ).append('('); diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/RelationalModel.java b/hibernate-core/src/main/java/org/hibernate/mapping/RelationalModel.java index 167a28bc1a72..3f011773febd 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/RelationalModel.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/RelationalModel.java @@ -6,7 +6,7 @@ */ package org.hibernate.mapping; import org.hibernate.HibernateException; -import org.hibernate.dialect.Dialect; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.engine.spi.Mapping; /** @@ -17,6 +17,6 @@ */ @Deprecated public interface RelationalModel { - String sqlCreateString(Dialect dialect, Mapping p, String defaultCatalog, String defaultSchema) throws HibernateException; - String sqlDropString(Dialect dialect, String defaultCatalog, String defaultSchema); + String sqlCreateString(Mapping p, SqlStringGenerationContext context, String defaultCatalog, String defaultSchema) throws HibernateException; + String sqlDropString(SqlStringGenerationContext context, String defaultCatalog, String defaultSchema); } diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Table.java b/hibernate-core/src/main/java/org/hibernate/mapping/Table.java index 2c5ae2f33f42..8f802ce637df 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Table.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Table.java @@ -28,8 +28,7 @@ import org.hibernate.boot.model.relational.QualifiedTableName; import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.dialect.Dialect; -import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; -import org.hibernate.engine.jdbc.env.spi.QualifiedObjectNameFormatter; +import org.hibernate.engine.jdbc.env.spi.IdentifierHelper; import org.hibernate.engine.spi.Mapping; import org.hibernate.tool.hbm2ddl.ColumnMetadata; import org.hibernate.tool.hbm2ddl.TableMetadata; @@ -114,28 +113,23 @@ public Table(Namespace namespace, String subselect, boolean isAbstract) { this.isAbstract = isAbstract; } - /** - * @deprecated Should use {@link QualifiedObjectNameFormatter#format} on QualifiedObjectNameFormatter - * obtained from {@link org.hibernate.engine.jdbc.env.spi.JdbcEnvironment} - */ - @Deprecated - public String getQualifiedName(Dialect dialect, String defaultCatalog, String defaultSchema) { + public String getQualifiedName(SqlStringGenerationContext context, String defaultCatalog, String defaultSchema) { if ( subselect != null ) { return "( " + subselect + " )"; } - String quotedName = getQuotedName( dialect ); - String usedSchema = schema == null ? - defaultSchema : - getQuotedSchema( dialect ); - String usedCatalog = catalog == null ? - defaultCatalog : - getQuotedCatalog( dialect ); - return qualify( usedCatalog, usedSchema, quotedName ); + IdentifierHelper identifierHelper = context.getIdentifierHelper(); + Identifier usedSchema = schema == null ? + identifierHelper.toIdentifier( defaultSchema ) : + schema; + Identifier usedCatalog = catalog == null ? + identifierHelper.toIdentifier( defaultCatalog ) : + catalog; + return context.format( new QualifiedTableName( usedCatalog, usedSchema, name ) ); } /** - * @deprecated Should use {@link QualifiedObjectNameFormatter#format} on QualifiedObjectNameFormatter - * obtained from {@link org.hibernate.engine.jdbc.env.spi.JdbcEnvironment} + * @deprecated Should build a {@link QualifiedTableName} + * then use {@link SqlStringGenerationContext#format(QualifiedTableName)}. */ @Deprecated public static String qualify(String catalog, String schema, String table) { @@ -448,17 +442,14 @@ public Iterator sqlAlterStrings( Metadata metadata, TableInformation tableInfo, Identifier defaultCatalog, - Identifier defaultSchema) throws HibernateException { - - final JdbcEnvironment jdbcEnvironment = metadata.getDatabase().getJdbcEnvironment(); - - final String tableName = jdbcEnvironment.getQualifiedObjectNameFormatter().format( + Identifier defaultSchema, + SqlStringGenerationContext sqlStringGenerationContext) throws HibernateException { + final String tableName = sqlStringGenerationContext.format( new QualifiedTableName( catalog != null ? catalog : defaultCatalog, schema != null ? schema : defaultSchema, name - ), - dialect + ) ); StringBuilder root = new StringBuilder( dialect.getAlterTableString( tableName ) ) @@ -497,7 +488,7 @@ public Iterator sqlAlterStrings( UniqueKey uk = getOrCreateUniqueKey( keyName ); uk.addColumn( column ); alter.append( dialect.getUniqueDelegate() - .getColumnDefinitionUniquenessFragment( column ) ); + .getColumnDefinitionUniquenessFragment( column, sqlStringGenerationContext ) ); } if ( column.hasCheckConstraint() && dialect.supportsColumnCheck() ) { @@ -529,10 +520,13 @@ public boolean hasPrimaryKey() { return getPrimaryKey() != null; } - public String sqlCreateString(Dialect dialect, Mapping p, String defaultCatalog, String defaultSchema) { + @Override + public String sqlCreateString(Mapping p, SqlStringGenerationContext context, String defaultCatalog, + String defaultSchema) { + Dialect dialect = context.getDialect(); StringBuilder buf = new StringBuilder( hasPrimaryKey() ? dialect.getCreateTableString() : dialect.getCreateMultisetTableString() ) .append( ' ' ) - .append( getQualifiedName( dialect, defaultCatalog, defaultSchema ) ) + .append( getQualifiedName( context, defaultCatalog, defaultSchema ) ) .append( " (" ); boolean identityColumn = idValue != null && idValue.isIdentityColumn( p.getIdentifierGeneratorFactory(), dialect ); @@ -581,7 +575,7 @@ public String sqlCreateString(Dialect dialect, Mapping p, String defaultCatalog, UniqueKey uk = getOrCreateUniqueKey( keyName ); uk.addColumn( col ); buf.append( dialect.getUniqueDelegate() - .getColumnDefinitionUniquenessFragment( col ) ); + .getColumnDefinitionUniquenessFragment( col, context ) ); } if ( col.hasCheckConstraint() && dialect.supportsColumnCheck() ) { @@ -605,7 +599,7 @@ public String sqlCreateString(Dialect dialect, Mapping p, String defaultCatalog, .append( getPrimaryKey().sqlConstraintString( dialect ) ); } - buf.append( dialect.getUniqueDelegate().getTableCreationUniqueConstraintsFragment( this ) ); + buf.append( dialect.getUniqueDelegate().getTableCreationUniqueConstraintsFragment( this, context ) ); if ( dialect.supportsTableCheck() ) { for ( String checkConstraint : checkConstraints ) { @@ -624,8 +618,10 @@ public String sqlCreateString(Dialect dialect, Mapping p, String defaultCatalog, return buf.append( dialect.getTableTypeString() ).toString(); } - public String sqlDropString(Dialect dialect, String defaultCatalog, String defaultSchema) { - return dialect.getDropTableString( getQualifiedName( dialect, defaultCatalog, defaultSchema ) ); + @Override + public String sqlDropString(SqlStringGenerationContext context, String defaultCatalog, String defaultSchema) { + Dialect dialect = context.getDialect(); + return dialect.getDropTableString( getQualifiedName( context, defaultCatalog, defaultSchema ) ); } public PrimaryKey getPrimaryKey() { @@ -831,25 +827,6 @@ public Iterator getCheckConstraintsIterator() { return checkConstraints.iterator(); } - public Iterator sqlCommentStrings(Dialect dialect, String defaultCatalog, String defaultSchema) { - List comments = new ArrayList<>(); - if ( dialect.supportsCommentOn() ) { - String tableName = getQualifiedName( dialect, defaultCatalog, defaultSchema ); - if ( comment != null ) { - comments.add( "comment on table " + tableName + " is '" + comment + "'" ); - } - Iterator iter = getColumnIterator(); - while ( iter.hasNext() ) { - Column column = (Column) iter.next(); - String columnComment = column.getComment(); - if ( columnComment != null ) { - comments.add( "comment on column " + tableName + '.' + column.getQuotedName( dialect ) + " is '" + columnComment + "'" ); - } - } - } - return comments.iterator(); - } - @Override public String getExportIdentifier() { return Table.qualify( diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/UniqueKey.java b/hibernate-core/src/main/java/org/hibernate/mapping/UniqueKey.java index b3ff9fdf5d0c..9ad096c2b562 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/UniqueKey.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/UniqueKey.java @@ -9,6 +9,7 @@ import java.util.HashMap; import java.util.Map; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.dialect.Dialect; import org.hibernate.engine.spi.Mapping; import org.hibernate.internal.util.StringHelper; @@ -23,7 +24,7 @@ public class UniqueKey extends Constraint { @Override public String sqlConstraintString( - Dialect dialect, + SqlStringGenerationContext context, String constraintName, String defaultCatalog, String defaultSchema) { @@ -34,9 +35,8 @@ public String sqlConstraintString( @Override public String sqlCreateString( - Dialect dialect, Mapping p, - String defaultCatalog, + SqlStringGenerationContext context, String defaultCatalog, String defaultSchema) { return null; // return dialect.getUniqueDelegate().getAlterTableToAddUniqueKeyCommand( @@ -46,8 +46,7 @@ public String sqlCreateString( @Override public String sqlDropString( - Dialect dialect, - String defaultCatalog, + SqlStringGenerationContext context, String defaultCatalog, String defaultSchema) { return null; // return dialect.getUniqueDelegate().getAlterTableToDropUniqueKeyCommand( diff --git a/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java index 2d95b4bdddb3..79252658cf60 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java @@ -240,7 +240,6 @@ public AbstractCollectionPersister( PersisterCreationContext creationContext) throws MappingException, CacheException { final Database database = creationContext.getMetadata().getDatabase(); - final JdbcEnvironment jdbcEnvironment = database.getJdbcEnvironment(); this.factory = creationContext.getSessionFactory(); this.cacheAccessStrategy = cacheAccessStrategy; @@ -272,7 +271,7 @@ public AbstractCollectionPersister( isArray = collectionBinding.isArray(); subselectLoadable = collectionBinding.isSubselectLoadable(); - qualifiedTableName = determineTableName( table, jdbcEnvironment ); + qualifiedTableName = determineTableName( table ); int spacesSize = 1 + collectionBinding.getSynchronizedTables().size(); spaces = new String[spacesSize]; @@ -615,15 +614,12 @@ else if ( !elementType.isEntityType() ) { initCollectionPropertyMap(); } - protected String determineTableName(Table table, JdbcEnvironment jdbcEnvironment) { + protected String determineTableName(Table table) { if ( table.getSubselect() != null ) { return "( " + table.getSubselect() + " )"; } - return jdbcEnvironment.getQualifiedObjectNameFormatter().format( - table.getQualifiedTableName(), - jdbcEnvironment.getDialect() - ); + return factory.getSqlStringGenerationContext().format( table.getQualifiedTableName() ); } private class ColumnMapperImpl implements ColumnMapper { diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index da6dcb72e859..4ac395e1c5b3 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -66,7 +66,6 @@ import org.hibernate.engine.internal.StatefulPersistenceContext; import org.hibernate.engine.internal.Versioning; import org.hibernate.engine.jdbc.batch.internal.BasicBatchKey; -import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.engine.jdbc.spi.JdbcCoordinator; import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.engine.spi.CachedNaturalIdValueSource; @@ -5803,15 +5802,12 @@ public int determineTableNumberForColumn(String columnName) { return 0; } - protected String determineTableName(Table table, JdbcEnvironment jdbcEnvironment) { + protected String determineTableName(Table table) { if ( table.getSubselect() != null ) { return "( " + table.getSubselect() + " )"; } - return jdbcEnvironment.getQualifiedObjectNameFormatter().format( - table.getQualifiedTableName(), - jdbcEnvironment.getDialect() - ); + return factory.getSqlStringGenerationContext().format( table.getQualifiedTableName() ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java index fa7f5cb30d88..9a5712d55eba 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java @@ -136,7 +136,6 @@ public JoinedSubclassEntityPersister( final SessionFactoryImplementor factory = creationContext.getSessionFactory(); final Database database = creationContext.getMetadata().getDatabase(); - final JdbcEnvironment jdbcEnvironment = database.getJdbcEnvironment(); // DISCRIMINATOR @@ -215,7 +214,7 @@ else if ( persistentClass.isDiscriminatorValueNotNull() ) { while ( tItr.hasNext() ) { final Table table = (Table) tItr.next(); final KeyValue key = (KeyValue) kItr.next(); - final String tableName = determineTableName( table, jdbcEnvironment ); + final String tableName = determineTableName( table ); tableNames.add( tableName ); String[] keyCols = new String[idColumnSpan]; String[] keyColReaders = new String[idColumnSpan]; @@ -248,7 +247,7 @@ else if ( persistentClass.isDiscriminatorValueNotNull() ) { isInverseTable[tableIndex] = join.isInverse(); Table table = join.getTable(); - final String tableName = determineTableName( table, jdbcEnvironment ); + final String tableName = determineTableName( table ); tableNames.add( tableName ); KeyValue key = join.getKey(); @@ -294,7 +293,7 @@ else if ( persistentClass.isDiscriminatorValueNotNull() ) { isLazies.add( Boolean.FALSE ); isInverses.add( Boolean.FALSE ); isNullables.add( Boolean.FALSE ); - final String tableName = determineTableName( tab, jdbcEnvironment ); + final String tableName = determineTableName( tab ); subclassTableNames.add( tableName ); String[] key = new String[idColumnSpan]; Iterator cItr = tab.getPrimaryKey().getColumnIterator(); @@ -316,7 +315,7 @@ else if ( persistentClass.isDiscriminatorValueNotNull() ) { isNullables.add( join.isOptional() ); isLazies.add( join.isLazy() ); - String joinTableName = determineTableName( joinTable, jdbcEnvironment ); + String joinTableName = determineTableName( joinTable ); subclassTableNames.add( joinTableName ); String[] key = new String[idColumnSpan]; Iterator citer = joinTable.getPrimaryKey().getColumnIterator(); @@ -440,7 +439,7 @@ else if ( persistentClass.isDiscriminatorValueNotNull() ) { while ( iter.hasNext() ) { Property prop = (Property) iter.next(); String tabname = prop.getValue().getTable().getQualifiedName( - factory.getDialect(), + factory.getSqlStringGenerationContext(), factory.getSettings().getDefaultCatalogName(), factory.getSettings().getDefaultSchemaName() ); @@ -462,7 +461,7 @@ else if ( persistentClass.isDiscriminatorValueNotNull() ) { Property prop = (Property) iter.next(); Table tab = prop.getValue().getTable(); String tabname = tab.getQualifiedName( - factory.getDialect(), + factory.getSqlStringGenerationContext(), factory.getSettings().getDefaultCatalogName(), factory.getSettings().getDefaultSchemaName() ); @@ -498,7 +497,7 @@ else if ( persistentClass.isDiscriminatorValueNotNull() ) { notNullColumnTableNumbers = new int[subclassSpan]; final int id = getTableId( persistentClass.getTable().getQualifiedName( - factory.getDialect(), + factory.getSqlStringGenerationContext(), factory.getSettings().getDefaultCatalogName(), factory.getSettings().getDefaultSchemaName() ), @@ -552,7 +551,7 @@ else if ( sc.isDiscriminatorValueNotNull() ) { discriminatorValues[k] = discriminatorValue.toString(); int id = getTableId( sc.getTable().getQualifiedName( - factory.getDialect(), + factory.getSqlStringGenerationContext(), factory.getSettings().getDefaultCatalogName(), factory.getSettings().getDefaultSchemaName() ), @@ -677,7 +676,7 @@ private void associateSubclassNamesToSubclassTableIndexes( SessionFactoryImplementor factory) { final String tableName = persistentClass.getTable().getQualifiedName( - factory.getDialect(), + factory.getSqlStringGenerationContext(), factory.getSettings().getDefaultCatalogName(), factory.getSettings().getDefaultSchemaName() ); @@ -688,7 +687,7 @@ private void associateSubclassNamesToSubclassTableIndexes( while ( itr.hasNext() ) { final Join join = (Join) itr.next(); final String secondaryTableName = join.getTable().getQualifiedName( - factory.getDialect(), + factory.getSqlStringGenerationContext(), factory.getSettings().getDefaultCatalogName(), factory.getSettings().getDefaultSchemaName() ); diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java index 566d8d5a49c0..33a9db1d43a1 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/SingleTableEntityPersister.java @@ -128,7 +128,6 @@ public SingleTableEntityPersister( final SessionFactoryImplementor factory = creationContext.getSessionFactory(); final Database database = creationContext.getMetadata().getDatabase(); - final JdbcEnvironment jdbcEnvironment = database.getJdbcEnvironment(); // CLASS + TABLE @@ -138,7 +137,7 @@ public SingleTableEntityPersister( isNullableTable = new boolean[joinSpan]; keyColumnNames = new String[joinSpan][]; final Table table = persistentClass.getRootTable(); - qualifiedTableNames[0] = determineTableName( table, jdbcEnvironment ); + qualifiedTableNames[0] = determineTableName( table ); isInverseTable[0] = false; isNullableTable[0] = false; @@ -178,7 +177,7 @@ public SingleTableEntityPersister( int j = 1; while ( joinIter.hasNext() ) { Join join = (Join) joinIter.next(); - qualifiedTableNames[j] = determineTableName( join.getTable(), jdbcEnvironment ); + qualifiedTableNames[j] = determineTableName( join.getTable() ); isInverseTable[j] = join.isInverse(); isNullableTable[j] = join.isOptional(); cascadeDeleteEnabled[j] = join.getKey().isCascadeDeleteEnabled() && @@ -255,7 +254,7 @@ public SingleTableEntityPersister( isDeferreds.add( isDeferred ); hasDeferred |= isDeferred; - String joinTableName = determineTableName( join.getTable(), jdbcEnvironment ); + String joinTableName = determineTableName( join.getTable() ); subclassTables.add( joinTableName ); Iterator iter = join.getKey().getColumnIterator(); diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/UnionSubclassEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/UnionSubclassEntityPersister.java index 820383b9c6fa..ac8331ff20d0 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/UnionSubclassEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/UnionSubclassEntityPersister.java @@ -20,6 +20,7 @@ import org.hibernate.LockMode; import org.hibernate.MappingException; import org.hibernate.boot.model.relational.Database; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.cache.spi.access.EntityDataAccess; import org.hibernate.cache.spi.access.NaturalIdDataAccess; import org.hibernate.cfg.Settings; @@ -85,11 +86,10 @@ public UnionSubclassEntityPersister( final SessionFactoryImplementor factory = creationContext.getSessionFactory(); final Database database = creationContext.getMetadata().getDatabase(); - final JdbcEnvironment jdbcEnvironment = database.getJdbcEnvironment(); // TABLE - tableName = determineTableName( persistentClass.getTable(), jdbcEnvironment ); + tableName = determineTableName( persistentClass.getTable() ); //Custom SQL @@ -168,7 +168,7 @@ public UnionSubclassEntityPersister( HashSet subclassTables = new HashSet(); Iterator subclassTableIter = persistentClass.getSubclassTableClosureIterator(); while ( subclassTableIter.hasNext() ) { - subclassTables.add( determineTableName( subclassTableIter.next(), jdbcEnvironment ) ); + subclassTables.add( determineTableName( subclassTableIter.next() ) ); } subclassSpaces = ArrayHelper.toStringArray( subclassTables ); @@ -182,7 +182,7 @@ public UnionSubclassEntityPersister( while ( tableIter.hasNext() ) { Table tab = tableIter.next(); if ( !tab.isAbstractUnionTable() ) { - final String tableName = determineTableName( tab, jdbcEnvironment ); + final String tableName = determineTableName( tab ); tableNames.add( tableName ); String[] key = new String[idColumnSpan]; Iterator citer = tab.getPrimaryKey().getColumnIterator(); @@ -363,10 +363,11 @@ protected String generateSubquery(PersistentClass model, Mapping mapping) { Dialect dialect = getFactory().getDialect(); Settings settings = getFactory().getSettings(); + SqlStringGenerationContext sqlStringGenerationContext = getFactory().getSqlStringGenerationContext(); if ( !model.hasSubclasses() ) { return model.getTable().getQualifiedName( - dialect, + sqlStringGenerationContext, settings.getDefaultCatalogName(), settings.getDefaultSchemaName() ); @@ -414,7 +415,7 @@ protected String generateSubquery(PersistentClass model, Mapping mapping) { buf.append( " from " ) .append( table.getQualifiedName( - dialect, + sqlStringGenerationContext, settings.getDefaultCatalogName(), settings.getDefaultSchemaName() ) diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/ExtractionContextImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/ExtractionContextImpl.java index 9da18060d212..1af9e2c66f65 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/ExtractionContextImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/ExtractionContextImpl.java @@ -11,6 +11,8 @@ import java.sql.SQLException; import org.hibernate.boot.model.naming.Identifier; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; +import org.hibernate.boot.model.relational.internal.SqlStringGenerationContextImpl; import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.service.ServiceRegistry; @@ -22,6 +24,7 @@ public class ExtractionContextImpl implements ExtractionContext { private final ServiceRegistry serviceRegistry; private final JdbcEnvironment jdbcEnvironment; + private final SqlStringGenerationContext sqlStringGenerationContext; private final JdbcConnectionAccess jdbcConnectionAccess; private final DatabaseObjectAccess registeredTableAccess; private final Identifier defaultCatalogName; @@ -39,6 +42,7 @@ public ExtractionContextImpl( Identifier defaultSchemaName) { this.serviceRegistry = serviceRegistry; this.jdbcEnvironment = jdbcEnvironment; + this.sqlStringGenerationContext = new SqlStringGenerationContextImpl( jdbcEnvironment ); this.jdbcConnectionAccess = jdbcConnectionAccess; this.registeredTableAccess = registeredTableAccess; this.defaultCatalogName = defaultCatalogName; @@ -55,6 +59,11 @@ public JdbcEnvironment getJdbcEnvironment() { return jdbcEnvironment; } + @Override + public SqlStringGenerationContext getSqlStringGenerationContext() { + return sqlStringGenerationContext; + } + @Override public Connection getJdbcConnection() { if ( jdbcConnection == null ) { diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/InformationExtractorJdbcDatabaseMetaDataImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/InformationExtractorJdbcDatabaseMetaDataImpl.java index 25d9f9c03e88..0f934484ccf5 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/InformationExtractorJdbcDatabaseMetaDataImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/InformationExtractorJdbcDatabaseMetaDataImpl.java @@ -137,11 +137,10 @@ protected void addColumns(TableInformation tableInformation) { final ExtractionContext extractionContext = getExtractionContext(); // We use this dummy query to retrieve the table information through the ResultSetMetaData // This is significantly better than to use the DatabaseMetaData especially on Oracle with synonyms enable - final String tableName = extractionContext.getJdbcEnvironment().getQualifiedObjectNameFormatter().format( + final String tableName = extractionContext.getSqlStringGenerationContext().format( // The name comes from the database, so the case is correct // But we quote here to avoid issues with reserved words - tableInformation.getName().quote(), - extractionContext.getJdbcEnvironment().getDialect() + tableInformation.getName().quote() ); try { diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/ExtractionContext.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/ExtractionContext.java index ab1c7c4d597d..ddd2d52e3ae7 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/ExtractionContext.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/spi/ExtractionContext.java @@ -16,6 +16,7 @@ import org.hibernate.boot.model.naming.Identifier; import org.hibernate.boot.model.relational.QualifiedSequenceName; import org.hibernate.boot.model.relational.QualifiedTableName; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.service.ServiceRegistry; @@ -30,6 +31,7 @@ public interface ExtractionContext { ServiceRegistry getServiceRegistry(); JdbcEnvironment getJdbcEnvironment(); + SqlStringGenerationContext getSqlStringGenerationContext(); Connection getJdbcConnection(); DatabaseMetaData getJdbcDatabaseMetaData(); @@ -83,6 +85,11 @@ public JdbcEnvironment getJdbcEnvironment() { return null; } + @Override + public SqlStringGenerationContext getSqlStringGenerationContext() { + return null; + } + @Override public Connection getJdbcConnection() { return null; diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/AbstractSchemaMigrator.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/AbstractSchemaMigrator.java index 6acbc9fe73e5..e91b829034fc 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/AbstractSchemaMigrator.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/AbstractSchemaMigrator.java @@ -22,6 +22,8 @@ import org.hibernate.boot.model.relational.Exportable; import org.hibernate.boot.model.relational.Namespace; import org.hibernate.boot.model.relational.Sequence; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; +import org.hibernate.boot.model.relational.internal.SqlStringGenerationContextImpl; import org.hibernate.boot.spi.MetadataImplementor; import org.hibernate.dialect.Dialect; import org.hibernate.engine.config.spi.ConfigurationService; @@ -150,7 +152,9 @@ protected abstract NameSpaceTablesInformation performTablesMigration( boolean tryToCreateCatalogs, boolean tryToCreateSchemas, Set exportedCatalogs, - Namespace namespace, GenerationTarget[] targets); + Namespace namespace, + SqlStringGenerationContext sqlStringGenerationContext, + GenerationTarget[] targets); private void performMigration( Metadata metadata, @@ -164,6 +168,8 @@ private void performMigration( final Set exportIdentifiers = new HashSet( 50 ); final Database database = metadata.getDatabase(); + SqlStringGenerationContext sqlStringGenerationContext = + new SqlStringGenerationContextImpl( database.getJdbcEnvironment() ); // Drop all AuxiliaryDatabaseObjects for ( AuxiliaryDatabaseObject auxiliaryDatabaseObject : database.getAuxiliaryDatabaseObjects() ) { @@ -171,7 +177,7 @@ private void performMigration( applySqlStrings( true, dialect.getAuxiliaryDatabaseObjectExporter() - .getSqlDropStrings( auxiliaryDatabaseObject, metadata ), + .getSqlDropStrings( auxiliaryDatabaseObject, metadata, sqlStringGenerationContext ), formatter, options, targets @@ -184,7 +190,7 @@ private void performMigration( if ( !auxiliaryDatabaseObject.beforeTablesOnCreation() && auxiliaryDatabaseObject.appliesToDialect( dialect ) ) { applySqlStrings( true, - auxiliaryDatabaseObject.sqlCreateStrings( dialect ), + auxiliaryDatabaseObject.sqlCreateStrings( sqlStringGenerationContext ), formatter, options, targets @@ -216,7 +222,7 @@ private void performMigration( tryToCreateSchemas, exportedCatalogs, namespace, - targets + sqlStringGenerationContext, targets ); tablesInformation.put( namespace, nameSpaceTablesInformation ); if ( schemaFilter.includeNamespace( namespace ) ) { @@ -228,7 +234,8 @@ private void performMigration( false, dialect.getSequenceExporter().getSqlCreateStrings( sequence, - metadata + metadata, + sqlStringGenerationContext ), formatter, options, @@ -247,7 +254,8 @@ private void performMigration( if ( schemaFilter.includeTable( table ) ) { final TableInformation tableInformation = nameSpaceTablesInformation.getTableInformation( table ); if ( tableInformation == null || tableInformation.isPhysicalTable() ) { - applyForeignKeys( table, tableInformation, dialect, metadata, formatter, options, targets ); + applyForeignKeys( table, tableInformation, dialect, metadata, formatter, options, + sqlStringGenerationContext, targets ); } } } @@ -259,7 +267,7 @@ private void performMigration( if ( auxiliaryDatabaseObject.beforeTablesOnCreation() && auxiliaryDatabaseObject.appliesToDialect( dialect )) { applySqlStrings( true, - auxiliaryDatabaseObject.sqlCreateStrings( dialect ), + auxiliaryDatabaseObject.sqlCreateStrings( sqlStringGenerationContext ), formatter, options, targets @@ -274,10 +282,11 @@ protected void createTable( Metadata metadata, Formatter formatter, ExecutionOptions options, + SqlStringGenerationContext sqlStringGenerationContext, GenerationTarget... targets) { applySqlStrings( false, - dialect.getTableExporter().getSqlCreateStrings( table, metadata ), + dialect.getTableExporter().getSqlCreateStrings( table, metadata, sqlStringGenerationContext ), formatter, options, targets @@ -291,6 +300,7 @@ protected void migrateTable( Metadata metadata, Formatter formatter, ExecutionOptions options, + SqlStringGenerationContext sqlStringGenerationContext, GenerationTarget... targets) { final Database database = metadata.getDatabase(); @@ -302,7 +312,8 @@ protected void migrateTable( metadata, tableInformation, database.getDefaultNamespace().getPhysicalName().getCatalog(), - database.getDefaultNamespace().getPhysicalName().getSchema() + database.getDefaultNamespace().getPhysicalName().getSchema(), + sqlStringGenerationContext ), formatter, options, @@ -317,6 +328,7 @@ protected void applyIndexes( Metadata metadata, Formatter formatter, ExecutionOptions options, + SqlStringGenerationContext sqlStringGenerationContext, GenerationTarget... targets) { final Exporter exporter = dialect.getIndexExporter(); @@ -331,7 +343,7 @@ protected void applyIndexes( if ( existingIndex == null ) { applySqlStrings( false, - exporter.getSqlCreateStrings( index, metadata ), + exporter.getSqlCreateStrings( index, metadata, sqlStringGenerationContext ), formatter, options, targets @@ -352,6 +364,7 @@ protected void applyUniqueKeys( Metadata metadata, Formatter formatter, ExecutionOptions options, + SqlStringGenerationContext sqlStringGenerationContext, GenerationTarget... targets) { if ( uniqueConstraintStrategy == null ) { uniqueConstraintStrategy = determineUniqueConstraintSchemaUpdateStrategy( metadata ); @@ -374,7 +387,7 @@ protected void applyUniqueKeys( if ( uniqueConstraintStrategy == UniqueConstraintSchemaUpdateStrategy.DROP_RECREATE_QUIETLY ) { applySqlStrings( true, - exporter.getSqlDropStrings( uniqueKey, metadata ), + exporter.getSqlDropStrings( uniqueKey, metadata, sqlStringGenerationContext ), formatter, options, targets @@ -383,7 +396,7 @@ protected void applyUniqueKeys( applySqlStrings( true, - exporter.getSqlCreateStrings( uniqueKey, metadata ), + exporter.getSqlCreateStrings( uniqueKey, metadata, sqlStringGenerationContext ), formatter, options, targets @@ -410,6 +423,7 @@ protected void applyForeignKeys( Metadata metadata, Formatter formatter, ExecutionOptions options, + SqlStringGenerationContext sqlStringGenerationContext, GenerationTarget... targets) { if ( dialect.hasAlterTable() ) { final Exporter exporter = dialect.getForeignKeyExporter(); @@ -433,7 +447,7 @@ protected void applyForeignKeys( // in old SchemaUpdate code, this was the trigger to "create" applySqlStrings( false, - exporter.getSqlCreateStrings( foreignKey, metadata ), + exporter.getSqlCreateStrings( foreignKey, metadata, sqlStringGenerationContext ), formatter, options, targets diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/GroupedSchemaMigratorImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/GroupedSchemaMigratorImpl.java index aada23b2aac0..47d631cb2c2d 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/GroupedSchemaMigratorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/GroupedSchemaMigratorImpl.java @@ -11,6 +11,7 @@ import org.hibernate.boot.Metadata; import org.hibernate.boot.model.naming.Identifier; import org.hibernate.boot.model.relational.Namespace; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.internal.Formatter; import org.hibernate.mapping.Table; @@ -46,7 +47,9 @@ protected NameSpaceTablesInformation performTablesMigration( boolean tryToCreateCatalogs, boolean tryToCreateSchemas, Set exportedCatalogs, - Namespace namespace, GenerationTarget[] targets) { + Namespace namespace, + SqlStringGenerationContext sqlStringGenerationContext, + GenerationTarget[] targets) { final NameSpaceTablesInformation tablesInformation = new NameSpaceTablesInformation( metadata.getDatabase().getJdbcEnvironment().getIdentifierHelper() ); @@ -68,11 +71,12 @@ protected NameSpaceTablesInformation performTablesMigration( checkExportIdentifier( table, exportIdentifiers ); final TableInformation tableInformation = tables.getTableInformation( table ); if ( tableInformation == null ) { - createTable( table, dialect, metadata, formatter, options, targets ); + createTable( table, dialect, metadata, formatter, options, sqlStringGenerationContext, targets ); } else if ( tableInformation.isPhysicalTable() ) { tablesInformation.addTableInformation( tableInformation ); - migrateTable( table, tableInformation, dialect, metadata, formatter, options, targets ); + migrateTable( table, tableInformation, dialect, metadata, formatter, options, + sqlStringGenerationContext, targets ); } } } @@ -81,8 +85,10 @@ else if ( tableInformation.isPhysicalTable() ) { if ( schemaFilter.includeTable( table ) && table.isPhysicalTable() ) { final TableInformation tableInformation = tablesInformation.getTableInformation( table ); if ( tableInformation == null || tableInformation.isPhysicalTable() ) { - applyIndexes( table, tableInformation, dialect, metadata, formatter, options, targets ); - applyUniqueKeys( table, tableInformation, dialect, metadata, formatter, options, targets ); + applyIndexes( table, tableInformation, dialect, metadata, formatter, options, + sqlStringGenerationContext, targets ); + applyUniqueKeys( table, tableInformation, dialect, metadata, formatter, options, + sqlStringGenerationContext, targets ); } } } diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/IndividuallySchemaMigratorImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/IndividuallySchemaMigratorImpl.java index 0f2ae8a6dd0e..de510ae1c60a 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/IndividuallySchemaMigratorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/IndividuallySchemaMigratorImpl.java @@ -11,6 +11,7 @@ import org.hibernate.boot.Metadata; import org.hibernate.boot.model.naming.Identifier; import org.hibernate.boot.model.relational.Namespace; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.internal.Formatter; import org.hibernate.mapping.Table; @@ -47,6 +48,7 @@ protected NameSpaceTablesInformation performTablesMigration( boolean tryToCreateSchemas, Set exportedCatalogs, Namespace namespace, + SqlStringGenerationContext sqlStringGenerationContext, GenerationTarget[] targets) { final NameSpaceTablesInformation tablesInformation = new NameSpaceTablesInformation( metadata.getDatabase().getJdbcEnvironment().getIdentifierHelper() ); @@ -68,11 +70,12 @@ protected NameSpaceTablesInformation performTablesMigration( checkExportIdentifier( table, exportIdentifiers ); final TableInformation tableInformation = existingDatabase.getTableInformation( table.getQualifiedTableName() ); if ( tableInformation == null ) { - createTable( table, dialect, metadata, formatter, options, targets ); + createTable( table, dialect, metadata, formatter, options, sqlStringGenerationContext, targets ); } else if ( tableInformation.isPhysicalTable() ) { tablesInformation.addTableInformation( tableInformation ); - migrateTable( table, tableInformation, dialect, metadata, formatter, options, targets ); + migrateTable( table, tableInformation, dialect, metadata, formatter, options, + sqlStringGenerationContext, targets ); } } } @@ -81,8 +84,10 @@ else if ( tableInformation.isPhysicalTable() ) { if ( schemaFilter.includeTable( table ) && table.isPhysicalTable() ) { final TableInformation tableInformation = tablesInformation.getTableInformation( table ); if ( tableInformation == null || tableInformation.isPhysicalTable() ) { - applyIndexes( table, tableInformation, dialect, metadata, formatter, options, targets ); - applyUniqueKeys( table, tableInformation, dialect, metadata, formatter, options, targets ); + applyIndexes( table, tableInformation, dialect, metadata, formatter, options, + sqlStringGenerationContext, targets ); + applyUniqueKeys( table, tableInformation, dialect, metadata, formatter, options, + sqlStringGenerationContext, targets ); } } } diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/SchemaCreatorImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/SchemaCreatorImpl.java index f2d8e530a60e..63dbca8351f1 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/SchemaCreatorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/SchemaCreatorImpl.java @@ -23,6 +23,8 @@ import org.hibernate.boot.model.relational.InitCommand; import org.hibernate.boot.model.relational.Namespace; import org.hibernate.boot.model.relational.Sequence; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; +import org.hibernate.boot.model.relational.internal.SqlStringGenerationContextImpl; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.boot.spi.MetadataImplementor; import org.hibernate.cfg.AvailableSettings; @@ -216,6 +218,8 @@ public void createFromMetadata( } final Database database = metadata.getDatabase(); + SqlStringGenerationContext sqlStringGenerationContext = + new SqlStringGenerationContextImpl( database.getJdbcEnvironment() ); final Set exportIdentifiers = new HashSet( 50 ); @@ -265,7 +269,8 @@ public void createFromMetadata( applySqlStrings( dialect.getAuxiliaryDatabaseObjectExporter().getSqlCreateStrings( auxiliaryDatabaseObject, - metadata + metadata, + sqlStringGenerationContext ), formatter, options, @@ -290,7 +295,8 @@ public void createFromMetadata( applySqlStrings( dialect.getSequenceExporter().getSqlCreateStrings( sequence, - metadata + metadata, + sqlStringGenerationContext ), // dialect.getCreateSequenceStrings( // jdbcEnvironment.getQualifiedObjectNameFormatter().format( sequence.getName(), dialect ), @@ -313,7 +319,7 @@ public void createFromMetadata( } checkExportIdentifier( table, exportIdentifiers ); applySqlStrings( - dialect.getTableExporter().getSqlCreateStrings( table, metadata ), + dialect.getTableExporter().getSqlCreateStrings( table, metadata, sqlStringGenerationContext ), formatter, options, targets @@ -334,7 +340,9 @@ public void createFromMetadata( final Index index = (Index) indexItr.next(); checkExportIdentifier( index, exportIdentifiers ); applySqlStrings( - dialect.getIndexExporter().getSqlCreateStrings( index, metadata ), + dialect.getIndexExporter().getSqlCreateStrings( index, metadata, + sqlStringGenerationContext + ), formatter, options, targets @@ -347,7 +355,9 @@ public void createFromMetadata( final UniqueKey uniqueKey = (UniqueKey) ukItr.next(); checkExportIdentifier( uniqueKey, exportIdentifiers ); applySqlStrings( - dialect.getUniqueKeyExporter().getSqlCreateStrings( uniqueKey, metadata ), + dialect.getUniqueKeyExporter().getSqlCreateStrings( uniqueKey, metadata, + sqlStringGenerationContext + ), formatter, options, targets @@ -373,7 +383,9 @@ public void createFromMetadata( while ( fkItr.hasNext() ) { final ForeignKey foreignKey = (ForeignKey) fkItr.next(); applySqlStrings( - dialect.getForeignKeyExporter().getSqlCreateStrings( foreignKey, metadata ), + dialect.getForeignKeyExporter().getSqlCreateStrings( foreignKey, metadata, + sqlStringGenerationContext + ), formatter, options, targets @@ -388,7 +400,9 @@ public void createFromMetadata( && !auxiliaryDatabaseObject.beforeTablesOnCreation() ) { checkExportIdentifier( auxiliaryDatabaseObject, exportIdentifiers ); applySqlStrings( - dialect.getAuxiliaryDatabaseObjectExporter().getSqlCreateStrings( auxiliaryDatabaseObject, metadata ), + dialect.getAuxiliaryDatabaseObjectExporter().getSqlCreateStrings( auxiliaryDatabaseObject, metadata, + sqlStringGenerationContext + ), formatter, options, targets diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/SchemaDropperImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/SchemaDropperImpl.java index eefebb38b9c7..f39e582d2368 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/SchemaDropperImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/SchemaDropperImpl.java @@ -216,7 +216,9 @@ private void dropFromMetadata( } applySqlStrings( - dialect.getAuxiliaryDatabaseObjectExporter().getSqlDropStrings( auxiliaryDatabaseObject, metadata ), + dialect.getAuxiliaryDatabaseObjectExporter().getSqlDropStrings( auxiliaryDatabaseObject, metadata, + sqlStringGenerationContext + ), formatter, options, targets @@ -230,7 +232,7 @@ private void dropFromMetadata( } // we need to drop all constraints/indexes prior to dropping the tables - applyConstraintDropping( namespace, metadata, formatter, options, targets ); + applyConstraintDropping( namespace, metadata, formatter, options, sqlStringGenerationContext, targets ); // now it's safe to drop the tables for ( Table table : namespace.getTables() ) { @@ -241,7 +243,9 @@ private void dropFromMetadata( continue; } checkExportIdentifier( table, exportIdentifiers ); - applySqlStrings( dialect.getTableExporter().getSqlDropStrings( table, metadata ), formatter, options,targets ); + applySqlStrings( dialect.getTableExporter().getSqlDropStrings( table, metadata, + sqlStringGenerationContext + ), formatter, options,targets ); } for ( Sequence sequence : namespace.getSequences() ) { @@ -249,7 +253,9 @@ private void dropFromMetadata( continue; } checkExportIdentifier( sequence, exportIdentifiers ); - applySqlStrings( dialect.getSequenceExporter().getSqlDropStrings( sequence, metadata ), formatter, options, targets ); + applySqlStrings( dialect.getSequenceExporter().getSqlDropStrings( sequence, metadata, + sqlStringGenerationContext + ), formatter, options, targets ); } } @@ -313,6 +319,7 @@ private void applyConstraintDropping( Metadata metadata, Formatter formatter, ExecutionOptions options, + SqlStringGenerationContext sqlStringGenerationContext, GenerationTarget... targets) { final Dialect dialect = metadata.getDatabase().getJdbcEnvironment().getDialect(); @@ -332,7 +339,9 @@ private void applyConstraintDropping( while ( fks.hasNext() ) { final ForeignKey foreignKey = (ForeignKey) fks.next(); applySqlStrings( - dialect.getForeignKeyExporter().getSqlDropStrings( foreignKey, metadata ), + dialect.getForeignKeyExporter().getSqlDropStrings( foreignKey, metadata, + sqlStringGenerationContext + ), formatter, options, targets diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardAuxiliaryDatabaseObjectExporter.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardAuxiliaryDatabaseObjectExporter.java index 09a67f5af44a..773807908b44 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardAuxiliaryDatabaseObjectExporter.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardAuxiliaryDatabaseObjectExporter.java @@ -8,7 +8,7 @@ import org.hibernate.boot.Metadata; import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject; -import org.hibernate.boot.model.relational.internal.SqlStringGenerationContextImpl; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.dialect.Dialect; import org.hibernate.tool.schema.spi.Exporter; @@ -23,12 +23,14 @@ public StandardAuxiliaryDatabaseObjectExporter(Dialect dialect) { } @Override - public String[] getSqlCreateStrings(AuxiliaryDatabaseObject object, Metadata metadata) { - return object.sqlCreateStrings( new SqlStringGenerationContextImpl( metadata.getDatabase().getJdbcEnvironment() ) ); + public String[] getSqlCreateStrings(AuxiliaryDatabaseObject object, Metadata metadata, + SqlStringGenerationContext context) { + return object.sqlCreateStrings( context ); } @Override - public String[] getSqlDropStrings(AuxiliaryDatabaseObject object, Metadata metadata) { - return object.sqlDropStrings( new SqlStringGenerationContextImpl( metadata.getDatabase().getJdbcEnvironment() ) ); + public String[] getSqlDropStrings(AuxiliaryDatabaseObject object, Metadata metadata, + SqlStringGenerationContext context) { + return object.sqlDropStrings( context ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardForeignKeyExporter.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardForeignKeyExporter.java index b6a61e7dc41d..5668e9b56a80 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardForeignKeyExporter.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardForeignKeyExporter.java @@ -11,6 +11,7 @@ import org.hibernate.AssertionFailure; import org.hibernate.boot.Metadata; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.mapping.Column; @@ -31,7 +32,7 @@ public StandardForeignKeyExporter(Dialect dialect) { } @Override - public String[] getSqlCreateStrings(ForeignKey foreignKey, Metadata metadata) { + public String[] getSqlCreateStrings(ForeignKey foreignKey, Metadata metadata, SqlStringGenerationContext context) { if ( !dialect.hasAlterTable() ) { return NO_COMMANDS; } @@ -90,15 +91,8 @@ public String[] getSqlCreateStrings(ForeignKey foreignKey, Metadata metadata) { i++; } - final JdbcEnvironment jdbcEnvironment = metadata.getDatabase().getJdbcEnvironment(); - final String sourceTableName = jdbcEnvironment.getQualifiedObjectNameFormatter().format( - foreignKey.getTable().getQualifiedTableName(), - dialect - ); - final String targetTableName = jdbcEnvironment.getQualifiedObjectNameFormatter().format( - foreignKey.getReferencedTable().getQualifiedTableName(), - dialect - ); + final String sourceTableName = context.format( foreignKey.getTable().getQualifiedTableName() ); + final String targetTableName = context.format( foreignKey.getReferencedTable().getQualifiedTableName() ); final StringBuilder buffer = new StringBuilder( dialect.getAlterTableString( sourceTableName ) ) .append( @@ -126,7 +120,7 @@ public String[] getSqlCreateStrings(ForeignKey foreignKey, Metadata metadata) { } @Override - public String[] getSqlDropStrings(ForeignKey foreignKey, Metadata metadata) { + public String[] getSqlDropStrings(ForeignKey foreignKey, Metadata metadata, SqlStringGenerationContext context) { if ( !dialect.hasAlterTable() ) { return NO_COMMANDS; } @@ -139,11 +133,7 @@ public String[] getSqlDropStrings(ForeignKey foreignKey, Metadata metadata) { return NO_COMMANDS; } - final JdbcEnvironment jdbcEnvironment = metadata.getDatabase().getJdbcEnvironment(); - final String sourceTableName = jdbcEnvironment.getQualifiedObjectNameFormatter().format( - foreignKey.getTable().getQualifiedTableName(), - dialect - ); + final String sourceTableName = context.format( foreignKey.getTable().getQualifiedTableName() ); return new String[] { getSqlDropStrings( sourceTableName, foreignKey, dialect ) }; diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardIndexExporter.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardIndexExporter.java index 426e6e1163a3..66def26486a6 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardIndexExporter.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardIndexExporter.java @@ -11,6 +11,7 @@ import org.hibernate.boot.Metadata; import org.hibernate.boot.model.relational.QualifiedNameImpl; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.internal.util.StringHelper; @@ -29,22 +30,18 @@ public StandardIndexExporter(Dialect dialect) { } @Override - public String[] getSqlCreateStrings(Index index, Metadata metadata) { + public String[] getSqlCreateStrings(Index index, Metadata metadata, SqlStringGenerationContext context) { final JdbcEnvironment jdbcEnvironment = metadata.getDatabase().getJdbcEnvironment(); - final String tableName = jdbcEnvironment.getQualifiedObjectNameFormatter().format( - index.getTable().getQualifiedTableName(), - dialect - ); + final String tableName = context.format( index.getTable().getQualifiedTableName() ); final String indexNameForCreation; if ( dialect.qualifyIndexName() ) { - indexNameForCreation = jdbcEnvironment.getQualifiedObjectNameFormatter().format( + indexNameForCreation = context.format( new QualifiedNameImpl( index.getTable().getQualifiedTableName().getCatalogName(), index.getTable().getQualifiedTableName().getSchemaName(), jdbcEnvironment.getIdentifierHelper().toIdentifier( index.getQuotedName( dialect ) ) - ), - jdbcEnvironment.getDialect() + ) ); } else { @@ -78,16 +75,12 @@ public String[] getSqlCreateStrings(Index index, Metadata metadata) { } @Override - public String[] getSqlDropStrings(Index index, Metadata metadata) { + public String[] getSqlDropStrings(Index index, Metadata metadata, SqlStringGenerationContext context) { if ( !dialect.dropConstraints() ) { return NO_COMMANDS; } - final JdbcEnvironment jdbcEnvironment = metadata.getDatabase().getJdbcEnvironment(); - final String tableName = jdbcEnvironment.getQualifiedObjectNameFormatter().format( - index.getTable().getQualifiedTableName(), - dialect - ); + final String tableName = context.format( index.getTable().getQualifiedTableName() ); final String indexNameForCreation; if ( dialect.qualifyIndexName() ) { diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardSequenceExporter.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardSequenceExporter.java index cb04d29b5514..97dbe6b3dfc1 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardSequenceExporter.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardSequenceExporter.java @@ -9,8 +9,8 @@ import org.hibernate.boot.Metadata; import org.hibernate.boot.model.relational.QualifiedSequenceName; import org.hibernate.boot.model.relational.Sequence; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.dialect.Dialect; -import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.tool.schema.spi.Exporter; /** @@ -24,26 +24,23 @@ public StandardSequenceExporter(Dialect dialect) { } @Override - public String[] getSqlCreateStrings(Sequence sequence, Metadata metadata) { + public String[] getSqlCreateStrings(Sequence sequence, Metadata metadata, SqlStringGenerationContext context) { return dialect.getCreateSequenceStrings( - getFormattedSequenceName( sequence.getName(), metadata ), + getFormattedSequenceName( sequence.getName(), metadata, context ), sequence.getInitialValue(), sequence.getIncrementSize() ); } @Override - public String[] getSqlDropStrings(Sequence sequence, Metadata metadata) { + public String[] getSqlDropStrings(Sequence sequence, Metadata metadata, SqlStringGenerationContext context) { return dialect.getDropSequenceStrings( - getFormattedSequenceName( sequence.getName(), metadata ) + getFormattedSequenceName( sequence.getName(), metadata, context ) ); } - protected String getFormattedSequenceName(QualifiedSequenceName name, Metadata metadata) { - final JdbcEnvironment jdbcEnvironment = metadata.getDatabase().getJdbcEnvironment(); - return jdbcEnvironment.getQualifiedObjectNameFormatter().format( - name, - jdbcEnvironment.getDialect() - ); + protected String getFormattedSequenceName(QualifiedSequenceName name, Metadata metadata, + SqlStringGenerationContext context) { + return context.format( name ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardTableExporter.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardTableExporter.java index 54ebf07bf603..8d0edf29617e 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardTableExporter.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardTableExporter.java @@ -17,9 +17,7 @@ import org.hibernate.boot.model.relational.QualifiedName; import org.hibernate.boot.model.relational.QualifiedNameParser; import org.hibernate.boot.model.relational.SqlStringGenerationContext; -import org.hibernate.boot.model.relational.internal.SqlStringGenerationContextImpl; import org.hibernate.dialect.Dialect; -import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.mapping.Column; import org.hibernate.mapping.Constraint; import org.hibernate.mapping.Table; @@ -37,23 +35,18 @@ public StandardTableExporter(Dialect dialect) { } @Override - public String[] getSqlCreateStrings(Table table, Metadata metadata) { + public String[] getSqlCreateStrings(Table table, Metadata metadata, + SqlStringGenerationContext context) { final QualifiedName tableName = new QualifiedNameParser.NameParts( Identifier.toIdentifier( table.getCatalog(), table.isCatalogQuoted() ), Identifier.toIdentifier( table.getSchema(), table.isSchemaQuoted() ), table.getNameIdentifier() ); - final JdbcEnvironment jdbcEnvironment = metadata.getDatabase().getJdbcEnvironment(); StringBuilder buf = new StringBuilder( tableCreateString( table.hasPrimaryKey() ) ) .append( ' ' ) - .append( - jdbcEnvironment.getQualifiedObjectNameFormatter().format( - tableName, - jdbcEnvironment.getDialect() - ) - ) + .append( context.format( tableName ) ) .append( " (" ); @@ -117,7 +110,7 @@ public String[] getSqlCreateStrings(Table table, Metadata metadata) { uk.addColumn( col ); buf.append( dialect.getUniqueDelegate() - .getColumnDefinitionUniquenessFragment( col ) + .getColumnDefinitionUniquenessFragment( col, context ) ); } @@ -137,7 +130,7 @@ public String[] getSqlCreateStrings(Table table, Metadata metadata) { .append( table.getPrimaryKey().sqlConstraintString( dialect ) ); } - buf.append( dialect.getUniqueDelegate().getTableCreationUniqueConstraintsFragment( table ) ); + buf.append( dialect.getUniqueDelegate().getTableCreationUniqueConstraintsFragment( table, context ) ); applyTableCheck( table, buf ); @@ -154,8 +147,6 @@ public String[] getSqlCreateStrings(Table table, Metadata metadata) { applyComments( table, tableName, sqlStrings ); - SqlStringGenerationContext context = - new SqlStringGenerationContextImpl( metadata.getDatabase().getJdbcEnvironment() ); applyInitCommands( table, sqlStrings, context ); return sqlStrings.toArray( new String[ sqlStrings.size() ] ); @@ -204,7 +195,7 @@ protected String tableCreateString(boolean hasPrimaryKey) { } @Override - public String[] getSqlDropStrings(Table table, Metadata metadata) { + public String[] getSqlDropStrings(Table table, Metadata metadata, SqlStringGenerationContext context) { StringBuilder buf = new StringBuilder( "drop table " ); if ( dialect.supportsIfExistsBeforeTableName() ) { buf.append( "if exists " ); @@ -215,8 +206,7 @@ public String[] getSqlDropStrings(Table table, Metadata metadata) { Identifier.toIdentifier( table.getSchema(), table.isSchemaQuoted() ), table.getNameIdentifier() ); - final JdbcEnvironment jdbcEnvironment = metadata.getDatabase().getJdbcEnvironment(); - buf.append( jdbcEnvironment.getQualifiedObjectNameFormatter().format( tableName, jdbcEnvironment.getDialect() ) ) + buf.append( context.format( tableName ) ) .append( dialect.getCascadeConstraintsString() ); if ( dialect.supportsIfExistsAfterTableName() ) { diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardUniqueKeyExporter.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardUniqueKeyExporter.java index 260f9d9e8971..cee8e41180cd 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardUniqueKeyExporter.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/StandardUniqueKeyExporter.java @@ -7,6 +7,7 @@ package org.hibernate.tool.schema.internal; import org.hibernate.boot.Metadata; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.dialect.Dialect; import org.hibernate.mapping.Constraint; import org.hibernate.mapping.UniqueKey; @@ -26,21 +27,25 @@ public StandardUniqueKeyExporter(Dialect dialect) { } @Override - public String[] getSqlCreateStrings(Constraint constraint, Metadata metadata) { + public String[] getSqlCreateStrings(Constraint constraint, Metadata metadata, + SqlStringGenerationContext context) { return new String[] { dialect.getUniqueDelegate().getAlterTableToAddUniqueKeyCommand( (UniqueKey) constraint, - metadata + metadata, + context ) }; } @Override - public String[] getSqlDropStrings(Constraint constraint, Metadata metadata) { + public String[] getSqlDropStrings(Constraint constraint, Metadata metadata, + SqlStringGenerationContext context) { return new String[] { dialect.getUniqueDelegate().getAlterTableToDropUniqueKeyCommand( (UniqueKey) constraint, - metadata + metadata, + context ) }; } diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/exec/ImprovedExtractionContextImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/exec/ImprovedExtractionContextImpl.java index 926673d739f8..20a56f55e850 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/exec/ImprovedExtractionContextImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/exec/ImprovedExtractionContextImpl.java @@ -11,6 +11,8 @@ import java.sql.SQLException; import org.hibernate.boot.model.naming.Identifier; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; +import org.hibernate.boot.model.relational.internal.SqlStringGenerationContextImpl; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.resource.transaction.spi.DdlTransactionIsolator; import org.hibernate.service.ServiceRegistry; @@ -22,6 +24,7 @@ public class ImprovedExtractionContextImpl implements ExtractionContext { private final ServiceRegistry serviceRegistry; private final JdbcEnvironment jdbcEnvironment; + private final SqlStringGenerationContext sqlStringGenerationContext; private final DdlTransactionIsolator ddlTransactionIsolator; private final Identifier defaultCatalog; private final Identifier defaultSchema; @@ -39,6 +42,7 @@ public ImprovedExtractionContextImpl( DatabaseObjectAccess databaseObjectAccess) { this.serviceRegistry = serviceRegistry; this.jdbcEnvironment = jdbcEnvironment; + this.sqlStringGenerationContext = new SqlStringGenerationContextImpl( jdbcEnvironment ); this.ddlTransactionIsolator = ddlTransactionIsolator; this.defaultCatalog = defaultCatalog; this.defaultSchema = defaultSchema; @@ -55,6 +59,11 @@ public JdbcEnvironment getJdbcEnvironment() { return jdbcEnvironment; } + @Override + public SqlStringGenerationContext getSqlStringGenerationContext() { + return sqlStringGenerationContext; + } + @Override public Connection getJdbcConnection() { return ddlTransactionIsolator.getIsolatedConnection(); diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/Exporter.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/Exporter.java index f7a5a00a23ba..ccb555505e75 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/Exporter.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/Exporter.java @@ -27,12 +27,12 @@ public interface Exporter { * * @return The commands needed for creation scripting. */ - String[] getSqlCreateStrings(T exportable, Metadata metadata); + String[] getSqlCreateStrings(T exportable, Metadata metadata, SqlStringGenerationContext context); /** * Get the commands needed for dropping. * * @return The commands needed for drop scripting. */ - String[] getSqlDropStrings(T exportable, Metadata metadata); + String[] getSqlDropStrings(T exportable, Metadata metadata, SqlStringGenerationContext context); } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/jpa/PersistenceUnitOverridesTests.java b/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/jpa/PersistenceUnitOverridesTests.java index 0deba30d7dd6..fa3da3d3caa8 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/jpa/PersistenceUnitOverridesTests.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/bootstrap/jpa/PersistenceUnitOverridesTests.java @@ -18,6 +18,7 @@ import javax.persistence.spi.PersistenceUnitInfo; import javax.sql.DataSource; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.boot.spi.MetadataImplementor; import org.hibernate.boot.spi.SessionFactoryOptions; import org.hibernate.cache.spi.access.AccessType; @@ -519,7 +520,8 @@ public void prepare( JdbcServices jdbcServices, JdbcConnectionAccess connectionAccess, MetadataImplementor metadata, - SessionFactoryOptions sessionFactoryOptions) { + SessionFactoryOptions sessionFactoryOptions, + SqlStringGenerationContext sqlStringGenerationContext) { } diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/id/sequences/HibernateSequenceTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/id/sequences/HibernateSequenceTest.java index d26a56c115a7..b8fe8eca1196 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/id/sequences/HibernateSequenceTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/id/sequences/HibernateSequenceTest.java @@ -55,7 +55,7 @@ public void testHibernateSequenceSchema() { Assert.assertTrue( SequenceStyleGenerator.class.isInstance( generator ) ); SequenceStyleGenerator seqGenerator = (SequenceStyleGenerator) generator; Assert.assertEquals( - Table.qualify( null, SCHEMA_NAME, SequenceStyleGenerator.DEF_SEQUENCE_NAME ), + SCHEMA_NAME + "." + SequenceStyleGenerator.DEF_SEQUENCE_NAME, seqGenerator.getDatabaseStructure().getPhysicalName().render() ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/hbm/uk/UniqueDelegateTest.java b/hibernate-core/src/test/java/org/hibernate/test/hbm/uk/UniqueDelegateTest.java index c2bd6ba76c41..488bf875adf3 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/hbm/uk/UniqueDelegateTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/hbm/uk/UniqueDelegateTest.java @@ -8,6 +8,7 @@ import org.hibernate.boot.Metadata; import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cfg.AvailableSettings; @@ -103,29 +104,33 @@ public MyUniqueDelegate(Dialect dialect) { } @Override - public String getColumnDefinitionUniquenessFragment(Column column) { + public String getColumnDefinitionUniquenessFragment(Column column, + SqlStringGenerationContext context) { getColumnDefinitionUniquenessFragmentCallCount++; - return super.getColumnDefinitionUniquenessFragment( column ); + return super.getColumnDefinitionUniquenessFragment( column, context ); } @Override - public String getTableCreationUniqueConstraintsFragment(Table table) { + public String getTableCreationUniqueConstraintsFragment(Table table, + SqlStringGenerationContext context) { getTableCreationUniqueConstraintsFragmentCallCount++; - return super.getTableCreationUniqueConstraintsFragment( table ); + return super.getTableCreationUniqueConstraintsFragment( table, context ); } @Override public String getAlterTableToAddUniqueKeyCommand( - UniqueKey uniqueKey, Metadata metadata) { + UniqueKey uniqueKey, Metadata metadata, + SqlStringGenerationContext context) { getAlterTableToAddUniqueKeyCommandCallCount++; - return super.getAlterTableToAddUniqueKeyCommand( uniqueKey, metadata ); + return super.getAlterTableToAddUniqueKeyCommand( uniqueKey, metadata, context ); } @Override public String getAlterTableToDropUniqueKeyCommand( - UniqueKey uniqueKey, Metadata metadata) { + UniqueKey uniqueKey, Metadata metadata, + SqlStringGenerationContext context) { getAlterTableToDropUniqueKeyCommandCallCount++; - return super.getAlterTableToDropUniqueKeyCommand( uniqueKey, metadata ); + return super.getAlterTableToDropUniqueKeyCommand( uniqueKey, metadata, context ); } } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/idgen/enhanced/table/Db2GenerationTest.java b/hibernate-core/src/test/java/org/hibernate/test/idgen/enhanced/table/Db2GenerationTest.java index cafc49a11186..5a90b082a57b 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/idgen/enhanced/table/Db2GenerationTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/idgen/enhanced/table/Db2GenerationTest.java @@ -10,6 +10,9 @@ import org.hibernate.boot.Metadata; import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.model.relational.Database; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; +import org.hibernate.boot.model.relational.internal.SqlStringGenerationContextImpl; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.cfg.AvailableSettings; @@ -52,8 +55,13 @@ public void testNewGeneratorTableCreationOnDb2() { assertEquals( 1, metadata.getDatabase().getDefaultNamespace().getTables().size() ); - final Table table = metadata.getDatabase().getDefaultNamespace().getTables().iterator().next(); - final String[] createCommands = new DB2Dialect().getTableExporter().getSqlCreateStrings( table, metadata ); + Database database = metadata.getDatabase(); + final Table table = database.getDefaultNamespace().getTables().iterator().next(); + SqlStringGenerationContext sqlStringGenerationContext = + SqlStringGenerationContextImpl.forTests( database.getJdbcEnvironment() ); + final String[] createCommands = new DB2Dialect().getTableExporter().getSqlCreateStrings( table, metadata, + sqlStringGenerationContext + ); assertContains( "sequence_name varchar(255) not null", createCommands[0] ); } finally { @@ -88,8 +96,13 @@ public void testLegacyGeneratorTableCreationOnDb2() { assertEquals( 1, metadata.getDatabase().getDefaultNamespace().getTables().size() ); - final Table table = metadata.getDatabase().getDefaultNamespace().getTables().iterator().next(); - final String[] createCommands = new DB2Dialect().getTableExporter().getSqlCreateStrings( table, metadata ); + Database database = metadata.getDatabase(); + final Table table = database.getDefaultNamespace().getTables().iterator().next(); + SqlStringGenerationContext sqlStringGenerationContext = + SqlStringGenerationContextImpl.forTests( database.getJdbcEnvironment() ); + final String[] createCommands = new DB2Dialect().getTableExporter().getSqlCreateStrings( table, metadata, + sqlStringGenerationContext + ); assertContains( "sequence_name varchar(255) not null", createCommands[0] ); } finally { diff --git a/hibernate-core/src/test/java/org/hibernate/test/jpa/compliance/tck2_2/GeneratedValueTests.java b/hibernate-core/src/test/java/org/hibernate/test/jpa/compliance/tck2_2/GeneratedValueTests.java index 85a650740e6a..de1d7458124e 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/jpa/compliance/tck2_2/GeneratedValueTests.java +++ b/hibernate-core/src/test/java/org/hibernate/test/jpa/compliance/tck2_2/GeneratedValueTests.java @@ -16,7 +16,9 @@ import org.hibernate.boot.Metadata; import org.hibernate.boot.MetadataSources; import org.hibernate.boot.model.naming.Identifier; +import org.hibernate.boot.model.relational.Database; import org.hibernate.boot.model.relational.Sequence; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.boot.model.relational.internal.SqlStringGenerationContextImpl; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; @@ -181,7 +183,10 @@ public void testExplicitSequenceGeneratorImplicitNamePreferGeneratorName() { null, (RootClass) entityMapping ); - generator.initialize( SqlStringGenerationContextImpl.forTests( bootModel.getDatabase().getJdbcEnvironment() ) ); + Database database = bootModel.getDatabase(); + SqlStringGenerationContext sqlStringGenerationContext = + SqlStringGenerationContextImpl.forTests( database.getJdbcEnvironment() ); + generator.initialize( sqlStringGenerationContext ); final SequenceStyleGenerator sequenceStyleGenerator = assertTyping( SequenceStyleGenerator.class, @@ -192,13 +197,13 @@ public void testExplicitSequenceGeneratorImplicitNamePreferGeneratorName() { assertThat( sequenceStyleGenerator.getDatabaseStructure().getInitialValue(), is( 100 ) ); assertThat( sequenceStyleGenerator.getDatabaseStructure().getIncrementSize(), is( 500 ) ); - final Sequence sequence = bootModel.getDatabase() - .getDefaultNamespace() + final Sequence sequence = database.getDefaultNamespace() .locateSequence( Identifier.toIdentifier( "my_db_sequence" ) ); assertThat( sequence, notNullValue() ); final String[] sqlCreateStrings = new H2Dialect().getSequenceExporter().getSqlCreateStrings( sequence, - bootModel + bootModel, + sqlStringGenerationContext ); assertThat( sqlCreateStrings.length, is( 1 ) ); final String cmd = sqlCreateStrings[0].toLowerCase(); diff --git a/hibernate-core/src/test/java/org/hibernate/test/tool/schema/internal/CheckForExistingForeignKeyTest.java b/hibernate-core/src/test/java/org/hibernate/test/tool/schema/internal/CheckForExistingForeignKeyTest.java index a0608944ba62..6a7d1b2bbe6f 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/tool/schema/internal/CheckForExistingForeignKeyTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/tool/schema/internal/CheckForExistingForeignKeyTest.java @@ -12,6 +12,7 @@ import org.hibernate.boot.model.relational.Namespace; import org.hibernate.boot.model.relational.Namespace.Name; import org.hibernate.boot.model.relational.QualifiedTableName; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.env.spi.IdentifierHelper; import org.hibernate.engine.jdbc.internal.Formatter; @@ -53,10 +54,14 @@ public SchemaMigrator() { * Needed implementation. Not used in test. */ @Override - protected NameSpaceTablesInformation performTablesMigration(Metadata metadata, DatabaseInformation existingDatabase, ExecutionOptions options, + protected NameSpaceTablesInformation performTablesMigration(Metadata metadata, + DatabaseInformation existingDatabase, ExecutionOptions options, Dialect dialect, - Formatter formatter, Set exportIdentifiers, boolean tryToCreateCatalogs, boolean tryToCreateSchemas, - Set exportedCatalogs, Namespace namespace, GenerationTarget[] targets) { + Formatter formatter, Set exportIdentifiers, boolean tryToCreateCatalogs, + boolean tryToCreateSchemas, + Set exportedCatalogs, Namespace namespace, + SqlStringGenerationContext sqlStringGenerationContext, + GenerationTarget[] targets) { return null; } } diff --git a/hibernate-core/src/test/java/org/hibernate/tool/schema/internal/AbstractSchemaMigratorTest.java b/hibernate-core/src/test/java/org/hibernate/tool/schema/internal/AbstractSchemaMigratorTest.java index 8635fb788a83..40ff8255890a 100644 --- a/hibernate-core/src/test/java/org/hibernate/tool/schema/internal/AbstractSchemaMigratorTest.java +++ b/hibernate-core/src/test/java/org/hibernate/tool/schema/internal/AbstractSchemaMigratorTest.java @@ -14,6 +14,7 @@ import org.hibernate.boot.model.naming.Identifier; import org.hibernate.boot.model.relational.Namespace; import org.hibernate.boot.model.relational.QualifiedTableName; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.internal.Formatter; import org.hibernate.testing.TestForIssue; @@ -44,7 +45,12 @@ public class AbstractSchemaMigratorTest { public void testForeignKeyPreExistenceDetectionIgnoresCaseForTableAndColumnName() { final AbstractSchemaMigrator schemaMigrator = new AbstractSchemaMigrator(null, null) { @Override - protected NameSpaceTablesInformation performTablesMigration(Metadata metadata, DatabaseInformation existingDatabase, ExecutionOptions options, Dialect dialect, Formatter formatter, Set exportIdentifiers, boolean tryToCreateCatalogs, boolean tryToCreateSchemas, Set exportedCatalogs, Namespace namespace, GenerationTarget[] targets) { return null; } + protected NameSpaceTablesInformation performTablesMigration(Metadata metadata, + DatabaseInformation existingDatabase, ExecutionOptions options, Dialect dialect, + Formatter formatter, Set exportIdentifiers, boolean tryToCreateCatalogs, + boolean tryToCreateSchemas, Set exportedCatalogs, Namespace namespace, + SqlStringGenerationContext sqlStringGenerationContext, + GenerationTarget[] targets) { return null; } }; final TableInformation existingTableInformation = mock(TableInformation.class); diff --git a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/reventity/MonotonicRevisionNumberTest.java b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/reventity/MonotonicRevisionNumberTest.java index e04e094183a5..0da7c9cee19b 100644 --- a/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/reventity/MonotonicRevisionNumberTest.java +++ b/hibernate-envers/src/test/java/org/hibernate/envers/test/integration/reventity/MonotonicRevisionNumberTest.java @@ -12,6 +12,8 @@ import org.hibernate.boot.model.relational.AuxiliaryDatabaseObject; import org.hibernate.boot.model.relational.Database; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; +import org.hibernate.boot.model.relational.internal.SqlStringGenerationContextImpl; import org.hibernate.dialect.Oracle8iDialect; import org.hibernate.envers.enhanced.OrderedSequenceGenerator; import org.hibernate.envers.enhanced.SequenceIdRevisionEntity; @@ -43,11 +45,13 @@ public void testOracleSequenceOrder() { Assert.assertTrue( OrderedSequenceGenerator.class.isInstance( generator ) ); Database database = metadata().getDatabase(); + SqlStringGenerationContext sqlStringGenerationContext = + SqlStringGenerationContextImpl.forTests( database.getJdbcEnvironment() ); Optional sequenceOptional = database.getAuxiliaryDatabaseObjects().stream() .filter( o -> "REVISION_GENERATOR".equals( o.getExportIdentifier() ) ) .findFirst(); assertThat( sequenceOptional ).isPresent(); - String[] sqlCreateStrings = sequenceOptional.get().sqlCreateStrings( database.getDialect() ); + String[] sqlCreateStrings = sequenceOptional.get().sqlCreateStrings( sqlStringGenerationContext ); Assert.assertTrue( "Oracle sequence needs to be ordered in RAC environment.", sqlCreateStrings[0].toLowerCase().endsWith( " order" ) From a9f1ada94d8f70966dadb5dab639e58176d4b853 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Wed, 10 Nov 2021 13:54:00 +0100 Subject: [PATCH 407/644] HHH-14921 Delay determination of the default catalog/schema until schema management tool or session factory creation --- .../InFlightMetadataCollectorImpl.java | 10 -- .../boot/internal/MetadataBuilderImpl.java | 17 +-- .../SessionFactoryOptionsBuilder.java | 22 +++- .../SqlStringGenerationContext.java | 17 +++ .../SqlStringGenerationContextImpl.java | 110 +++++++++++++++++- .../source/internal/hbm/ModelBinder.java | 20 ++-- ...stractDelegatingSessionFactoryOptions.java | 10 ++ .../boot/spi/SessionFactoryOptions.java | 20 ++++ .../main/java/org/hibernate/cfg/Settings.java | 4 +- .../cfg/annotations/TableBinder.java | 4 +- .../internal/FilterConfiguration.java | 4 +- .../internal/SessionFactoryImpl.java | 11 +- .../loader/custom/sql/SQLQueryParser.java | 20 ++-- .../org/hibernate/mapping/Constraint.java | 4 +- .../org/hibernate/mapping/ForeignKey.java | 6 +- .../java/org/hibernate/mapping/Index.java | 6 +- .../java/org/hibernate/mapping/KeyValue.java | 10 ++ .../org/hibernate/mapping/SimpleValue.java | 23 ++-- .../java/org/hibernate/mapping/Table.java | 26 +---- .../AbstractCollectionPersister.java | 2 - .../entity/JoinedSubclassEntityPersister.java | 25 +--- .../entity/UnionSubclassEntityPersister.java | 9 +- .../internal/DatabaseInformationImpl.java | 6 +- .../internal/ExtractionContextImpl.java | 16 +-- .../internal/AbstractSchemaMigrator.java | 16 ++- .../internal/AbstractSchemaValidator.java | 10 +- .../tool/schema/internal/Helper.java | 6 +- .../HibernateSchemaManagementTool.java | 7 +- .../schema/internal/SchemaCreatorImpl.java | 5 +- .../schema/internal/SchemaDropperImpl.java | 4 +- .../exec/ImprovedExtractionContextImpl.java | 14 +-- .../tool/schema/spi/ExtractionTool.java | 4 +- .../TestExtraPhysicalTableTypes.java | 14 ++- .../SchemaUpdateTableBackedSequenceTest.java | 2 +- 34 files changed, 307 insertions(+), 177 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java index 5b780c15eef0..4f0c817e8c15 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/InFlightMetadataCollectorImpl.java @@ -2197,8 +2197,6 @@ private void processExportableProducers() { // for now we only handle id generators as ExportableProducers final Dialect dialect = getDatabase().getJdbcEnvironment().getDialect(); - final String defaultCatalog = extractName( getDatabase().getDefaultNamespace().getName().getCatalog(), dialect ); - final String defaultSchema = extractName( getDatabase().getDefaultNamespace().getName().getSchema(), dialect ); for ( PersistentClass entityBinding : entityBindingMap.values() ) { if ( entityBinding.isInherited() ) { @@ -2208,8 +2206,6 @@ private void processExportableProducers() { handleIdentifierValueBinding( entityBinding.getIdentifier(), dialect, - defaultCatalog, - defaultSchema, (RootClass) entityBinding ); } @@ -2222,8 +2218,6 @@ private void processExportableProducers() { handleIdentifierValueBinding( ( (IdentifierCollection) collection ).getIdentifier(), dialect, - defaultCatalog, - defaultSchema, null ); } @@ -2232,8 +2226,6 @@ private void processExportableProducers() { private void handleIdentifierValueBinding( KeyValue identifierValueBinding, Dialect dialect, - String defaultCatalog, - String defaultSchema, RootClass entityBinding) { // todo : store this result (back into the entity or into the KeyValue, maybe?) // This process of instantiating the id-generator is called multiple times. @@ -2243,8 +2235,6 @@ private void handleIdentifierValueBinding( final IdentifierGenerator ig = identifierValueBinding.createIdentifierGenerator( getIdentifierGeneratorFactory(), dialect, - defaultCatalog, - defaultSchema, entityBinding ); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/MetadataBuilderImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/MetadataBuilderImpl.java index 61f98f680e9a..6f44c9c7d2e7 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/MetadataBuilderImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/MetadataBuilderImpl.java @@ -499,17 +499,12 @@ public static class MappingDefaultsImpl implements MappingDefaults { public MappingDefaultsImpl(StandardServiceRegistry serviceRegistry) { final ConfigurationService configService = serviceRegistry.getService( ConfigurationService.class ); - this.implicitSchemaName = configService.getSetting( - AvailableSettings.DEFAULT_SCHEMA, - StandardConverters.STRING, - null - ); - - this.implicitCatalogName = configService.getSetting( - AvailableSettings.DEFAULT_CATALOG, - StandardConverters.STRING, - null - ); + // AvailableSettings.DEFAULT_SCHEMA and AvailableSettings.DEFAULT_CATALOG + // are taken into account later, at runtime, when rendering table/sequence names. + // These fields are exclusively about mapping defaults, + // overridden in XML mappings or through setters in MetadataBuilder. + this.implicitSchemaName = null; + this.implicitCatalogName = null; this.implicitlyQuoteIdentifiers = configService.getSetting( AvailableSettings.GLOBALLY_QUOTED_IDENTIFIERS, diff --git a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java index 704437008fc9..dfff98061cdd 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java @@ -82,7 +82,9 @@ import static org.hibernate.cfg.AvailableSettings.CRITERIA_LITERAL_HANDLING_MODE; import static org.hibernate.cfg.AvailableSettings.CUSTOM_ENTITY_DIRTINESS_STRATEGY; import static org.hibernate.cfg.AvailableSettings.DEFAULT_BATCH_FETCH_SIZE; +import static org.hibernate.cfg.AvailableSettings.DEFAULT_CATALOG; import static org.hibernate.cfg.AvailableSettings.DEFAULT_ENTITY_MODE; +import static org.hibernate.cfg.AvailableSettings.DEFAULT_SCHEMA; import static org.hibernate.cfg.AvailableSettings.DELAY_ENTITY_LOADER_CREATIONS; import static org.hibernate.cfg.AvailableSettings.ENABLE_LAZY_LOAD_NO_TRANS; import static org.hibernate.cfg.AvailableSettings.FAIL_ON_PAGINATION_OVER_COLLECTION_FETCH; @@ -242,6 +244,12 @@ public class SessionFactoryOptionsBuilder implements SessionFactoryOptions { private boolean queryParametersValidationEnabled; private LiteralHandlingMode criteriaLiteralHandlingMode; private ImmutableEntityUpdateQueryHandlingMode immutableEntityUpdateQueryHandlingMode; + // These two settings cannot be modified from the builder, + // in order to maintain consistency. + // Indeed, other components (the schema tools) also make use of these settings, + // and THOSE do not have access to session factory options. + private final String defaultCatalog; + private final String defaultSchema; private Map sqlFunctions; @@ -531,6 +539,9 @@ else if ( jdbcTimeZoneValue != null ) { configurationSettings.get( IMMUTABLE_ENTITY_UPDATE_QUERY_HANDLING_MODE ) ); + this.defaultCatalog = ConfigurationHelper.getString( DEFAULT_CATALOG, configurationSettings ); + this.defaultSchema = ConfigurationHelper.getString( DEFAULT_SCHEMA, configurationSettings ); + this.inClauseParameterPaddingEnabled = ConfigurationHelper.getBoolean( IN_CLAUSE_PARAMETER_PADDING, configurationSettings, @@ -1047,6 +1058,16 @@ public ImmutableEntityUpdateQueryHandlingMode getImmutableEntityUpdateQueryHandl return immutableEntityUpdateQueryHandlingMode; } + @Override + public String getDefaultCatalog() { + return defaultCatalog; + } + + @Override + public String getDefaultSchema() { + return defaultSchema; + } + @Override public boolean jdbcStyleParamsZeroBased() { return this.jdbcStyleParamsZeroBased; @@ -1092,7 +1113,6 @@ public boolean isOmitJoinOfSuperclassTablesEnabled() { return omitJoinOfSuperclassTablesEnabled; } - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // In-flight mutation access diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/relational/SqlStringGenerationContext.java b/hibernate-core/src/main/java/org/hibernate/boot/model/relational/SqlStringGenerationContext.java index 522fbb0bb480..fcd682ae7e44 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/relational/SqlStringGenerationContext.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/relational/SqlStringGenerationContext.java @@ -6,6 +6,7 @@ */ package org.hibernate.boot.model.relational; +import org.hibernate.boot.model.naming.Identifier; import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.env.spi.IdentifierHelper; @@ -27,6 +28,22 @@ public interface SqlStringGenerationContext { */ IdentifierHelper getIdentifierHelper(); + /** + * @return The default catalog, used for table/sequence names that do not explicitly mention a catalog. + * May be {@code null}. + * This default is generally applied automatically by the {@link #format(QualifiedName) format methods}, + * but in some cases it can be useful to access it directly. + */ + Identifier getDefaultCatalog(); + + /** + * @return The default schema, used for table/sequence names that do not explicitly mention a schema. + * May be {@code null}. + * This default is generally applied automatically by the {@link #format(QualifiedName) format methods}, + * but in some cases it can be useful to access it directly. + */ + Identifier getDefaultSchema(); + /** * Render a formatted a table name * diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/relational/internal/SqlStringGenerationContextImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/model/relational/internal/SqlStringGenerationContextImpl.java index 6311ddc2779e..1b395e317e6c 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/relational/internal/SqlStringGenerationContextImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/relational/internal/SqlStringGenerationContextImpl.java @@ -6,31 +6,90 @@ */ package org.hibernate.boot.model.relational.internal; +import java.util.Map; + +import org.hibernate.boot.model.naming.Identifier; +import org.hibernate.boot.model.relational.Database; +import org.hibernate.boot.model.relational.Namespace; import org.hibernate.boot.model.relational.QualifiedName; import org.hibernate.boot.model.relational.QualifiedSequenceName; import org.hibernate.boot.model.relational.QualifiedTableName; import org.hibernate.boot.model.relational.SqlStringGenerationContext; +import org.hibernate.cfg.AvailableSettings; import org.hibernate.dialect.Dialect; import org.hibernate.engine.jdbc.env.spi.IdentifierHelper; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; +import org.hibernate.engine.jdbc.env.spi.NameQualifierSupport; import org.hibernate.engine.jdbc.env.spi.QualifiedObjectNameFormatter; public class SqlStringGenerationContextImpl implements SqlStringGenerationContext { + /** + * @param jdbcEnvironment The JDBC environment, to extract the dialect, identifier helper, etc. + * @param database The database metadata, to retrieve the implicit namespace name configured through XML mapping. + * @param configurationMap The configuration map, holding settings such as {@link AvailableSettings#DEFAULT_SCHEMA}. + * @return An {@link SqlStringGenerationContext}. + */ + public static SqlStringGenerationContext fromConfigurationMap(JdbcEnvironment jdbcEnvironment, + Database database, Map configurationMap) { + String defaultCatalog = (String) configurationMap.get( AvailableSettings.DEFAULT_CATALOG ); + String defaultSchema = (String) configurationMap.get( AvailableSettings.DEFAULT_SCHEMA ); + return fromExplicit( jdbcEnvironment, database, defaultCatalog, defaultSchema ); + } + + /** + * @param jdbcEnvironment The JDBC environment, to extract the dialect, identifier helper, etc. + * @param database The database metadata, to retrieve the implicit namespace name configured through XML mapping. + * @param defaultCatalog The default catalog to use, unless an implicit catalog was configured through XML mapping. + * @param defaultSchema The default schema to use, unless an implicit schema was configured through XML mapping. + * @return An {@link SqlStringGenerationContext}. + */ + public static SqlStringGenerationContext fromExplicit(JdbcEnvironment jdbcEnvironment, + Database database, String defaultCatalog, String defaultSchema) { + Namespace.Name implicitNamespaceName = database.getDefaultNamespace().getPhysicalName(); + IdentifierHelper identifierHelper = jdbcEnvironment.getIdentifierHelper(); + NameQualifierSupport nameQualifierSupport = jdbcEnvironment.getNameQualifierSupport(); + Identifier actualDefaultCatalog = null; + if ( nameQualifierSupport.supportsCatalogs() ) { + actualDefaultCatalog = implicitNamespaceName.getCatalog() != null + ? implicitNamespaceName.getCatalog() + : identifierHelper.toIdentifier( defaultCatalog ); + } + Identifier actualDefaultSchema = null; + if ( nameQualifierSupport.supportsSchemas() ) { + actualDefaultSchema = implicitNamespaceName.getSchema() != null + ? implicitNamespaceName.getSchema() + : identifierHelper.toIdentifier( defaultSchema ); + } + return new SqlStringGenerationContextImpl( jdbcEnvironment, actualDefaultCatalog, actualDefaultSchema ); + } + public static SqlStringGenerationContext forTests(JdbcEnvironment jdbcEnvironment) { - return new SqlStringGenerationContextImpl( jdbcEnvironment ); + return forTests( jdbcEnvironment, null, null ); + } + + public static SqlStringGenerationContext forTests(JdbcEnvironment jdbcEnvironment, + String defaultCatalog, String defaultSchema) { + IdentifierHelper identifierHelper = jdbcEnvironment.getIdentifierHelper(); + return new SqlStringGenerationContextImpl( jdbcEnvironment, + identifierHelper.toIdentifier( defaultCatalog ), identifierHelper.toIdentifier( defaultSchema ) ); } private final Dialect dialect; private final IdentifierHelper identifierHelper; private final QualifiedObjectNameFormatter qualifiedObjectNameFormatter; + private final Identifier defaultCatalog; + private final Identifier defaultSchema; @SuppressWarnings("deprecation") - public SqlStringGenerationContextImpl(JdbcEnvironment jdbcEnvironment) { + private SqlStringGenerationContextImpl(JdbcEnvironment jdbcEnvironment, + Identifier defaultCatalog, Identifier defaultSchema) { this.dialect = jdbcEnvironment.getDialect(); this.identifierHelper = jdbcEnvironment.getIdentifierHelper(); this.qualifiedObjectNameFormatter = jdbcEnvironment.getQualifiedObjectNameFormatter(); + this.defaultCatalog = defaultCatalog; + this.defaultSchema = defaultSchema; } @Override @@ -43,19 +102,60 @@ public IdentifierHelper getIdentifierHelper() { return identifierHelper; } + @Override + public Identifier getDefaultCatalog() { + return defaultCatalog; + } + + @Override + public Identifier getDefaultSchema() { + return defaultSchema; + } + @Override public String format(QualifiedTableName qualifiedName) { - return qualifiedObjectNameFormatter.format( qualifiedName, dialect ); + return qualifiedObjectNameFormatter.format( withDefaults( qualifiedName ), dialect ); } @Override public String format(QualifiedSequenceName qualifiedName) { - return qualifiedObjectNameFormatter.format( qualifiedName, dialect ); + return qualifiedObjectNameFormatter.format( withDefaults( qualifiedName ), dialect ); } @Override public String format(QualifiedName qualifiedName) { - return qualifiedObjectNameFormatter.format( qualifiedName, dialect ); + 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 diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/ModelBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/ModelBinder.java index 3efebf2d3f62..5d63c44fcfe3 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/ModelBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/ModelBinder.java @@ -804,17 +804,13 @@ private void makeIdentifier( // YUCK! but cannot think of a clean way to do this given the string-config based scheme params.put( PersistentIdentifierGenerator.IDENTIFIER_NORMALIZER, objectNameNormalizer); - if ( database.getDefaultNamespace().getPhysicalName().getSchema() != null ) { - params.setProperty( - PersistentIdentifierGenerator.SCHEMA, - database.getDefaultNamespace().getPhysicalName().getSchema().render( database.getDialect() ) - ); + String implicitSchemaName = metadataBuildingContext.getMappingDefaults().getImplicitSchemaName(); + if ( implicitSchemaName != null ) { + params.setProperty( PersistentIdentifierGenerator.SCHEMA, implicitSchemaName ); } - if ( database.getDefaultNamespace().getPhysicalName().getCatalog() != null ) { - params.setProperty( - PersistentIdentifierGenerator.CATALOG, - database.getDefaultNamespace().getPhysicalName().getCatalog().render( database.getDialect() ) - ); + String implicitCatalogName = metadataBuildingContext.getMappingDefaults().getImplicitCatalogName(); + if ( implicitCatalogName != null ) { + params.setProperty( PersistentIdentifierGenerator.CATALOG, implicitCatalogName ); } params.putAll( generator.getParameters() ); @@ -2961,7 +2957,7 @@ private Identifier determineCatalogName(TableSpecificationSource tableSpecSource return database.toIdentifier( tableSpecSource.getExplicitCatalogName() ); } else { - return database.getDefaultNamespace().getName().getCatalog(); + return database.toIdentifier( metadataBuildingContext.getMappingDefaults().getImplicitCatalogName() ); } } @@ -2970,7 +2966,7 @@ private Identifier determineSchemaName(TableSpecificationSource tableSpecSource) return database.toIdentifier( tableSpecSource.getExplicitSchemaName() ); } else { - return database.getDefaultNamespace().getName().getSchema(); + return database.toIdentifier( metadataBuildingContext.getMappingDefaults().getImplicitSchemaName() ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingSessionFactoryOptions.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingSessionFactoryOptions.java index 1ac730e0e52c..84953eac45ab 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingSessionFactoryOptions.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/AbstractDelegatingSessionFactoryOptions.java @@ -423,6 +423,16 @@ public ImmutableEntityUpdateQueryHandlingMode getImmutableEntityUpdateQueryHandl return delegate.getImmutableEntityUpdateQueryHandlingMode(); } + @Override + public String getDefaultCatalog() { + return delegate.getDefaultCatalog(); + } + + @Override + public String getDefaultSchema() { + return delegate.getDefaultSchema(); + } + @Override public boolean inClauseParameterPaddingEnabled() { return delegate.inClauseParameterPaddingEnabled(); diff --git a/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java b/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java index 93cb7516128e..30b3a761c2c1 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/spi/SessionFactoryOptions.java @@ -293,6 +293,26 @@ default ImmutableEntityUpdateQueryHandlingMode getImmutableEntityUpdateQueryHand return ImmutableEntityUpdateQueryHandlingMode.WARNING; } + /** + * The default catalog to use in generated SQL when a catalog wasn't specified in the mapping, + * neither explicitly nor implicitly (see the concept of implicit catalog in XML mapping). + * + * @return The default catalog to use. + */ + default String getDefaultCatalog() { + return null; + } + + /** + * The default schema to use in generated SQL when a catalog wasn't specified in the mapping, + * neither explicitly nor implicitly (see the concept of implicit schema in XML mapping). + * + * @return The default schema to use. + */ + default String getDefaultSchema() { + return null; + } + default boolean inClauseParameterPaddingEnabled() { return false; } diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/Settings.java b/hibernate-core/src/main/java/org/hibernate/cfg/Settings.java index 244835656fce..3203190d9086 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/Settings.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/Settings.java @@ -61,8 +61,8 @@ private static String extractName(Identifier identifier) { public Settings(SessionFactoryOptions sessionFactoryOptions, String defaultCatalogName, String defaultSchemaName) { this.sessionFactoryOptions = sessionFactoryOptions; - this.defaultCatalogName = defaultCatalogName; - this.defaultSchemaName = defaultSchemaName; + this.defaultCatalogName = defaultCatalogName != null ? defaultCatalogName : sessionFactoryOptions.getDefaultCatalog(); + this.defaultSchemaName = defaultSchemaName != null ? defaultSchemaName : sessionFactoryOptions.getDefaultSchema(); if ( LOG.isDebugEnabled() ) { LOG.debugf( "SessionFactory name : %s", sessionFactoryOptions.getSessionFactoryName() ); diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/TableBinder.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/TableBinder.java index 2e5995f45647..2dfb2d132e87 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/TableBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/TableBinder.java @@ -477,10 +477,10 @@ public static Table buildAndFillTable( String subselect, InFlightMetadataCollector.EntityTableXref denormalizedSuperTableXref) { schema = BinderHelper.isEmptyOrNullAnnotationValue( schema ) - ? extract( buildingContext.getMetadataCollector().getDatabase().getDefaultNamespace().getPhysicalName().getSchema() ) + ? buildingContext.getBuildingOptions().getMappingDefaults().getImplicitSchemaName() : schema; catalog = BinderHelper.isEmptyOrNullAnnotationValue( catalog ) - ? extract( buildingContext.getMetadataCollector().getDatabase().getDefaultNamespace().getPhysicalName().getCatalog() ) + ? buildingContext.getBuildingOptions().getMappingDefaults().getImplicitCatalogName() : catalog; final Table table; diff --git a/hibernate-core/src/main/java/org/hibernate/internal/FilterConfiguration.java b/hibernate-core/src/main/java/org/hibernate/internal/FilterConfiguration.java index c494da3c2029..33f169649b8e 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/FilterConfiguration.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/FilterConfiguration.java @@ -59,9 +59,7 @@ public Map getAliasTableMap(SessionFactoryImplementor factory) { } else if ( persistentClass != null ) { String table = persistentClass.getTable().getQualifiedName( - factory.getSqlStringGenerationContext(), - factory.getSettings().getDefaultCatalogName(), - factory.getSettings().getDefaultSchemaName() + factory.getSqlStringGenerationContext() ); return Collections.singletonMap( null, table ); } diff --git a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java index 099de0dcb53c..6ee59ac1a42b 100644 --- a/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/internal/SessionFactoryImpl.java @@ -233,10 +233,11 @@ public SessionFactoryImpl( this.uuid = options.getUuid(); jdbcServices = serviceRegistry.getService( JdbcServices.class ); - sqlStringGenerationContext = new SqlStringGenerationContextImpl( jdbcServices.getJdbcEnvironment() ); + + ConfigurationService configurationService = serviceRegistry.getService( ConfigurationService.class ); this.properties = new HashMap<>(); - this.properties.putAll( serviceRegistry.getService( ConfigurationService.class ).getSettings() ); + this.properties.putAll( configurationService.getSettings() ); if ( !properties.containsKey( AvailableSettings.JPA_VALIDATION_FACTORY ) && !properties.containsKey( AvailableSettings.JAKARTA_JPA_VALIDATION_FACTORY ) ) { if ( getSessionFactoryOptions().getValidatorFactoryReference() != null ) { @@ -254,6 +255,10 @@ public SessionFactoryImpl( maskOutSensitiveInformation(this.properties); logIfEmptyCompositesEnabled( this.properties ); + sqlStringGenerationContext = SqlStringGenerationContextImpl.fromExplicit( + jdbcServices.getJdbcEnvironment(), metadata.getDatabase(), + options.getDefaultCatalog(), options.getDefaultSchema() ); + this.sqlFunctionRegistry = new SQLFunctionRegistry( jdbcServices.getJdbcEnvironment().getDialect(), options.getCustomSqlFunctionMap() ); this.cacheAccess = this.serviceRegistry.getService( CacheImplementor.class ); this.criteriaBuilder = new CriteriaBuilderImpl( this ); @@ -301,8 +306,6 @@ public void sessionFactoryClosed(SessionFactory factory) { IdentifierGenerator generator = model.getIdentifier().createIdentifierGenerator( metadata.getIdentifierGeneratorFactory(), jdbcServices.getJdbcEnvironment().getDialect(), - settings.getDefaultCatalogName(), - settings.getDefaultSchemaName(), (RootClass) model ); generator.initialize( sqlStringGenerationContext ); diff --git a/hibernate-core/src/main/java/org/hibernate/loader/custom/sql/SQLQueryParser.java b/hibernate-core/src/main/java/org/hibernate/loader/custom/sql/SQLQueryParser.java index 73efc374e559..16add7c282b3 100755 --- a/hibernate-core/src/main/java/org/hibernate/loader/custom/sql/SQLQueryParser.java +++ b/hibernate-core/src/main/java/org/hibernate/loader/custom/sql/SQLQueryParser.java @@ -13,6 +13,8 @@ import java.util.regex.Pattern; import org.hibernate.QueryException; +import org.hibernate.boot.model.naming.Identifier; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.engine.query.spi.ParameterParser; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.param.ParameterBinder; @@ -85,6 +87,8 @@ protected String substituteBrackets(String sqlQuery) throws QueryException { StringBuilder result = new StringBuilder( sqlQuery.length() + 20 ); int left, right; + SqlStringGenerationContext sqlStringGenerationContext = factory.getSqlStringGenerationContext(); + // replace {....} with corresponding column aliases for ( int curr = 0; curr < sqlQuery.length(); curr = right + 1 ) { if ( ( left = sqlQuery.indexOf( '{', curr ) ) < 0 ) { @@ -107,30 +111,30 @@ protected String substituteBrackets(String sqlQuery) throws QueryException { if ( isPlaceholder ) { // Domain replacement if ( DOMAIN_PLACEHOLDER.equals( aliasPath ) ) { - final String catalogName = factory.getSettings().getDefaultCatalogName(); + final Identifier catalogName = sqlStringGenerationContext.getDefaultCatalog(); if ( catalogName != null ) { - result.append( catalogName ); + result.append( catalogName.render( sqlStringGenerationContext.getDialect() ) ); result.append( "." ); } - final String schemaName = factory.getSettings().getDefaultSchemaName(); + final Identifier schemaName = sqlStringGenerationContext.getDefaultSchema(); if ( schemaName != null ) { - result.append( schemaName ); + result.append( schemaName.render( sqlStringGenerationContext.getDialect() ) ); result.append( "." ); } } // Schema replacement else if ( SCHEMA_PLACEHOLDER.equals( aliasPath ) ) { - final String schemaName = factory.getSettings().getDefaultSchemaName(); + final Identifier schemaName = sqlStringGenerationContext.getDefaultSchema(); if ( schemaName != null ) { - result.append(schemaName); + result.append( schemaName.render( sqlStringGenerationContext.getDialect() ) ); result.append("."); } } // Catalog replacement else if ( CATALOG_PLACEHOLDER.equals( aliasPath ) ) { - final String catalogName = factory.getSettings().getDefaultCatalogName(); + final Identifier catalogName = sqlStringGenerationContext.getDefaultCatalog(); if ( catalogName != null ) { - result.append( catalogName ); + result.append( catalogName.render( sqlStringGenerationContext.getDialect() ) ); result.append( "." ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Constraint.java b/hibernate-core/src/main/java/org/hibernate/mapping/Constraint.java index 85ab53899aff..37d68b6f00fc 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Constraint.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Constraint.java @@ -185,7 +185,7 @@ public String sqlDropString(SqlStringGenerationContext context, String defaultCatalog, String defaultSchema) { Dialect dialect = context.getDialect(); if ( isGenerated( dialect ) ) { - final String tableName = getTable().getQualifiedName( context, defaultCatalog, defaultSchema ); + final String tableName = getTable().getQualifiedName( context ); return String.format( Locale.ROOT, "%s evictData constraint %s", @@ -208,7 +208,7 @@ public String sqlCreateString(Mapping p, SqlStringGenerationContext context, Str // empty string. Prevent blank "alter table" statements. String constraintString = sqlConstraintString( context, getName(), defaultCatalog, defaultSchema ); if ( !StringHelper.isEmpty( constraintString ) ) { - final String tableName = getTable().getQualifiedName( context, defaultCatalog, defaultSchema ); + final String tableName = getTable().getQualifiedName( context ); return dialect.getAlterTableString( tableName ) + " " + constraintString; } } diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/ForeignKey.java b/hibernate-core/src/main/java/org/hibernate/mapping/ForeignKey.java index 3f309d1d4f9e..ffd3dc23784d 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/ForeignKey.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/ForeignKey.java @@ -90,9 +90,7 @@ public String sqlConstraintString( constraintName, columnNames, referencedTable.getQualifiedName( - context, - defaultCatalog, - defaultSchema + context ), referencedColumnNames, isReferenceToPrimaryKey() @@ -179,7 +177,7 @@ public void setKeyDefinition(String keyDefinition) { public String sqlDropString(SqlStringGenerationContext context, String defaultCatalog, String defaultSchema) { Dialect dialect = context.getDialect(); - String tableName = getTable().getQualifiedName( context, defaultCatalog, defaultSchema ); + String tableName = getTable().getQualifiedName( context ); final StringBuilder buf = new StringBuilder( dialect.getAlterTableString( tableName ) ); buf.append( dialect.getDropForeignKeyString() ); if ( dialect.supportsIfExistsBeforeConstraintName() ) { diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Index.java b/hibernate-core/src/main/java/org/hibernate/mapping/Index.java index cbc96c2ea023..c0937b19ff58 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Index.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Index.java @@ -55,7 +55,7 @@ public static String buildSqlDropIndexString( String name, String defaultCatalog, String defaultSchema) { - return buildSqlDropIndexString( name, table.getQualifiedName( context, defaultCatalog, defaultSchema ) ); + return buildSqlDropIndexString( name, table.getQualifiedName( context ) ); } public static String buildSqlDropIndexString( @@ -76,7 +76,7 @@ public static String buildSqlCreateIndexString( return buildSqlCreateIndexString( context.getDialect(), name, - table.getQualifiedName( context, defaultCatalog, defaultSchema ), + table.getQualifiedName( context ), columns, columnOrderMap, unique @@ -151,7 +151,7 @@ public String sqlDropString(SqlStringGenerationContext context, Dialect dialect = context.getDialect(); return "drop index " + StringHelper.qualify( - table.getQualifiedName( context, defaultCatalog, defaultSchema ), + table.getQualifiedName( context ), getQuotedName( dialect ) ); } diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/KeyValue.java b/hibernate-core/src/main/java/org/hibernate/mapping/KeyValue.java index 8635fb99f630..bda09a04c4db 100755 --- a/hibernate-core/src/main/java/org/hibernate/mapping/KeyValue.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/KeyValue.java @@ -18,6 +18,11 @@ */ public interface KeyValue extends Value { + /** + * @deprecated Use {@link #createIdentifierGenerator(IdentifierGeneratorFactory, Dialect, RootClass)} + * instead. + */ + @Deprecated public IdentifierGenerator createIdentifierGenerator( IdentifierGeneratorFactory identifierGeneratorFactory, Dialect dialect, @@ -25,6 +30,11 @@ public IdentifierGenerator createIdentifierGenerator( String defaultSchema, RootClass rootClass) throws MappingException; + IdentifierGenerator createIdentifierGenerator( + IdentifierGeneratorFactory identifierGeneratorFactory, + Dialect dialect, + RootClass rootClass) throws MappingException; + public boolean isIdentityColumn(IdentifierGeneratorFactory identifierGeneratorFactory, Dialect dialect); public void createForeignKeyOfEntity(String entityName); diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java b/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java index da3afbe33ea5..97fac7f3ab61 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java @@ -52,13 +52,9 @@ import org.hibernate.type.descriptor.converter.AttributeConverterSqlTypeDescriptorAdapter; import org.hibernate.type.descriptor.converter.AttributeConverterTypeAdapter; import org.hibernate.type.descriptor.java.BasicJavaDescriptor; -import org.hibernate.type.descriptor.java.JavaTypeDescriptor; -import org.hibernate.type.descriptor.spi.JdbcRecommendedSqlTypeMappingContext; -import org.hibernate.type.descriptor.sql.JdbcTypeJavaClassMappings; import org.hibernate.type.descriptor.sql.LobTypeMappings; import org.hibernate.type.descriptor.sql.NationalizedTypeMappings; import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; -import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.usertype.DynamicParameterizedType; /** @@ -276,6 +272,14 @@ public IdentifierGenerator getIdentifierGenerator() { return identifierGenerator; } + @Override + public IdentifierGenerator createIdentifierGenerator( + IdentifierGeneratorFactory identifierGeneratorFactory, + Dialect dialect, + RootClass rootClass) throws MappingException { + return createIdentifierGenerator( identifierGeneratorFactory, dialect, null, null, rootClass ); + } + @Override public IdentifierGenerator createIdentifierGenerator( IdentifierGeneratorFactory identifierGeneratorFactory, @@ -289,18 +293,17 @@ public IdentifierGenerator createIdentifierGenerator( } Properties params = new Properties(); - - //if the hibernate-mapping did not specify a schema/catalog, use the defaults - //specified by properties - but note that if the schema/catalog were specified - //in hibernate-mapping, or as params, they will already be initialized and - //will override the values set here (they are in identifierGeneratorProperties) + + // This is for backwards compatibility only; + // when this method is called by Hibernate ORM, defaultSchema and defaultCatalog are always + // null, and defaults are handled later. if ( defaultSchema!=null ) { params.setProperty(PersistentIdentifierGenerator.SCHEMA, defaultSchema); } if ( defaultCatalog!=null ) { params.setProperty(PersistentIdentifierGenerator.CATALOG, defaultCatalog); } - + //pass the entity-name, if not a collection-id if (rootClass!=null) { params.setProperty( IdentifierGenerator.ENTITY_NAME, rootClass.getEntityName() ); diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/Table.java b/hibernate-core/src/main/java/org/hibernate/mapping/Table.java index 8f802ce637df..827058d65202 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/Table.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/Table.java @@ -28,7 +28,6 @@ import org.hibernate.boot.model.relational.QualifiedTableName; import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.dialect.Dialect; -import org.hibernate.engine.jdbc.env.spi.IdentifierHelper; import org.hibernate.engine.spi.Mapping; import org.hibernate.tool.hbm2ddl.ColumnMetadata; import org.hibernate.tool.hbm2ddl.TableMetadata; @@ -113,18 +112,11 @@ public Table(Namespace namespace, String subselect, boolean isAbstract) { this.isAbstract = isAbstract; } - public String getQualifiedName(SqlStringGenerationContext context, String defaultCatalog, String defaultSchema) { + public String getQualifiedName(SqlStringGenerationContext context) { if ( subselect != null ) { return "( " + subselect + " )"; } - IdentifierHelper identifierHelper = context.getIdentifierHelper(); - Identifier usedSchema = schema == null ? - identifierHelper.toIdentifier( defaultSchema ) : - schema; - Identifier usedCatalog = catalog == null ? - identifierHelper.toIdentifier( defaultCatalog ) : - catalog; - return context.format( new QualifiedTableName( usedCatalog, usedSchema, name ) ); + return context.format( new QualifiedTableName( catalog, schema, name ) ); } /** @@ -441,16 +433,8 @@ public Iterator sqlAlterStrings( Dialect dialect, Metadata metadata, TableInformation tableInfo, - Identifier defaultCatalog, - Identifier defaultSchema, SqlStringGenerationContext sqlStringGenerationContext) throws HibernateException { - final String tableName = sqlStringGenerationContext.format( - new QualifiedTableName( - catalog != null ? catalog : defaultCatalog, - schema != null ? schema : defaultSchema, - name - ) - ); + final String tableName = sqlStringGenerationContext.format( new QualifiedTableName( catalog, schema, name ) ); StringBuilder root = new StringBuilder( dialect.getAlterTableString( tableName ) ) .append( ' ' ) @@ -526,7 +510,7 @@ public String sqlCreateString(Mapping p, SqlStringGenerationContext context, Str Dialect dialect = context.getDialect(); StringBuilder buf = new StringBuilder( hasPrimaryKey() ? dialect.getCreateTableString() : dialect.getCreateMultisetTableString() ) .append( ' ' ) - .append( getQualifiedName( context, defaultCatalog, defaultSchema ) ) + .append( getQualifiedName( context ) ) .append( " (" ); boolean identityColumn = idValue != null && idValue.isIdentityColumn( p.getIdentifierGeneratorFactory(), dialect ); @@ -621,7 +605,7 @@ public String sqlCreateString(Mapping p, SqlStringGenerationContext context, Str @Override public String sqlDropString(SqlStringGenerationContext context, String defaultCatalog, String defaultSchema) { Dialect dialect = context.getDialect(); - return dialect.getDropTableString( getQualifiedName( context, defaultCatalog, defaultSchema ) ); + return dialect.getDropTableString( getQualifiedName( context ) ); } public PrimaryKey getPrimaryKey() { diff --git a/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java index 79252658cf60..81c5ec033306 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/collection/AbstractCollectionPersister.java @@ -454,8 +454,6 @@ public AbstractCollectionPersister( identifierGenerator = idColl.getIdentifier().createIdentifierGenerator( creationContext.getMetadata().getIdentifierGeneratorFactory(), factory.getDialect(), - factory.getSettings().getDefaultCatalogName(), - factory.getSettings().getDefaultSchemaName(), null ); identifierGenerator.initialize( creationContext.getSessionFactory().getSqlStringGenerationContext() ); diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java index 9a5712d55eba..64da81c8e03a 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/JoinedSubclassEntityPersister.java @@ -13,7 +13,6 @@ import org.hibernate.boot.model.relational.Database; import org.hibernate.cache.spi.access.EntityDataAccess; import org.hibernate.cache.spi.access.NaturalIdDataAccess; -import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle; import org.hibernate.engine.spi.SessionFactoryImplementor; import org.hibernate.internal.DynamicFilterAliasGenerator; @@ -439,9 +438,7 @@ else if ( persistentClass.isDiscriminatorValueNotNull() ) { while ( iter.hasNext() ) { Property prop = (Property) iter.next(); String tabname = prop.getValue().getTable().getQualifiedName( - factory.getSqlStringGenerationContext(), - factory.getSettings().getDefaultCatalogName(), - factory.getSettings().getDefaultSchemaName() + factory.getSqlStringGenerationContext() ); propertyTableNumbers[i] = getTableId( tabname, this.tableNames ); naturalOrderPropertyTableNumbers[i] = getTableId( tabname, naturalOrderTableNames ); @@ -461,9 +458,7 @@ else if ( persistentClass.isDiscriminatorValueNotNull() ) { Property prop = (Property) iter.next(); Table tab = prop.getValue().getTable(); String tabname = tab.getQualifiedName( - factory.getSqlStringGenerationContext(), - factory.getSettings().getDefaultCatalogName(), - factory.getSettings().getDefaultSchemaName() + factory.getSqlStringGenerationContext() ); Integer tabnum = getTableId( tabname, subclassTableNameClosure ); propTableNumbers.add( tabnum ); @@ -497,9 +492,7 @@ else if ( persistentClass.isDiscriminatorValueNotNull() ) { notNullColumnTableNumbers = new int[subclassSpan]; final int id = getTableId( persistentClass.getTable().getQualifiedName( - factory.getSqlStringGenerationContext(), - factory.getSettings().getDefaultCatalogName(), - factory.getSettings().getDefaultSchemaName() + factory.getSqlStringGenerationContext() ), subclassTableNameClosure ); @@ -551,9 +544,7 @@ else if ( sc.isDiscriminatorValueNotNull() ) { discriminatorValues[k] = discriminatorValue.toString(); int id = getTableId( sc.getTable().getQualifiedName( - factory.getSqlStringGenerationContext(), - factory.getSettings().getDefaultCatalogName(), - factory.getSettings().getDefaultSchemaName() + factory.getSqlStringGenerationContext() ), subclassTableNameClosure ); @@ -676,9 +667,7 @@ private void associateSubclassNamesToSubclassTableIndexes( SessionFactoryImplementor factory) { final String tableName = persistentClass.getTable().getQualifiedName( - factory.getSqlStringGenerationContext(), - factory.getSettings().getDefaultCatalogName(), - factory.getSettings().getDefaultSchemaName() + factory.getSqlStringGenerationContext() ); associateSubclassNamesToSubclassTableIndex( tableName, classNames, mapping ); @@ -687,9 +676,7 @@ private void associateSubclassNamesToSubclassTableIndexes( while ( itr.hasNext() ) { final Join join = (Join) itr.next(); final String secondaryTableName = join.getTable().getQualifiedName( - factory.getSqlStringGenerationContext(), - factory.getSettings().getDefaultCatalogName(), - factory.getSettings().getDefaultSchemaName() + factory.getSqlStringGenerationContext() ); associateSubclassNamesToSubclassTableIndex( secondaryTableName, classNames, mapping ); } diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/UnionSubclassEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/UnionSubclassEntityPersister.java index ac8331ff20d0..5d50cca35865 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/UnionSubclassEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/UnionSubclassEntityPersister.java @@ -25,7 +25,6 @@ import org.hibernate.cache.spi.access.NaturalIdDataAccess; import org.hibernate.cfg.Settings; import org.hibernate.dialect.Dialect; -import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.engine.spi.ExecuteUpdateResultCheckStyle; import org.hibernate.engine.spi.Mapping; import org.hibernate.engine.spi.SessionFactoryImplementor; @@ -367,9 +366,7 @@ protected String generateSubquery(PersistentClass model, Mapping mapping) { if ( !model.hasSubclasses() ) { return model.getTable().getQualifiedName( - sqlStringGenerationContext, - settings.getDefaultCatalogName(), - settings.getDefaultSchemaName() + sqlStringGenerationContext ); } @@ -415,9 +412,7 @@ protected String generateSubquery(PersistentClass model, Mapping mapping) { buf.append( " from " ) .append( table.getQualifiedName( - sqlStringGenerationContext, - settings.getDefaultCatalogName(), - settings.getDefaultSchemaName() + sqlStringGenerationContext ) ); buf.append( " union " ); diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/DatabaseInformationImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/DatabaseInformationImpl.java index 9af4d368df98..38748838b128 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/DatabaseInformationImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/DatabaseInformationImpl.java @@ -14,6 +14,7 @@ import org.hibernate.boot.model.relational.Namespace; import org.hibernate.boot.model.relational.QualifiedSequenceName; import org.hibernate.boot.model.relational.QualifiedTableName; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.resource.transaction.spi.DdlTransactionIsolator; import org.hibernate.service.ServiceRegistry; @@ -39,16 +40,15 @@ public class DatabaseInformationImpl public DatabaseInformationImpl( ServiceRegistry serviceRegistry, JdbcEnvironment jdbcEnvironment, + SqlStringGenerationContext sqlStringGenerationContext, DdlTransactionIsolator ddlTransactionIsolator, - Namespace.Name defaultNamespace, SchemaManagementTool tool) throws SQLException { this.jdbcEnvironment = jdbcEnvironment; this.extractionContext = tool.getExtractionTool().createExtractionContext( serviceRegistry, jdbcEnvironment, + sqlStringGenerationContext, ddlTransactionIsolator, - defaultNamespace.getCatalog(), - defaultNamespace.getSchema(), this ); diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/ExtractionContextImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/ExtractionContextImpl.java index 1af9e2c66f65..2dd8d5365347 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/ExtractionContextImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/ExtractionContextImpl.java @@ -12,7 +12,6 @@ import org.hibernate.boot.model.naming.Identifier; import org.hibernate.boot.model.relational.SqlStringGenerationContext; -import org.hibernate.boot.model.relational.internal.SqlStringGenerationContextImpl; import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.service.ServiceRegistry; @@ -27,8 +26,6 @@ public class ExtractionContextImpl implements ExtractionContext { private final SqlStringGenerationContext sqlStringGenerationContext; private final JdbcConnectionAccess jdbcConnectionAccess; private final DatabaseObjectAccess registeredTableAccess; - private final Identifier defaultCatalogName; - private final Identifier defaultSchemaName; private Connection jdbcConnection; private DatabaseMetaData jdbcDatabaseMetaData; @@ -36,17 +33,14 @@ public class ExtractionContextImpl implements ExtractionContext { public ExtractionContextImpl( ServiceRegistry serviceRegistry, JdbcEnvironment jdbcEnvironment, + SqlStringGenerationContext sqlStringGenerationContext, JdbcConnectionAccess jdbcConnectionAccess, - DatabaseObjectAccess registeredTableAccess, - Identifier defaultCatalogName, - Identifier defaultSchemaName) { + DatabaseObjectAccess registeredTableAccess) { this.serviceRegistry = serviceRegistry; this.jdbcEnvironment = jdbcEnvironment; - this.sqlStringGenerationContext = new SqlStringGenerationContextImpl( jdbcEnvironment ); + this.sqlStringGenerationContext = sqlStringGenerationContext; this.jdbcConnectionAccess = jdbcConnectionAccess; this.registeredTableAccess = registeredTableAccess; - this.defaultCatalogName = defaultCatalogName; - this.defaultSchemaName = defaultSchemaName; } @Override @@ -92,12 +86,12 @@ public DatabaseMetaData getJdbcDatabaseMetaData() { @Override public Identifier getDefaultCatalog() { - return defaultCatalogName; + return sqlStringGenerationContext.getDefaultCatalog(); } @Override public Identifier getDefaultSchema() { - return defaultSchemaName; + return sqlStringGenerationContext.getDefaultSchema(); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/AbstractSchemaMigrator.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/AbstractSchemaMigrator.java index e91b829034fc..815febc060e5 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/AbstractSchemaMigrator.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/AbstractSchemaMigrator.java @@ -28,6 +28,7 @@ import org.hibernate.dialect.Dialect; import org.hibernate.engine.config.spi.ConfigurationService; import org.hibernate.engine.config.spi.StandardConverters; +import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.engine.jdbc.internal.FormatStyle; import org.hibernate.engine.jdbc.internal.Formatter; import org.hibernate.internal.util.StringHelper; @@ -91,6 +92,11 @@ public void setUniqueConstraintStrategy(UniqueConstraintSchemaUpdateStrategy uni @Override public void doMigration(Metadata metadata, ExecutionOptions options, TargetDescriptor targetDescriptor) { + SqlStringGenerationContext sqlStringGenerationContext = SqlStringGenerationContextImpl.fromConfigurationMap( + tool.getServiceRegistry().getService( JdbcEnvironment.class ), + metadata.getDatabase(), + options.getConfigurationValues() + ); if ( !targetDescriptor.getTargetTypes().isEmpty() ) { final JdbcContext jdbcContext = tool.resolveJdbcContext( options.getConfigurationValues() ); final DdlTransactionIsolator ddlTransactionIsolator = tool.getDdlTransactionIsolator( jdbcContext ); @@ -98,7 +104,7 @@ public void doMigration(Metadata metadata, ExecutionOptions options, TargetDescr final DatabaseInformation databaseInformation = Helper.buildDatabaseInformation( tool.getServiceRegistry(), ddlTransactionIsolator, - metadata.getDatabase().getDefaultNamespace().getName(), + sqlStringGenerationContext, tool ); @@ -114,7 +120,8 @@ public void doMigration(Metadata metadata, ExecutionOptions options, TargetDescr } try { - performMigration( metadata, databaseInformation, options, jdbcContext.getDialect(), targets ); + performMigration( metadata, databaseInformation, options, jdbcContext.getDialect(), + sqlStringGenerationContext, targets ); } finally { for ( GenerationTarget target : targets ) { @@ -161,6 +168,7 @@ private void performMigration( DatabaseInformation existingDatabase, ExecutionOptions options, Dialect dialect, + SqlStringGenerationContext sqlStringGenerationContext, GenerationTarget... targets) { final boolean format = Helper.interpretFormattingEnabled( options.getConfigurationValues() ); final Formatter formatter = format ? FormatStyle.DDL.getFormatter() : FormatStyle.NONE.getFormatter(); @@ -168,8 +176,6 @@ private void performMigration( final Set exportIdentifiers = new HashSet( 50 ); final Database database = metadata.getDatabase(); - SqlStringGenerationContext sqlStringGenerationContext = - new SqlStringGenerationContextImpl( database.getJdbcEnvironment() ); // Drop all AuxiliaryDatabaseObjects for ( AuxiliaryDatabaseObject auxiliaryDatabaseObject : database.getAuxiliaryDatabaseObjects() ) { @@ -311,8 +317,6 @@ protected void migrateTable( dialect, metadata, tableInformation, - database.getDefaultNamespace().getPhysicalName().getCatalog(), - database.getDefaultNamespace().getPhysicalName().getSchema(), sqlStringGenerationContext ), formatter, diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/AbstractSchemaValidator.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/AbstractSchemaValidator.java index ffe60ab61686..4b86bf903955 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/AbstractSchemaValidator.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/AbstractSchemaValidator.java @@ -13,7 +13,10 @@ import org.hibernate.boot.model.naming.Identifier; import org.hibernate.boot.model.relational.Namespace; import org.hibernate.boot.model.relational.Sequence; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; +import org.hibernate.boot.model.relational.internal.SqlStringGenerationContextImpl; import org.hibernate.dialect.Dialect; +import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.mapping.Column; import org.hibernate.mapping.Selectable; import org.hibernate.mapping.Table; @@ -54,13 +57,18 @@ public AbstractSchemaValidator( @Override public void doValidation(Metadata metadata, ExecutionOptions options) { + SqlStringGenerationContext sqlStringGenerationContext = SqlStringGenerationContextImpl.fromConfigurationMap( + tool.getServiceRegistry().getService( JdbcEnvironment.class ), + metadata.getDatabase(), + options.getConfigurationValues() + ); final JdbcContext jdbcContext = tool.resolveJdbcContext( options.getConfigurationValues() ); final DdlTransactionIsolator isolator = tool.getDdlTransactionIsolator( jdbcContext ); final DatabaseInformation databaseInformation = Helper.buildDatabaseInformation( tool.getServiceRegistry(), isolator, - metadata.getDatabase().getDefaultNamespace().getName(), + sqlStringGenerationContext, tool ); diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/Helper.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/Helper.java index 131a961a074a..b09c9993586a 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/Helper.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/Helper.java @@ -14,7 +14,7 @@ import java.util.Map; import java.util.regex.Pattern; -import org.hibernate.boot.model.relational.Namespace; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; import org.hibernate.cfg.AvailableSettings; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; @@ -176,15 +176,15 @@ public static boolean interpretFormattingEnabled(Map configurationValues) { public static DatabaseInformation buildDatabaseInformation( ServiceRegistry serviceRegistry, DdlTransactionIsolator ddlTransactionIsolator, - Namespace.Name defaultNamespace, + SqlStringGenerationContext sqlStringGenerationContext, SchemaManagementTool tool) { final JdbcEnvironment jdbcEnvironment = serviceRegistry.getService( JdbcEnvironment.class ); try { return new DatabaseInformationImpl( serviceRegistry, jdbcEnvironment, + sqlStringGenerationContext, ddlTransactionIsolator, - defaultNamespace, tool ); } diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/HibernateSchemaManagementTool.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/HibernateSchemaManagementTool.java index 7741de5d8f5f..e6d5b97f0fee 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/HibernateSchemaManagementTool.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/HibernateSchemaManagementTool.java @@ -10,6 +10,7 @@ import java.util.Map; import org.hibernate.boot.model.naming.Identifier; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.boot.registry.selector.spi.StrategySelector; import org.hibernate.cfg.AvailableSettings; import org.hibernate.dialect.Dialect; @@ -375,16 +376,14 @@ private HibernateExtractionTool() { public ExtractionContext createExtractionContext( ServiceRegistry serviceRegistry, JdbcEnvironment jdbcEnvironment, + SqlStringGenerationContext sqlStringGenerationContext, DdlTransactionIsolator ddlTransactionIsolator, - Identifier defaultCatalog, - Identifier defaultSchema, ExtractionContext.DatabaseObjectAccess databaseObjectAccess) { return new ImprovedExtractionContextImpl( serviceRegistry, jdbcEnvironment, + sqlStringGenerationContext, ddlTransactionIsolator, - defaultCatalog, - defaultSchema, databaseObjectAccess ); } diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/SchemaCreatorImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/SchemaCreatorImpl.java index 63dbca8351f1..0d14dcabf768 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/SchemaCreatorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/SchemaCreatorImpl.java @@ -218,8 +218,9 @@ public void createFromMetadata( } final Database database = metadata.getDatabase(); - SqlStringGenerationContext sqlStringGenerationContext = - new SqlStringGenerationContextImpl( database.getJdbcEnvironment() ); + final JdbcEnvironment jdbcEnvironment = database.getJdbcEnvironment(); + SqlStringGenerationContext sqlStringGenerationContext = SqlStringGenerationContextImpl.fromConfigurationMap( + jdbcEnvironment, database, options.getConfigurationValues() ); final Set exportIdentifiers = new HashSet( 50 ); diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/SchemaDropperImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/SchemaDropperImpl.java index f39e582d2368..753e95f3fd99 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/SchemaDropperImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/SchemaDropperImpl.java @@ -189,8 +189,8 @@ private void dropFromMetadata( Formatter formatter, GenerationTarget... targets) { final Database database = metadata.getDatabase(); - SqlStringGenerationContext sqlStringGenerationContext = - new SqlStringGenerationContextImpl( metadata.getDatabase().getJdbcEnvironment() ); + SqlStringGenerationContext sqlStringGenerationContext = SqlStringGenerationContextImpl.fromConfigurationMap( + metadata.getDatabase().getJdbcEnvironment(), database, options.getConfigurationValues()); boolean tryToDropCatalogs = false; boolean tryToDropSchemas = false; diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/exec/ImprovedExtractionContextImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/exec/ImprovedExtractionContextImpl.java index 20a56f55e850..479419e0ab89 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/exec/ImprovedExtractionContextImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/exec/ImprovedExtractionContextImpl.java @@ -12,7 +12,6 @@ import org.hibernate.boot.model.naming.Identifier; import org.hibernate.boot.model.relational.SqlStringGenerationContext; -import org.hibernate.boot.model.relational.internal.SqlStringGenerationContextImpl; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.resource.transaction.spi.DdlTransactionIsolator; import org.hibernate.service.ServiceRegistry; @@ -26,8 +25,6 @@ public class ImprovedExtractionContextImpl implements ExtractionContext { private final JdbcEnvironment jdbcEnvironment; private final SqlStringGenerationContext sqlStringGenerationContext; private final DdlTransactionIsolator ddlTransactionIsolator; - private final Identifier defaultCatalog; - private final Identifier defaultSchema; private final DatabaseObjectAccess databaseObjectAccess; @@ -36,16 +33,13 @@ public class ImprovedExtractionContextImpl implements ExtractionContext { public ImprovedExtractionContextImpl( ServiceRegistry serviceRegistry, JdbcEnvironment jdbcEnvironment, + SqlStringGenerationContext sqlStringGenerationContext, DdlTransactionIsolator ddlTransactionIsolator, - Identifier defaultCatalog, - Identifier defaultSchema, DatabaseObjectAccess databaseObjectAccess) { this.serviceRegistry = serviceRegistry; this.jdbcEnvironment = jdbcEnvironment; - this.sqlStringGenerationContext = new SqlStringGenerationContextImpl( jdbcEnvironment ); + this.sqlStringGenerationContext = sqlStringGenerationContext; this.ddlTransactionIsolator = ddlTransactionIsolator; - this.defaultCatalog = defaultCatalog; - this.defaultSchema = defaultSchema; this.databaseObjectAccess = databaseObjectAccess; } @@ -87,12 +81,12 @@ public DatabaseMetaData getJdbcDatabaseMetaData() { @Override public Identifier getDefaultCatalog() { - return defaultCatalog; + return sqlStringGenerationContext.getDefaultCatalog(); } @Override public Identifier getDefaultSchema() { - return defaultSchema; + return sqlStringGenerationContext.getDefaultSchema(); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/ExtractionTool.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/ExtractionTool.java index e0b35cd58d4b..6a38c73620d2 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/ExtractionTool.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/spi/ExtractionTool.java @@ -8,6 +8,7 @@ import org.hibernate.Incubating; import org.hibernate.boot.model.naming.Identifier; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.resource.transaction.spi.DdlTransactionIsolator; import org.hibernate.service.ServiceRegistry; @@ -26,9 +27,8 @@ public interface ExtractionTool { ExtractionContext createExtractionContext( ServiceRegistry serviceRegistry, JdbcEnvironment jdbcEnvironment, + SqlStringGenerationContext sqlStringGenerationContext, DdlTransactionIsolator ddlTransactionIsolator, - Identifier defaultCatalog, - Identifier defaultSchema, ExtractionContext.DatabaseObjectAccess databaseObjectAccess); InformationExtractor createInformationExtractor(ExtractionContext extractionContext); diff --git a/hibernate-core/src/test/java/org/hibernate/test/schematools/TestExtraPhysicalTableTypes.java b/hibernate-core/src/test/java/org/hibernate/test/schematools/TestExtraPhysicalTableTypes.java index 7a5a6d0b637d..986674b46b1c 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/schematools/TestExtraPhysicalTableTypes.java +++ b/hibernate-core/src/test/java/org/hibernate/test/schematools/TestExtraPhysicalTableTypes.java @@ -11,13 +11,14 @@ import org.hibernate.boot.MetadataSources; import org.hibernate.boot.model.relational.Database; +import org.hibernate.boot.model.relational.SqlStringGenerationContext; +import org.hibernate.boot.model.relational.internal.SqlStringGenerationContextImpl; import org.hibernate.boot.registry.StandardServiceRegistry; import org.hibernate.boot.registry.StandardServiceRegistryBuilder; import org.hibernate.boot.spi.MetadataImplementor; import org.hibernate.cfg.Environment; import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider; import org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator; -import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment; import org.hibernate.engine.jdbc.spi.JdbcServices; import org.hibernate.resource.transaction.spi.DdlTransactionIsolator; import org.hibernate.tool.schema.extract.internal.DatabaseInformationImpl; @@ -25,7 +26,6 @@ import org.hibernate.tool.schema.extract.internal.InformationExtractorJdbcDatabaseMetaDataImpl; import org.hibernate.tool.schema.extract.spi.DatabaseInformation; import org.hibernate.tool.schema.extract.spi.ExtractionContext; -import org.hibernate.tool.schema.internal.exec.ImprovedExtractionContextImpl; import org.hibernate.tool.schema.internal.exec.JdbcContext; import org.hibernate.tool.schema.spi.SchemaManagementTool; @@ -121,21 +121,23 @@ private InformationExtractorJdbcDatabaseMetaDataImplTest buildInformationExtract throws SQLException { Database database = metadata.getDatabase(); + SqlStringGenerationContext sqlStringGenerationContext = + SqlStringGenerationContextImpl.forTests( database.getJdbcEnvironment() ); + DatabaseInformation dbInfo = new DatabaseInformationImpl( ssr, database.getJdbcEnvironment(), + sqlStringGenerationContext, ddlTransactionIsolator, - database.getDefaultNamespace().getName(), database.getServiceRegistry().getService( SchemaManagementTool.class ) ); ExtractionContextImpl extractionContext = new ExtractionContextImpl( ssr, database.getJdbcEnvironment(), + sqlStringGenerationContext, ssr.getService( JdbcServices.class ).getBootstrapJdbcConnectionAccess(), - (ExtractionContext.DatabaseObjectAccess) dbInfo, - database.getDefaultNamespace().getPhysicalName().getCatalog(), - database.getDefaultNamespace().getPhysicalName().getSchema() + (ExtractionContext.DatabaseObjectAccess) dbInfo ); return new InformationExtractorJdbcDatabaseMetaDataImplTest( diff --git a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaUpdateTableBackedSequenceTest.java b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaUpdateTableBackedSequenceTest.java index 1d4f1ee5e2d3..b3588d3e2225 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaUpdateTableBackedSequenceTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/schemaupdate/SchemaUpdateTableBackedSequenceTest.java @@ -78,7 +78,7 @@ public void testCreateTableOnUpdate() throws SQLException { // lets make sure the InitCommand is there assertEquals( 1, database.getDefaultNamespace().getTables().size() ); Table table = database.getDefaultNamespace().getTables().iterator().next(); - SqlStringGenerationContext context = SqlStringGenerationContextImpl.forTests( database.getJdbcEnvironment() ); + SqlStringGenerationContext context = SqlStringGenerationContextImpl.forTests( database.getJdbcEnvironment(), null, null ); assertEquals( 1, table.getInitCommands( context ).size() ); final TargetImpl target = new TargetImpl(); From 1ee0e2e338cab26c8af84916afe2500ff565142f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Fri, 5 Nov 2021 13:35:47 +0100 Subject: [PATCH 408/644] HHH-14921 Test handling of default catalog and schema --- .../org/hibernate/id/IncrementGenerator.java | 8 + .../org/hibernate/id/SequenceGenerator.java | 8 + .../id/enhanced/DatabaseStructure.java | 8 + .../id/enhanced/SequenceStructure.java | 5 + .../hibernate/id/enhanced/TableGenerator.java | 8 + .../hibernate/id/enhanced/TableStructure.java | 5 + .../entity/AbstractEntityPersister.java | 8 + .../DefaultCatalogAndSchemaTest.java | 1190 +++++++++++++++++ ...icit-file-level-catalog-and-schema.hbm.xml | 17 + ...icit-file-level-catalog-and-schema.orm.xml | 46 + ...implicit-global-catalog-and-schema.orm.xml | 19 + 11 files changed, 1322 insertions(+) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/boot/database/qualfiedTableNaming/DefaultCatalogAndSchemaTest.java create mode 100644 hibernate-core/src/test/resources/org/hibernate/test/boot/database/qualfiedTableNaming/implicit-file-level-catalog-and-schema.hbm.xml create mode 100644 hibernate-core/src/test/resources/org/hibernate/test/boot/database/qualfiedTableNaming/implicit-file-level-catalog-and-schema.orm.xml create mode 100644 hibernate-core/src/test/resources/org/hibernate/test/boot/database/qualfiedTableNaming/implicit-global-catalog-and-schema.orm.xml diff --git a/hibernate-core/src/main/java/org/hibernate/id/IncrementGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/IncrementGenerator.java index 4a3ca87b6549..bfb9ccf51fbe 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/IncrementGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/IncrementGenerator.java @@ -54,6 +54,14 @@ public class IncrementGenerator implements IdentifierGenerator { private IntegralDataTypeHolder previousValueHolder; + /** + * @deprecated Exposed for tests only. + */ + @Deprecated + public String[] getAllSqlForTests() { + return new String[] { sql }; + } + @Override public synchronized Serializable generate(SharedSessionContractImplementor session, Object object) throws HibernateException { if ( sql != null ) { diff --git a/hibernate-core/src/main/java/org/hibernate/id/SequenceGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/SequenceGenerator.java index 4058c906f2b4..d480034c5dcd 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/SequenceGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/SequenceGenerator.java @@ -75,6 +75,14 @@ public QualifiedName getPhysicalSequenceName() { return physicalSequenceName; } + /** + * @deprecated Exposed for tests only. + */ + @Deprecated + public String[] getAllSqlForTests() { + return new String[] { sql }; + } + @Override @SuppressWarnings("StatementWithEmptyBody") public void configure(Type type, Properties params, ServiceRegistry serviceRegistry) throws MappingException { diff --git a/hibernate-core/src/main/java/org/hibernate/id/enhanced/DatabaseStructure.java b/hibernate-core/src/main/java/org/hibernate/id/enhanced/DatabaseStructure.java index edbf54eb08db..80b493ed5e8c 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/enhanced/DatabaseStructure.java +++ b/hibernate-core/src/main/java/org/hibernate/id/enhanced/DatabaseStructure.java @@ -107,4 +107,12 @@ default void initialize(SqlStringGenerationContext context) { * @return {@code true} if the actual database structure is a sequence; {@code false} otherwise. */ boolean isPhysicalSequence(); + + /** + * @deprecated Exposed for tests only. + */ + @Deprecated + public default String[] getAllSqlForTests() { + return new String[] { }; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/id/enhanced/SequenceStructure.java b/hibernate-core/src/main/java/org/hibernate/id/enhanced/SequenceStructure.java index 330f6a6577ec..fe3051fae5b9 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/enhanced/SequenceStructure.java +++ b/hibernate-core/src/main/java/org/hibernate/id/enhanced/SequenceStructure.java @@ -78,6 +78,11 @@ public int getInitialValue() { return initialValue; } + @Override + public String[] getAllSqlForTests() { + return new String[] { sql }; + } + @Override public AccessCallback buildCallback(final SharedSessionContractImplementor session) { if ( sql == null ) { diff --git a/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableGenerator.java b/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableGenerator.java index 509fc4cc5cd1..250d7c26d635 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableGenerator.java +++ b/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableGenerator.java @@ -350,6 +350,14 @@ public final long getTableAccessCount() { return accessCount; } + /** + * @deprecated Exposed for tests only. + */ + @Deprecated + public String[] getAllSqlForTests() { + return new String[] { selectQuery, insertQuery, updateQuery }; + } + @Override public void configure(Type type, Properties params, ServiceRegistry serviceRegistry) throws MappingException { storeLastUsedValue = serviceRegistry.getService( ConfigurationService.class ) diff --git a/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableStructure.java b/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableStructure.java index 17c44e9002b4..e9924fe01708 100644 --- a/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableStructure.java +++ b/hibernate-core/src/main/java/org/hibernate/id/enhanced/TableStructure.java @@ -98,6 +98,11 @@ public int getTimesAccessed() { return accessCounter; } + @Override + public String[] getAllSqlForTests() { + return new String[] { selectQuery, updateQuery }; + } + @Override public void prepare(Optimizer optimizer) { applyIncrementSizeToSourceValues = optimizer.applyIncrementSizeToSourceValues(); diff --git a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java index 4ac395e1c5b3..366450c3048b 100644 --- a/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java +++ b/hibernate-core/src/main/java/org/hibernate/persister/entity/AbstractEntityPersister.java @@ -5045,6 +5045,14 @@ public IdentifierGenerator getIdentifierGenerator() throws HibernateException { return entityMetamodel.getIdentifierProperty().getIdentifierGenerator(); } + /** + * @deprecated Exposed for tests only + */ + @Deprecated + public InsertGeneratedIdentifierDelegate getIdentityDelegate() { + return identityDelegate; + } + public String getRootEntityName() { return entityMetamodel.getRootName(); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/boot/database/qualfiedTableNaming/DefaultCatalogAndSchemaTest.java b/hibernate-core/src/test/java/org/hibernate/test/boot/database/qualfiedTableNaming/DefaultCatalogAndSchemaTest.java new file mode 100644 index 000000000000..dd78d99cf77c --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/boot/database/qualfiedTableNaming/DefaultCatalogAndSchemaTest.java @@ -0,0 +1,1190 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.test.boot.database.qualfiedTableNaming; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.io.StringWriter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.regex.Pattern; +import javax.persistence.Basic; +import javax.persistence.ElementCollection; +import javax.persistence.Entity; +import javax.persistence.ForeignKey; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Inheritance; +import javax.persistence.InheritanceType; +import javax.persistence.JoinColumn; +import javax.persistence.JoinTable; +import javax.persistence.OneToMany; +import javax.persistence.SequenceGenerator; +import javax.persistence.Table; +import javax.persistence.TableGenerator; + +import org.hibernate.MappingException; +import org.hibernate.annotations.GenericGenerator; +import org.hibernate.annotations.Parameter; +import org.hibernate.annotations.SQLDelete; +import org.hibernate.annotations.SQLInsert; +import org.hibernate.annotations.SQLUpdate; +import org.hibernate.boot.MetadataBuilder; +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.SessionFactoryBuilder; +import org.hibernate.boot.registry.BootstrapServiceRegistry; +import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder; +import org.hibernate.boot.registry.StandardServiceRegistry; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.boot.spi.MetadataImplementor; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.cfg.Environment; +import org.hibernate.dialect.SQLServer2012Dialect; +import org.hibernate.engine.config.spi.ConfigurationService; +import org.hibernate.engine.jdbc.env.spi.NameQualifierSupport; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.hql.spi.id.global.GlobalTemporaryTableBulkIdStrategy; +import org.hibernate.hql.spi.id.local.LocalTemporaryTableBulkIdStrategy; +import org.hibernate.id.IdentifierGenerator; +import org.hibernate.persister.entity.AbstractEntityPersister; +import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.service.spi.ServiceRegistryImplementor; +import org.hibernate.tool.hbm2ddl.SchemaExport; +import org.hibernate.tool.schema.TargetType; +import org.hibernate.tool.schema.internal.exec.ScriptTargetOutputToWriter; +import org.hibernate.tool.schema.spi.DelayedDropRegistryNotAvailableImpl; +import org.hibernate.tool.schema.spi.SchemaManagementToolCoordinator; +import org.hibernate.tool.schema.spi.ScriptTargetOutput; +import org.hibernate.tool.schema.spi.TargetDescriptor; + +import org.hibernate.testing.AfterClassOnce; +import org.hibernate.testing.BeforeClassOnce; +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.jdbc.SharedDriverManagerConnectionProviderImpl; +import org.hibernate.testing.junit4.CustomParameterized; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; + +@RunWith(CustomParameterized.class) +@TestForIssue(jiraKey = "HHH-14921") +public class DefaultCatalogAndSchemaTest { + + private static final String SQL_QUOTE_CHARACTER_CLASS = "([`\"]|\\[|\\])"; + + private static final String EXPLICIT_CATALOG = "someExplicitCatalog"; + private static final String EXPLICIT_SCHEMA = "someExplicitSchema"; + + // Yes this is invalid SQL, and in most cases it simply wouldn't work because of missing columns, + // but in this case we don't care: we just want to check catalog/schema substitution. + private static final String CUSTOM_INSERT_SQL_PART_1 = "insert into {h-catalog}{h-schema}"; + private static final String CUSTOM_INSERT_SQL_PART_2 = ", {h-domain}"; + private static final String CUSTOM_INSERT_SQL_PART_3 = " VALUES(basic = ?)"; + private static final String CUSTOM_UPDATE_SQL_PART_1 = "update {h-catalog}{h-schema}"; + private static final String CUSTOM_UPDATE_SQL_PART_2 = ", {h-domain}"; + private static final String CUSTOM_UPDATE_SQL_PART_3 = " SET basic = ?"; + private static final String CUSTOM_DELETE_SQL_PART_1 = "delete from {h-catalog}{h-schema}"; + private static final String CUSTOM_DELETE_SQL_PART_2 = ", {h-domain}"; + private static final String CUSTOM_DELETE_SQL_PART_3 = " WHERE id = ?"; + + @Parameterized.Parameters(name = "configuredXmlMappingPath = {0}, configuredDefaultCatalog = {1}, configuredDefaultSchema = {2}") + public static List params() { + List params = new ArrayList<>(); + for ( String defaultCatalog : Arrays.asList( null, "someDefaultCatalog" ) ) { + for ( String defaultSchema : Arrays.asList( null, "someDefaultSchema" ) ) { + params.add( new Object[] { null, defaultCatalog, defaultSchema, + // The default catalog/schema should be used when + // there is no implicit catalog/schema defined in the mapping. + defaultCatalog, defaultSchema } ); + } + } + params.add( new Object[] { "implicit-global-catalog-and-schema.orm.xml", + null, null, + "someImplicitCatalog", "someImplicitSchema" } ); + // HHH-14922: Inconsistent precedence of orm.xml implicit catalog/schema over "default_catalog"/"default_schema" +// params.add( new Object[] { "implicit-global-catalog-and-schema.orm.xml", +// "someDefaultCatalog", "someDefaultSchema", +// // The implicit catalog/schema defined in the mapping should take precedence +// // over the default catalog/schema defined in settings. +// "someImplicitCatalog", "someImplicitSchema" } ); + return params; + } + + @Parameterized.Parameter + public String configuredXmlMappingPath; + @Parameterized.Parameter(1) + public String configuredDefaultCatalog; + @Parameterized.Parameter(2) + public String configuredDefaultSchema; + @Parameterized.Parameter(3) + public String expectedDefaultCatalog; + @Parameterized.Parameter(4) + public String expectedDefaultSchema; + + private boolean dbSupportsCatalogs; + private boolean dbSupportsSchemas; + + private MetadataImplementor metadata; + private final List toClose = new ArrayList<>(); + private SessionFactoryImplementor sessionFactory; + + @BeforeClassOnce + public void initSessionFactory() { + List> annotatedClasses = Arrays.asList( + EntityWithDefaultQualifiers.class, + EntityWithExplicitQualifiers.class, + EntityWithJoinedInheritanceWithDefaultQualifiers.class, + EntityWithJoinedInheritanceWithDefaultQualifiersSubclass.class, + EntityWithJoinedInheritanceWithExplicitQualifiers.class, + EntityWithJoinedInheritanceWithExplicitQualifiersSubclass.class, + EntityWithTablePerClassInheritanceWithDefaultQualifiers.class, + EntityWithTablePerClassInheritanceWithDefaultQualifiersSubclass.class, + EntityWithTablePerClassInheritanceWithExplicitQualifiers.class, + EntityWithTablePerClassInheritanceWithExplicitQualifiersSubclass.class, + EntityWithDefaultQualifiersWithCustomSql.class, + EntityWithDefaultQualifiersWithIdentityGenerator.class, + EntityWithExplicitQualifiersWithIdentityGenerator.class, + EntityWithDefaultQualifiersWithTableGenerator.class, + EntityWithExplicitQualifiersWithTableGenerator.class, + EntityWithDefaultQualifiersWithSequenceGenerator.class, + EntityWithExplicitQualifiersWithSequenceGenerator.class, + EntityWithDefaultQualifiersWithSeqHiLoGenerator.class, + EntityWithExplicitQualifiersWithSeqHiLoGenerator.class, + EntityWithDefaultQualifiersWithIncrementGenerator.class, + EntityWithExplicitQualifiersWithIncrementGenerator.class, + EntityWithDefaultQualifiersWithSequenceIdentityGenerator.class, + EntityWithExplicitQualifiersWithSequenceIdentityGenerator.class, + EntityWithDefaultQualifiersWithEnhancedSequenceGenerator.class, + EntityWithExplicitQualifiersWithEnhancedSequenceGenerator.class, + EntityWithDefaultQualifiersWithLegacySequenceGenerator.class, + EntityWithExplicitQualifiersWithLegacySequenceGenerator.class + ); + + StandardServiceRegistry serviceRegistry = createStandardServiceRegistry( configuredDefaultCatalog, configuredDefaultSchema ); + + final MetadataSources metadataSources = new MetadataSources( serviceRegistry ); + metadataSources.addInputStream( getClass().getResourceAsStream( "implicit-file-level-catalog-and-schema.orm.xml" ) ); + metadataSources.addInputStream( getClass().getResourceAsStream( "implicit-file-level-catalog-and-schema.hbm.xml" ) ); + if ( configuredXmlMappingPath != null ) { + metadataSources.addInputStream( getClass().getResourceAsStream( configuredXmlMappingPath ) ); + } + for ( Class annotatedClass : annotatedClasses ) { + metadataSources.addAnnotatedClass( annotatedClass ); + } + + final MetadataBuilder metadataBuilder = metadataSources.getMetadataBuilder(); + metadata = (MetadataImplementor) metadataBuilder.build(); + + SessionFactoryBuilder sfb = metadata.getSessionFactoryBuilder(); + + sessionFactory = (SessionFactoryImplementor) sfb.build(); + toClose.add( sessionFactory ); + + NameQualifierSupport nameQualifierSupport = sessionFactory.getJdbcServices().getJdbcEnvironment() + .getNameQualifierSupport(); + dbSupportsCatalogs = nameQualifierSupport.supportsCatalogs(); + dbSupportsSchemas = nameQualifierSupport.supportsSchemas(); + } + + @AfterClassOnce + public void cleanup() throws Throwable { + Throwable thrown = null; + Collections.reverse( toClose ); + for ( AutoCloseable closeable : toClose ) { + try { + closeable.close(); + } + catch (Throwable t) { + if ( thrown == null ) { + thrown = t; + } + else { + thrown.addSuppressed( t ); + } + } + } + if ( thrown != null ) { + throw thrown; + } + } + + private StandardServiceRegistry createStandardServiceRegistry(String defaultCatalog, String defaultSchema) { + final BootstrapServiceRegistryBuilder bsrb = new BootstrapServiceRegistryBuilder(); + bsrb.applyClassLoader( getClass().getClassLoader() ); + // by default we do not share the BootstrapServiceRegistry nor the StandardServiceRegistry, + // so we want the BootstrapServiceRegistry to be automatically closed when the + // StandardServiceRegistry is closed. + bsrb.enableAutoClose(); + + final BootstrapServiceRegistry bsr = bsrb.build(); + + final Map settings = new HashMap<>(); + settings.put( GlobalTemporaryTableBulkIdStrategy.DROP_ID_TABLES, "true" ); + settings.put( LocalTemporaryTableBulkIdStrategy.DROP_ID_TABLES, "true" ); + if ( !Environment.getProperties().containsKey( Environment.CONNECTION_PROVIDER ) ) { + settings.put( + AvailableSettings.CONNECTION_PROVIDER, + SharedDriverManagerConnectionProviderImpl.getInstance() + ); + } + if ( defaultCatalog != null ) { + settings.put( AvailableSettings.DEFAULT_CATALOG, defaultCatalog ); + } + if ( defaultSchema != null ) { + settings.put( AvailableSettings.DEFAULT_SCHEMA, defaultSchema ); + } + + final StandardServiceRegistryBuilder ssrb = new StandardServiceRegistryBuilder( bsr ); + ssrb.applySettings( settings ); + StandardServiceRegistry registry = ssrb.build(); + toClose.add( registry ); + return registry; + } + + @Test + public void createSchema_fromSessionFactory() { + String script = generateScriptFromSessionFactory( "create" ); + verifyDDLQualifiers( script ); + } + + @Test + public void dropSchema_fromSessionFactory() { + String script = generateScriptFromSessionFactory( "drop" ); + verifyDDLQualifiers( script ); + } + + @Test + public void createSchema_fromMetadata() { + String script = generateScriptFromMetadata( SchemaExport.Action.CREATE ); + verifyDDLQualifiers( script ); + } + + @Test + public void dropSchema_fromMetadata() { + String script = generateScriptFromMetadata( SchemaExport.Action.DROP ); + verifyDDLQualifiers( script ); + } + + @Test + public void entityPersister() { + verifyEntityPersisterQualifiers( EntityWithDefaultQualifiers.class, expectedDefaultQualifier() ); + verifyEntityPersisterQualifiers( EntityWithExplicitQualifiers.class, expectedExplicitQualifier() ); + verifyEntityPersisterQualifiers( EntityWithOrmXmlImplicitFileLevelQualifiers.class, expectedImplicitFileLevelQualifier() ); + verifyEntityPersisterQualifiers( EntityWithHbmXmlImplicitFileLevelQualifiers.class, expectedImplicitFileLevelQualifier() ); + + verifyEntityPersisterQualifiers( EntityWithJoinedInheritanceWithDefaultQualifiers.class, expectedDefaultQualifier() ); + verifyEntityPersisterQualifiers( EntityWithJoinedInheritanceWithDefaultQualifiersSubclass.class, expectedDefaultQualifier() ); + verifyEntityPersisterQualifiers( EntityWithJoinedInheritanceWithExplicitQualifiers.class, expectedExplicitQualifier() ); + verifyEntityPersisterQualifiers( EntityWithJoinedInheritanceWithExplicitQualifiersSubclass.class, expectedExplicitQualifier() ); + + verifyEntityPersisterQualifiers( EntityWithTablePerClassInheritanceWithDefaultQualifiers.class, expectedDefaultQualifier() ); + verifyEntityPersisterQualifiers( EntityWithTablePerClassInheritanceWithDefaultQualifiersSubclass.class, expectedDefaultQualifier() ); + verifyEntityPersisterQualifiers( EntityWithTablePerClassInheritanceWithExplicitQualifiers.class, expectedExplicitQualifier() ); + verifyEntityPersisterQualifiers( EntityWithTablePerClassInheritanceWithExplicitQualifiersSubclass.class, expectedExplicitQualifier() ); + + verifyEntityPersisterQualifiers( EntityWithDefaultQualifiersWithCustomSql.class, expectedDefaultQualifier() ); + + + verifyEntityPersisterQualifiers( EntityWithDefaultQualifiersWithIdentityGenerator.class, expectedDefaultQualifier() ); + verifyEntityPersisterQualifiers( EntityWithExplicitQualifiersWithIdentityGenerator.class, expectedExplicitQualifier() ); + verifyEntityPersisterQualifiers( EntityWithDefaultQualifiersWithTableGenerator.class, expectedDefaultQualifier() ); + verifyEntityPersisterQualifiers( EntityWithExplicitQualifiersWithTableGenerator.class, expectedExplicitQualifier() ); + verifyEntityPersisterQualifiers( EntityWithDefaultQualifiersWithSequenceGenerator.class, expectedDefaultQualifier() ); + verifyEntityPersisterQualifiers( EntityWithExplicitQualifiersWithSequenceGenerator.class, expectedExplicitQualifier() ); + verifyEntityPersisterQualifiers( EntityWithDefaultQualifiersWithSeqHiLoGenerator.class, expectedDefaultQualifier() ); + verifyEntityPersisterQualifiers( EntityWithExplicitQualifiersWithSeqHiLoGenerator.class, expectedExplicitQualifier() ); + verifyEntityPersisterQualifiers( EntityWithDefaultQualifiersWithIncrementGenerator.class, expectedDefaultQualifier() ); + verifyEntityPersisterQualifiers( EntityWithExplicitQualifiersWithIncrementGenerator.class, expectedExplicitQualifier() ); + verifyEntityPersisterQualifiers( EntityWithDefaultQualifiersWithSequenceIdentityGenerator.class, expectedDefaultQualifier() ); + verifyEntityPersisterQualifiers( EntityWithExplicitQualifiersWithSequenceIdentityGenerator.class, expectedExplicitQualifier() ); + verifyEntityPersisterQualifiers( EntityWithDefaultQualifiersWithEnhancedSequenceGenerator.class, expectedDefaultQualifier() ); + verifyEntityPersisterQualifiers( EntityWithExplicitQualifiersWithEnhancedSequenceGenerator.class, expectedExplicitQualifier() ); + verifyEntityPersisterQualifiers( EntityWithDefaultQualifiersWithLegacySequenceGenerator.class, expectedDefaultQualifier() ); + verifyEntityPersisterQualifiers( EntityWithExplicitQualifiersWithLegacySequenceGenerator.class, expectedExplicitQualifier() ); + } + + private void verifyEntityPersisterQualifiers(Class entityClass, ExpectedQualifier expectedQualifier) { + // The hbm.xml mapping unfortunately sets the native entity name on top of the JPA entity name, + // so many methods that allow retrieving the entity persister or entity metamodel from the entity class no longer work, + // because these methods generally assume the native entity name is the FQCN. + // Thus we use custom code. + AbstractEntityPersister persister = (AbstractEntityPersister) sessionFactory.getMetamodel().entityPersisters() + .values().stream() + .filter( p -> p.getMappedClass().equals( entityClass ) ) + .findFirst() + .orElseThrow( () -> new IllegalStateException( "Cannot find persister for " + entityClass ) ); + String jpaEntityName = sessionFactory.getMetamodel().getEntities().stream() + .filter( p -> p.getBindableJavaType().equals( entityClass ) ) + .findFirst() + .orElseThrow( () -> new IllegalStateException( "Cannot find entity metamodel for " + entityClass ) ) + .getName(); + + // Table names are what's used for Query, in particular. + verifyOnlyQualifier( persister.getTableName(), SqlType.RUNTIME, + jpaEntityName, expectedQualifier ); + // Here, to simplify assertions, we assume all derived entity types have: + // - an entity name prefixed with the name of their super entity type + // - the same explicit catalog and schema, if any, as their super entity type + verifyOnlyQualifier( persister.getTableNames(), SqlType.RUNTIME, + jpaEntityName, expectedQualifier ); + + // This will include SQL generated by ID generators in some cases, which will be validated here + // because ID generators table/sequence names are prefixed with the owning entity name. + verifyOnlyQualifier( persister.getSQLInsertStrings(), SqlType.RUNTIME, + jpaEntityName, expectedQualifier ); + if ( persister.isIdentifierAssignedByInsert() ) { + verifyOnlyQualifier( persister.getSQLIdentityInsertString(), SqlType.RUNTIME, + jpaEntityName, expectedQualifier ); + } + try { + verifyOnlyQualifierOptional( persister.getIdentitySelectString(), SqlType.RUNTIME, + jpaEntityName, expectedQualifier ); + } + catch (MappingException e) { + if ( e.getMessage().contains( "does not support identity key generation" ) ) { + // For some reason Oracle12cIdentityColumnSupport#supportsInsertSelectIdentity() returns true, + // but getIdentitySelectString is not implemented, resulting in runtime exceptions. + // Whatever, we'll just ignore this for now. + } + else { + throw e; + } + } + + verifyOnlyQualifier( persister.getSQLUpdateStrings(), SqlType.RUNTIME, + jpaEntityName, expectedQualifier ); + verifyOnlyQualifier( persister.getSQLLazyUpdateStrings(), SqlType.RUNTIME, + jpaEntityName, expectedQualifier ); + + verifyOnlyQualifier( persister.getSQLDeleteStrings(), SqlType.RUNTIME, + jpaEntityName, expectedQualifier ); + + verifyOnlyQualifier( persister.getSQLSnapshotSelectString(), SqlType.RUNTIME, + jpaEntityName, expectedQualifier ); + + // This is used in the "select" id generator in particular. + verifyOnlyQualifierOptional( persister.getSelectByUniqueKeyString( "basic" ), SqlType.RUNTIME, + jpaEntityName, expectedQualifier ); + } + + @Test + public void tableGenerator() { + org.hibernate.id.enhanced.TableGenerator generator = idGenerator( + org.hibernate.id.enhanced.TableGenerator.class, + EntityWithDefaultQualifiersWithTableGenerator.class ); + verifyOnlyQualifier( generator.getAllSqlForTests(), SqlType.RUNTIME, + EntityWithDefaultQualifiersWithTableGenerator.NAME, expectedDefaultQualifier() ); + + generator = idGenerator( org.hibernate.id.enhanced.TableGenerator.class, + EntityWithExplicitQualifiersWithTableGenerator.class ); + verifyOnlyQualifier( generator.getAllSqlForTests(), SqlType.RUNTIME, + EntityWithExplicitQualifiersWithTableGenerator.NAME, expectedExplicitQualifier() ); + } + + @Test + public void enhancedTableGenerator() { + org.hibernate.id.enhanced.TableGenerator generator = idGenerator( + org.hibernate.id.enhanced.TableGenerator.class, + EntityWithDefaultQualifiersWithTableGenerator.class ); + verifyOnlyQualifier( generator.getAllSqlForTests(), SqlType.RUNTIME, + EntityWithDefaultQualifiersWithTableGenerator.NAME, expectedDefaultQualifier() ); + + generator = idGenerator( org.hibernate.id.enhanced.TableGenerator.class, + EntityWithExplicitQualifiersWithTableGenerator.class ); + verifyOnlyQualifier( generator.getAllSqlForTests(), SqlType.RUNTIME, + EntityWithExplicitQualifiersWithTableGenerator.NAME, expectedExplicitQualifier() ); + } + + @Test + public void sequenceGenerator() { + org.hibernate.id.enhanced.SequenceStyleGenerator generator = idGenerator( + org.hibernate.id.enhanced.SequenceStyleGenerator.class, + EntityWithDefaultQualifiersWithSequenceGenerator.class ); + verifyOnlyQualifier( generator.getDatabaseStructure().getAllSqlForTests(), SqlType.RUNTIME, + EntityWithDefaultQualifiersWithSequenceGenerator.NAME, expectedDefaultQualifier() ); + + generator = idGenerator( org.hibernate.id.enhanced.SequenceStyleGenerator.class, + EntityWithExplicitQualifiersWithSequenceGenerator.class ); + verifyOnlyQualifier( generator.getDatabaseStructure().getAllSqlForTests(), SqlType.RUNTIME, + EntityWithExplicitQualifiersWithSequenceGenerator.NAME, expectedExplicitQualifier() ); + } + + @Test + public void enhancedSequenceGenerator() { + org.hibernate.id.enhanced.SequenceStyleGenerator generator = idGenerator( + org.hibernate.id.enhanced.SequenceStyleGenerator.class, + EntityWithDefaultQualifiersWithEnhancedSequenceGenerator.class ); + verifyOnlyQualifier( generator.getDatabaseStructure().getAllSqlForTests(), SqlType.RUNTIME, + EntityWithDefaultQualifiersWithEnhancedSequenceGenerator.NAME, expectedDefaultQualifier() ); + + generator = idGenerator( org.hibernate.id.enhanced.SequenceStyleGenerator.class, + EntityWithExplicitQualifiersWithEnhancedSequenceGenerator.class ); + verifyOnlyQualifier( generator.getDatabaseStructure().getAllSqlForTests(), SqlType.RUNTIME, + EntityWithExplicitQualifiersWithEnhancedSequenceGenerator.NAME, expectedExplicitQualifier() ); + } + + @Test + public void legacySequenceGenerator() { + org.hibernate.id.SequenceGenerator generator = idGenerator( org.hibernate.id.SequenceGenerator.class, + EntityWithDefaultQualifiersWithLegacySequenceGenerator.class ); + verifyOnlyQualifier( generator.getAllSqlForTests(), SqlType.RUNTIME, + EntityWithDefaultQualifiersWithLegacySequenceGenerator.NAME, expectedDefaultQualifier() ); + + generator = idGenerator( org.hibernate.id.SequenceGenerator.class, + EntityWithExplicitQualifiersWithLegacySequenceGenerator.class ); + verifyOnlyQualifier( generator.getAllSqlForTests(), SqlType.RUNTIME, + EntityWithExplicitQualifiersWithLegacySequenceGenerator.NAME, expectedExplicitQualifier() ); + } + + @Test + public void seqHiLoGenerator() { + org.hibernate.id.SequenceHiLoGenerator generator = idGenerator( org.hibernate.id.SequenceHiLoGenerator.class, + EntityWithDefaultQualifiersWithSeqHiLoGenerator.class ); + verifyOnlyQualifier( generator.getAllSqlForTests(), SqlType.RUNTIME, + EntityWithDefaultQualifiersWithSeqHiLoGenerator.NAME, expectedDefaultQualifier() ); + + generator = idGenerator( org.hibernate.id.SequenceHiLoGenerator.class, + EntityWithExplicitQualifiersWithSeqHiLoGenerator.class ); + verifyOnlyQualifier( generator.getAllSqlForTests(), SqlType.RUNTIME, + EntityWithExplicitQualifiersWithSeqHiLoGenerator.NAME, expectedExplicitQualifier() ); + } + + @Test + public void incrementGenerator() { + org.hibernate.id.IncrementGenerator generator = idGenerator( org.hibernate.id.IncrementGenerator.class, + EntityWithDefaultQualifiersWithIncrementGenerator.class ); + verifyOnlyQualifier( generator.getAllSqlForTests(), SqlType.RUNTIME, + EntityWithDefaultQualifiersWithIncrementGenerator.NAME, expectedDefaultQualifier() ); + + generator = idGenerator( org.hibernate.id.IncrementGenerator.class, + EntityWithExplicitQualifiersWithIncrementGenerator.class ); + verifyOnlyQualifier( generator.getAllSqlForTests(), SqlType.RUNTIME, + EntityWithExplicitQualifiersWithIncrementGenerator.NAME, expectedExplicitQualifier() ); + } + + @Test + public void sequenceIdentityGenerator() { + org.hibernate.id.SequenceIdentityGenerator generator = idGenerator( org.hibernate.id.SequenceIdentityGenerator.class, + EntityWithDefaultQualifiersWithSequenceIdentityGenerator.class ); + verifyOnlyQualifier( generator.getAllSqlForTests(), SqlType.RUNTIME, + EntityWithDefaultQualifiersWithSequenceIdentityGenerator.NAME, expectedDefaultQualifier() ); + + generator = idGenerator( org.hibernate.id.SequenceIdentityGenerator.class, + EntityWithExplicitQualifiersWithSequenceIdentityGenerator.class ); + verifyOnlyQualifier( generator.getAllSqlForTests(), SqlType.RUNTIME, + EntityWithExplicitQualifiersWithSequenceIdentityGenerator.NAME, expectedExplicitQualifier() ); + } + + private T idGenerator(Class expectedType, Class entityClass) { + AbstractEntityPersister persister = (AbstractEntityPersister) + sessionFactory.getMetamodel().entityPersister( entityClass ); + return expectedType.cast( persister.getIdentifierGenerator() ); + } + + private void verifyDDLQualifiers(String sql) { + // Here, to simplify assertions, we assume: + // - that all entity types have a table name identical to the entity name + // - that all association tables have a name prefixed with the name of their owning entity type + // - that all association tables have the same explicit catalog and schema, if any, as their owning entity type + // - that all ID generator tables/sequences have a name prefixed with the name of their owning entity type + + verifyOnlyQualifier( sql, SqlType.DDL, EntityWithExplicitQualifiers.NAME, expectedExplicitQualifier() ); + verifyOnlyQualifier( sql, SqlType.DDL, EntityWithDefaultQualifiers.NAME, expectedDefaultQualifier() ); + verifyOnlyQualifier( sql, SqlType.DDL, EntityWithOrmXmlImplicitFileLevelQualifiers.NAME, expectedImplicitFileLevelQualifier() ); + verifyOnlyQualifier( sql, SqlType.DDL, EntityWithHbmXmlImplicitFileLevelQualifiers.NAME, expectedImplicitFileLevelQualifier() ); + + verifyOnlyQualifier( sql, SqlType.DDL, EntityWithJoinedInheritanceWithDefaultQualifiers.NAME, expectedDefaultQualifier() ); + verifyOnlyQualifier( sql, SqlType.DDL, EntityWithJoinedInheritanceWithDefaultQualifiersSubclass.NAME, expectedDefaultQualifier() ); + verifyOnlyQualifier( sql, SqlType.DDL, EntityWithJoinedInheritanceWithExplicitQualifiers.NAME, expectedExplicitQualifier() ); + verifyOnlyQualifier( sql, SqlType.DDL, EntityWithJoinedInheritanceWithExplicitQualifiersSubclass.NAME, expectedExplicitQualifier() ); + + verifyOnlyQualifier( sql, SqlType.DDL, EntityWithTablePerClassInheritanceWithDefaultQualifiers.NAME, expectedDefaultQualifier() ); + verifyOnlyQualifier( sql, SqlType.DDL, EntityWithTablePerClassInheritanceWithDefaultQualifiersSubclass.NAME, expectedDefaultQualifier() ); + verifyOnlyQualifier( sql, SqlType.DDL, EntityWithTablePerClassInheritanceWithExplicitQualifiers.NAME, expectedExplicitQualifier() ); + verifyOnlyQualifier( sql, SqlType.DDL, EntityWithTablePerClassInheritanceWithExplicitQualifiersSubclass.NAME, expectedExplicitQualifier() ); + + verifyOnlyQualifier( sql, SqlType.DDL, EntityWithDefaultQualifiersWithCustomSql.NAME, expectedDefaultQualifier() ); + + verifyOnlyQualifier( sql, SqlType.DDL, EntityWithDefaultQualifiersWithIdentityGenerator.NAME, expectedDefaultQualifier() ); + verifyOnlyQualifier( sql, SqlType.DDL, EntityWithExplicitQualifiersWithIdentityGenerator.NAME, expectedExplicitQualifier() ); + verifyOnlyQualifier( sql, SqlType.DDL, EntityWithDefaultQualifiersWithTableGenerator.NAME, expectedDefaultQualifier() ); + verifyOnlyQualifier( sql, SqlType.DDL, EntityWithExplicitQualifiersWithTableGenerator.NAME, expectedExplicitQualifier() ); + verifyOnlyQualifier( sql, SqlType.DDL, EntityWithDefaultQualifiersWithSequenceGenerator.NAME, expectedDefaultQualifier() ); + verifyOnlyQualifier( sql, SqlType.DDL, EntityWithExplicitQualifiersWithSequenceGenerator.NAME, expectedExplicitQualifier() ); + verifyOnlyQualifier( sql, SqlType.DDL, EntityWithDefaultQualifiersWithSeqHiLoGenerator.NAME, expectedDefaultQualifier() ); + verifyOnlyQualifier( sql, SqlType.DDL, EntityWithExplicitQualifiersWithSeqHiLoGenerator.NAME, expectedExplicitQualifier() ); + verifyOnlyQualifier( sql, SqlType.DDL, EntityWithDefaultQualifiersWithIncrementGenerator.NAME, expectedDefaultQualifier() ); + verifyOnlyQualifier( sql, SqlType.DDL, EntityWithExplicitQualifiersWithIncrementGenerator.NAME, expectedExplicitQualifier() ); + verifyOnlyQualifier( sql, SqlType.DDL, EntityWithDefaultQualifiersWithSequenceIdentityGenerator.NAME, expectedDefaultQualifier() ); + verifyOnlyQualifier( sql, SqlType.DDL, EntityWithExplicitQualifiersWithSequenceIdentityGenerator.NAME, expectedExplicitQualifier() ); + verifyOnlyQualifier( sql, SqlType.DDL, EntityWithDefaultQualifiersWithEnhancedSequenceGenerator.NAME, expectedDefaultQualifier() ); + verifyOnlyQualifier( sql, SqlType.DDL, EntityWithExplicitQualifiersWithEnhancedSequenceGenerator.NAME, expectedExplicitQualifier() ); + verifyOnlyQualifier( sql, SqlType.DDL, EntityWithDefaultQualifiersWithLegacySequenceGenerator.NAME, expectedDefaultQualifier() ); + verifyOnlyQualifier( sql, SqlType.DDL, EntityWithExplicitQualifiersWithLegacySequenceGenerator.NAME, expectedExplicitQualifier() ); + } + + private enum SqlType { + DDL, + RUNTIME + } + + private void verifyOnlyQualifier(String[] sql, SqlType sqlType, String name, ExpectedQualifier expectedQualifier) { + verifyOnlyQualifier( String.join( "\n", sql ), sqlType, name, expectedQualifier ); + } + + private void verifyOnlyQualifierOptional(String sql, SqlType sqlType, String name, ExpectedQualifier expectedQualifier) { + verifyOnlyQualifier( sql, sqlType, name, expectedQualifier, true ); + } + + private void verifyOnlyQualifier(String sql, SqlType sqlType, String name, ExpectedQualifier expectedQualifier) { + verifyOnlyQualifier( sql, sqlType, name, expectedQualifier, false ); + } + + private void verifyOnlyQualifier(String sql, SqlType sqlType, String name, ExpectedQualifier expectedQualifier, boolean optional) { + String patternStringForTableName = SQL_QUOTE_CHARACTER_CLASS + "?" + Pattern.quote( name ) + "(?!\\w*_seq)" + SQL_QUOTE_CHARACTER_CLASS + "?"; + String patternStringForSequenceName = SQL_QUOTE_CHARACTER_CLASS + "?" + Pattern.quote( name ) + "\\w*_seq" + SQL_QUOTE_CHARACTER_CLASS + "?"; + + ExpectedQualifier expectedQualifierForTables = expectedQualifier; + ExpectedQualifier expectedQualifierForSequences; + if ( SqlType.DDL == sqlType && sessionFactory.getJdbcServices().getDialect() instanceof SQLServer2012Dialect ) { + // SQL Server does not allow the catalog in the sequence name when creating the sequence, + // so we need different patterns for sequence names and table names. + // See org.hibernate.dialect.SQLServer2012Dialect.SqlServerSequenceExporter.getFormattedSequenceName + expectedQualifierForSequences = new ExpectedQualifier( null, expectedQualifier.schema ); + } + else { + expectedQualifierForSequences = expectedQualifier; + } + + if ( !optional ) { + // Check that we find the name at least once with the proper qualifier, be it a table or a sequence. + // While not strictly necessary, this ensures our patterns are not completely wrong. + assertThat( sql ) + .containsPattern( + "(" + expectedQualifierForTables.patternStringForNameWithThisQualifier( patternStringForTableName ) + + ")|(" + + expectedQualifierForSequences.patternStringForNameWithThisQualifier( patternStringForSequenceName ) + + ")" ); + } + + // Check that we don't find any name with an incorrect qualifier + assertThat( sql.split( System.getProperty( "line.separator" ) ) ) + .allSatisfy( line -> assertThat( line ) + .doesNotContainPattern( expectedQualifierForTables + .patternStringForNameWithDifferentQualifier( patternStringForTableName ) ) + .doesNotContainPattern( expectedQualifierForSequences + .patternStringForNameWithDifferentQualifier( patternStringForSequenceName ) ) ); + } + + private ExpectedQualifier expectedDefaultQualifier() { + return expectedQualifier( expectedDefaultCatalog, expectedDefaultSchema ); + } + + private ExpectedQualifier expectedExplicitQualifier() { + return expectedQualifier( EXPLICIT_CATALOG, EXPLICIT_SCHEMA ); + } + + private ExpectedQualifier expectedImplicitFileLevelQualifier() { + return expectedQualifier( "someImplicitFileLevelCatalog", "someImplicitFileLevelSchema" ); + } + + private ExpectedQualifier expectedQualifier(String catalog, String schema) { + return new ExpectedQualifier( + dbSupportsCatalogs ? catalog : null, + dbSupportsSchemas ? schema : null + ); + } + + @SuppressWarnings({ "unchecked", "rawtypes" }) + private String generateScriptFromSessionFactory(String action) { + ServiceRegistryImplementor serviceRegistry = sessionFactory.getServiceRegistry(); + Map settings = new HashMap<>( + serviceRegistry.getService( ConfigurationService.class ).getSettings() + ); + StringWriter writer = new StringWriter(); + settings.put( AvailableSettings.HBM2DDL_SCRIPTS_ACTION, action ); + settings.put( AvailableSettings.HBM2DDL_SCRIPTS_CREATE_TARGET, writer ); + settings.put( AvailableSettings.HBM2DDL_SCRIPTS_DROP_TARGET, writer ); + + SchemaManagementToolCoordinator.process( + metadata, serviceRegistry, settings, DelayedDropRegistryNotAvailableImpl.INSTANCE ); + return writer.toString(); + } + + // This is precisely how scripts are generated for the Quarkus DevUI + // Don't change this code except to match changes in + // https://github.com/quarkusio/quarkus/blob/d07ecb23bfba38ee48868635e155c4b513ce6af9/extensions/hibernate-orm/runtime/src/main/java/io/quarkus/hibernate/orm/runtime/devconsole/HibernateOrmDevConsoleInfoSupplier.java#L61-L92 + private String generateScriptFromMetadata(SchemaExport.Action action) { + ServiceRegistryImplementor sessionFactoryServiceRegistry = sessionFactory.getServiceRegistry(); + SchemaExport schemaExport = new SchemaExport(); + schemaExport.setFormat( true ); + schemaExport.setDelimiter( ";" ); + StringWriter writer = new StringWriter(); + schemaExport.doExecution( action, false, metadata, sessionFactoryServiceRegistry, + new TargetDescriptor() { + @Override + public EnumSet getTargetTypes() { + return EnumSet.of( TargetType.SCRIPT ); + } + + @Override + public ScriptTargetOutput getScriptTargetOutput() { + return new ScriptTargetOutputToWriter( writer ) { + @Override + public void accept(String command) { + super.accept( command ); + } + }; + } + } + ); + return writer.toString(); + } + + private static class ExpectedQualifier { + private final String catalog; + private final String schema; + + private ExpectedQualifier(String catalog, String schema) { + this.catalog = catalog; + this.schema = schema; + } + + String patternStringForNameWithThisQualifier(String patternStringForName) { + if ( catalog == null && schema == null ) { + // Look for unqualified names + return "(? oneToMany; + @OneToMany + @JoinTable(name = NAME + "_manyToMany", + // Custom names to avoid false positive in assertions + joinColumns = @JoinColumn(name = "forward"), + inverseJoinColumns = @JoinColumn(name = "inverse"), + foreignKey = @ForeignKey(name = "FK_manyToMany")) + private List manyToMany; + @ElementCollection + @JoinTable(name = NAME + "_elementCollection", + // Custom names to avoid false positive in assertions + joinColumns = @JoinColumn(name = "forward"), + foreignKey = @ForeignKey(name = "FK_elementCollection")) + private List elementCollection; + } + + @Entity(name = EntityWithExplicitQualifiers.NAME) + @Table(catalog = EXPLICIT_CATALOG, schema = EXPLICIT_SCHEMA) + public static class EntityWithExplicitQualifiers { + public static final String NAME = "EntityWithExplicitQualifiers"; + @Id + private Long id; + @Basic + private String basic; + @OneToMany + @JoinTable(name = NAME + "_oneToMany", catalog = EXPLICIT_CATALOG, schema = EXPLICIT_SCHEMA, + // Custom names to avoid false positive in assertions + joinColumns = @JoinColumn(name = "forward"), + inverseJoinColumns = @JoinColumn(name = "inverse"), + foreignKey = @ForeignKey(name = "FK_oneToMany")) + private List oneToMany; + @OneToMany + @JoinTable(name = NAME + "_manyToMany", catalog = EXPLICIT_CATALOG, schema = EXPLICIT_SCHEMA, + // Custom names to avoid false positive in assertions + joinColumns = @JoinColumn(name = "forward"), + inverseJoinColumns = @JoinColumn(name = "inverse"), + foreignKey = @ForeignKey(name = "FK_manyToMany")) + private List manyToMany; + @ElementCollection + @JoinTable(name = NAME + "_elementCollection", catalog = EXPLICIT_CATALOG, schema = EXPLICIT_SCHEMA, + // Custom names to avoid false positive in assertions + joinColumns = @JoinColumn(name = "forward"), + foreignKey = @ForeignKey(name = "FK_elementCollection")) + private List elementCollection; + } + + public static class EntityWithOrmXmlImplicitFileLevelQualifiers { + public static final String NAME = "EntityWithOrmXmlImplicitFileLevelQualifiers"; + private Long id; + private String basic; + private List oneToMany; + private List manyToMany; + private List elementCollection; + } + + public static class EntityWithHbmXmlImplicitFileLevelQualifiers { + public static final String NAME = "EntityWithHbmXmlImplicitFileLevelQualifiers"; + private Long id; + private String basic; + } + + @Entity(name = EntityWithJoinedInheritanceWithDefaultQualifiers.NAME) + @Inheritance(strategy = InheritanceType.JOINED) + public static class EntityWithJoinedInheritanceWithDefaultQualifiers { + public static final String NAME = "EntityWithJoinedInheritanceWithDefaultQualifiers"; + @Id + private Long id; + @Basic + private String basic; + @OneToMany + @JoinTable(name = NAME + "_oneToMany", + // Custom names to avoid false positive in assertions + joinColumns = @JoinColumn(name = "forward"), + inverseJoinColumns = @JoinColumn(name = "inverse"), + foreignKey = @ForeignKey(name = "FK_oneToMany")) + private List oneToMany; + @OneToMany + @JoinTable(name = NAME + "_manyToMany", + // Custom names to avoid false positive in assertions + joinColumns = @JoinColumn(name = "forward"), + inverseJoinColumns = @JoinColumn(name = "inverse"), + foreignKey = @ForeignKey(name = "FK_manyToMany")) + private List manyToMany; + @ElementCollection + @JoinTable(name = NAME + "_elementCollection", + // Custom names to avoid false positive in assertions + joinColumns = @JoinColumn(name = "forward"), + foreignKey = @ForeignKey(name = "FK_elementCollection")) + private List elementCollection; + } + + @Entity(name = EntityWithJoinedInheritanceWithDefaultQualifiersSubclass.NAME) + public static class EntityWithJoinedInheritanceWithDefaultQualifiersSubclass + extends EntityWithJoinedInheritanceWithDefaultQualifiers { + public static final String NAME = "EntityWithJoinedInheritanceWithDefaultQualifiersSubclass"; + @Basic + private String basic2; + } + + @Entity(name = EntityWithJoinedInheritanceWithExplicitQualifiers.NAME) + @Inheritance(strategy = InheritanceType.JOINED) + @Table(catalog = EXPLICIT_CATALOG, schema = EXPLICIT_SCHEMA) + public static class EntityWithJoinedInheritanceWithExplicitQualifiers { + public static final String NAME = "EntityWithJoinedInheritanceWithExplicitQualifiers"; + @Id + private Long id; + @Basic + private String basic; + @OneToMany + @JoinTable(name = NAME + "_oneToMany", catalog = EXPLICIT_CATALOG, schema = EXPLICIT_SCHEMA, + // Custom names to avoid false positive in assertions + joinColumns = @JoinColumn(name = "forward"), + inverseJoinColumns = @JoinColumn(name = "inverse"), + foreignKey = @ForeignKey(name = "FK_oneToMany")) + private List oneToMany; + @OneToMany + @JoinTable(name = NAME + "_manyToMany", catalog = EXPLICIT_CATALOG, schema = EXPLICIT_SCHEMA, + // Custom names to avoid false positive in assertions + joinColumns = @JoinColumn(name = "forward"), + inverseJoinColumns = @JoinColumn(name = "inverse"), + foreignKey = @ForeignKey(name = "FK_manyToMany")) + private List manyToMany; + @ElementCollection + @JoinTable(name = NAME + "_elementCollection", catalog = EXPLICIT_CATALOG, schema = EXPLICIT_SCHEMA, + // Custom names to avoid false positive in assertions + joinColumns = @JoinColumn(name = "forward"), + foreignKey = @ForeignKey(name = "FK_elementCollection")) + private List elementCollection; + } + + @Entity(name = EntityWithJoinedInheritanceWithExplicitQualifiersSubclass.NAME) + @Table(catalog = EXPLICIT_CATALOG, schema = EXPLICIT_SCHEMA) + public static class EntityWithJoinedInheritanceWithExplicitQualifiersSubclass + extends EntityWithJoinedInheritanceWithExplicitQualifiers { + public static final String NAME = "EntityWithJoinedInheritanceWithExplicitQualifiersSubclass"; + @Basic + private String basic2; + } + + @Entity(name = EntityWithTablePerClassInheritanceWithDefaultQualifiers.NAME) + @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) + public static class EntityWithTablePerClassInheritanceWithDefaultQualifiers { + public static final String NAME = "EntityWithTablePerClassInheritanceWithDefaultQualifiers"; + @Id + private Long id; + @Basic + private String basic; + @OneToMany + @JoinTable(name = NAME + "_oneToMany", + // Custom names to avoid false positive in assertions + joinColumns = @JoinColumn(name = "forward"), + inverseJoinColumns = @JoinColumn(name = "inverse"), + foreignKey = @ForeignKey(name = "FK_oneToMany")) + private List oneToMany; + @OneToMany + @JoinTable(name = NAME + "_manyToMany", + // Custom names to avoid false positive in assertions + joinColumns = @JoinColumn(name = "forward"), + inverseJoinColumns = @JoinColumn(name = "inverse"), + foreignKey = @ForeignKey(name = "FK_manyToMany")) + private List manyToMany; + @ElementCollection + @JoinTable(name = NAME + "_elementCollection", + // Custom names to avoid false positive in assertions + joinColumns = @JoinColumn(name = "forward"), + foreignKey = @ForeignKey(name = "FK_elementCollection")) + private List elementCollection; + } + + @Entity(name = EntityWithTablePerClassInheritanceWithDefaultQualifiersSubclass.NAME) + public static class EntityWithTablePerClassInheritanceWithDefaultQualifiersSubclass + extends EntityWithTablePerClassInheritanceWithDefaultQualifiers { + public static final String NAME = "EntityWithTablePerClassInheritanceWithDefaultQualifiersSubclass"; + @Basic + private String basic2; + } + + @Entity(name = EntityWithTablePerClassInheritanceWithExplicitQualifiers.NAME) + @Inheritance(strategy = InheritanceType.TABLE_PER_CLASS) + @Table(catalog = EXPLICIT_CATALOG, schema = EXPLICIT_SCHEMA) + public static class EntityWithTablePerClassInheritanceWithExplicitQualifiers { + public static final String NAME = "EntityWithTablePerClassInheritanceWithExplicitQualifiers"; + @Id + private Long id; + @Basic + private String basic; + @OneToMany + @JoinTable(name = NAME + "_oneToMany", catalog = EXPLICIT_CATALOG, schema = EXPLICIT_SCHEMA, + // Custom names to avoid false positive in assertions + joinColumns = @JoinColumn(name = "forward"), + inverseJoinColumns = @JoinColumn(name = "inverse"), + foreignKey = @ForeignKey(name = "FK_oneToMany")) + private List oneToMany; + @OneToMany + @JoinTable(name = NAME + "_manyToMany", catalog = EXPLICIT_CATALOG, schema = EXPLICIT_SCHEMA, + // Custom names to avoid false positive in assertions + joinColumns = @JoinColumn(name = "forward"), + inverseJoinColumns = @JoinColumn(name = "inverse"), + foreignKey = @ForeignKey(name = "FK_manyToMany")) + private List manyToMany; + @ElementCollection + @JoinTable(name = NAME + "_elementCollection", catalog = EXPLICIT_CATALOG, schema = EXPLICIT_SCHEMA, + // Custom names to avoid false positive in assertions + joinColumns = @JoinColumn(name = "forward"), + foreignKey = @ForeignKey(name = "FK_elementCollection")) + private List elementCollection; + } + + @Entity(name = EntityWithTablePerClassInheritanceWithExplicitQualifiersSubclass.NAME) + @Table(catalog = EXPLICIT_CATALOG, schema = EXPLICIT_SCHEMA) + public static class EntityWithTablePerClassInheritanceWithExplicitQualifiersSubclass + extends EntityWithTablePerClassInheritanceWithExplicitQualifiers { + public static final String NAME = "EntityWithTablePerClassInheritanceWithExplicitQualifiersSubclass"; + @Basic + private String basic2; + } + + @Entity(name = EntityWithDefaultQualifiersWithCustomSql.NAME) + @SQLInsert(sql = CUSTOM_INSERT_SQL_PART_1 + EntityWithDefaultQualifiersWithCustomSql.NAME + CUSTOM_INSERT_SQL_PART_2 + + EntityWithDefaultQualifiersWithCustomSql.NAME + CUSTOM_INSERT_SQL_PART_3) + @SQLUpdate(sql = CUSTOM_UPDATE_SQL_PART_1 + EntityWithDefaultQualifiersWithCustomSql.NAME + CUSTOM_UPDATE_SQL_PART_2 + + EntityWithDefaultQualifiersWithCustomSql.NAME + CUSTOM_UPDATE_SQL_PART_3) + @SQLDelete(sql = CUSTOM_DELETE_SQL_PART_1 + EntityWithDefaultQualifiersWithCustomSql.NAME + CUSTOM_DELETE_SQL_PART_2 + + EntityWithDefaultQualifiersWithCustomSql.NAME + CUSTOM_DELETE_SQL_PART_3) + public static class EntityWithDefaultQualifiersWithCustomSql { + public static final String NAME = "EntityWithDefaultQualifiersWithCustomSql"; + @Id + private Long id; + @Basic + private String basic; + @OneToMany + @JoinTable(name = NAME + "_oneToMany", + // Custom names to avoid false positive in assertions + joinColumns = @JoinColumn(name = "forward"), + inverseJoinColumns = @JoinColumn(name = "inverse"), + foreignKey = @ForeignKey(name = "FK_oneToMany")) + @SQLInsert(sql = CUSTOM_INSERT_SQL_PART_1 + EntityWithDefaultQualifiersWithCustomSql.NAME + "_oneToMany" + CUSTOM_INSERT_SQL_PART_2 + + EntityWithDefaultQualifiersWithCustomSql.NAME + "_oneToMany" + CUSTOM_INSERT_SQL_PART_3) + @SQLUpdate(sql = CUSTOM_UPDATE_SQL_PART_1 + EntityWithDefaultQualifiersWithCustomSql.NAME + "_oneToMany" + CUSTOM_UPDATE_SQL_PART_2 + + EntityWithDefaultQualifiersWithCustomSql.NAME + "_oneToMany" + CUSTOM_UPDATE_SQL_PART_3) + @SQLDelete(sql = CUSTOM_DELETE_SQL_PART_1 + EntityWithDefaultQualifiersWithCustomSql.NAME + "_oneToMany" + CUSTOM_DELETE_SQL_PART_2 + + EntityWithDefaultQualifiersWithCustomSql.NAME + "_oneToMany" + CUSTOM_DELETE_SQL_PART_3) + private List oneToMany; + @OneToMany + @JoinTable(name = NAME + "_manyToMany", + // Custom names to avoid false positive in assertions + joinColumns = @JoinColumn(name = "forward"), + inverseJoinColumns = @JoinColumn(name = "inverse"), + foreignKey = @ForeignKey(name = "FK_manyToMany")) + @SQLInsert(sql = CUSTOM_INSERT_SQL_PART_1 + EntityWithDefaultQualifiersWithCustomSql.NAME + "_manyToMany" + CUSTOM_INSERT_SQL_PART_2 + + EntityWithDefaultQualifiersWithCustomSql.NAME + "_manyToMany" + CUSTOM_INSERT_SQL_PART_3) + @SQLUpdate(sql = CUSTOM_UPDATE_SQL_PART_1 + EntityWithDefaultQualifiersWithCustomSql.NAME + "_manyToMany" + CUSTOM_UPDATE_SQL_PART_2 + + EntityWithDefaultQualifiersWithCustomSql.NAME + "_manyToMany" + CUSTOM_UPDATE_SQL_PART_3) + @SQLDelete(sql = CUSTOM_DELETE_SQL_PART_1 + EntityWithDefaultQualifiersWithCustomSql.NAME + "_manyToMany" + CUSTOM_DELETE_SQL_PART_2 + + EntityWithDefaultQualifiersWithCustomSql.NAME + "_manyToMany" + CUSTOM_DELETE_SQL_PART_3) + private List manyToMany; + @ElementCollection + @JoinTable(name = NAME + "_elementCollection", + // Custom names to avoid false positive in assertions + joinColumns = @JoinColumn(name = "forward"), + foreignKey = @ForeignKey(name = "FK_elementCollection")) + @SQLInsert(sql = CUSTOM_INSERT_SQL_PART_1 + EntityWithDefaultQualifiersWithCustomSql.NAME + "_elementCollection" + CUSTOM_INSERT_SQL_PART_2 + + EntityWithDefaultQualifiersWithCustomSql.NAME + "_elementCollection" + CUSTOM_INSERT_SQL_PART_3) + @SQLUpdate(sql = CUSTOM_UPDATE_SQL_PART_1 + EntityWithDefaultQualifiersWithCustomSql.NAME + "_elementCollection" + CUSTOM_UPDATE_SQL_PART_2 + + EntityWithDefaultQualifiersWithCustomSql.NAME + "_elementCollection" + CUSTOM_UPDATE_SQL_PART_3) + @SQLDelete(sql = CUSTOM_DELETE_SQL_PART_1 + EntityWithDefaultQualifiersWithCustomSql.NAME + "_elementCollection" + CUSTOM_DELETE_SQL_PART_2 + + EntityWithDefaultQualifiersWithCustomSql.NAME + "_elementCollection" + CUSTOM_DELETE_SQL_PART_3) + private List elementCollection; + } + + @Entity(name = EntityWithDefaultQualifiersWithIdentityGenerator.NAME) + public static class EntityWithDefaultQualifiersWithIdentityGenerator { + public static final String NAME = "EntityWithDefaultQualifiersWithIdentityGenerator"; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Basic + private String basic; + } + + @Entity(name = EntityWithExplicitQualifiersWithIdentityGenerator.NAME) + @Table(catalog = EXPLICIT_CATALOG, schema = EXPLICIT_SCHEMA) + public static class EntityWithExplicitQualifiersWithIdentityGenerator { + public static final String NAME = "EntityWithExplicitQualifiersWithIdentityGenerator"; + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + @Basic + private String basic; + } + + @Entity(name = EntityWithDefaultQualifiersWithSequenceGenerator.NAME) + public static class EntityWithDefaultQualifiersWithSequenceGenerator { + public static final String NAME = "EntityWithDefaultQualifiersWithSequenceGenerator"; + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = NAME + "_generator") + @SequenceGenerator(name = NAME + "_generator", sequenceName = NAME + "_seq") + private Long id; + @Basic + private String basic; + } + + @Entity(name = EntityWithExplicitQualifiersWithSequenceGenerator.NAME) + @Table(catalog = EXPLICIT_CATALOG, schema = EXPLICIT_SCHEMA) + public static class EntityWithExplicitQualifiersWithSequenceGenerator { + public static final String NAME = "EntityWithExplicitQualifiersWithSequenceGenerator"; + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = NAME + "_generator") + @SequenceGenerator(name = NAME + "_generator", sequenceName = NAME + "_seq", + catalog = EXPLICIT_CATALOG, schema = EXPLICIT_SCHEMA) + private Long id; + @Basic + private String basic; + } + + + @Entity(name = EntityWithDefaultQualifiersWithTableGenerator.NAME) + public static class EntityWithDefaultQualifiersWithTableGenerator { + public static final String NAME = "EntityWithDefaultQualifiersWithTableGenerator"; + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = NAME + "_generator") + @TableGenerator(name = NAME + "_generator", table = NAME + "_tableseq") + private Long id; + @Basic + private String basic; + } + + @Entity(name = EntityWithExplicitQualifiersWithTableGenerator.NAME) + @Table(catalog = EXPLICIT_CATALOG, schema = EXPLICIT_SCHEMA) + public static class EntityWithExplicitQualifiersWithTableGenerator { + public static final String NAME = "EntityWithExplicitQualifiersWithTableGenerator"; + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = NAME + "_generator") + @TableGenerator(name = NAME + "_generator", table = NAME + "_tableseq", + catalog = EXPLICIT_CATALOG, schema = EXPLICIT_SCHEMA) + private Long id; + @Basic + private String basic; + } + + @Entity(name = EntityWithDefaultQualifiersWithSeqHiLoGenerator.NAME) + public static class EntityWithDefaultQualifiersWithSeqHiLoGenerator { + public static final String NAME = "EntityWithDefaultQualifiersWithSeqHiLoGenerator"; + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = NAME + "_generator") + @GenericGenerator(name = NAME + "_generator", strategy = "org.hibernate.id.SequenceHiLoGenerator", parameters = { + @Parameter(name = "sequence", value = NAME + "_seq"), + @Parameter(name = "max_lo", value = "5") + }) + private Long id; + @Basic + private String basic; + } + + @Entity(name = EntityWithExplicitQualifiersWithSeqHiLoGenerator.NAME) + @Table(catalog = EXPLICIT_CATALOG, schema = EXPLICIT_SCHEMA) + public static class EntityWithExplicitQualifiersWithSeqHiLoGenerator { + public static final String NAME = "EntityWithExplicitQualifiersWithSeqHiLoGenerator"; + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = NAME + "_generator") + @GenericGenerator(name = NAME + "_generator", strategy = "org.hibernate.id.SequenceHiLoGenerator", parameters = { + @Parameter(name = "sequence", value = NAME + "_seq"), + @Parameter(name = "max_lo", value = "5"), + @Parameter(name = "catalog", value = EXPLICIT_CATALOG), + @Parameter(name = "schema", value = EXPLICIT_SCHEMA) + }) + private Long id; + @Basic + private String basic; + } + + @Entity(name = EntityWithDefaultQualifiersWithIncrementGenerator.NAME) + public static class EntityWithDefaultQualifiersWithIncrementGenerator { + public static final String NAME = "EntityWithDefaultQualifiersWithIncrementGenerator"; + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = NAME + "_generator") + @GenericGenerator(name = NAME + "_generator", strategy = "increment") + private Long id; + @Basic + private String basic; + } + + @Entity(name = EntityWithExplicitQualifiersWithIncrementGenerator.NAME) + @Table(catalog = EXPLICIT_CATALOG, schema = EXPLICIT_SCHEMA) + public static class EntityWithExplicitQualifiersWithIncrementGenerator { + public static final String NAME = "EntityWithExplicitQualifiersWithIncrementGenerator"; + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = NAME + "_generator") + @GenericGenerator(name = NAME + "_generator", strategy = "increment", parameters = { + @Parameter(name = "catalog", value = EXPLICIT_CATALOG), + @Parameter(name = "schema", value = EXPLICIT_SCHEMA) + }) + private Long id; + @Basic + private String basic; + } + + @Entity(name = EntityWithDefaultQualifiersWithSequenceIdentityGenerator.NAME) + public static class EntityWithDefaultQualifiersWithSequenceIdentityGenerator { + public static final String NAME = "EntityWithDefaultQualifiersWithSequenceIdentityGenerator"; + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = NAME + "_generator") + @GenericGenerator(name = NAME + "_generator", strategy = "sequence-identity", parameters = { + @Parameter(name = "sequence", value = NAME + "_seq") + }) + private Long id; + @Basic + private String basic; + } + + @Entity(name = EntityWithExplicitQualifiersWithSequenceIdentityGenerator.NAME) + @Table(catalog = EXPLICIT_CATALOG, schema = EXPLICIT_SCHEMA) + public static class EntityWithExplicitQualifiersWithSequenceIdentityGenerator { + public static final String NAME = "EntityWithExplicitQualifiersWithSequenceIdentityGenerator"; + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = NAME + "_generator") + @GenericGenerator(name = NAME + "_generator", strategy = "sequence-identity", parameters = { + @Parameter(name = "sequence", value = NAME + "_seq"), + @Parameter(name = "catalog", value = EXPLICIT_CATALOG), + @Parameter(name = "schema", value = EXPLICIT_SCHEMA) + }) + private Long id; + @Basic + private String basic; + } + + @Entity(name = EntityWithDefaultQualifiersWithEnhancedSequenceGenerator.NAME) + public static class EntityWithDefaultQualifiersWithEnhancedSequenceGenerator { + public static final String NAME = "EntityWithDefaultQualifiersWithEnhancedSequenceGenerator"; + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = NAME + "_generator") + @GenericGenerator(name = NAME + "_generator", strategy = "enhanced-sequence", parameters = { + @Parameter(name = "sequence_name", value = NAME + "_seq") + }) + private Long id; + @Basic + private String basic; + } + + @Entity(name = EntityWithExplicitQualifiersWithEnhancedSequenceGenerator.NAME) + @Table(catalog = EXPLICIT_CATALOG, schema = EXPLICIT_SCHEMA) + public static class EntityWithExplicitQualifiersWithEnhancedSequenceGenerator { + public static final String NAME = "EntityWithExplicitQualifiersWithEnhancedSequenceGenerator"; + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = NAME + "_generator") + @GenericGenerator(name = NAME + "_generator", strategy = "enhanced-sequence", parameters = { + @Parameter(name = "sequence_name", value = NAME + "_seq"), + @Parameter(name = "catalog", value = EXPLICIT_CATALOG), + @Parameter(name = "schema", value = EXPLICIT_SCHEMA) + }) + private Long id; + @Basic + private String basic; + } + + + @Entity(name = EntityWithDefaultQualifiersWithLegacySequenceGenerator.NAME) + public static class EntityWithDefaultQualifiersWithLegacySequenceGenerator { + public static final String NAME = "EntityWithDefaultQualifiersWithLegacySequenceGenerator"; + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = NAME + "_generator") + @GenericGenerator(name = NAME + "_generator", strategy = "org.hibernate.id.SequenceGenerator", parameters = { + @Parameter(name = "sequence", value = NAME + "_seq") + }) + private Long id; + @Basic + private String basic; + } + + @Entity(name = EntityWithExplicitQualifiersWithLegacySequenceGenerator.NAME) + @Table(catalog = EXPLICIT_CATALOG, schema = EXPLICIT_SCHEMA) + public static class EntityWithExplicitQualifiersWithLegacySequenceGenerator { + public static final String NAME = "EntityWithExplicitQualifiersWithLegacySequenceGenerator"; + @Id + @GeneratedValue(strategy = GenerationType.SEQUENCE, generator = NAME + "_generator") + @GenericGenerator(name = NAME + "_generator", strategy = "org.hibernate.id.SequenceGenerator", parameters = { + @Parameter(name = "sequence", value = NAME + "_seq"), + @Parameter(name = "catalog", value = EXPLICIT_CATALOG), + @Parameter(name = "schema", value = EXPLICIT_SCHEMA) + }) + private Long id; + @Basic + private String basic; + } + +} diff --git a/hibernate-core/src/test/resources/org/hibernate/test/boot/database/qualfiedTableNaming/implicit-file-level-catalog-and-schema.hbm.xml b/hibernate-core/src/test/resources/org/hibernate/test/boot/database/qualfiedTableNaming/implicit-file-level-catalog-and-schema.hbm.xml new file mode 100644 index 000000000000..fc5317d20da2 --- /dev/null +++ b/hibernate-core/src/test/resources/org/hibernate/test/boot/database/qualfiedTableNaming/implicit-file-level-catalog-and-schema.hbm.xml @@ -0,0 +1,17 @@ + + + + + + + + diff --git a/hibernate-core/src/test/resources/org/hibernate/test/boot/database/qualfiedTableNaming/implicit-file-level-catalog-and-schema.orm.xml b/hibernate-core/src/test/resources/org/hibernate/test/boot/database/qualfiedTableNaming/implicit-file-level-catalog-and-schema.orm.xml new file mode 100644 index 000000000000..cff6d97f8bc7 --- /dev/null +++ b/hibernate-core/src/test/resources/org/hibernate/test/boot/database/qualfiedTableNaming/implicit-file-level-catalog-and-schema.orm.xml @@ -0,0 +1,46 @@ + + + + org.hibernate.test.boot.database.qualfiedTableNaming + someImplicitFileLevelSchema + someImplicitFileLevelCatalog + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/hibernate-core/src/test/resources/org/hibernate/test/boot/database/qualfiedTableNaming/implicit-global-catalog-and-schema.orm.xml b/hibernate-core/src/test/resources/org/hibernate/test/boot/database/qualfiedTableNaming/implicit-global-catalog-and-schema.orm.xml new file mode 100644 index 000000000000..a8c02b858be8 --- /dev/null +++ b/hibernate-core/src/test/resources/org/hibernate/test/boot/database/qualfiedTableNaming/implicit-global-catalog-and-schema.orm.xml @@ -0,0 +1,19 @@ + + + + + + someImplicitSchema + someImplicitCatalog + + + From 3071f58c217d8933766b75270879a6dba7f1f166 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Fri, 5 Nov 2021 18:25:23 +0100 Subject: [PATCH 409/644] HHH-14921 Test handling of default catalog and schema when not configured during metadata creation --- .../DefaultCatalogAndSchemaTest.java | 84 ++++++++++++++----- 1 file changed, 62 insertions(+), 22 deletions(-) diff --git a/hibernate-core/src/test/java/org/hibernate/test/boot/database/qualfiedTableNaming/DefaultCatalogAndSchemaTest.java b/hibernate-core/src/test/java/org/hibernate/test/boot/database/qualfiedTableNaming/DefaultCatalogAndSchemaTest.java index dd78d99cf77c..f249d0bd5468 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/boot/database/qualfiedTableNaming/DefaultCatalogAndSchemaTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/boot/database/qualfiedTableNaming/DefaultCatalogAndSchemaTest.java @@ -42,6 +42,9 @@ import org.hibernate.boot.MetadataBuilder; import org.hibernate.boot.MetadataSources; import org.hibernate.boot.SessionFactoryBuilder; +import org.hibernate.boot.internal.MetadataImpl; +import org.hibernate.boot.internal.SessionFactoryBuilderImpl; +import org.hibernate.boot.internal.SessionFactoryOptionsBuilder; import org.hibernate.boot.registry.BootstrapServiceRegistry; import org.hibernate.boot.registry.BootstrapServiceRegistryBuilder; import org.hibernate.boot.registry.StandardServiceRegistry; @@ -97,38 +100,53 @@ public class DefaultCatalogAndSchemaTest { private static final String CUSTOM_DELETE_SQL_PART_2 = ", {h-domain}"; private static final String CUSTOM_DELETE_SQL_PART_3 = " WHERE id = ?"; - @Parameterized.Parameters(name = "configuredXmlMappingPath = {0}, configuredDefaultCatalog = {1}, configuredDefaultSchema = {2}") + enum SettingsMode { + // "Standard" way of providing settings, though configuration properties: + // both metadata and session factory receive the same settings + METADATA_SERVICE_REGISTRY, + // An alternative way of providing settings so that they are applied late, + // when the session factory is created. + // This mode is used by frameworks relying on build-time initialization of the application, + // like Quarkus and its "static init". + SESSION_FACTORY_SERVICE_REGISTRY + } + + @Parameterized.Parameters(name = "settingsMode = {0}, configuredXmlMappingPath = {1}, configuredDefaultCatalog = {2}, configuredDefaultSchema = {3}") public static List params() { List params = new ArrayList<>(); - for ( String defaultCatalog : Arrays.asList( null, "someDefaultCatalog" ) ) { - for ( String defaultSchema : Arrays.asList( null, "someDefaultSchema" ) ) { - params.add( new Object[] { null, defaultCatalog, defaultSchema, - // The default catalog/schema should be used when - // there is no implicit catalog/schema defined in the mapping. - defaultCatalog, defaultSchema } ); + for ( SettingsMode mode : SettingsMode.values() ) { + for ( String defaultCatalog : Arrays.asList( null, "someDefaultCatalog" ) ) { + for ( String defaultSchema : Arrays.asList( null, "someDefaultSchema" ) ) { + params.add( new Object[] { mode, null, defaultCatalog, defaultSchema, + // The default catalog/schema should be used when + // there is no implicit catalog/schema defined in the mapping. + defaultCatalog, defaultSchema } ); + } } + params.add( new Object[] { mode, "implicit-global-catalog-and-schema.orm.xml", + null, null, + "someImplicitCatalog", "someImplicitSchema" } ); + // HHH-14922: Inconsistent precedence of orm.xml implicit catalog/schema over "default_catalog"/"default_schema" +// params.add( new Object[] { mode, "implicit-global-catalog-and-schema.orm.xml", +// "someDefaultCatalog", "someDefaultSchema", +// // The implicit catalog/schema defined in the mapping should take precedence +// // over the default catalog/schema defined in settings. +// "someImplicitCatalog", "someImplicitSchema" } ); } - params.add( new Object[] { "implicit-global-catalog-and-schema.orm.xml", - null, null, - "someImplicitCatalog", "someImplicitSchema" } ); - // HHH-14922: Inconsistent precedence of orm.xml implicit catalog/schema over "default_catalog"/"default_schema" -// params.add( new Object[] { "implicit-global-catalog-and-schema.orm.xml", -// "someDefaultCatalog", "someDefaultSchema", -// // The implicit catalog/schema defined in the mapping should take precedence -// // over the default catalog/schema defined in settings. -// "someImplicitCatalog", "someImplicitSchema" } ); return params; } @Parameterized.Parameter - public String configuredXmlMappingPath; + public SettingsMode settingsMode; @Parameterized.Parameter(1) - public String configuredDefaultCatalog; + public String configuredXmlMappingPath; @Parameterized.Parameter(2) - public String configuredDefaultSchema; + public String configuredDefaultCatalog; @Parameterized.Parameter(3) - public String expectedDefaultCatalog; + public String configuredDefaultSchema; @Parameterized.Parameter(4) + public String expectedDefaultCatalog; + @Parameterized.Parameter(5) public String expectedDefaultSchema; private boolean dbSupportsCatalogs; @@ -170,7 +188,17 @@ public void initSessionFactory() { EntityWithExplicitQualifiersWithLegacySequenceGenerator.class ); - StandardServiceRegistry serviceRegistry = createStandardServiceRegistry( configuredDefaultCatalog, configuredDefaultSchema ); + StandardServiceRegistry serviceRegistry; + switch ( settingsMode ) { + case METADATA_SERVICE_REGISTRY: + serviceRegistry = createStandardServiceRegistry( configuredDefaultCatalog, configuredDefaultSchema ); + break; + case SESSION_FACTORY_SERVICE_REGISTRY: + serviceRegistry = createStandardServiceRegistry( null, null ); + break; + default: + throw new IllegalStateException( "Unknown settings mode: " + settingsMode ); + } final MetadataSources metadataSources = new MetadataSources( serviceRegistry ); metadataSources.addInputStream( getClass().getResourceAsStream( "implicit-file-level-catalog-and-schema.orm.xml" ) ); @@ -185,7 +213,19 @@ public void initSessionFactory() { final MetadataBuilder metadataBuilder = metadataSources.getMetadataBuilder(); metadata = (MetadataImplementor) metadataBuilder.build(); - SessionFactoryBuilder sfb = metadata.getSessionFactoryBuilder(); + SessionFactoryBuilder sfb; + switch ( settingsMode ) { + case METADATA_SERVICE_REGISTRY: + sfb = metadata.getSessionFactoryBuilder(); + break; + case SESSION_FACTORY_SERVICE_REGISTRY: + serviceRegistry = createStandardServiceRegistry( configuredDefaultCatalog, configuredDefaultSchema ); + sfb = new SessionFactoryBuilderImpl( metadata, new SessionFactoryOptionsBuilder( serviceRegistry, + ((MetadataImpl) metadata).getBootstrapContext() ) ); + break; + default: + throw new IllegalStateException( "Unknown settings mode: " + settingsMode ); + } sessionFactory = (SessionFactoryImplementor) sfb.build(); toClose.add( sessionFactory ); From 9b47fcdfa825bc77003e4fb985b02bb2131d82e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Tue, 9 Nov 2021 18:02:28 +0100 Subject: [PATCH 410/644] HHH-14922 Test behavior when setting both implicit catalog/schema and default catalog/schema --- .../DefaultCatalogAndSchemaTest.java | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/hibernate-core/src/test/java/org/hibernate/test/boot/database/qualfiedTableNaming/DefaultCatalogAndSchemaTest.java b/hibernate-core/src/test/java/org/hibernate/test/boot/database/qualfiedTableNaming/DefaultCatalogAndSchemaTest.java index f249d0bd5468..f0c497a6efcf 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/boot/database/qualfiedTableNaming/DefaultCatalogAndSchemaTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/boot/database/qualfiedTableNaming/DefaultCatalogAndSchemaTest.java @@ -80,7 +80,7 @@ import org.junit.runners.Parameterized; @RunWith(CustomParameterized.class) -@TestForIssue(jiraKey = "HHH-14921") +@TestForIssue(jiraKey = { "HHH-14921", "HHH-14922" }) public class DefaultCatalogAndSchemaTest { private static final String SQL_QUOTE_CHARACTER_CLASS = "([`\"]|\\[|\\])"; @@ -127,11 +127,11 @@ public static List params() { null, null, "someImplicitCatalog", "someImplicitSchema" } ); // HHH-14922: Inconsistent precedence of orm.xml implicit catalog/schema over "default_catalog"/"default_schema" -// params.add( new Object[] { mode, "implicit-global-catalog-and-schema.orm.xml", -// "someDefaultCatalog", "someDefaultSchema", -// // The implicit catalog/schema defined in the mapping should take precedence -// // over the default catalog/schema defined in settings. -// "someImplicitCatalog", "someImplicitSchema" } ); + params.add( new Object[] { mode, "implicit-global-catalog-and-schema.orm.xml", + "someDefaultCatalog", "someDefaultSchema", + // The implicit catalog/schema defined in the mapping should take precedence + // over the default catalog/schema defined in settings. + "someImplicitCatalog", "someImplicitSchema" } ); } return params; } From 795d5cd4e98a539790f2f6332e5399e506af8e20 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Wed, 10 Nov 2021 09:55:56 +0100 Subject: [PATCH 411/644] 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. --- .../boot/model/relational/Database.java | 50 +++++++++++-------- .../SqlStringGenerationContext.java | 12 +++++ .../SqlStringGenerationContextImpl.java | 46 +++++++++-------- .../source/internal/hbm/ModelBinder.java | 11 +--- .../org/hibernate/cfg/AnnotationBinder.java | 15 ------ .../java/org/hibernate/cfg/BinderHelper.java | 9 ---- .../main/java/org/hibernate/cfg/Settings.java | 4 +- .../cfg/annotations/TableBinder.java | 4 +- .../JPAXMLOverriddenAnnotationReader.java | 4 +- .../JPAXMLOverriddenMetadataProvider.java | 2 +- .../reflection/internal/XMLContext.java | 36 ++++++++----- .../internal/DatabaseInformationImpl.java | 14 ++++-- .../schema/internal/SchemaCreatorImpl.java | 9 ++-- .../id/sequences/HibernateSequenceTest.java | 4 +- .../JPAXMLOverriddenAnnotationReaderTest.java | 29 +++++++---- 15 files changed, 135 insertions(+), 114 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/relational/Database.java b/hibernate-core/src/main/java/org/hibernate/boot/model/relational/Database.java index ef77cb757248..5cf503dad07e 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/relational/Database.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/relational/Database.java @@ -35,7 +35,7 @@ public class Database { private final ServiceRegistry serviceRegistry; private final PhysicalNamingStrategy physicalNamingStrategy; - private Namespace implicitNamespace; + private Namespace.Name physicalImplicitNamespaceName; private List initCommands; public Database(MetadataBuildingOptions buildingOptions) { @@ -48,11 +48,16 @@ public Database(MetadataBuildingOptions buildingOptions, JdbcEnvironment jdbcEnv 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 Iterable getNamespaces() { 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 ); } - public Namespace locateNamespace(Identifier catalogName, Identifier schemaName) { - if ( catalogName == null && schemaName == null ) { - return getDefaultNamespace(); - } + /** + * @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) { final Namespace.Name name = new Namespace.Name( catalogName, schemaName ); Namespace namespace = namespaceMap.get( name ); if ( namespace == null ) { @@ -126,17 +141,8 @@ public Namespace locateNamespace(Identifier catalogName, Identifier schemaName) } 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) { diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/relational/SqlStringGenerationContext.java b/hibernate-core/src/main/java/org/hibernate/boot/model/relational/SqlStringGenerationContext.java index fcd682ae7e44..d808e7c20ef2 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/relational/SqlStringGenerationContext.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/relational/SqlStringGenerationContext.java @@ -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 * diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/relational/internal/SqlStringGenerationContextImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/model/relational/internal/SqlStringGenerationContextImpl.java index 1b395e317e6c..05091caa25d8 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/relational/internal/SqlStringGenerationContextImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/relational/internal/SqlStringGenerationContextImpl.java @@ -47,7 +47,7 @@ public static SqlStringGenerationContext fromConfigurationMap(JdbcEnvironment jd */ 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; @@ -108,30 +108,25 @@ public Identifier getDefaultCatalog() { } @Override - public Identifier getDefaultSchema() { - return defaultSchema; - } - - @Override - public String format(QualifiedTableName qualifiedName) { - return qualifiedObjectNameFormatter.format( withDefaults( qualifiedName ), dialect ); + public Identifier catalogWithDefault(Identifier explicitCatalogOrNull) { + return explicitCatalogOrNull != null ? explicitCatalogOrNull : defaultCatalog; } @Override - public String format(QualifiedSequenceName qualifiedName) { - return qualifiedObjectNameFormatter.format( withDefaults( qualifiedName ), dialect ); + public Identifier getDefaultSchema() { + return defaultSchema; } @Override - public String format(QualifiedName qualifiedName) { - return qualifiedObjectNameFormatter.format( withDefaults( qualifiedName ), dialect ); + 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( withDefault( name.getCatalogName(), defaultCatalog ), - withDefault( name.getSchemaName(), defaultSchema ), name.getTableName() ); + return new QualifiedTableName( catalogWithDefault( name.getCatalogName() ), + schemaWithDefault( name.getSchemaName() ), name.getTableName() ); } return name; } @@ -139,8 +134,8 @@ private QualifiedTableName withDefaults(QualifiedTableName 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 new QualifiedSequenceName( catalogWithDefault( name.getCatalogName() ), + schemaWithDefault( name.getSchemaName() ), name.getSequenceName() ); } return name; } @@ -148,14 +143,25 @@ private QualifiedSequenceName withDefaults(QualifiedSequenceName 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 new QualifiedSequenceName( catalogWithDefault( name.getCatalogName() ), + schemaWithDefault( name.getSchemaName() ), name.getObjectName() ); } return name; } - private static Identifier withDefault(Identifier value, Identifier defaultValue) { - return value != null ? value : defaultValue; + @Override + public String format(QualifiedTableName qualifiedName) { + return qualifiedObjectNameFormatter.format( withDefaults( qualifiedName ), dialect ); + } + + @Override + public String format(QualifiedSequenceName qualifiedName) { + return qualifiedObjectNameFormatter.format( withDefaults( qualifiedName ), dialect ); + } + + @Override + public String format(QualifiedName qualifiedName) { + return qualifiedObjectNameFormatter.format( withDefaults( qualifiedName ), dialect ); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/ModelBinder.java b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/ModelBinder.java index 5d63c44fcfe3..e0f7310847d1 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/ModelBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/source/internal/hbm/ModelBinder.java @@ -804,15 +804,6 @@ private void makeIdentifier( // 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 @@ private Identifier determineSchemaName(TableSpecificationSource tableSpecSource) return database.toIdentifier( tableSpecSource.getExplicitSchemaName() ); } else { - return database.toIdentifier( metadataBuildingContext.getMappingDefaults().getImplicitSchemaName() ); + return null; } } diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java b/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java index 786acc6b1296..3881e9912105 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/AnnotationBinder.java @@ -149,7 +149,6 @@ 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 @@ private static IdentifierGeneratorDefinition buildIdGenerator( 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, diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/BinderHelper.java b/hibernate-core/src/main/java/org/hibernate/cfg/BinderHelper.java index 4dd9882d5a17..b30c2180c54f 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/BinderHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/BinderHelper.java @@ -525,15 +525,6 @@ public static void makeIdGenerator( 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, diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/Settings.java b/hibernate-core/src/main/java/org/hibernate/cfg/Settings.java index 3203190d9086..1b89ae77ed4c 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/Settings.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/Settings.java @@ -50,8 +50,8 @@ public Settings(SessionFactoryOptions sessionFactoryOptions) { 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() ) ); } diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/TableBinder.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/TableBinder.java index 2dfb2d132e87..7b9f7c5eff7b 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/TableBinder.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/TableBinder.java @@ -477,10 +477,10 @@ public static Table buildAndFillTable( 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; diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenAnnotationReader.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenAnnotationReader.java index 8a8c3167522c..a020b8607da1 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenAnnotationReader.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenAnnotationReader.java @@ -407,7 +407,9 @@ public Annotation[] getAnnotations() { */ 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 ); diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenMetadataProvider.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenMetadataProvider.java index fef5c77f0b3f..afd35add4866 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenMetadataProvider.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/JPAXMLOverriddenMetadataProvider.java @@ -94,7 +94,7 @@ public Map getDefaults() { 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() ); diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/XMLContext.java b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/XMLContext.java index 06f1da27f913..c43223900ead 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/XMLContext.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/annotations/reflection/internal/XMLContext.java @@ -124,12 +124,12 @@ private void addClass(List managedTypes, String packageNa 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 static String buildSafeClassName(String className, Default defaults) { 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 @@ void setCascadePersist(Boolean cascadePersist) { 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 void override(Default globalDefault) { 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(); } diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/DatabaseInformationImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/DatabaseInformationImpl.java index 38748838b128..f2ad3077ad60 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/DatabaseInformationImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/extract/internal/DatabaseInformationImpl.java @@ -32,6 +32,7 @@ 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 DatabaseInformationImpl( DdlTransactionIsolator ddlTransactionIsolator, SchemaManagementTool tool) throws SQLException { this.jdbcEnvironment = jdbcEnvironment; + this.sqlStringGenerationContext = sqlStringGenerationContext; this.extractionContext = tool.getExtractionTool().createExtractionContext( serviceRegistry, jdbcEnvironment, @@ -78,12 +80,13 @@ private void initializeSequences() throws SQLException { @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 TableInformation getTableInformation(QualifiedTableName tableName) { } 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 diff --git a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/SchemaCreatorImpl.java b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/SchemaCreatorImpl.java index 0d14dcabf768..529558e55c09 100644 --- a/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/SchemaCreatorImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/tool/schema/internal/SchemaCreatorImpl.java @@ -235,7 +235,8 @@ public void createFromMetadata( 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 void createFromMetadata( } } - 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 diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/id/sequences/HibernateSequenceTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/id/sequences/HibernateSequenceTest.java index b8fe8eca1196..efd1b47d596e 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/id/sequences/HibernateSequenceTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/id/sequences/HibernateSequenceTest.java @@ -11,6 +11,7 @@ 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 void testHibernateSequenceSchema() { 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() ) ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/JPAXMLOverriddenAnnotationReaderTest.java b/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/JPAXMLOverriddenAnnotationReaderTest.java index 1c12a7a146cd..dcf8d8c7d47b 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/JPAXMLOverriddenAnnotationReaderTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/annotations/reflection/JPAXMLOverriddenAnnotationReaderTest.java @@ -64,7 +64,9 @@ public void testEntityRelatedAnnotations() throws Exception { ); 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 void testEntityRelatedAnnotations() throws Exception { 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 void testEntityRelatedAnnotations() throws Exception { 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 void testEntityRelatedAnnotationsMetadataComplete() throws Exception { 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 ) ); From 67e09b12908de27686169ade8d590b5b7ea1f9ef Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Yoann=20Rodi=C3=A8re?= Date: Wed, 10 Nov 2021 09:57:31 +0100 Subject: [PATCH 412/644] HHH-14922 Give precedence to default catalog/schema over implicit catalog/schema --- .../SqlStringGenerationContextImpl.java | 18 ++++++++++-------- .../main/java/org/hibernate/cfg/Settings.java | 4 ++-- .../DefaultCatalogAndSchemaTest.java | 6 +++--- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/relational/internal/SqlStringGenerationContextImpl.java b/hibernate-core/src/main/java/org/hibernate/boot/model/relational/internal/SqlStringGenerationContextImpl.java index 05091caa25d8..bef59f450300 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/relational/internal/SqlStringGenerationContextImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/relational/internal/SqlStringGenerationContextImpl.java @@ -41,8 +41,8 @@ public static SqlStringGenerationContext fromConfigurationMap(JdbcEnvironment jd /** * @param jdbcEnvironment The JDBC environment, to extract the dialect, identifier helper, etc. * @param database The database metadata, to retrieve the implicit namespace name configured through XML mapping. - * @param defaultCatalog The default catalog to use, unless an implicit catalog was configured through XML mapping. - * @param defaultSchema The default schema to use, unless an implicit schema was configured through XML mapping. + * @param defaultCatalog The default catalog to use; if {@code null}, will use the implicit catalog that was configured through XML mapping. + * @param defaultSchema The default schema to use; if {@code null}, will use the implicit schema that was configured through XML mapping. * @return An {@link SqlStringGenerationContext}. */ public static SqlStringGenerationContext fromExplicit(JdbcEnvironment jdbcEnvironment, @@ -52,15 +52,17 @@ public static SqlStringGenerationContext fromExplicit(JdbcEnvironment jdbcEnviro NameQualifierSupport nameQualifierSupport = jdbcEnvironment.getNameQualifierSupport(); Identifier actualDefaultCatalog = null; if ( nameQualifierSupport.supportsCatalogs() ) { - actualDefaultCatalog = implicitNamespaceName.getCatalog() != null - ? implicitNamespaceName.getCatalog() - : identifierHelper.toIdentifier( defaultCatalog ); + actualDefaultCatalog = identifierHelper.toIdentifier( defaultCatalog ); + if ( actualDefaultCatalog == null ) { + actualDefaultCatalog = implicitNamespaceName.getCatalog(); + } } Identifier actualDefaultSchema = null; if ( nameQualifierSupport.supportsSchemas() ) { - actualDefaultSchema = implicitNamespaceName.getSchema() != null - ? implicitNamespaceName.getSchema() - : identifierHelper.toIdentifier( defaultSchema ); + actualDefaultSchema = identifierHelper.toIdentifier( defaultSchema ); + if ( defaultSchema == null ) { + actualDefaultSchema = implicitNamespaceName.getSchema(); + } } return new SqlStringGenerationContextImpl( jdbcEnvironment, actualDefaultCatalog, actualDefaultSchema ); } diff --git a/hibernate-core/src/main/java/org/hibernate/cfg/Settings.java b/hibernate-core/src/main/java/org/hibernate/cfg/Settings.java index 1b89ae77ed4c..ad9c46ad38e9 100644 --- a/hibernate-core/src/main/java/org/hibernate/cfg/Settings.java +++ b/hibernate-core/src/main/java/org/hibernate/cfg/Settings.java @@ -61,8 +61,8 @@ private static String extractName(Identifier identifier) { public Settings(SessionFactoryOptions sessionFactoryOptions, String defaultCatalogName, String defaultSchemaName) { this.sessionFactoryOptions = sessionFactoryOptions; - this.defaultCatalogName = defaultCatalogName != null ? defaultCatalogName : sessionFactoryOptions.getDefaultCatalog(); - this.defaultSchemaName = defaultSchemaName != null ? defaultSchemaName : sessionFactoryOptions.getDefaultSchema(); + this.defaultCatalogName = sessionFactoryOptions.getDefaultCatalog() != null ? sessionFactoryOptions.getDefaultCatalog() : defaultCatalogName; + this.defaultSchemaName = sessionFactoryOptions.getDefaultSchema() != null ? sessionFactoryOptions.getDefaultSchema() : defaultSchemaName; if ( LOG.isDebugEnabled() ) { LOG.debugf( "SessionFactory name : %s", sessionFactoryOptions.getSessionFactoryName() ); diff --git a/hibernate-core/src/test/java/org/hibernate/test/boot/database/qualfiedTableNaming/DefaultCatalogAndSchemaTest.java b/hibernate-core/src/test/java/org/hibernate/test/boot/database/qualfiedTableNaming/DefaultCatalogAndSchemaTest.java index f0c497a6efcf..37fc2926bbaf 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/boot/database/qualfiedTableNaming/DefaultCatalogAndSchemaTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/boot/database/qualfiedTableNaming/DefaultCatalogAndSchemaTest.java @@ -129,9 +129,9 @@ public static List params() { // HHH-14922: Inconsistent precedence of orm.xml implicit catalog/schema over "default_catalog"/"default_schema" params.add( new Object[] { mode, "implicit-global-catalog-and-schema.orm.xml", "someDefaultCatalog", "someDefaultSchema", - // The implicit catalog/schema defined in the mapping should take precedence - // over the default catalog/schema defined in settings. - "someImplicitCatalog", "someImplicitSchema" } ); + // The default catalog/schema should replace the + // implicit catalog/schema defined in the mapping. + "someDefaultCatalog", "someDefaultSchema" } ); } return params; } From dc00552cf5a6f95ed9b03d0bc17293db789904f0 Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Wed, 8 Dec 2021 13:03:25 +0000 Subject: [PATCH 413/644] 5.6.2.Final --- changelog.txt | 27 +++++++++++++++++++++++++++ gradle/version.properties | 2 +- 2 files changed, 28 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 35e957f9c6f1..3bcb0aef47cc 100644 --- a/changelog.txt +++ b/changelog.txt @@ -3,6 +3,33 @@ Hibernate 5 Changelog Note: Please refer to JIRA to learn more about each issue. +Changes in 5.6.2.Final (December 08, 2021) +------------------------------------------------------------------------------------------------------------------------ + +https://hibernate.atlassian.net/projects/HHH/versions/32001 + +** Bug + * [HHH-14956] - Invalid link to MetadataBuilderContributor javadocs in Configurations docs + * [HHH-14937] - SybaseDialect does not support schema anymore + * [HHH-14936] - JdbcConnectionContext in hibernate-testing throws NPE when user/password are not provided in configuration + * [HHH-14935] - Type annotation is deprecated without an available replacement + * [HHH-14927] - "Current" documentation is 5.5 instead of 5.6 + * [HHH-14926] - fix asciidoc error in 'test-case-guide.adoc' + * [HHH-14922] - Inconsistent precedence of orm.xml implicit catalog/schema over "default_catalog"/"default_schema" + * [HHH-14918] - Key-to-one to id-class entity with key-to-one doesn't work anymore + * [HHH-14916] - JPA Critera query Join on Fetch not working + * [HHH-14540] - Interceptor instance is shared between ORM session and Enver's temporary session resulting in multiple calls. + * [HHH-14211] - @Lob String mapping broken + +** Improvement + * [HHH-14921] - Definition of the default catalog/schema on session factory creation + * [HHH-14903] - Method getConfiguredJdbcBatchSize can be optimised for StatelessSession as well + * [HHH-14897] - Allow ordering with nulls first/last from JPA implementation + +** Task + * [HHH-14938] - Upgrade to MySQL Connector/J 8.0.27 + + Changes in 5.6.1.Final (October 27, 2021) ------------------------------------------------------------------------------------------------------------------------ diff --git a/gradle/version.properties b/gradle/version.properties index 5c72c9b3ea00..5298d1f40ec3 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -hibernateVersion=5.6.2-SNAPSHOT \ No newline at end of file +hibernateVersion=5.6.2.Final \ No newline at end of file From f6f765426b6541e3a144ebff69e004d950e4b507 Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Wed, 8 Dec 2021 13:08:18 +0000 Subject: [PATCH 414/644] 5.6.3-SNAPSHOT --- gradle/version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/version.properties b/gradle/version.properties index 5298d1f40ec3..998d3b40c681 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -hibernateVersion=5.6.2.Final \ No newline at end of file +hibernateVersion=5.6.3-SNAPSHOT \ No newline at end of file From fc957ec91e17197b9ef6fbef514f16c38b334de6 Mon Sep 17 00:00:00 2001 From: Ivaylo Mitrev Date: Thu, 2 Dec 2021 17:38:26 +0200 Subject: [PATCH 415/644] HHH-14948 - Reduce the size of the imports cache in the metamodel We have agreed to mitigate a memory issue by introducing a hard-coded (for the time being) cap on the imports cache in MetamodelImpl. This would preserve the previously available performance improvement for the majority of applications using Hibernate (which are expected to have less than 1000 imports) while mitigating an unbounded memory consumption issue for applications that exceed this limit when dynamically generating queries with random entity aliases. The commit also adds a not-so-beautiful test, which, however, is beneficial considering the consequences of introduing a regression. --- .../metamodel/internal/MetamodelImpl.java | 8 +++++- .../hibernate/test/hql/QuerySplitterTest.java | 27 +++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetamodelImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetamodelImpl.java index 055485700e8d..19c63b85033a 100755 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetamodelImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/internal/MetamodelImpl.java @@ -632,7 +632,13 @@ public String getImportedClassName(String className) { return className; } catch ( ClassLoadingException cnfe ) { - imports.put( className, INVALID_IMPORT ); + // This check doesn't necessarily mean that the map can't exceed 1000 elements because + // new entries might be added _while_ performing the check (making it 1000+ since size() isn't + // synchronized). Regardless, this would pass as "good enough" to prevent the map from growing + // above a certain threshold, thus, avoiding memory issues. + if ( imports.size() < 1_000 ) { + imports.put( className, INVALID_IMPORT ); + } return null; } } diff --git a/hibernate-core/src/test/java/org/hibernate/test/hql/QuerySplitterTest.java b/hibernate-core/src/test/java/org/hibernate/test/hql/QuerySplitterTest.java index 8fe9115577a6..54f3015169e1 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/hql/QuerySplitterTest.java +++ b/hibernate-core/src/test/java/org/hibernate/test/hql/QuerySplitterTest.java @@ -6,11 +6,15 @@ */ package org.hibernate.test.hql; +import java.lang.reflect.Field; +import java.util.Map; +import java.util.stream.IntStream; import javax.persistence.Entity; import javax.persistence.Id; import javax.persistence.Table; import org.hibernate.hql.internal.QuerySplitter; +import org.hibernate.metamodel.internal.MetamodelImpl; import org.hibernate.testing.TestForIssue; import org.hibernate.testing.junit4.BaseNonConfigCoreFunctionalTestCase; @@ -47,6 +51,29 @@ public void testQueryWithEntityNameAsStringLiteral2() { ); } + @Test + @TestForIssue(jiraKey = "HHH-14948") + public void testMemoryConsumptionOfFailedImportsCache() throws NoSuchFieldException, IllegalAccessException { + + IntStream.range( 0, 1001 ) + .forEach( i -> QuerySplitter.concreteQueries( + "from Employee e join e.company" + i, + sessionFactory() + ) ); + + MetamodelImpl metamodel = (MetamodelImpl) sessionFactory().getMetamodel(); + + Field field = MetamodelImpl.class.getDeclaredField( "imports" ); + field.setAccessible( true ); + + //noinspection unchecked + Map imports = (Map) field.get( metamodel ); + + // VERY hard-coded, but considering the possibility of a regression of a memory-related issue, + // it should be worth it + assertEquals( 1000, imports.size() ); + } + @Test @TestForIssue(jiraKey = "HHH-7973" ) public void testQueryWithEntityNameAsStringLiteralAndEscapeQuoteChar() { From ad8723c31b5214a3d9f62db7377ba8144b333043 Mon Sep 17 00:00:00 2001 From: Sebastian Nohn Date: Fri, 10 Dec 2021 14:05:15 +0100 Subject: [PATCH 416/644] HHH-14972 bump log4j to 2.15.0 fixing an RCE (CVE-2021-44228) --- gradle/libraries.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libraries.gradle b/gradle/libraries.gradle index 7ddc2ff28f03..32a22bc26f61 100644 --- a/gradle/libraries.gradle +++ b/gradle/libraries.gradle @@ -116,7 +116,7 @@ ext { // ~~~~~~~~~~~~~~~~~~~~~~~~~~ testing - log4j2: "org.apache.logging.log4j:log4j-core:2.14.1", + log4j2: "org.apache.logging.log4j:log4j-core:2.15.0", junit: "junit:junit:${junitVersion}", byteman: "org.jboss.byteman:byteman:${bytemanVersion}", byteman_install: "org.jboss.byteman:byteman-install:${bytemanVersion}", From ab808954a27ca9cca67979457f3a3e9d5d868469 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Tue, 14 Dec 2021 21:45:29 +0000 Subject: [PATCH 417/644] HHH-14979 Upgrade to Log4J 2 2.16.0 --- gradle/libraries.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libraries.gradle b/gradle/libraries.gradle index 32a22bc26f61..5b057b101481 100644 --- a/gradle/libraries.gradle +++ b/gradle/libraries.gradle @@ -116,7 +116,7 @@ ext { // ~~~~~~~~~~~~~~~~~~~~~~~~~~ testing - log4j2: "org.apache.logging.log4j:log4j-core:2.15.0", + log4j2: "org.apache.logging.log4j:log4j-core:2.16.0", junit: "junit:junit:${junitVersion}", byteman: "org.jboss.byteman:byteman:${bytemanVersion}", byteman_install: "org.jboss.byteman:byteman-install:${bytemanVersion}", From 8d1027f96770196d9e42233b0d433f0209fafa6b Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Wed, 15 Dec 2021 20:31:57 +0000 Subject: [PATCH 418/644] HHH-14935 Revert deprecation of org.hibernate.annotations.Type, TypeDef and TypeDefs --- .../src/main/java/org/hibernate/annotations/Type.java | 3 --- .../src/main/java/org/hibernate/annotations/TypeDef.java | 3 --- .../src/main/java/org/hibernate/annotations/TypeDefs.java | 3 --- 3 files changed, 9 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/Type.java b/hibernate-core/src/main/java/org/hibernate/annotations/Type.java index 3290021b77c8..8b8e40ea172b 100644 --- a/hibernate-core/src/main/java/org/hibernate/annotations/Type.java +++ b/hibernate-core/src/main/java/org/hibernate/annotations/Type.java @@ -24,12 +24,9 @@ * * @author Emmanuel Bernard * @author Steve Ebersole - * - * @deprecated 6.0 will introduce a new type-safe {@code CustomType} annotation */ @Target({FIELD, METHOD}) @Retention(RUNTIME) -@Deprecated public @interface Type { /** * The Hibernate type name. Usually the fully qualified name of an implementation class for diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/TypeDef.java b/hibernate-core/src/main/java/org/hibernate/annotations/TypeDef.java index 51f7c8abe7d4..4810824de0e6 100644 --- a/hibernate-core/src/main/java/org/hibernate/annotations/TypeDef.java +++ b/hibernate-core/src/main/java/org/hibernate/annotations/TypeDef.java @@ -28,13 +28,10 @@ * * @author Emmanuel Bernard * @author Steve Ebersole - * - * @deprecated 6.0 will introduce a new series of type-safe annotations to serve the same purpose */ @Target({TYPE, PACKAGE}) @Retention(RUNTIME) @Repeatable(TypeDefs.class) -@Deprecated public @interface TypeDef { /** * The type name. This is the name that would be used in other locations. diff --git a/hibernate-core/src/main/java/org/hibernate/annotations/TypeDefs.java b/hibernate-core/src/main/java/org/hibernate/annotations/TypeDefs.java index cdc175b0e282..6f05951eafc4 100644 --- a/hibernate-core/src/main/java/org/hibernate/annotations/TypeDefs.java +++ b/hibernate-core/src/main/java/org/hibernate/annotations/TypeDefs.java @@ -18,12 +18,9 @@ * * @author Emmanuel Bernard * @author Steve Ebersole - * - * @deprecated 6.0 will introduce a new series of type-safe annotations to serve the same purpose */ @Target({TYPE, PACKAGE}) @Retention(RUNTIME) -@Deprecated public @interface TypeDefs { /** * The grouping of type definitions. From 2607c9150241bb5fd71f6a339aae6168b45a0044 Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Wed, 15 Dec 2021 22:20:26 +0000 Subject: [PATCH 419/644] 5.6.3.Final --- changelog.txt | 14 ++++++++++++++ gradle/version.properties | 2 +- 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/changelog.txt b/changelog.txt index 3bcb0aef47cc..4337deb1b0db 100644 --- a/changelog.txt +++ b/changelog.txt @@ -3,6 +3,20 @@ Hibernate 5 Changelog Note: Please refer to JIRA to learn more about each issue. +Changes in 5.6.3.Final (December 15, 2021) +------------------------------------------------------------------------------------------------------------------------ + +https://hibernate.atlassian.net/projects/HHH/versions/32006 + +** Bug + * [HHH-14972] - log4j2 <= 2.14.1 has an RCE (CVE-2021-44228) + * [HHH-14948] - Metamodel imports cache increases indefinitely for dynamically generated HQL aliases eventually leading to an OOM + * [HHH-14935] - Type annotation is deprecated without an available replacement + +** Task + * [HHH-14979] - Upgrade to Log4J 2 2.16.0 + + Changes in 5.6.2.Final (December 08, 2021) ------------------------------------------------------------------------------------------------------------------------ diff --git a/gradle/version.properties b/gradle/version.properties index 998d3b40c681..8c9b9ac012dd 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -hibernateVersion=5.6.3-SNAPSHOT \ No newline at end of file +hibernateVersion=5.6.3.Final \ No newline at end of file From 373ac4e1172a6b7f20d12cc58d3fc41c2e5096a0 Mon Sep 17 00:00:00 2001 From: Hibernate-CI Date: Wed, 15 Dec 2021 22:27:45 +0000 Subject: [PATCH 420/644] 5.6.4-SNAPSHOT --- gradle/version.properties | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/version.properties b/gradle/version.properties index 8c9b9ac012dd..6efeb0d047b9 100644 --- a/gradle/version.properties +++ b/gradle/version.properties @@ -1 +1 @@ -hibernateVersion=5.6.3.Final \ No newline at end of file +hibernateVersion=5.6.4-SNAPSHOT \ No newline at end of file From 29a8e533b214c6ccbb30014fe40d2a215bb60303 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Thu, 16 Dec 2021 22:01:04 +0000 Subject: [PATCH 421/644] HHH-14988 Upgrade to ByteBuddy 1.12.5 --- gradle/libraries.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libraries.gradle b/gradle/libraries.gradle index 5b057b101481..01d6a9bb6c00 100644 --- a/gradle/libraries.gradle +++ b/gradle/libraries.gradle @@ -24,7 +24,7 @@ ext { weldVersion = '3.1.5.Final' jakartaWeldVersion = '4.0.1.SP1' - byteBuddyVersion = '1.11.20' + byteBuddyVersion = '1.12.5' agroalVersion = '1.9' From 6f77882fbaeba4931c53445947bb500df00ea5ec Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Sat, 18 Dec 2021 10:21:54 +0000 Subject: [PATCH 422/644] HHH-14987 Upgrade to Log4j 2.17.0 --- gradle/libraries.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libraries.gradle b/gradle/libraries.gradle index 01d6a9bb6c00..2aee8e6005cb 100644 --- a/gradle/libraries.gradle +++ b/gradle/libraries.gradle @@ -116,7 +116,7 @@ ext { // ~~~~~~~~~~~~~~~~~~~~~~~~~~ testing - log4j2: "org.apache.logging.log4j:log4j-core:2.16.0", + log4j2: "org.apache.logging.log4j:log4j-core:2.17.0", junit: "junit:junit:${junitVersion}", byteman: "org.jboss.byteman:byteman:${bytemanVersion}", byteman_install: "org.jboss.byteman:byteman-install:${bytemanVersion}", From 11552b3e93a4f07b2d4968b490810dd6a04d62cc Mon Sep 17 00:00:00 2001 From: Filipe Roque Date: Mon, 3 Jan 2022 19:01:16 +0000 Subject: [PATCH 423/644] HHH-15002 H2 supports 'true' and 'false' boolean literals Cherry picked from 1706141ffc154c1b61e304445a603ebf9a3e0a2e --- .../src/main/java/org/hibernate/dialect/H2Dialect.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java index 319b64943d9d..e114f79769cb 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/H2Dialect.java @@ -245,6 +245,11 @@ public String getForUpdateString() { return " for update"; } + @Override + public String toBooleanValueString(boolean bool) { + return String.valueOf( bool ); + } + @Override public LimitHandler getLimitHandler() { return LIMIT_HANDLER; From 0496515252045384156caef9664f3a104280674d Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Mon, 10 Jan 2022 15:18:05 +0000 Subject: [PATCH 424/644] HHH-14998 Upgrade to GraalVM SDK 21.3.0 --- gradle/libraries.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libraries.gradle b/gradle/libraries.gradle index 2aee8e6005cb..d020731c5a5b 100644 --- a/gradle/libraries.gradle +++ b/gradle/libraries.gradle @@ -44,7 +44,7 @@ ext { jakartaJaxbRuntimeVersion = '3.0.0' //GraalVM - graalvmVersion = '21.2.0' + graalvmVersion = '21.3.0' micrometerVersion = '1.6.1' From 7c67cf72d13d33ad70477ed701867f9a5fbfe159 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Mon, 10 Jan 2022 15:55:41 +0000 Subject: [PATCH 425/644] HHH-15018 OracleTypesHelper shouldn't log stacktraces when the Oracle JDBC driver isn't loadable --- .../src/main/java/org/hibernate/dialect/OracleTypesHelper.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/OracleTypesHelper.java b/hibernate-core/src/main/java/org/hibernate/dialect/OracleTypesHelper.java index 4b757ab4385a..8c18edd73978 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/OracleTypesHelper.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/OracleTypesHelper.java @@ -36,7 +36,7 @@ private OracleTypesHelper() { typeCode = extractOracleCursorTypeValue(); } catch (Exception e) { - log.warn( "Unable to resolve Oracle CURSOR JDBC type code", e ); + log.warn( "Unable to resolve Oracle CURSOR JDBC type code: the class OracleTypesHelper was initialized but the Oracle JDBC driver could not be loaded." ); } oracleCursorTypeSqlType = typeCode; } From a4dde380b7d7009a2dcce70898a8b64c80df6037 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Wed, 12 Jan 2022 11:11:23 +0000 Subject: [PATCH 426/644] HHH-15024 Upgrade to Jandex 2.4.2.Final --- gradle/libraries.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libraries.gradle b/gradle/libraries.gradle index d020731c5a5b..a0b1014a1995 100644 --- a/gradle/libraries.gradle +++ b/gradle/libraries.gradle @@ -57,7 +57,7 @@ ext { // Annotations commons_annotations: "org.hibernate.common:hibernate-commons-annotations:${hibernateCommonsVersion}", - jandex: 'org.jboss:jandex:2.2.3.Final', + jandex: 'org.jboss:jandex:2.4.2.Final', classmate: 'com.fasterxml:classmate:1.5.1', // Dom4J From 3b94ea5f69d40cbd52db83339d15f65503e5b5ad Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Wed, 12 Jan 2022 15:47:57 +0000 Subject: [PATCH 427/644] HHH-15026 Upgrade to Log4J 2.17.1 --- gradle/libraries.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libraries.gradle b/gradle/libraries.gradle index a0b1014a1995..5ed129a99c5f 100644 --- a/gradle/libraries.gradle +++ b/gradle/libraries.gradle @@ -116,7 +116,7 @@ ext { // ~~~~~~~~~~~~~~~~~~~~~~~~~~ testing - log4j2: "org.apache.logging.log4j:log4j-core:2.17.0", + log4j2: "org.apache.logging.log4j:log4j-core:2.17.1", junit: "junit:junit:${junitVersion}", byteman: "org.jboss.byteman:byteman:${bytemanVersion}", byteman_install: "org.jboss.byteman:byteman-install:${bytemanVersion}", From be0f01a6ba6e4019e144a6168354f018fa213f6b Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Fri, 14 Jan 2022 12:17:49 +0000 Subject: [PATCH 428/644] HHH-15028 Upgrade to JBoss Logging 3.4.3.Final --- gradle/libraries.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libraries.gradle b/gradle/libraries.gradle index 5ed129a99c5f..fdb0de62e85f 100644 --- a/gradle/libraries.gradle +++ b/gradle/libraries.gradle @@ -88,7 +88,7 @@ ext { jakarta_cdi: 'jakarta.enterprise:jakarta.enterprise.cdi-api:3.0.0', // logging - logging: 'org.jboss.logging:jboss-logging:3.4.2.Final', + logging: 'org.jboss.logging:jboss-logging:3.4.3.Final', logging_annotations: 'org.jboss.logging:jboss-logging-annotations:2.1.0.Final', logging_processor: 'org.jboss.logging:jboss-logging-processor:2.1.0.Final', From fdd4eb3854e5319b102976175ced5d339bcb51e2 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Sat, 15 Jan 2022 16:41:44 +0000 Subject: [PATCH 429/644] HHH-15031 Upgrade to ByteBuddy 1.12.7 --- gradle/libraries.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/gradle/libraries.gradle b/gradle/libraries.gradle index fdb0de62e85f..ba9581f1d5ab 100644 --- a/gradle/libraries.gradle +++ b/gradle/libraries.gradle @@ -24,7 +24,7 @@ ext { weldVersion = '3.1.5.Final' jakartaWeldVersion = '4.0.1.SP1' - byteBuddyVersion = '1.12.5' + byteBuddyVersion = '1.12.7' agroalVersion = '1.9' From 157716095a2929f0ad9f743eb90b654c066c1370 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Sat, 15 Jan 2022 23:30:52 +0000 Subject: [PATCH 430/644] HHH-15002 Add integration test for the H2 Dialect change --- .../test/booleans/BooleanMappingTest.java | 61 +++++++++++++++++++ .../org/hibernate/test/booleans/Event.java | 38 ++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 hibernate-core/src/test/java/org/hibernate/test/booleans/BooleanMappingTest.java create mode 100644 hibernate-core/src/test/java/org/hibernate/test/booleans/Event.java diff --git a/hibernate-core/src/test/java/org/hibernate/test/booleans/BooleanMappingTest.java b/hibernate-core/src/test/java/org/hibernate/test/booleans/BooleanMappingTest.java new file mode 100644 index 000000000000..adf08a0f7efa --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/booleans/BooleanMappingTest.java @@ -0,0 +1,61 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.booleans; + +import java.util.List; + +import org.hibernate.testing.TestForIssue; +import org.hibernate.testing.junit4.BaseCoreFunctionalTestCase; +import org.junit.Test; + +import static org.hibernate.testing.transaction.TransactionUtil.doInHibernate; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; + +/** + * Useful to verify Boolean mappings; in particular we had a new + * error on recent versions of H2, so let's ensure this works + * on whatever version the testsuite is being run with. + */ +public class BooleanMappingTest extends BaseCoreFunctionalTestCase { + + @Test + @TestForIssue(jiraKey = "HHH-15002") + public void testFetchEager() { + doInHibernate( this::sessionFactory, s -> { + Event activeEvent = new Event(); + activeEvent.setActive( Boolean.TRUE ); + s.persist( activeEvent ); + + Event inactiveEvent = new Event(); + inactiveEvent.setActive( Boolean.FALSE ); + s.persist( inactiveEvent ); + } ); + + final List activeEvents = doInHibernate( this::sessionFactory, s -> { + return s.createQuery( "SELECT e FROM Event e WHERE e.active = true", Event.class ).getResultList(); + } ); + + assertNotNull( activeEvents ); + assertEquals( 1, activeEvents.size() ); + + final List allEvents = doInHibernate( this::sessionFactory, s -> { + return s.createQuery( "FROM Event", Event.class ).getResultList(); + } ); + + assertNotNull( allEvents ); + assertEquals( 2, allEvents.size() ); + } + + @Override + protected Class[] getAnnotatedClasses() { + return new Class[] { + Event.class, + }; + } + +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/booleans/Event.java b/hibernate-core/src/test/java/org/hibernate/test/booleans/Event.java new file mode 100644 index 000000000000..37503f3e287a --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/booleans/Event.java @@ -0,0 +1,38 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later. + * See the lgpl.txt file in the root directory or . + */ +package org.hibernate.test.booleans; + +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.Id; + +@Entity +public class Event { + + @Id + @GeneratedValue + private Long id; + + private Boolean active; + + public Long getId() { + return id; + } + + public void setId(Long id) { + this.id = id; + } + + public Boolean getActive() { + return active; + } + + public void setActive(Boolean active) { + this.active = active; + } + +} From 30b0ad267e02654dcb6d7cd03d7c604aeb71c143 Mon Sep 17 00:00:00 2001 From: Sanne Grinovero Date: Tue, 4 Jan 2022 16:54:13 +0000 Subject: [PATCH 431/644] HHH-15033 Restrict JNDI lookups to "java" scheme --- .../org/hibernate/engine/jndi/JndiException.java | 10 ++++++++++ .../engine/jndi/internal/JndiServiceImpl.java | 12 ++++++++++++ 2 files changed, 22 insertions(+) diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jndi/JndiException.java b/hibernate-core/src/main/java/org/hibernate/engine/jndi/JndiException.java index 0d28b6632fb3..d18076e59698 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jndi/JndiException.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jndi/JndiException.java @@ -22,4 +22,14 @@ public class JndiException extends HibernateException { public JndiException(String message, Throwable cause) { super( message, cause ); } + + /** + * Constructs a JndiException + * + * @param message Message explaining the exception condition + */ + public JndiException(String message) { + super( message ); + } + } diff --git a/hibernate-core/src/main/java/org/hibernate/engine/jndi/internal/JndiServiceImpl.java b/hibernate-core/src/main/java/org/hibernate/engine/jndi/internal/JndiServiceImpl.java index 48ae9156cc6f..001a52a8d5e5 100644 --- a/hibernate-core/src/main/java/org/hibernate/engine/jndi/internal/JndiServiceImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/engine/jndi/internal/JndiServiceImpl.java @@ -6,6 +6,8 @@ */ package org.hibernate.engine.jndi.internal; +import java.net.URI; +import java.net.URISyntaxException; import java.util.Hashtable; import java.util.Map; import java.util.Properties; @@ -114,6 +116,16 @@ private InitialContext buildInitialContext() { } private Name parseName(String jndiName, Context context) { + try { + final URI uri = new URI( jndiName ); + final String scheme = uri.getScheme(); + if ( scheme != null && (! "java".equals( scheme ) ) ) { + throw new JndiException( "JNDI lookups for scheme '" + scheme + "' are not allowed" ); + } + } + catch (URISyntaxException e) { + //Ok + } try { return context.getNameParser( "" ).parse( jndiName ); } From ca2b8cb2f39dc30a2d83a952d8d39486e6924f9c Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Mon, 17 Jan 2022 17:07:43 +0100 Subject: [PATCH 432/644] HHH-15032 Fix backwards incompatible SPI change that happened in 5.6.2 due to introducing SqlStringGenerationContext --- .../hql/spi/id/MultiTableBulkIdStrategy.java | 28 ++++++++++++++-- .../hibernate/tool/schema/spi/Exporter.java | 32 +++++++++++++++++-- 2 files changed, 56 insertions(+), 4 deletions(-) diff --git a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/MultiTableBulkIdStrategy.java b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/MultiTableBulkIdStrategy.java index 48553f3b128a..b9c6c95148cb 100644 --- a/hibernate-core/src/main/java/org/hibernate/hql/spi/id/MultiTableBulkIdStrategy.java +++ b/hibernate-core/src/main/java/org/hibernate/hql/spi/id/MultiTableBulkIdStrategy.java @@ -23,6 +23,28 @@ * @author Steve Ebersole */ public interface MultiTableBulkIdStrategy { + + /** + * Prepare the strategy. Called as the SessionFactory is being built. Intended patterns here include:
      + *
    • Adding tables to the passed Mappings, to be picked by by "schema management tools"
    • + *
    • Manually creating the tables immediately through the passed JDBC Connection access
    • + *
    + * @param jdbcServices The JdbcService object + * @param connectionAccess Access to the JDBC Connection + * @param metadata Access to the O/RM mapping information + * @param sessionFactoryOptions + * @deprecated Will be removed in favor of the variant accepting a {@link SqlStringGenerationContext} + * @see #prepare(JdbcServices, JdbcConnectionAccess, MetadataImplementor, SessionFactoryOptions, SqlStringGenerationContext) + */ + @Deprecated + default void prepare( + JdbcServices jdbcServices, + JdbcConnectionAccess connectionAccess, + MetadataImplementor metadata, + SessionFactoryOptions sessionFactoryOptions) { + throw new IllegalStateException("prepare() was not implemented!"); + } + /** * Prepare the strategy. Called as the SessionFactory is being built. Intended patterns here include: