From 8d93c0ca3387a71c4055a840b1118148577f9530 Mon Sep 17 00:00:00 2001 From: Christian Beikov Date: Thu, 2 Mar 2023 20:36:48 +0100 Subject: [PATCH] HHH-16224 Refactor discovery of exact JDBC drivers, avoid static state in specialized types --- .../dialect/CockroachLegacyDialect.java | 16 +- .../dialect/OracleLegacyDialect.java | 24 +- .../dialect/PostgreSQLLegacyDialect.java | 29 +- hibernate-core/hibernate-core.gradle | 1 + .../AbstractPostgreSQLJsonJdbcType.java | 74 ---- .../AbstractPostgreSQLJsonPGObjectType.java | 106 +++++ ... => AbstractPostgreSQLStructJdbcType.java} | 83 ++-- .../hibernate/dialect/CockroachDialect.java | 8 +- .../dialect/OracleArrayJdbcType.java | 81 +--- .../org/hibernate/dialect/OracleDialect.java | 19 +- .../hibernate/dialect/OracleJdbcHelper.java | 59 +++ .../OracleReflectionStructJdbcType.java | 91 ++++ .../dialect/OracleStructJdbcType.java | 405 +----------------- .../org/hibernate/dialect/OracleTypes.java | 1 + .../hibernate/dialect/OracleTypesHelper.java | 111 ----- .../org/hibernate/dialect/PgJdbcHelper.java | 71 +++ .../hibernate/dialect/PostgreSQLDialect.java | 14 +- .../dialect/PostgreSQLInetJdbcType.java | 90 +++- .../PostgreSQLIntervalSecondJdbcType.java | 96 +---- ...va => PostgreSQLJsonPGObjectJsonType.java} | 14 +- ...a => PostgreSQLJsonPGObjectJsonbType.java} | 14 +- .../dialect/PostgreSQLPGObjectJdbcType.java | 176 -------- ...a => PostgreSQLStructCastingJdbcType.java} | 15 +- .../PostgreSQLStructPGObjectJdbcType.java | 102 +++++ .../org/hibernate/dialect/StructJdbcType.java | 401 +++++++++++++++++ .../PostgreSQLCallableStatementSupport.java | 6 +- .../type/descriptor/jdbc/ArrayJdbcType.java | 33 +- .../test/id/usertype/inet/InetJdbcType.java | 1 + .../orm/test/id/usertype/json/JsonType.java | 4 +- .../contributor/ContributorImplementor.java | 4 +- .../contributor/SpatialTypeContributor.java | 4 +- .../cockroachdb/CockroachDbContributor.java | 6 +- .../h2gis/H2GisDialectContributor.java | 2 +- .../mariadb/MariaDBDialectContributor.java | 2 +- .../mysql/MySQLDialectContributor.java | 2 +- .../oracle/OracleDialectContributor.java | 2 +- .../postgis/PostgisDialectContributor.java | 12 +- .../SqlServerDialectContributor.java | 2 +- 38 files changed, 1131 insertions(+), 1050 deletions(-) delete mode 100644 hibernate-core/src/main/java/org/hibernate/dialect/AbstractPostgreSQLJsonJdbcType.java create mode 100644 hibernate-core/src/main/java/org/hibernate/dialect/AbstractPostgreSQLJsonPGObjectType.java rename hibernate-core/src/main/java/org/hibernate/dialect/{PostgreSQLStructJdbcType.java => AbstractPostgreSQLStructJdbcType.java} (94%) create mode 100644 hibernate-core/src/main/java/org/hibernate/dialect/OracleJdbcHelper.java create mode 100644 hibernate-core/src/main/java/org/hibernate/dialect/OracleReflectionStructJdbcType.java delete mode 100644 hibernate-core/src/main/java/org/hibernate/dialect/OracleTypesHelper.java create mode 100644 hibernate-core/src/main/java/org/hibernate/dialect/PgJdbcHelper.java rename hibernate-core/src/main/java/org/hibernate/dialect/{PostgreSQLJsonbJdbcType.java => PostgreSQLJsonPGObjectJsonType.java} (64%) rename hibernate-core/src/main/java/org/hibernate/dialect/{PostgreSQLJsonJdbcType.java => PostgreSQLJsonPGObjectJsonbType.java} (64%) delete mode 100644 hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLPGObjectJdbcType.java rename hibernate-core/src/main/java/org/hibernate/dialect/{PostgreSQLCastingStructJdbcType.java => PostgreSQLStructCastingJdbcType.java} (83%) create mode 100644 hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLStructPGObjectJdbcType.java create mode 100644 hibernate-core/src/main/java/org/hibernate/dialect/StructJdbcType.java diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacyDialect.java index c0e6ba38ed..1b0cb8c089 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/CockroachLegacyDialect.java @@ -30,15 +30,11 @@ import org.hibernate.boot.model.TypeContributions; import org.hibernate.dialect.DatabaseVersion; import org.hibernate.dialect.Dialect; import org.hibernate.dialect.NationalizationSupport; +import org.hibernate.dialect.PgJdbcHelper; import org.hibernate.dialect.PostgreSQLCastingInetJdbcType; import org.hibernate.dialect.PostgreSQLCastingIntervalSecondJdbcType; import org.hibernate.dialect.PostgreSQLCastingJsonJdbcType; import org.hibernate.dialect.PostgreSQLDriverKind; -import org.hibernate.dialect.PostgreSQLInetJdbcType; -import org.hibernate.dialect.PostgreSQLIntervalSecondJdbcType; -import org.hibernate.dialect.PostgreSQLJsonJdbcType; -import org.hibernate.dialect.PostgreSQLJsonbJdbcType; -import org.hibernate.dialect.PostgreSQLPGObjectJdbcType; import org.hibernate.dialect.RowLockStrategy; import org.hibernate.dialect.SimpleDatabaseVersion; import org.hibernate.dialect.SpannerDialect; @@ -331,15 +327,15 @@ public class CockroachLegacyDialect extends Dialect { jdbcTypeRegistry.addDescriptor( TIMESTAMP_UTC, InstantAsTimestampWithTimeZoneJdbcType.INSTANCE ); if ( driverKind == PostgreSQLDriverKind.PG_JDBC ) { jdbcTypeRegistry.addDescriptorIfAbsent( UUIDJdbcType.INSTANCE ); - if ( PostgreSQLPGObjectJdbcType.isUsable() ) { - jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLIntervalSecondJdbcType.INSTANCE ); + if ( PgJdbcHelper.isUsable( serviceRegistry ) ) { + jdbcTypeRegistry.addDescriptorIfAbsent( PgJdbcHelper.getIntervalJdbcType( serviceRegistry ) ); if ( getVersion().isSameOrAfter( 20, 0 ) ) { - jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLInetJdbcType.INSTANCE ); - jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLJsonbJdbcType.INSTANCE ); + jdbcTypeRegistry.addDescriptorIfAbsent( PgJdbcHelper.getInetJdbcType( serviceRegistry ) ); + jdbcTypeRegistry.addDescriptorIfAbsent( PgJdbcHelper.getJsonbJdbcType( serviceRegistry ) ); } else { - jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLJsonJdbcType.INSTANCE ); + jdbcTypeRegistry.addDescriptorIfAbsent( PgJdbcHelper.getJsonJdbcType( serviceRegistry ) ); } } else { diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacyDialect.java index 6f64cb7350..615634a848 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/OracleLegacyDialect.java @@ -23,12 +23,11 @@ import org.hibernate.cfg.Environment; import org.hibernate.dialect.BooleanDecoder; import org.hibernate.dialect.DatabaseVersion; import org.hibernate.dialect.Dialect; -import org.hibernate.dialect.OracleArrayJdbcType; import org.hibernate.dialect.OracleBooleanJdbcType; +import org.hibernate.dialect.OracleJdbcHelper; import org.hibernate.dialect.OracleJsonJdbcType; +import org.hibernate.dialect.OracleReflectionStructJdbcType; import org.hibernate.dialect.OracleTypes; -import org.hibernate.dialect.OracleStructJdbcType; -import org.hibernate.dialect.OracleTypesHelper; import org.hibernate.dialect.OracleXmlJdbcType; import org.hibernate.dialect.Replacer; import org.hibernate.dialect.RowLockStrategy; @@ -94,6 +93,7 @@ import org.hibernate.type.SqlTypes; import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.descriptor.java.PrimitiveByteArrayJavaType; import org.hibernate.type.descriptor.jdbc.AggregateJdbcType; +import org.hibernate.type.descriptor.jdbc.ArrayJdbcType; import org.hibernate.type.descriptor.jdbc.BlobJdbcType; import org.hibernate.type.descriptor.jdbc.JdbcType; import org.hibernate.type.descriptor.jdbc.OracleJsonBlobJdbcType; @@ -777,7 +777,12 @@ public class OracleLegacyDialect extends Dialect { typeContributions.contributeJdbcType( OracleBooleanJdbcType.INSTANCE ); typeContributions.contributeJdbcType( OracleXmlJdbcType.INSTANCE ); - typeContributions.contributeJdbcType( OracleStructJdbcType.INSTANCE ); + if ( OracleJdbcHelper.isUsable( serviceRegistry ) ) { + typeContributions.contributeJdbcType( OracleJdbcHelper.getStructJdbcType( serviceRegistry ) ); + } + else { + typeContributions.contributeJdbcType( OracleReflectionStructJdbcType.INSTANCE ); + } if ( getVersion().isSameOrAfter( 12 ) ) { // account for Oracle's deprecated support for LONGVARBINARY @@ -802,7 +807,12 @@ public class OracleLegacyDialect extends Dialect { } } - typeContributions.contributeJdbcType( OracleArrayJdbcType.INSTANCE ); + if ( OracleJdbcHelper.isUsable( serviceRegistry ) ) { + typeContributions.contributeJdbcType( OracleJdbcHelper.getArrayJdbcType( serviceRegistry ) ); + } + else { + typeContributions.contributeJdbcType( ArrayJdbcType.INSTANCE ); + } // Oracle requires a custom binder for binding untyped nulls with the NULL type typeContributions.contributeJdbcType( NullJdbcType.INSTANCE ); typeContributions.contributeJdbcType( ObjectNullAsNullTypeJdbcType.INSTANCE ); @@ -984,7 +994,7 @@ public class OracleLegacyDialect extends Dialect { @Override public int registerResultSetOutParameter(CallableStatement statement, int col) throws SQLException { // register the type of the out param - an Oracle specific type - statement.registerOutParameter( col, OracleTypesHelper.INSTANCE.getOracleCursorTypeSqlType() ); + statement.registerOutParameter( col, OracleTypes.CURSOR ); col++; return col; } @@ -1371,7 +1381,7 @@ public class OracleLegacyDialect extends Dialect { @Override public int registerResultSetOutParameter(CallableStatement statement, String name) throws SQLException { - statement.registerOutParameter( name, OracleTypesHelper.INSTANCE.getOracleCursorTypeSqlType() ); + statement.registerOutParameter( name, OracleTypes.CURSOR ); return 1; } diff --git a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgreSQLLegacyDialect.java b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgreSQLLegacyDialect.java index 7b7d330328..fec96ae927 100644 --- a/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgreSQLLegacyDialect.java +++ b/hibernate-community-dialects/src/main/java/org/hibernate/community/dialect/PostgreSQLLegacyDialect.java @@ -30,17 +30,12 @@ import org.hibernate.dialect.DatabaseVersion; import org.hibernate.dialect.Dialect; import org.hibernate.dialect.NationalizationSupport; import org.hibernate.dialect.OracleDialect; +import org.hibernate.dialect.PgJdbcHelper; import org.hibernate.dialect.PostgreSQLCastingInetJdbcType; import org.hibernate.dialect.PostgreSQLCastingIntervalSecondJdbcType; import org.hibernate.dialect.PostgreSQLCastingJsonJdbcType; -import org.hibernate.dialect.PostgreSQLCastingStructJdbcType; import org.hibernate.dialect.PostgreSQLDriverKind; -import org.hibernate.dialect.PostgreSQLInetJdbcType; -import org.hibernate.dialect.PostgreSQLIntervalSecondJdbcType; -import org.hibernate.dialect.PostgreSQLJsonJdbcType; -import org.hibernate.dialect.PostgreSQLJsonbJdbcType; -import org.hibernate.dialect.PostgreSQLPGObjectJdbcType; -import org.hibernate.dialect.PostgreSQLStructJdbcType; +import org.hibernate.dialect.PostgreSQLStructCastingJdbcType; import org.hibernate.dialect.Replacer; import org.hibernate.dialect.RowLockStrategy; import org.hibernate.dialect.SelectItemReferenceStrategy; @@ -1334,15 +1329,15 @@ public class PostgreSQLLegacyDialect extends Dialect { jdbcTypeRegistry.addDescriptor( XmlJdbcType.INSTANCE ); if ( driverKind == PostgreSQLDriverKind.PG_JDBC ) { - if ( PostgreSQLPGObjectJdbcType.isUsable() ) { - jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLInetJdbcType.INSTANCE ); - jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLIntervalSecondJdbcType.INSTANCE ); - jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLStructJdbcType.INSTANCE ); + if ( PgJdbcHelper.isUsable( serviceRegistry ) ) { + jdbcTypeRegistry.addDescriptorIfAbsent( PgJdbcHelper.getInetJdbcType( serviceRegistry ) ); + jdbcTypeRegistry.addDescriptorIfAbsent( PgJdbcHelper.getIntervalJdbcType( serviceRegistry ) ); + jdbcTypeRegistry.addDescriptorIfAbsent( PgJdbcHelper.getStructJdbcType( serviceRegistry ) ); } else { jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingInetJdbcType.INSTANCE ); jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingIntervalSecondJdbcType.INSTANCE ); - jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingStructJdbcType.INSTANCE ); + jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLStructCastingJdbcType.INSTANCE ); } if ( getVersion().isSameOrAfter( 8, 2 ) ) { @@ -1350,16 +1345,16 @@ public class PostgreSQLLegacyDialect extends Dialect { jdbcTypeRegistry.addDescriptorIfAbsent( UUIDJdbcType.INSTANCE ); if ( getVersion().isSameOrAfter( 9, 2 ) ) { if ( getVersion().isSameOrAfter( 9, 4 ) ) { - if ( PostgreSQLPGObjectJdbcType.isUsable() ) { - jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLJsonbJdbcType.INSTANCE ); + if ( PgJdbcHelper.isUsable( serviceRegistry ) ) { + jdbcTypeRegistry.addDescriptorIfAbsent( PgJdbcHelper.getJsonbJdbcType( serviceRegistry ) ); } else { jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingJsonJdbcType.JSONB_INSTANCE ); } } else { - if ( PostgreSQLPGObjectJdbcType.isUsable() ) { - jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLJsonJdbcType.INSTANCE ); + if ( PgJdbcHelper.isUsable( serviceRegistry ) ) { + jdbcTypeRegistry.addDescriptorIfAbsent( PgJdbcHelper.getJsonJdbcType( serviceRegistry ) ); } else { jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingJsonJdbcType.JSON_INSTANCE ); @@ -1371,7 +1366,7 @@ public class PostgreSQLLegacyDialect extends Dialect { else { jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingInetJdbcType.INSTANCE ); jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingIntervalSecondJdbcType.INSTANCE ); - jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingStructJdbcType.INSTANCE ); + jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLStructCastingJdbcType.INSTANCE ); if ( getVersion().isSameOrAfter( 8, 2 ) ) { jdbcTypeRegistry.addDescriptorIfAbsent( UUIDJdbcType.INSTANCE ); diff --git a/hibernate-core/hibernate-core.gradle b/hibernate-core/hibernate-core.gradle index e516027fb9..41353a722e 100644 --- a/hibernate-core/hibernate-core.gradle +++ b/hibernate-core/hibernate-core.gradle @@ -45,6 +45,7 @@ dependencies { compileOnly jakartaLibs.jsonbApi compileOnly libs.jackson compileOnly libs.jacksonXml + compileOnly dbLibs.postgresql testImplementation project(':hibernate-testing') testImplementation project(':hibernate-ant') diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/AbstractPostgreSQLJsonJdbcType.java b/hibernate-core/src/main/java/org/hibernate/dialect/AbstractPostgreSQLJsonJdbcType.java deleted file mode 100644 index 4dea9f6db5..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/dialect/AbstractPostgreSQLJsonJdbcType.java +++ /dev/null @@ -1,74 +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.dialect; - -import java.sql.SQLException; - -import org.hibernate.metamodel.mapping.EmbeddableMappingType; -import org.hibernate.type.SqlTypes; -import org.hibernate.type.descriptor.WrapperOptions; -import org.hibernate.type.descriptor.java.JavaType; -import org.hibernate.type.descriptor.jdbc.AggregateJdbcType; - -/** - * @author Christian Beikov - */ -public abstract class AbstractPostgreSQLJsonJdbcType extends PostgreSQLPGObjectJdbcType implements AggregateJdbcType { - - private final EmbeddableMappingType embeddableMappingType; - - public AbstractPostgreSQLJsonJdbcType(EmbeddableMappingType embeddableMappingType, String typeName) { - super( typeName, SqlTypes.JSON ); - this.embeddableMappingType = embeddableMappingType; - } - - @Override - public EmbeddableMappingType getEmbeddableMappingType() { - return embeddableMappingType; - } - - @Override - protected X fromString(String string, JavaType javaType, WrapperOptions options) throws SQLException { - if ( embeddableMappingType != null ) { - return JsonHelper.fromString( - embeddableMappingType, - string, - javaType.getJavaTypeClass() != Object[].class, - options - ); - } - return options.getSessionFactory().getFastSessionServices().getJsonFormatMapper().fromString( - string, - javaType, - options - ); - } - - @Override - protected String toString(X value, JavaType javaType, WrapperOptions options) { - if ( embeddableMappingType != null ) { - return JsonHelper.toString( embeddableMappingType, value, options ); - } - return options.getSessionFactory().getFastSessionServices().getJsonFormatMapper().toString( - value, - javaType, - options - ); - } - - @Override - public Object createJdbcValue(Object domainValue, WrapperOptions options) throws SQLException { - assert embeddableMappingType != null; - return JsonHelper.toString( embeddableMappingType, domainValue, options ); - } - - @Override - public Object[] extractJdbcValues(Object rawJdbcValue, WrapperOptions options) throws SQLException { - assert embeddableMappingType != null; - return JsonHelper.fromString( embeddableMappingType, (String) rawJdbcValue, false, options ); - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/AbstractPostgreSQLJsonPGObjectType.java b/hibernate-core/src/main/java/org/hibernate/dialect/AbstractPostgreSQLJsonPGObjectType.java new file mode 100644 index 0000000000..3641204bdb --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/dialect/AbstractPostgreSQLJsonPGObjectType.java @@ -0,0 +1,106 @@ +/* + * Hibernate, Relational Persistence for 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; + +import java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; + +import org.hibernate.metamodel.mapping.EmbeddableMappingType; +import org.hibernate.type.SqlTypes; +import org.hibernate.type.descriptor.ValueBinder; +import org.hibernate.type.descriptor.ValueExtractor; +import org.hibernate.type.descriptor.WrapperOptions; +import org.hibernate.type.descriptor.java.JavaType; +import org.hibernate.type.descriptor.jdbc.BasicBinder; +import org.hibernate.type.descriptor.jdbc.BasicExtractor; +import org.hibernate.type.descriptor.jdbc.JsonJdbcType; + +import org.postgresql.util.PGobject; + +/** + * @author Christian Beikov + */ +public abstract class AbstractPostgreSQLJsonPGObjectType extends JsonJdbcType { + + private final boolean jsonb; + protected AbstractPostgreSQLJsonPGObjectType(EmbeddableMappingType embeddableMappingType, boolean jsonb) { + super( embeddableMappingType ); + this.jsonb = jsonb; + } + + @Override + public int getJdbcTypeCode() { + return SqlTypes.OTHER; + } + + @Override + public ValueBinder getBinder(JavaType javaType) { + return new BasicBinder<>( javaType, this ) { + @Override + protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) + throws SQLException { + final String stringValue = ( (AbstractPostgreSQLJsonPGObjectType) getJdbcType() ).toString( + value, + getJavaType(), + options + ); + final PGobject holder = new PGobject(); + holder.setType( jsonb ? "jsonb" : "json" ); + holder.setValue( stringValue ); + st.setObject( index, holder ); + } + + @Override + protected void doBind(CallableStatement st, X value, String name, WrapperOptions options) + throws SQLException { + final String stringValue = ( (AbstractPostgreSQLJsonPGObjectType) getJdbcType() ).toString( + value, + getJavaType(), + options + ); + final PGobject holder = new PGobject(); + holder.setType( jsonb ? "jsonb" : "json" ); + holder.setValue( stringValue ); + st.setObject( name, holder ); + } + }; + } + + @Override + public ValueExtractor getExtractor(JavaType javaType) { + return new BasicExtractor<>( javaType, this ) { + @Override + protected X doExtract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException { + return getObject( rs.getObject( paramIndex ), options ); + } + + @Override + protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException { + return getObject( statement.getObject( index ), options ); + } + + @Override + protected X doExtract(CallableStatement statement, String name, WrapperOptions options) + throws SQLException { + return getObject( statement.getObject( name ), options ); + } + + private X getObject(Object object, WrapperOptions options) throws SQLException { + if ( object == null ) { + return null; + } + return ( (AbstractPostgreSQLJsonPGObjectType) getJdbcType() ).fromString( + object.toString(), + getJavaType(), + options + ); + } + }; + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLStructJdbcType.java b/hibernate-core/src/main/java/org/hibernate/dialect/AbstractPostgreSQLStructJdbcType.java similarity index 94% rename from hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLStructJdbcType.java rename to hibernate-core/src/main/java/org/hibernate/dialect/AbstractPostgreSQLStructJdbcType.java index 317f4780b5..01570ef28b 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLStructJdbcType.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/AbstractPostgreSQLStructJdbcType.java @@ -6,6 +6,10 @@ */ package org.hibernate.dialect; +import java.lang.reflect.Constructor; +import java.lang.reflect.Method; +import java.sql.CallableStatement; +import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Timestamp; import java.time.Instant; @@ -30,6 +34,7 @@ import org.hibernate.metamodel.mapping.MappingType; import org.hibernate.metamodel.mapping.SelectableMapping; import org.hibernate.metamodel.mapping.internal.EmbeddedAttributeMapping; import org.hibernate.metamodel.spi.RuntimeModelCreationContext; +import org.hibernate.service.ServiceRegistry; import org.hibernate.sql.ast.spi.SqlAppender; import org.hibernate.sql.ast.spi.StringBuilderSqlAppender; import org.hibernate.type.SqlTypes; @@ -39,6 +44,7 @@ import org.hibernate.type.descriptor.java.JavaType; import org.hibernate.type.descriptor.java.PrimitiveByteArrayJavaType; import org.hibernate.type.descriptor.java.spi.UnknownBasicJavaType; import org.hibernate.type.descriptor.jdbc.AggregateJdbcType; +import org.hibernate.type.descriptor.jdbc.BasicExtractor; import org.hibernate.type.spi.TypeConfiguration; import static org.hibernate.type.descriptor.DateTimeUtils.appendAsDate; @@ -54,9 +60,7 @@ import static org.hibernate.type.descriptor.DateTimeUtils.appendAsTimestampWithM * * @author Christian Beikov */ -public class PostgreSQLStructJdbcType extends PostgreSQLPGObjectJdbcType implements AggregateJdbcType { - - public static final PostgreSQLStructJdbcType INSTANCE = new PostgreSQLStructJdbcType( null, null, null ); +public abstract class AbstractPostgreSQLStructJdbcType implements AggregateJdbcType { private static final DateTimeFormatter LOCAL_DATE_TIME; static { @@ -83,14 +87,16 @@ public class PostgreSQLStructJdbcType extends PostgreSQLPGObjectJdbcType impleme .appendOffset( "+HH:mm", "+00" ) .toFormatter(); } - + private final String typeName; private final int[] orderMapping; private final int[] inverseOrderMapping; private final EmbeddableMappingType embeddableMappingType; - private final ValueExtractor objectArrayExtractor; - public PostgreSQLStructJdbcType(EmbeddableMappingType embeddableMappingType, String typeName, int[] orderMapping) { - super( typeName, SqlTypes.STRUCT ); + protected AbstractPostgreSQLStructJdbcType( + EmbeddableMappingType embeddableMappingType, + String typeName, + int[] orderMapping) { + this.typeName = typeName; this.embeddableMappingType = embeddableMappingType; this.orderMapping = orderMapping; if ( orderMapping == null ) { @@ -103,10 +109,6 @@ public class PostgreSQLStructJdbcType extends PostgreSQLPGObjectJdbcType impleme } this.inverseOrderMapping = inverseOrderMapping; } - // We cache the extractor for Obje - // We cache the extractor for Object[] here - // since that is used in AggregateEmbeddableFetchImpl and AggregateEmbeddableResultImpl - this.objectArrayExtractor = super.getExtractor( new UnknownBasicJavaType<>( Object[].class ) ); } @Override @@ -114,20 +116,8 @@ public class PostgreSQLStructJdbcType extends PostgreSQLPGObjectJdbcType impleme return SqlTypes.STRUCT; } - @Override - public AggregateJdbcType resolveAggregateJdbcType( - EmbeddableMappingType mappingType, - String sqlType, - RuntimeModelCreationContext creationContext) { - return new PostgreSQLStructJdbcType( - mappingType, - sqlType, - creationContext.getBootModel() - .getDatabase() - .getDefaultNamespace() - .locateUserDefinedType( Identifier.toIdentifier( sqlType ) ) - .getOrderMapping() - ); + public String getTypeName() { + return typeName; } @Override @@ -151,14 +141,36 @@ public class PostgreSQLStructJdbcType extends PostgreSQLPGObjectJdbcType impleme @Override public ValueExtractor getExtractor(JavaType javaType) { - if ( javaType.getJavaTypeClass() == Object[].class ) { - //noinspection unchecked - return (ValueExtractor) objectArrayExtractor; - } - return super.getExtractor( javaType ); + return new BasicExtractor<>( javaType, this ) { + @Override + protected X doExtract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException { + return getObject( rs.getObject( paramIndex ), options ); + } + + @Override + protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException { + return getObject( statement.getObject( index ), options ); + } + + @Override + protected X doExtract(CallableStatement statement, String name, WrapperOptions options) + throws SQLException { + return getObject( statement.getObject( name ), options ); + } + + private X getObject(Object object, WrapperOptions options) throws SQLException { + if ( object == null ) { + return null; + } + return ( (AbstractPostgreSQLStructJdbcType) getJdbcType() ).fromString( + object.toString(), + getJavaType(), + options + ); + } + }; } - @Override protected X fromString(String string, JavaType javaType, WrapperOptions options) throws SQLException { if ( string == null ) { return null; @@ -407,9 +419,9 @@ public class PostgreSQLStructJdbcType extends PostgreSQLPGObjectJdbcType impleme if ( string.charAt( i + 1 ) == '(' ) { // This could be a nested struct final JdbcMapping jdbcMapping = getJdbcValueSelectable( column ).getJdbcMapping(); - if ( jdbcMapping.getJdbcType() instanceof PostgreSQLStructJdbcType ) { - final PostgreSQLStructJdbcType structJdbcType; - structJdbcType = (PostgreSQLStructJdbcType) jdbcMapping.getJdbcType(); + if ( jdbcMapping.getJdbcType() instanceof AbstractPostgreSQLStructJdbcType ) { + final AbstractPostgreSQLStructJdbcType structJdbcType; + structJdbcType = (AbstractPostgreSQLStructJdbcType) jdbcMapping.getJdbcType(); final Object[] subValues = new Object[structJdbcType.embeddableMappingType.getJdbcValueCount()]; final int subEnd = structJdbcType.deserializeStruct( string, @@ -655,7 +667,6 @@ public class PostgreSQLStructJdbcType extends PostgreSQLPGObjectJdbcType impleme return array; } - @Override protected String toString(X value, JavaType javaType, WrapperOptions options) { if ( value == null ) { return null; @@ -718,7 +729,7 @@ public class PostgreSQLStructJdbcType extends PostgreSQLPGObjectJdbcType impleme continue; } appender.quoteStart(); - ( (PostgreSQLStructJdbcType) aggregateMapping.getJdbcMapping().getJdbcType() ).serializeStructTo( + ( (AbstractPostgreSQLStructJdbcType) aggregateMapping.getJdbcMapping().getJdbcType() ).serializeStructTo( appender, attributeValue, options diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/CockroachDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/CockroachDialect.java index a119f539ec..0d9283b740 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/CockroachDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/CockroachDialect.java @@ -342,10 +342,10 @@ public class CockroachDialect extends Dialect { jdbcTypeRegistry.addDescriptor( TIMESTAMP_UTC, InstantAsTimestampWithTimeZoneJdbcType.INSTANCE ); if ( driverKind == PostgreSQLDriverKind.PG_JDBC ) { jdbcTypeRegistry.addDescriptorIfAbsent( UUIDJdbcType.INSTANCE ); - if ( PostgreSQLPGObjectJdbcType.isUsable() ) { - jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLIntervalSecondJdbcType.INSTANCE ); - jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLInetJdbcType.INSTANCE ); - jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLJsonbJdbcType.INSTANCE ); + if ( PgJdbcHelper.isUsable( serviceRegistry ) ) { + jdbcTypeRegistry.addDescriptorIfAbsent( PgJdbcHelper.getIntervalJdbcType( serviceRegistry ) ); + jdbcTypeRegistry.addDescriptorIfAbsent( PgJdbcHelper.getInetJdbcType( serviceRegistry ) ); + jdbcTypeRegistry.addDescriptorIfAbsent( PgJdbcHelper.getJsonbJdbcType( serviceRegistry ) ); } else { jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingIntervalSecondJdbcType.INSTANCE ); diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/OracleArrayJdbcType.java b/hibernate-core/src/main/java/org/hibernate/dialect/OracleArrayJdbcType.java index 8f90de9e49..088f94a26b 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/OracleArrayJdbcType.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/OracleArrayJdbcType.java @@ -7,15 +7,14 @@ package org.hibernate.dialect; import java.lang.reflect.Array; -import java.lang.reflect.Method; import java.sql.CallableStatement; import java.sql.PreparedStatement; import java.sql.SQLException; import java.sql.Types; +import java.util.Objects; import org.hibernate.HibernateException; import org.hibernate.engine.spi.SharedSessionContractImplementor; -import org.hibernate.internal.CoreMessageLogger; import org.hibernate.tool.schema.extract.spi.ColumnTypeInformation; import org.hibernate.type.SqlTypes; import org.hibernate.type.descriptor.ValueBinder; @@ -29,7 +28,7 @@ import org.hibernate.type.descriptor.jdbc.JdbcType; import org.hibernate.type.descriptor.jdbc.ObjectJdbcType; import org.hibernate.type.spi.TypeConfiguration; -import org.jboss.logging.Logger; +import oracle.jdbc.OracleConnection; /** * Descriptor for {@link Types#ARRAY ARRAY} handling. @@ -39,43 +38,14 @@ import org.jboss.logging.Logger; */ public class OracleArrayJdbcType extends ArrayJdbcType { - public static final OracleArrayJdbcType INSTANCE = new OracleArrayJdbcType( null, ObjectJdbcType.INSTANCE ); - private static final CoreMessageLogger LOG = Logger.getMessageLogger( CoreMessageLogger.class, OracleArrayJdbcType.class.getName() ); - private static final ClassValue NAME_BINDER = new ClassValue() { - @Override - protected Method computeValue(Class type) { - try { - return type.getMethod( "setArray", String.class, java.sql.Array.class ); - } - catch ( Exception ex ) { - // add logging? Did we get NoSuchMethodException or SecurityException? - // Doesn't matter which. We can't use it. - } - return null; - } - }; - private static final Class ORACLE_CONNECTION_CLASS; - private static final Method CREATE_ARRAY_METHOD; - - static { - Class oracleConnectionClass = null; - Method createArrayMethod = null; - try { - oracleConnectionClass = Class.forName( "oracle.jdbc.OracleConnection" ); - createArrayMethod = oracleConnectionClass.getMethod( "createOracleArray", String.class, Object.class ); - } - catch (Exception e) { - // Ignore since #resolveType should be called anyway and the OracleArrayJdbcType shouldn't be used - // if driver classes are unavailable - LOG.warn( "Oracle JDBC driver classes are inaccessible and thus, certain DDL types like ARRAY can not be used!", e ); - } - ORACLE_CONNECTION_CLASS = oracleConnectionClass; - CREATE_ARRAY_METHOD = createArrayMethod; - } - private final String typeName; - public OracleArrayJdbcType(String typeName, JdbcType elementJdbcType) { + public OracleArrayJdbcType() { + super( ObjectJdbcType.INSTANCE ); + this.typeName = null; + } + + private OracleArrayJdbcType(String typeName, JdbcType elementJdbcType) { super( elementJdbcType ); this.typeName = typeName; } @@ -101,7 +71,7 @@ public class OracleArrayJdbcType extends ArrayJdbcType { ) ); } - if ( typeName == null || CREATE_ARRAY_METHOD == null ) { + if ( typeName == null ) { // Fallback to XML type for the representation of arrays as the native JSON type was only introduced in 21 // Also, use the XML type if the Oracle JDBC driver classes are not visible return typeConfiguration.getJdbcTypeRegistry().getDescriptor( SqlTypes.SQLXML ); @@ -111,9 +81,6 @@ public class OracleArrayJdbcType extends ArrayJdbcType { @Override public ValueBinder getBinder(final JavaType javaTypeDescriptor) { - if ( CREATE_ARRAY_METHOD == null ) { - throw new RuntimeException( "OracleArrayJdbcType shouldn't be used since JDBC driver classes are not visible." ); - } //noinspection unchecked final BasicPluralJavaType containerJavaType = (BasicPluralJavaType) javaTypeDescriptor; return new BasicBinder( javaTypeDescriptor, this ) { @@ -137,25 +104,11 @@ public class OracleArrayJdbcType extends ArrayJdbcType { protected void doBind(CallableStatement st, X value, String name, WrapperOptions options) throws SQLException { final java.sql.Array arr = getArray( value, containerJavaType, options ); - final Method nameBinder = NAME_BINDER.get( st.getClass() ); - if ( nameBinder == null ) { - try { - st.setObject( name, arr, Types.ARRAY ); - return; - } - catch (SQLException ex) { - throw new HibernateException( "JDBC driver does not support named parameters for setArray. Use positional.", ex ); - } - } - // Not that it's supposed to have setArray(String,Array) by standard. - // There are numerous missing methods that only have versions for positional parameter, - // but not named ones. - try { - nameBinder.invoke( st, name, arr ); + st.setObject( name, arr, Types.ARRAY ); } - catch ( Throwable t ) { - throw new HibernateException( t ); + catch (SQLException ex) { + throw new HibernateException( "JDBC driver does not support named parameters for setArray. Use positional.", ex ); } } @@ -171,10 +124,10 @@ public class OracleArrayJdbcType extends ArrayJdbcType { final Object[] objects = javaTypeDescriptor.unwrap( value, arrayClass, options ); final SharedSessionContractImplementor session = options.getSession(); - final Object oracleConnection = session.getJdbcCoordinator().getLogicalConnection().getPhysicalConnection() - .unwrap( ORACLE_CONNECTION_CLASS ); + final OracleConnection oracleConnection = session.getJdbcCoordinator().getLogicalConnection().getPhysicalConnection() + .unwrap( OracleConnection.class ); try { - return (java.sql.Array) CREATE_ARRAY_METHOD.invoke( oracleConnection, typeName, objects ); + return oracleConnection.createOracleArray( typeName, objects ); } catch (Exception e) { throw new HibernateException( "Couldn't create a java.sql.Array", e ); @@ -194,11 +147,11 @@ public class OracleArrayJdbcType extends ArrayJdbcType { OracleArrayJdbcType that = (OracleArrayJdbcType) o; - return typeName.equals( that.typeName ); + return Objects.equals( typeName, that.typeName ); } @Override public int hashCode() { - return typeName.hashCode(); + return typeName != null ? typeName.hashCode() : 0; } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java index 5acd47acb7..d8d055ff2e 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java @@ -81,6 +81,7 @@ import org.hibernate.type.NullType; import org.hibernate.type.StandardBasicTypes; import org.hibernate.type.descriptor.java.PrimitiveByteArrayJavaType; import org.hibernate.type.descriptor.jdbc.AggregateJdbcType; +import org.hibernate.type.descriptor.jdbc.ArrayJdbcType; import org.hibernate.type.descriptor.jdbc.BlobJdbcType; import org.hibernate.type.descriptor.jdbc.JdbcType; import org.hibernate.type.descriptor.jdbc.NullJdbcType; @@ -782,7 +783,12 @@ public class OracleDialect extends Dialect { typeContributions.contributeJdbcType( OracleBooleanJdbcType.INSTANCE ); typeContributions.contributeJdbcType( OracleXmlJdbcType.INSTANCE ); - typeContributions.contributeJdbcType( OracleStructJdbcType.INSTANCE ); + if ( OracleJdbcHelper.isUsable( serviceRegistry ) ) { + typeContributions.contributeJdbcType( OracleJdbcHelper.getStructJdbcType( serviceRegistry ) ); + } + else { + typeContributions.contributeJdbcType( OracleReflectionStructJdbcType.INSTANCE ); + } if ( getVersion().isSameOrAfter( 12 ) ) { // account for Oracle's deprecated support for LONGVARBINARY @@ -807,7 +813,12 @@ public class OracleDialect extends Dialect { } } - typeContributions.contributeJdbcType( OracleArrayJdbcType.INSTANCE ); + if ( OracleJdbcHelper.isUsable( serviceRegistry ) ) { + typeContributions.contributeJdbcType( OracleJdbcHelper.getArrayJdbcType( serviceRegistry ) ); + } + else { + typeContributions.contributeJdbcType( OracleReflectionStructJdbcType.INSTANCE ); + } // Oracle requires a custom binder for binding untyped nulls with the NULL type typeContributions.contributeJdbcType( NullJdbcType.INSTANCE ); typeContributions.contributeJdbcType( ObjectNullAsNullTypeJdbcType.INSTANCE ); @@ -976,7 +987,7 @@ public class OracleDialect extends Dialect { @Override public int registerResultSetOutParameter(CallableStatement statement, int col) throws SQLException { // register the type of the out param - an Oracle specific type - statement.registerOutParameter( col, OracleTypesHelper.INSTANCE.getOracleCursorTypeSqlType() ); + statement.registerOutParameter( col, OracleTypes.CURSOR ); col++; return col; } @@ -1374,7 +1385,7 @@ public class OracleDialect extends Dialect { @Override public int registerResultSetOutParameter(CallableStatement statement, String name) throws SQLException { - statement.registerOutParameter( name, OracleTypesHelper.INSTANCE.getOracleCursorTypeSqlType() ); + statement.registerOutParameter( name, OracleTypes.CURSOR ); return 1; } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/OracleJdbcHelper.java b/hibernate-core/src/main/java/org/hibernate/dialect/OracleJdbcHelper.java new file mode 100644 index 0000000000..0acd8d41c6 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/dialect/OracleJdbcHelper.java @@ -0,0 +1,59 @@ +/* + * Hibernate, Relational Persistence for 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; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + +import org.hibernate.HibernateError; +import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; +import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; +import org.hibernate.service.ServiceRegistry; +import org.hibernate.type.descriptor.jdbc.JdbcType; + +/** + * The following class provides some convenience methods for accessing JdbcType instance, + * that are loaded into the app class loader, where they have access to the JDBC driver classes. + * + * @author Christian Beikov + */ +public class OracleJdbcHelper { + + public static boolean isUsable(ServiceRegistry serviceRegistry) { + final ClassLoaderService classLoaderService = serviceRegistry.getService( ClassLoaderService.class ); + try { + classLoaderService.classForName( "oracle.jdbc.OracleConnection" ); + return true; + } + catch (ClassLoadingException ex) { + return false; + } + } + + public static JdbcType getArrayJdbcType(ServiceRegistry serviceRegistry) { + return createJdbcType( serviceRegistry, "org.hibernate.dialect.OracleArrayJdbcType" ); + } + + public static JdbcType getStructJdbcType(ServiceRegistry serviceRegistry) { + return createJdbcType( serviceRegistry, "org.hibernate.dialect.OracleStructJdbcType" ); + } + + public static JdbcType createJdbcType(ServiceRegistry serviceRegistry, String className) { + final ClassLoaderService classLoaderService = serviceRegistry.getService( ClassLoaderService.class ); + try { + final Class clazz = classLoaderService.classForName( className ); + final Constructor constructor = clazz.getConstructor(); + return (JdbcType) constructor.newInstance(); + } + catch (NoSuchMethodException e) { + throw new HibernateError( "Class does not have an empty constructor", e ); + } + catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { + throw new HibernateError( "Could not construct JdbcType", e ); + } + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/OracleReflectionStructJdbcType.java b/hibernate-core/src/main/java/org/hibernate/dialect/OracleReflectionStructJdbcType.java new file mode 100644 index 0000000000..49a9b4f303 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/dialect/OracleReflectionStructJdbcType.java @@ -0,0 +1,91 @@ +/* + * Hibernate, Relational Persistence for 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; + +import java.lang.reflect.Method; +import java.sql.Connection; +import java.util.Locale; + +import org.hibernate.HibernateException; +import org.hibernate.boot.model.naming.Identifier; +import org.hibernate.metamodel.mapping.EmbeddableMappingType; +import org.hibernate.metamodel.spi.RuntimeModelCreationContext; +import org.hibernate.type.descriptor.WrapperOptions; +import org.hibernate.type.descriptor.jdbc.AggregateJdbcType; + +/** + * @author Christian Beikov + */ +public class OracleReflectionStructJdbcType extends StructJdbcType { + public static final AggregateJdbcType INSTANCE = new OracleReflectionStructJdbcType(); + + private static final ClassValue RAW_JDBC_TRANSFORMER = new ClassValue<>() { + @Override + protected Method computeValue(Class type) { + if ( "oracle.sql.TIMESTAMPTZ".equals( type.getName() ) ) { + try { + return type.getMethod( "offsetDateTimeValue", Connection.class ); + } + catch (NoSuchMethodException e) { + throw new RuntimeException( e ); + } + } + return null; + } + }; + + + private OracleReflectionStructJdbcType() { + // The default instance is for reading only and will return an Object[] + this( null, null, null ); + } + + public OracleReflectionStructJdbcType(EmbeddableMappingType embeddableMappingType, String typeName, int[] orderMapping) { + super( + embeddableMappingType, + typeName == null ? null : typeName.toUpperCase( Locale.ROOT ), + orderMapping + ); + } + + @Override + public AggregateJdbcType resolveAggregateJdbcType( + EmbeddableMappingType mappingType, + String sqlType, + RuntimeModelCreationContext creationContext) { + return new OracleReflectionStructJdbcType( + mappingType, + sqlType, + creationContext.getBootModel() + .getDatabase() + .getDefaultNamespace() + .locateUserDefinedType( Identifier.toIdentifier( sqlType ) ) + .getOrderMapping() + ); + } + + @Override + protected Object transformRawJdbcValue(Object rawJdbcValue, WrapperOptions options) { + Method rawJdbcTransformer = RAW_JDBC_TRANSFORMER.get( rawJdbcValue.getClass() ); + if ( rawJdbcTransformer == null ) { + return rawJdbcValue; + } + try { + return rawJdbcTransformer.invoke( + rawJdbcValue, + options.getSession() + .getJdbcCoordinator() + .getLogicalConnection() + .getPhysicalConnection() + ); + } + catch (Exception e) { + throw new HibernateException( "Could not transform the raw jdbc value", e ); + } + } + +} diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/OracleStructJdbcType.java b/hibernate-core/src/main/java/org/hibernate/dialect/OracleStructJdbcType.java index 251611d563..0157e5e679 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/OracleStructJdbcType.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/OracleStructJdbcType.java @@ -6,88 +6,33 @@ */ package org.hibernate.dialect; -import java.lang.reflect.Method; -import java.sql.CallableStatement; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Struct; import java.util.Locale; import org.hibernate.HibernateException; import org.hibernate.boot.model.naming.Identifier; -import org.hibernate.metamodel.mapping.AttributeMapping; import org.hibernate.metamodel.mapping.EmbeddableMappingType; -import org.hibernate.metamodel.mapping.JdbcMapping; -import org.hibernate.metamodel.mapping.MappingType; import org.hibernate.metamodel.spi.RuntimeModelCreationContext; -import org.hibernate.type.SqlTypes; -import org.hibernate.type.descriptor.ValueBinder; -import org.hibernate.type.descriptor.ValueExtractor; import org.hibernate.type.descriptor.WrapperOptions; -import org.hibernate.type.descriptor.java.JavaType; -import org.hibernate.type.descriptor.java.spi.UnknownBasicJavaType; -import org.hibernate.type.descriptor.jdbc.BasicBinder; -import org.hibernate.type.descriptor.jdbc.BasicExtractor; import org.hibernate.type.descriptor.jdbc.AggregateJdbcType; -import org.hibernate.type.spi.TypeConfiguration; + +import oracle.sql.TIMESTAMPTZ; /** * @author Christian Beikov */ -public class OracleStructJdbcType implements AggregateJdbcType { +public class OracleStructJdbcType extends StructJdbcType { - public static final AggregateJdbcType INSTANCE = new OracleStructJdbcType(); - - private static final ClassValue RAW_JDBC_TRANSFORMER = new ClassValue<>() { - @Override - protected Method computeValue(Class type) { - if ( "oracle.sql.TIMESTAMPTZ".equals( type.getName() ) ) { - try { - return type.getMethod( "offsetDateTimeValue", Connection.class ); - } - catch (NoSuchMethodException e) { - throw new RuntimeException( e ); - } - } - return null; - } - }; - - private final String oracleTypeName; - private final int[] orderMapping; - private final int[] inverseOrderMapping; - private final EmbeddableMappingType embeddableMappingType; - private final ValueExtractor objectArrayExtractor; - - private OracleStructJdbcType() { + public OracleStructJdbcType() { // The default instance is for reading only and will return an Object[] this( null, null, null ); } - public OracleStructJdbcType(EmbeddableMappingType embeddableMappingType, String typeName, int[] orderMapping) { - this.embeddableMappingType = embeddableMappingType; - this.oracleTypeName = typeName == null ? null : typeName.toUpperCase( Locale.ROOT ); - this.orderMapping = orderMapping; - if ( orderMapping == null ) { - this.inverseOrderMapping = null; - } - else { - final int[] inverseOrderMapping = new int[orderMapping.length]; - for ( int i = 0; i < orderMapping.length; i++ ) { - inverseOrderMapping[orderMapping[i]] = i; - } - this.inverseOrderMapping = inverseOrderMapping; - } - // We cache the extractor for Object[] here - // since that is used in AggregateEmbeddableFetchImpl and AggregateEmbeddableResultImpl - this.objectArrayExtractor = createBasicExtractor( new UnknownBasicJavaType<>( Object[].class ) ); - } - - @Override - public int getJdbcTypeCode() { - return SqlTypes.STRUCT; + private OracleStructJdbcType(EmbeddableMappingType embeddableMappingType, String typeName, int[] orderMapping) { + super( + embeddableMappingType, + typeName == null ? null : typeName.toUpperCase( Locale.ROOT ), + orderMapping + ); } @Override @@ -107,329 +52,21 @@ public class OracleStructJdbcType implements AggregateJdbcType { } @Override - public EmbeddableMappingType getEmbeddableMappingType() { - return embeddableMappingType; - } - - @Override - public JavaType getJdbcRecommendedJavaTypeMapping( - Integer precision, - Integer scale, - TypeConfiguration typeConfiguration) { - if ( embeddableMappingType == null ) { - return typeConfiguration.getJavaTypeRegistry().getDescriptor( Object[].class ); - } - else { - //noinspection unchecked - return (JavaType) embeddableMappingType.getMappedJavaType(); - } - } - - @Override - public void registerOutParameter(CallableStatement callableStatement, String name) throws SQLException { - callableStatement.registerOutParameter( name, getJdbcTypeCode(), oracleTypeName ); - } - - @Override - public void registerOutParameter(CallableStatement callableStatement, int index) throws SQLException { - callableStatement.registerOutParameter( index, getJdbcTypeCode(), oracleTypeName ); - } - - @Override - public Object createJdbcValue(Object domainValue, WrapperOptions options) throws SQLException { - final Object[] jdbcValues = StructHelper.getJdbcValues( - embeddableMappingType, - orderMapping, - embeddableMappingType.getValues( domainValue ), - options - ); - return options.getSession() - .getJdbcCoordinator() - .getLogicalConnection() - .getPhysicalConnection() - .createStruct( oracleTypeName, jdbcValues ); - } - - @Override - public Object[] extractJdbcValues(Object rawJdbcValue, WrapperOptions options) throws SQLException { - final Object[] attributes = ( (Struct) rawJdbcValue ).getAttributes(); - wrapRawJdbcValues( embeddableMappingType, orderMapping, inverseOrderMapping, attributes, 0, options ); - return attributes; - } - - @Override - public ValueBinder getBinder(JavaType javaType) { - return new BasicBinder<>( javaType, this ) { - @Override - protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) - throws SQLException { - st.setObject( index, createJdbcValue( value, options ) ); - } - - @Override - protected void doBind(CallableStatement st, X value, String name, WrapperOptions options) - throws SQLException { - st.setObject( name, createJdbcValue( value, options ) ); - } - }; - } - - @Override - public ValueExtractor getExtractor(JavaType javaType) { - if ( javaType.getJavaTypeClass() == Object[].class ) { - //noinspection unchecked - return (ValueExtractor) objectArrayExtractor; - } - return createBasicExtractor( javaType ); - } - - private BasicExtractor createBasicExtractor(JavaType javaType) { - return new BasicExtractor<>( javaType, this ) { - @Override - protected X doExtract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException { - return getValue( rs.getObject( paramIndex ), options ); - } - - @Override - protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException { - return getValue( statement.getObject( index ), options ); - } - - @Override - protected X doExtract(CallableStatement statement, String name, WrapperOptions options) - throws SQLException { - return getValue( statement.getObject( name ), options ); - } - - private X getValue(Object object, WrapperOptions options) throws SQLException { - if ( object == null ) { - return null; - } - final Struct struct = (Struct) object; - final Object[] values = struct.getAttributes(); - final boolean jdbcRepresentation = getJavaType().getJavaTypeClass() == Object[].class; - if ( jdbcRepresentation ) { - wrapRawJdbcValues( embeddableMappingType, orderMapping, inverseOrderMapping, values, 0, options ); - //noinspection unchecked - return (X) values; - } - assert embeddableMappingType != null && embeddableMappingType.getJavaType() == getJavaType(); - final Object[] attributeValues = getAttributeValues( - embeddableMappingType, - orderMapping, - values, - options - ); - //noinspection unchecked - return (X) embeddableMappingType.getRepresentationStrategy().getInstantiator().instantiate( - () -> attributeValues, - options.getSessionFactory() + protected Object transformRawJdbcValue(Object rawJdbcValue, WrapperOptions options) { + if ( rawJdbcValue.getClass() == TIMESTAMPTZ.class ) { + try { + return ( (TIMESTAMPTZ) rawJdbcValue ).offsetDateTimeValue( + options.getSession() + .getJdbcCoordinator() + .getLogicalConnection() + .getPhysicalConnection() ); } - }; - } - - private static Object[] getAttributeValues( - EmbeddableMappingType embeddableMappingType, - int[] orderMapping, - Object[] rawJdbcValues, - WrapperOptions options) throws SQLException { - final int numberOfAttributeMappings = embeddableMappingType.getNumberOfAttributeMappings(); - final Object[] attributeValues; - if ( numberOfAttributeMappings != rawJdbcValues.length || orderMapping != null ) { - attributeValues = new Object[numberOfAttributeMappings]; - } - else { - attributeValues = rawJdbcValues; - } - int jdbcIndex = 0; - for ( int i = 0; i < numberOfAttributeMappings; i++ ) { - final int attributeIndex; - if ( orderMapping == null ) { - attributeIndex = i; - } - else { - attributeIndex = orderMapping[i]; - } - final AttributeMapping attributeMapping = embeddableMappingType.getAttributeMapping( attributeIndex ); - jdbcIndex += injectAttributeValue( - attributeMapping, - attributeValues, - attributeIndex, - rawJdbcValues, - jdbcIndex, - options - ); - } - return attributeValues; - } - - private static int injectAttributeValue( - AttributeMapping attributeMapping, - Object[] attributeValues, - int attributeIndex, - Object[] rawJdbcValues, - int jdbcIndex, - WrapperOptions options) throws SQLException { - final MappingType mappedType = attributeMapping.getMappedType(); - final int jdbcValueCount; - final Object rawJdbcValue = rawJdbcValues[jdbcIndex]; - if ( mappedType instanceof EmbeddableMappingType ) { - final EmbeddableMappingType embeddableMappingType = (EmbeddableMappingType) mappedType; - if ( embeddableMappingType.getAggregateMapping() != null ) { - jdbcValueCount = 1; - if ( rawJdbcValue == null ) { - attributeValues[attributeIndex] = null; - } - else { - final AggregateJdbcType aggregateJdbcType = (AggregateJdbcType) embeddableMappingType.getAggregateMapping() - .getJdbcMapping() - .getJdbcType(); - final Object[] subValues; - if ( aggregateJdbcType instanceof OracleStructJdbcType ) { - subValues = getAttributeValues( - embeddableMappingType, - ( (OracleStructJdbcType) aggregateJdbcType ).orderMapping, - ( (Struct) rawJdbcValue ).getAttributes(), - options - ); - } - else { - subValues = aggregateJdbcType.extractJdbcValues( rawJdbcValue, options ); - } - attributeValues[attributeIndex] = embeddableMappingType.getRepresentationStrategy() - .getInstantiator() - .instantiate( - () -> subValues, - embeddableMappingType.findContainingEntityMapping() - .getEntityPersister() - .getFactory() - ); - } - } - else { - jdbcValueCount = embeddableMappingType.getJdbcValueCount(); - final Object[] jdbcValues = new Object[jdbcValueCount]; - System.arraycopy( rawJdbcValues, jdbcIndex, jdbcValues, 0, jdbcValues.length ); - final Object[] subValues = getAttributeValues( embeddableMappingType, null, jdbcValues, options ); - attributeValues[attributeIndex] = embeddableMappingType.getRepresentationStrategy() - .getInstantiator() - .instantiate( - () -> subValues, - embeddableMappingType.findContainingEntityMapping() - .getEntityPersister() - .getFactory() - ); + catch (Exception e) { + throw new HibernateException( "Could not transform the raw jdbc value", e ); } } - else { - assert attributeMapping.getJdbcTypeCount() == 1; - jdbcValueCount = 1; - final JdbcMapping jdbcMapping = attributeMapping.getSingleJdbcMapping(); - final Object jdbcValue; - if ( rawJdbcValue == null ) { - jdbcValue = null; - } - else { - switch ( jdbcMapping.getJdbcType().getDefaultSqlTypeCode() ) { - case SqlTypes.TIMESTAMP_WITH_TIMEZONE: - case SqlTypes.TIMESTAMP_UTC: - // Only transform the raw jdbc value if it could be a TIMESTAMPTZ - jdbcValue = jdbcMapping.getJdbcJavaType() - .wrap( transformRawJdbcValue( rawJdbcValue, options ), options ); - break; - default: - jdbcValue = jdbcMapping.getJdbcJavaType().wrap( rawJdbcValue, options ); - break; - } - } - attributeValues[attributeIndex] = jdbcMapping.convertToDomainValue( jdbcValue ); - } - return jdbcValueCount; - } - - private static int wrapRawJdbcValues( - EmbeddableMappingType embeddableMappingType, - int[] orderMapping, - int[] inverseOrderMapping, - Object[] jdbcValues, - int jdbcIndex, - WrapperOptions options) throws SQLException { - final Object[] targetJdbcValues; - if ( orderMapping == null ) { - targetJdbcValues = jdbcValues; - } - else { - targetJdbcValues = jdbcValues.clone(); - } - final int numberOfAttributeMappings = embeddableMappingType.getNumberOfAttributeMappings(); - for ( int i = 0; i < numberOfAttributeMappings; i++ ) { - final AttributeMapping attributeMapping; - if ( orderMapping == null ) { - attributeMapping = embeddableMappingType.getAttributeMapping( i ); - } - else { - attributeMapping = embeddableMappingType.getAttributeMapping( orderMapping[i] ); - } - final MappingType mappedType = attributeMapping.getMappedType(); - - if ( mappedType instanceof EmbeddableMappingType ) { - final EmbeddableMappingType embeddableType = (EmbeddableMappingType) mappedType; - if ( embeddableType.getAggregateMapping() != null ) { - final AggregateJdbcType aggregateJdbcType = (AggregateJdbcType) embeddableType.getAggregateMapping() - .getJdbcMapping() - .getJdbcType(); - final Object rawJdbcValue = targetJdbcValues[jdbcIndex]; - targetJdbcValues[jdbcIndex] = aggregateJdbcType.extractJdbcValues( rawJdbcValue, options ); - jdbcIndex++; - } - else { - jdbcIndex = wrapRawJdbcValues( embeddableType, null, null, targetJdbcValues, jdbcIndex, options ); - } - } - else { - assert attributeMapping.getJdbcTypeCount() == 1; - final Object rawJdbcValue = targetJdbcValues[jdbcIndex]; - if ( rawJdbcValue != null ) { - final JdbcMapping jdbcMapping = attributeMapping.getSingleJdbcMapping(); - switch ( jdbcMapping.getJdbcType().getDefaultSqlTypeCode() ) { - case SqlTypes.TIMESTAMP_WITH_TIMEZONE: - case SqlTypes.TIMESTAMP_UTC: - // Only transform the raw jdbc value if it could be a TIMESTAMPTZ - targetJdbcValues[jdbcIndex] = jdbcMapping.getJdbcJavaType() - .wrap( transformRawJdbcValue( rawJdbcValue, options ), options ); - break; - default: - targetJdbcValues[jdbcIndex] = jdbcMapping.getJdbcJavaType().wrap( rawJdbcValue, options ); - break; - } - } - jdbcIndex++; - } - } - if ( orderMapping != null ) { - StructHelper.orderJdbcValues( embeddableMappingType, inverseOrderMapping, targetJdbcValues, jdbcValues ); - } - return jdbcIndex; - } - - private static Object transformRawJdbcValue(Object rawJdbcValue, WrapperOptions options) { - Method rawJdbcTransformer = RAW_JDBC_TRANSFORMER.get( rawJdbcValue.getClass() ); - if ( rawJdbcTransformer == null ) { - return rawJdbcValue; - } - try { - return rawJdbcTransformer.invoke( - rawJdbcValue, - options.getSession() - .getJdbcCoordinator() - .getLogicalConnection() - .getPhysicalConnection() - ); - } - catch (Exception e) { - throw new HibernateException( "Could not transform the raw jdbc value", e ); - } + return rawJdbcValue; } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/OracleTypes.java b/hibernate-core/src/main/java/org/hibernate/dialect/OracleTypes.java index 92acf7195c..bb0b3d7d32 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/OracleTypes.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/OracleTypes.java @@ -10,5 +10,6 @@ package org.hibernate.dialect; * The Oracle specific JDBC type code. */ public class OracleTypes { + public static final int CURSOR = -10; public static final int JSON = 2016; } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/OracleTypesHelper.java b/hibernate-core/src/main/java/org/hibernate/dialect/OracleTypesHelper.java deleted file mode 100644 index 8c18edd739..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/dialect/OracleTypesHelper.java +++ /dev/null @@ -1,111 +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.dialect; - -import org.hibernate.HibernateException; -import org.hibernate.internal.CoreMessageLogger; -import org.hibernate.internal.util.ReflectHelper; - -import org.jboss.logging.Logger; - -/** - * A Helper for dealing with the OracleTypes class - * - * @author Steve Ebersole - */ -public class OracleTypesHelper { - private static final CoreMessageLogger log = Logger.getMessageLogger( CoreMessageLogger.class, OracleTypesHelper.class.getName() ); - - /** - * Singleton access - */ - public static final OracleTypesHelper INSTANCE = new OracleTypesHelper(); - - private static final String ORACLE_TYPES_CLASS_NAME = "oracle.jdbc.OracleTypes"; - private static final String DEPRECATED_ORACLE_TYPES_CLASS_NAME = "oracle.jdbc.driver.OracleTypes"; - - private final int oracleCursorTypeSqlType; - - private OracleTypesHelper() { - int typeCode = -99; - try { - typeCode = extractOracleCursorTypeValue(); - } - catch (Exception 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; - } - - private int extractOracleCursorTypeValue() { - try { - return locateOracleTypesClass().getField( "CURSOR" ).getInt( null ); - } - catch ( Exception se ) { - throw new HibernateException( "Unable to access OracleTypes.CURSOR value", se ); - } - } - - private Class locateOracleTypesClass() { - try { - return ReflectHelper.classForName( ORACLE_TYPES_CLASS_NAME ); - } - catch (ClassNotFoundException e) { - try { - return ReflectHelper.classForName( DEPRECATED_ORACLE_TYPES_CLASS_NAME ); - } - catch (ClassNotFoundException e2) { - throw new HibernateException( - String.format( - "Unable to locate OracleTypes class using either known FQN [%s, %s]", - ORACLE_TYPES_CLASS_NAME, - DEPRECATED_ORACLE_TYPES_CLASS_NAME - ), - e - ); - } - } - } - - public int getOracleCursorTypeSqlType() { - return oracleCursorTypeSqlType; - } - -// initial code as copied from Oracle8iDialect -// -// private int oracleCursorTypeSqlType = INIT_ORACLETYPES_CURSOR_VALUE; -// -// public int getOracleCursorTypeSqlType() { -// if ( oracleCursorTypeSqlType == INIT_ORACLETYPES_CURSOR_VALUE ) { -// // todo : is there really any reason to keep trying if this fails once? -// oracleCursorTypeSqlType = extractOracleCursorTypeValue(); -// } -// return oracleCursorTypeSqlType; -// } -// -// private int extractOracleCursorTypeValue() { -// Class oracleTypesClass; -// try { -// oracleTypesClass = ReflectHelper.classForName( ORACLE_TYPES_CLASS_NAME ); -// } -// catch ( ClassNotFoundException cnfe ) { -// try { -// oracleTypesClass = ReflectHelper.classForName( DEPRECATED_ORACLE_TYPES_CLASS_NAME ); -// } -// catch ( ClassNotFoundException e ) { -// throw new HibernateException( "Unable to locate OracleTypes class", e ); -// } -// } -// -// try { -// return oracleTypesClass.getField( "CURSOR" ).getInt( null ); -// } -// catch ( Exception se ) { -// throw new HibernateException( "Unable to access OracleTypes.CURSOR value", se ); -// } -// } -} diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/PgJdbcHelper.java b/hibernate-core/src/main/java/org/hibernate/dialect/PgJdbcHelper.java new file mode 100644 index 0000000000..199ca05506 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/dialect/PgJdbcHelper.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.dialect; + +import java.lang.reflect.Constructor; +import java.lang.reflect.InvocationTargetException; + +import org.hibernate.HibernateError; +import org.hibernate.boot.registry.classloading.spi.ClassLoaderService; +import org.hibernate.boot.registry.classloading.spi.ClassLoadingException; +import org.hibernate.service.ServiceRegistry; +import org.hibernate.type.descriptor.jdbc.JdbcType; + +/** + * The following class provides some convenience methods for accessing JdbcType instance, + * that are loaded into the app class loader, where they have access to the JDBC driver classes. + * + * @author Christian Beikov + */ +public final class PgJdbcHelper { + + public static boolean isUsable(ServiceRegistry serviceRegistry) { + final ClassLoaderService classLoaderService = serviceRegistry.getService( ClassLoaderService.class ); + try { + classLoaderService.classForName( "org.postgresql.util.PGobject" ); + return true; + } + catch (ClassLoadingException ex) { + return false; + } + } + + public static JdbcType getStructJdbcType(ServiceRegistry serviceRegistry) { + return createJdbcType( serviceRegistry, "org.hibernate.dialect.PostgreSQLStructPGObjectJdbcType" ); + } + + public static JdbcType getIntervalJdbcType(ServiceRegistry serviceRegistry) { + return createJdbcType( serviceRegistry, "org.hibernate.dialect.PostgreSQLIntervalSecondJdbcType" ); + } + + public static JdbcType getInetJdbcType(ServiceRegistry serviceRegistry) { + return createJdbcType( serviceRegistry, "org.hibernate.dialect.PostgreSQLInetJdbcType" ); + } + + public static JdbcType getJsonJdbcType(ServiceRegistry serviceRegistry) { + return createJdbcType( serviceRegistry, "org.hibernate.dialect.PostgreSQLJsonPGObjectJsonType" ); + } + + public static JdbcType getJsonbJdbcType(ServiceRegistry serviceRegistry) { + return createJdbcType( serviceRegistry, "org.hibernate.dialect.PostgreSQLJsonPGObjectJsonbType" ); + } + + public static JdbcType createJdbcType(ServiceRegistry serviceRegistry, String className) { + final ClassLoaderService classLoaderService = serviceRegistry.getService( ClassLoaderService.class ); + try { + final Class clazz = classLoaderService.classForName( className ); + final Constructor constructor = clazz.getConstructor(); + return (JdbcType) constructor.newInstance(); + } + catch (NoSuchMethodException e) { + throw new HibernateError( "Class does not have an empty constructor", e ); + } + catch (InstantiationException | IllegalAccessException | InvocationTargetException e) { + throw new HibernateError( "Could not construct JdbcType", e ); + } + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java index 396ad37321..87558f32eb 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLDialect.java @@ -1337,16 +1337,16 @@ public class PostgreSQLDialect extends Dialect { if ( driverKind == PostgreSQLDriverKind.PG_JDBC ) { // HHH-9562 jdbcTypeRegistry.addDescriptorIfAbsent( UUIDJdbcType.INSTANCE ); - if ( PostgreSQLPGObjectJdbcType.isUsable() ) { - jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLInetJdbcType.INSTANCE ); - jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLIntervalSecondJdbcType.INSTANCE ); - jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLStructJdbcType.INSTANCE ); - jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLJsonbJdbcType.INSTANCE ); + if ( PgJdbcHelper.isUsable( serviceRegistry ) ) { + jdbcTypeRegistry.addDescriptorIfAbsent( PgJdbcHelper.getInetJdbcType( serviceRegistry ) ); + jdbcTypeRegistry.addDescriptorIfAbsent( PgJdbcHelper.getIntervalJdbcType( serviceRegistry ) ); + jdbcTypeRegistry.addDescriptorIfAbsent( PgJdbcHelper.getStructJdbcType( serviceRegistry ) ); + jdbcTypeRegistry.addDescriptorIfAbsent( PgJdbcHelper.getJsonbJdbcType( serviceRegistry ) ); } else { jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingInetJdbcType.INSTANCE ); jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingIntervalSecondJdbcType.INSTANCE ); - jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingStructJdbcType.INSTANCE ); + jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLStructCastingJdbcType.INSTANCE ); jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingJsonJdbcType.JSONB_INSTANCE ); } } @@ -1354,7 +1354,7 @@ public class PostgreSQLDialect extends Dialect { jdbcTypeRegistry.addDescriptorIfAbsent( UUIDJdbcType.INSTANCE ); jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingInetJdbcType.INSTANCE ); jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingIntervalSecondJdbcType.INSTANCE ); - jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingStructJdbcType.INSTANCE ); + jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLStructCastingJdbcType.INSTANCE ); jdbcTypeRegistry.addDescriptorIfAbsent( PostgreSQLCastingJsonJdbcType.JSONB_INSTANCE ); } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLInetJdbcType.java b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLInetJdbcType.java index 5b6f1ac6b9..fef32f81b9 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLInetJdbcType.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLInetJdbcType.java @@ -6,22 +6,45 @@ */ package org.hibernate.dialect; +import java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Types; + import org.hibernate.type.SqlTypes; +import org.hibernate.type.descriptor.ValueBinder; +import org.hibernate.type.descriptor.ValueExtractor; import org.hibernate.type.descriptor.WrapperOptions; import org.hibernate.type.descriptor.java.JavaType; +import org.hibernate.type.descriptor.jdbc.BasicBinder; +import org.hibernate.type.descriptor.jdbc.BasicExtractor; +import org.hibernate.type.descriptor.jdbc.JdbcLiteralFormatter; +import org.hibernate.type.descriptor.jdbc.JdbcType; + +import org.postgresql.util.PGobject; /** * @author Christian Beikov */ -public class PostgreSQLInetJdbcType extends PostgreSQLPGObjectJdbcType { +public class PostgreSQLInetJdbcType implements JdbcType { - public static final PostgreSQLInetJdbcType INSTANCE = new PostgreSQLInetJdbcType(); - - public PostgreSQLInetJdbcType() { - super( "inet", SqlTypes.INET ); + @Override + public int getJdbcTypeCode() { + return Types.OTHER; } @Override + public int getDefaultSqlTypeCode() { + return SqlTypes.INET; + } + + @Override + public JdbcLiteralFormatter getJdbcLiteralFormatter(JavaType javaType) { + // No literal support for now + return null; + } + protected X fromString(String string, JavaType javaType, WrapperOptions options) { final String host; if ( string == null ) { @@ -39,4 +62,61 @@ public class PostgreSQLInetJdbcType extends PostgreSQLPGObjectJdbcType { } return javaType.wrap( host, options ); } + + protected String toString(X value, JavaType javaType, WrapperOptions options) { + return javaType.unwrap( value, String.class, options ); + } + + @Override + public ValueBinder getBinder(JavaType javaType) { + return new BasicBinder<>( javaType, this ) { + @Override + protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) + throws SQLException { + final String stringValue = PostgreSQLInetJdbcType.this.toString( value, getJavaType(), options ); + final PGobject holder = new PGobject(); + holder.setType( "inet" ); + holder.setValue( stringValue ); + st.setObject( index, holder ); + } + + @Override + protected void doBind(CallableStatement st, X value, String name, WrapperOptions options) + throws SQLException { + final String stringValue = PostgreSQLInetJdbcType.this.toString( value, getJavaType(), options ); + final PGobject holder = new PGobject(); + holder.setType( "inet" ); + holder.setValue( stringValue ); + st.setObject( name, holder ); + } + }; + } + + @Override + public ValueExtractor getExtractor(JavaType javaType) { + return new BasicExtractor<>( javaType, this ) { + @Override + protected X doExtract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException { + return getObject( rs.getObject( paramIndex ), options ); + } + + @Override + protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException { + return getObject( statement.getObject( index ), options ); + } + + @Override + protected X doExtract(CallableStatement statement, String name, WrapperOptions options) + throws SQLException { + return getObject( statement.getObject( name ), options ); + } + + private X getObject(Object object, WrapperOptions options) throws SQLException { + if ( object == null ) { + return null; + } + return fromString( object.toString(), getJavaType(), options ); + } + }; + } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLIntervalSecondJdbcType.java b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLIntervalSecondJdbcType.java index 3027d08a8c..c9ee4fe727 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLIntervalSecondJdbcType.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLIntervalSecondJdbcType.java @@ -6,9 +6,6 @@ */ package org.hibernate.dialect; -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; import java.sql.CallableStatement; import java.sql.PreparedStatement; import java.sql.ResultSet; @@ -16,8 +13,6 @@ import java.sql.SQLException; import java.sql.Types; import java.time.Duration; -import org.hibernate.HibernateException; -import org.hibernate.internal.util.ReflectHelper; import org.hibernate.type.SqlTypes; import org.hibernate.type.descriptor.ValueBinder; import org.hibernate.type.descriptor.ValueExtractor; @@ -30,62 +25,16 @@ import org.hibernate.type.descriptor.jdbc.JdbcLiteralFormatter; import org.hibernate.type.descriptor.jdbc.JdbcType; import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators; +import org.postgresql.util.PGInterval; + /** * @author Christian Beikov */ public class PostgreSQLIntervalSecondJdbcType implements AdjustableJdbcType { - - public static final PostgreSQLIntervalSecondJdbcType INSTANCE = new PostgreSQLIntervalSecondJdbcType(); - private static final Class PG_INTERVAL_CLASS; - private static final Constructor PG_INTERVAL_CONSTRUCTOR; - private static final Method PG_INTERVAL_GET_DAYS; - private static final Method PG_INTERVAL_GET_HOURS; - private static final Method PG_INTERVAL_GET_MINUTES; - private static final Method PG_INTERVAL_GET_SECONDS; - private static final Method PG_INTERVAL_GET_MICRO_SECONDS; private static final long SECONDS_PER_DAY = 86400; private static final long SECONDS_PER_HOUR = 3600; private static final long SECONDS_PER_MINUTE = 60; - static { - Constructor constructor; - Class pgIntervalClass; - Method pgIntervalGetDays; - Method pgIntervalGetHours; - Method pgIntervalGetMinutes; - Method pgIntervalGetSeconds; - Method pgIntervalGetMicroSeconds; - try { - pgIntervalClass = ReflectHelper.classForName( - "org.postgresql.util.PGInterval", - PostgreSQLIntervalSecondJdbcType.class - ); - constructor = (Constructor) pgIntervalClass.getConstructor( - int.class, - int.class, - int.class, - int.class, - int.class, - double.class - ); - pgIntervalGetDays = pgIntervalClass.getDeclaredMethod( "getDays" ); - pgIntervalGetHours = pgIntervalClass.getDeclaredMethod( "getHours" ); - pgIntervalGetMinutes = pgIntervalClass.getDeclaredMethod( "getMinutes" ); - pgIntervalGetSeconds = pgIntervalClass.getDeclaredMethod( "getWholeSeconds" ); - pgIntervalGetMicroSeconds = pgIntervalClass.getDeclaredMethod( "getMicroSeconds" ); - } - catch (Exception e) { - throw new RuntimeException( "Could not initialize PostgreSQLPGObjectJdbcType", e ); - } - PG_INTERVAL_CLASS = pgIntervalClass; - PG_INTERVAL_CONSTRUCTOR = constructor; - PG_INTERVAL_GET_DAYS = pgIntervalGetDays; - PG_INTERVAL_GET_HOURS = pgIntervalGetHours; - PG_INTERVAL_GET_MINUTES = pgIntervalGetMinutes; - PG_INTERVAL_GET_SECONDS = pgIntervalGetSeconds; - PG_INTERVAL_GET_MICRO_SECONDS = pgIntervalGetMicroSeconds; - } - @Override public int getJdbcTypeCode() { return Types.OTHER; @@ -161,19 +110,14 @@ public class PostgreSQLIntervalSecondJdbcType implements AdjustableJdbcType { double seconds = ( (double) ( secondsLong - minutesLong * 60 ) ) + ( (double) d.getNano() ) / 1_000_000_000d; - try { - return PG_INTERVAL_CONSTRUCTOR.newInstance( - 0,// years - 0, // months - days, - hours, - minutes, - seconds - ); - } - catch (IllegalAccessException | InstantiationException | InvocationTargetException e) { - throw new IllegalArgumentException( e ); - } + return new PGInterval( + 0,// years + 0, // months + days, + hours, + minutes, + seconds + ); } }; } @@ -198,19 +142,15 @@ public class PostgreSQLIntervalSecondJdbcType implements AdjustableJdbcType { } private Object getValue(Object value) { - if ( PG_INTERVAL_CLASS.isInstance( value ) ) { - try { - final long seconds = (int) PG_INTERVAL_GET_SECONDS.invoke( value ) - + SECONDS_PER_DAY * (int) PG_INTERVAL_GET_DAYS.invoke( value ) - + SECONDS_PER_HOUR * (int) PG_INTERVAL_GET_HOURS.invoke( value ) - + SECONDS_PER_MINUTE * (int) PG_INTERVAL_GET_MINUTES.invoke( value ); - final long nanos = 1000L * (int) PG_INTERVAL_GET_MICRO_SECONDS.invoke( value ); + if ( value instanceof PGInterval ) { + final PGInterval interval = (PGInterval) value; + final long seconds = ( (long) interval.getSeconds() ) + + SECONDS_PER_DAY * ( (long) interval.getDays() ) + + SECONDS_PER_HOUR * ( (long) interval.getHours() ) + + SECONDS_PER_MINUTE * ( (long) interval.getMinutes() ); + final long nanos = 1000L * ( (long) interval.getMicroSeconds() ); - return Duration.ofSeconds( seconds, nanos ); - } - catch (Exception e) { - throw new HibernateException( "Couldn't create Duration from interval", e ); - } + return Duration.ofSeconds( seconds, nanos ); } return value; } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLJsonbJdbcType.java b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLJsonPGObjectJsonType.java similarity index 64% rename from hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLJsonbJdbcType.java rename to hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLJsonPGObjectJsonType.java index 5afa3446d0..65ce0ec372 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLJsonbJdbcType.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLJsonPGObjectJsonType.java @@ -13,12 +13,12 @@ import org.hibernate.type.descriptor.jdbc.AggregateJdbcType; /** * @author Christian Beikov */ -public class PostgreSQLJsonbJdbcType extends AbstractPostgreSQLJsonJdbcType { - - public static final PostgreSQLJsonbJdbcType INSTANCE = new PostgreSQLJsonbJdbcType( null ); - - public PostgreSQLJsonbJdbcType(EmbeddableMappingType embeddableMappingType) { - super( embeddableMappingType, "jsonb" ); +public class PostgreSQLJsonPGObjectJsonType extends AbstractPostgreSQLJsonPGObjectType { + public PostgreSQLJsonPGObjectJsonType() { + this( null, false ); + } + private PostgreSQLJsonPGObjectJsonType(EmbeddableMappingType embeddableMappingType, boolean jsonb) { + super( embeddableMappingType, jsonb ); } @Override @@ -26,6 +26,6 @@ public class PostgreSQLJsonbJdbcType extends AbstractPostgreSQLJsonJdbcType { EmbeddableMappingType mappingType, String sqlType, RuntimeModelCreationContext creationContext) { - return new PostgreSQLJsonbJdbcType( mappingType ); + return new PostgreSQLJsonPGObjectJsonType( mappingType, false ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLJsonJdbcType.java b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLJsonPGObjectJsonbType.java similarity index 64% rename from hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLJsonJdbcType.java rename to hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLJsonPGObjectJsonbType.java index 5f1b9fcdca..ed0236e521 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLJsonJdbcType.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLJsonPGObjectJsonbType.java @@ -13,12 +13,13 @@ import org.hibernate.type.descriptor.jdbc.AggregateJdbcType; /** * @author Christian Beikov */ -public class PostgreSQLJsonJdbcType extends AbstractPostgreSQLJsonJdbcType { +public class PostgreSQLJsonPGObjectJsonbType extends AbstractPostgreSQLJsonPGObjectType { - public static final PostgreSQLJsonJdbcType INSTANCE = new PostgreSQLJsonJdbcType( null ); - - private PostgreSQLJsonJdbcType(EmbeddableMappingType embeddableMappingType) { - super( embeddableMappingType, "json" ); + public PostgreSQLJsonPGObjectJsonbType() { + this( null, true ); + } + protected PostgreSQLJsonPGObjectJsonbType(EmbeddableMappingType embeddableMappingType, boolean jsonb) { + super( embeddableMappingType, jsonb ); } @Override @@ -26,7 +27,6 @@ public class PostgreSQLJsonJdbcType extends AbstractPostgreSQLJsonJdbcType { EmbeddableMappingType mappingType, String sqlType, RuntimeModelCreationContext creationContext) { - return new PostgreSQLJsonJdbcType( mappingType ); + return new PostgreSQLJsonPGObjectJsonbType( mappingType, true ); } - } diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLPGObjectJdbcType.java b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLPGObjectJdbcType.java deleted file mode 100644 index 20f5747f53..0000000000 --- a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLPGObjectJdbcType.java +++ /dev/null @@ -1,176 +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.dialect; - -import java.lang.reflect.Constructor; -import java.lang.reflect.InvocationTargetException; -import java.lang.reflect.Method; -import java.sql.CallableStatement; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Types; - -import org.hibernate.internal.CoreLogging; -import org.hibernate.internal.CoreMessageLogger; -import org.hibernate.internal.util.ReflectHelper; -import org.hibernate.type.descriptor.ValueBinder; -import org.hibernate.type.descriptor.ValueExtractor; -import org.hibernate.type.descriptor.WrapperOptions; -import org.hibernate.type.descriptor.java.JavaType; -import org.hibernate.type.descriptor.jdbc.BasicBinder; -import org.hibernate.type.descriptor.jdbc.BasicExtractor; -import org.hibernate.type.descriptor.jdbc.JdbcLiteralFormatter; -import org.hibernate.type.descriptor.jdbc.JdbcType; - -/** - * @author Christian Beikov - */ -public abstract class PostgreSQLPGObjectJdbcType implements JdbcType { - - private static final CoreMessageLogger LOG = CoreLogging.messageLogger( PostgreSQLPGObjectJdbcType.class ); - private static final Constructor PG_OBJECT_CONSTRUCTOR; - private static final Method TYPE_SETTER; - private static final Method VALUE_SETTER; - - static { - Constructor constructor = null; - Method typeSetter = null; - Method valueSetter = null; - try { - final Class pgObjectClass = ReflectHelper.classForName( - "org.postgresql.util.PGobject", - PostgreSQLPGObjectJdbcType.class - ); - //noinspection unchecked - constructor = (Constructor) pgObjectClass.getConstructor(); - typeSetter = ReflectHelper.setterMethodOrNull( pgObjectClass, "type", String.class ); - valueSetter = ReflectHelper.setterMethodOrNull( pgObjectClass, "value", String.class ); - } - catch (Exception e) { - LOG.postgreSQLJdbcDriverNotAccessible(); - } - PG_OBJECT_CONSTRUCTOR = constructor; - TYPE_SETTER = typeSetter; - VALUE_SETTER = valueSetter; - } - - private final String typeName; - private final int sqlTypeCode; - - public PostgreSQLPGObjectJdbcType(String typeName, int sqlTypeCode) { - this.typeName = typeName; - this.sqlTypeCode = sqlTypeCode; - } - - public static boolean isUsable() { - return PG_OBJECT_CONSTRUCTOR != null; - } - - @Override - public int getJdbcTypeCode() { - return Types.OTHER; - } - - @Override - public int getDefaultSqlTypeCode() { - return sqlTypeCode; - } - - public String getTypeName() { - return typeName; - } - - protected X fromString(String string, JavaType javaType, WrapperOptions options) throws SQLException { - return javaType.wrap( string, options ); - } - - protected String toString(X value, JavaType javaType, WrapperOptions options) { - return javaType.unwrap( value, String.class, options ); - } - - @Override - public JdbcLiteralFormatter getJdbcLiteralFormatter(JavaType javaType) { - // No literal support for now - return null; - } - - @Override - public ValueBinder getBinder(JavaType javaType) { - return new BasicBinder<>( javaType, this ) { - @Override - protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) - throws SQLException { - final String stringValue = ( (PostgreSQLPGObjectJdbcType) getJdbcType() ).toString( - value, - getJavaType(), - options - ); - try { - Object holder = PG_OBJECT_CONSTRUCTOR.newInstance(); - TYPE_SETTER.invoke( holder, typeName ); - VALUE_SETTER.invoke( holder, stringValue ); - st.setObject( index, holder ); - } - catch (IllegalAccessException | InstantiationException | InvocationTargetException e) { - throw new IllegalArgumentException( e ); - } - } - - @Override - protected void doBind(CallableStatement st, X value, String name, WrapperOptions options) - throws SQLException { - final String stringValue = ( (PostgreSQLPGObjectJdbcType) getJdbcType() ).toString( - value, - getJavaType(), - options - ); - try { - Object holder = PG_OBJECT_CONSTRUCTOR.newInstance(); - TYPE_SETTER.invoke( holder, typeName ); - VALUE_SETTER.invoke( holder, stringValue ); - st.setObject( name, holder ); - } - catch (IllegalAccessException | InstantiationException | InvocationTargetException e) { - throw new IllegalArgumentException( e ); - } - } - }; - } - - @Override - public ValueExtractor getExtractor(JavaType javaType) { - return new BasicExtractor<>( javaType, this ) { - @Override - protected X doExtract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException { - return getObject( rs.getObject( paramIndex ), options ); - } - - @Override - protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException { - return getObject( statement.getObject( index ), options ); - } - - @Override - protected X doExtract(CallableStatement statement, String name, WrapperOptions options) - throws SQLException { - return getObject( statement.getObject( name ), options ); - } - - private X getObject(Object object, WrapperOptions options) throws SQLException { - if ( object == null ) { - return null; - } - return ( (PostgreSQLPGObjectJdbcType) getJdbcType() ).fromString( - object.toString(), - getJavaType(), - options - ); - } - }; - } -} diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLCastingStructJdbcType.java b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLStructCastingJdbcType.java similarity index 83% rename from hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLCastingStructJdbcType.java rename to hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLStructCastingJdbcType.java index e411c68590..b7886d6377 100644 --- a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLCastingStructJdbcType.java +++ b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLStructCastingJdbcType.java @@ -23,11 +23,14 @@ import org.hibernate.type.descriptor.jdbc.BasicBinder; /** * @author Christian Beikov */ -public class PostgreSQLCastingStructJdbcType extends PostgreSQLStructJdbcType { +public class PostgreSQLStructCastingJdbcType extends AbstractPostgreSQLStructJdbcType { - public static final PostgreSQLCastingStructJdbcType INSTANCE = new PostgreSQLCastingStructJdbcType( null, null, null ); + public static final PostgreSQLStructCastingJdbcType INSTANCE = new PostgreSQLStructCastingJdbcType(); + public PostgreSQLStructCastingJdbcType() { + this( null, null, null ); + } - public PostgreSQLCastingStructJdbcType( + private PostgreSQLStructCastingJdbcType( EmbeddableMappingType embeddableMappingType, String typeName, int[] orderMapping) { @@ -39,7 +42,7 @@ public class PostgreSQLCastingStructJdbcType extends PostgreSQLStructJdbcType { EmbeddableMappingType mappingType, String sqlType, RuntimeModelCreationContext creationContext) { - return new PostgreSQLCastingStructJdbcType( + return new PostgreSQLStructCastingJdbcType( mappingType, sqlType, creationContext.getBootModel() @@ -68,7 +71,7 @@ public class PostgreSQLCastingStructJdbcType extends PostgreSQLStructJdbcType { @Override protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) throws SQLException { - final String stringValue = ( (PostgreSQLCastingStructJdbcType) getJdbcType() ).toString( + final String stringValue = ( (PostgreSQLStructCastingJdbcType) getJdbcType() ).toString( value, getJavaType(), options @@ -79,7 +82,7 @@ public class PostgreSQLCastingStructJdbcType extends PostgreSQLStructJdbcType { @Override protected void doBind(CallableStatement st, X value, String name, WrapperOptions options) throws SQLException { - final String stringValue = ( (PostgreSQLCastingStructJdbcType) getJdbcType() ).toString( + final String stringValue = ( (PostgreSQLStructCastingJdbcType) getJdbcType() ).toString( value, getJavaType(), options diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLStructPGObjectJdbcType.java b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLStructPGObjectJdbcType.java new file mode 100644 index 0000000000..e34376c724 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/dialect/PostgreSQLStructPGObjectJdbcType.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.dialect; + +import java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.SQLException; + +import org.hibernate.boot.model.naming.Identifier; +import org.hibernate.metamodel.mapping.EmbeddableMappingType; +import org.hibernate.metamodel.spi.RuntimeModelCreationContext; +import org.hibernate.type.descriptor.ValueBinder; +import org.hibernate.type.descriptor.ValueExtractor; +import org.hibernate.type.descriptor.WrapperOptions; +import org.hibernate.type.descriptor.java.JavaType; +import org.hibernate.type.descriptor.java.spi.UnknownBasicJavaType; +import org.hibernate.type.descriptor.jdbc.AggregateJdbcType; +import org.hibernate.type.descriptor.jdbc.BasicBinder; + +import org.postgresql.util.PGobject; + +/** + * @author Christian Beikov + */ +public class PostgreSQLStructPGObjectJdbcType extends AbstractPostgreSQLStructJdbcType { + + private final ValueExtractor objectArrayExtractor; + + public PostgreSQLStructPGObjectJdbcType() { + this( null, null, null ); + } + + private PostgreSQLStructPGObjectJdbcType( + EmbeddableMappingType embeddableMappingType, + String typeName, + int[] orderMapping) { + super( embeddableMappingType, typeName, orderMapping ); + this.objectArrayExtractor = super.getExtractor( new UnknownBasicJavaType<>( Object[].class ) ); + } + + @Override + public AggregateJdbcType resolveAggregateJdbcType( + EmbeddableMappingType mappingType, + String sqlType, + RuntimeModelCreationContext creationContext) { + return new PostgreSQLStructPGObjectJdbcType( + mappingType, + sqlType, + creationContext.getBootModel() + .getDatabase() + .getDefaultNamespace() + .locateUserDefinedType( Identifier.toIdentifier( sqlType ) ) + .getOrderMapping() + ); + } + + @Override + public ValueBinder getBinder(JavaType javaType) { + return new BasicBinder<>( javaType, this ) { + @Override + protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) + throws SQLException { + final String stringValue = ( (AbstractPostgreSQLStructJdbcType) getJdbcType() ).toString( + value, + getJavaType(), + options + ); + final PGobject holder = new PGobject(); + holder.setType( getTypeName() ); + holder.setValue( stringValue ); + st.setObject( index, holder ); + } + + @Override + protected void doBind(CallableStatement st, X value, String name, WrapperOptions options) + throws SQLException { + final String stringValue = ( (AbstractPostgreSQLStructJdbcType) getJdbcType() ).toString( + value, + getJavaType(), + options + ); + final PGobject holder = new PGobject(); + holder.setType( getTypeName() ); + holder.setValue( stringValue ); + st.setObject( name, holder ); + } + }; + } + + @Override + public ValueExtractor getExtractor(JavaType javaType) { + if ( javaType.getJavaTypeClass() == Object[].class ) { + //noinspection unchecked + return (ValueExtractor) objectArrayExtractor; + } + return super.getExtractor( javaType ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/dialect/StructJdbcType.java b/hibernate-core/src/main/java/org/hibernate/dialect/StructJdbcType.java new file mode 100644 index 0000000000..f2fc9dddd2 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/dialect/StructJdbcType.java @@ -0,0 +1,401 @@ +/* + * Hibernate, Relational Persistence for 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; + +import java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Struct; + +import org.hibernate.boot.model.naming.Identifier; +import org.hibernate.metamodel.mapping.AttributeMapping; +import org.hibernate.metamodel.mapping.EmbeddableMappingType; +import org.hibernate.metamodel.mapping.JdbcMapping; +import org.hibernate.metamodel.mapping.MappingType; +import org.hibernate.metamodel.spi.RuntimeModelCreationContext; +import org.hibernate.type.SqlTypes; +import org.hibernate.type.descriptor.ValueBinder; +import org.hibernate.type.descriptor.ValueExtractor; +import org.hibernate.type.descriptor.WrapperOptions; +import org.hibernate.type.descriptor.java.JavaType; +import org.hibernate.type.descriptor.java.spi.UnknownBasicJavaType; +import org.hibernate.type.descriptor.jdbc.AggregateJdbcType; +import org.hibernate.type.descriptor.jdbc.BasicBinder; +import org.hibernate.type.descriptor.jdbc.BasicExtractor; +import org.hibernate.type.spi.TypeConfiguration; + +/** + * @author Christian Beikov + */ +public class StructJdbcType implements AggregateJdbcType { + + public static final AggregateJdbcType INSTANCE = new StructJdbcType(); + + private final String typeName; + private final int[] orderMapping; + private final int[] inverseOrderMapping; + private final EmbeddableMappingType embeddableMappingType; + private final ValueExtractor objectArrayExtractor; + + private StructJdbcType() { + // The default instance is for reading only and will return an Object[] + this( null, null, null ); + } + + public StructJdbcType(EmbeddableMappingType embeddableMappingType, String typeName, int[] orderMapping) { + this.embeddableMappingType = embeddableMappingType; + this.typeName = typeName; + this.orderMapping = orderMapping; + if ( orderMapping == null ) { + this.inverseOrderMapping = null; + } + else { + final int[] inverseOrderMapping = new int[orderMapping.length]; + for ( int i = 0; i < orderMapping.length; i++ ) { + inverseOrderMapping[orderMapping[i]] = i; + } + this.inverseOrderMapping = inverseOrderMapping; + } + // We cache the extractor for Object[] here + // since that is used in AggregateEmbeddableFetchImpl and AggregateEmbeddableResultImpl + this.objectArrayExtractor = createBasicExtractor( new UnknownBasicJavaType<>( Object[].class ) ); + } + + @Override + public int getJdbcTypeCode() { + return SqlTypes.STRUCT; + } + + @Override + public AggregateJdbcType resolveAggregateJdbcType( + EmbeddableMappingType mappingType, + String sqlType, + RuntimeModelCreationContext creationContext) { + return new StructJdbcType( + mappingType, + sqlType, + creationContext.getBootModel() + .getDatabase() + .getDefaultNamespace() + .locateUserDefinedType( Identifier.toIdentifier( sqlType ) ) + .getOrderMapping() + ); + } + + @Override + public EmbeddableMappingType getEmbeddableMappingType() { + return embeddableMappingType; + } + + @Override + public JavaType getJdbcRecommendedJavaTypeMapping( + Integer precision, + Integer scale, + TypeConfiguration typeConfiguration) { + if ( embeddableMappingType == null ) { + return typeConfiguration.getJavaTypeRegistry().getDescriptor( Object[].class ); + } + else { + //noinspection unchecked + return (JavaType) embeddableMappingType.getMappedJavaType(); + } + } + + @Override + public void registerOutParameter(CallableStatement callableStatement, String name) throws SQLException { + callableStatement.registerOutParameter( name, getJdbcTypeCode(), typeName ); + } + + @Override + public void registerOutParameter(CallableStatement callableStatement, int index) throws SQLException { + callableStatement.registerOutParameter( index, getJdbcTypeCode(), typeName ); + } + + @Override + public Object createJdbcValue(Object domainValue, WrapperOptions options) throws SQLException { + final Object[] jdbcValues = StructHelper.getJdbcValues( + embeddableMappingType, + orderMapping, + embeddableMappingType.getValues( domainValue ), + options + ); + return options.getSession() + .getJdbcCoordinator() + .getLogicalConnection() + .getPhysicalConnection() + .createStruct( typeName, jdbcValues ); + } + + @Override + public Object[] extractJdbcValues(Object rawJdbcValue, WrapperOptions options) throws SQLException { + final Object[] attributes = ( (Struct) rawJdbcValue ).getAttributes(); + wrapRawJdbcValues( embeddableMappingType, orderMapping, inverseOrderMapping, attributes, 0, options ); + return attributes; + } + + @Override + public ValueBinder getBinder(JavaType javaType) { + return new BasicBinder<>( javaType, this ) { + @Override + protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) + throws SQLException { + st.setObject( index, createJdbcValue( value, options ) ); + } + + @Override + protected void doBind(CallableStatement st, X value, String name, WrapperOptions options) + throws SQLException { + st.setObject( name, createJdbcValue( value, options ) ); + } + }; + } + + @Override + public ValueExtractor getExtractor(JavaType javaType) { + if ( javaType.getJavaTypeClass() == Object[].class ) { + //noinspection unchecked + return (ValueExtractor) objectArrayExtractor; + } + return createBasicExtractor( javaType ); + } + + private BasicExtractor createBasicExtractor(JavaType javaType) { + return new BasicExtractor<>( javaType, this ) { + @Override + protected X doExtract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException { + return getValue( rs.getObject( paramIndex ), options ); + } + + @Override + protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException { + return getValue( statement.getObject( index ), options ); + } + + @Override + protected X doExtract(CallableStatement statement, String name, WrapperOptions options) + throws SQLException { + return getValue( statement.getObject( name ), options ); + } + + private X getValue(Object object, WrapperOptions options) throws SQLException { + if ( object == null ) { + return null; + } + final Struct struct = (Struct) object; + final Object[] values = struct.getAttributes(); + final boolean jdbcRepresentation = getJavaType().getJavaTypeClass() == Object[].class; + if ( jdbcRepresentation ) { + wrapRawJdbcValues( embeddableMappingType, orderMapping, inverseOrderMapping, values, 0, options ); + //noinspection unchecked + return (X) values; + } + assert embeddableMappingType != null && embeddableMappingType.getJavaType() == getJavaType(); + final Object[] attributeValues = getAttributeValues( + embeddableMappingType, + orderMapping, + values, + options + ); + //noinspection unchecked + return (X) embeddableMappingType.getRepresentationStrategy().getInstantiator().instantiate( + () -> attributeValues, + options.getSessionFactory() + ); + } + }; + } + + private Object[] getAttributeValues( + EmbeddableMappingType embeddableMappingType, + int[] orderMapping, + Object[] rawJdbcValues, + WrapperOptions options) throws SQLException { + final int numberOfAttributeMappings = embeddableMappingType.getNumberOfAttributeMappings(); + final Object[] attributeValues; + if ( numberOfAttributeMappings != rawJdbcValues.length || orderMapping != null ) { + attributeValues = new Object[numberOfAttributeMappings]; + } + else { + attributeValues = rawJdbcValues; + } + int jdbcIndex = 0; + for ( int i = 0; i < numberOfAttributeMappings; i++ ) { + final int attributeIndex; + if ( orderMapping == null ) { + attributeIndex = i; + } + else { + attributeIndex = orderMapping[i]; + } + final AttributeMapping attributeMapping = embeddableMappingType.getAttributeMapping( attributeIndex ); + jdbcIndex += injectAttributeValue( + attributeMapping, + attributeValues, + attributeIndex, + rawJdbcValues, + jdbcIndex, + options + ); + } + return attributeValues; + } + + private int injectAttributeValue( + AttributeMapping attributeMapping, + Object[] attributeValues, + int attributeIndex, + Object[] rawJdbcValues, + int jdbcIndex, + WrapperOptions options) throws SQLException { + final MappingType mappedType = attributeMapping.getMappedType(); + final int jdbcValueCount; + final Object rawJdbcValue = rawJdbcValues[jdbcIndex]; + if ( mappedType instanceof EmbeddableMappingType ) { + final EmbeddableMappingType embeddableMappingType = (EmbeddableMappingType) mappedType; + if ( embeddableMappingType.getAggregateMapping() != null ) { + jdbcValueCount = 1; + if ( rawJdbcValue == null ) { + attributeValues[attributeIndex] = null; + } + else { + final AggregateJdbcType aggregateJdbcType = (AggregateJdbcType) embeddableMappingType.getAggregateMapping() + .getJdbcMapping() + .getJdbcType(); + final Object[] subValues; + if ( aggregateJdbcType instanceof StructJdbcType ) { + subValues = getAttributeValues( + embeddableMappingType, + ( (StructJdbcType) aggregateJdbcType ).orderMapping, + ( (Struct) rawJdbcValue ).getAttributes(), + options + ); + } + else { + subValues = aggregateJdbcType.extractJdbcValues( rawJdbcValue, options ); + } + attributeValues[attributeIndex] = embeddableMappingType.getRepresentationStrategy() + .getInstantiator() + .instantiate( + () -> subValues, + embeddableMappingType.findContainingEntityMapping() + .getEntityPersister() + .getFactory() + ); + } + } + else { + jdbcValueCount = embeddableMappingType.getJdbcValueCount(); + final Object[] jdbcValues = new Object[jdbcValueCount]; + System.arraycopy( rawJdbcValues, jdbcIndex, jdbcValues, 0, jdbcValues.length ); + final Object[] subValues = getAttributeValues( embeddableMappingType, null, jdbcValues, options ); + attributeValues[attributeIndex] = embeddableMappingType.getRepresentationStrategy() + .getInstantiator() + .instantiate( + () -> subValues, + embeddableMappingType.findContainingEntityMapping() + .getEntityPersister() + .getFactory() + ); + } + } + else { + assert attributeMapping.getJdbcTypeCount() == 1; + jdbcValueCount = 1; + final JdbcMapping jdbcMapping = attributeMapping.getSingleJdbcMapping(); + final Object jdbcValue; + if ( rawJdbcValue == null ) { + jdbcValue = null; + } + else { + switch ( jdbcMapping.getJdbcType().getDefaultSqlTypeCode() ) { + case SqlTypes.TIMESTAMP_WITH_TIMEZONE: + case SqlTypes.TIMESTAMP_UTC: + // Only transform the raw jdbc value if it could be a TIMESTAMPTZ + jdbcValue = jdbcMapping.getJdbcJavaType() + .wrap( transformRawJdbcValue( rawJdbcValue, options ), options ); + break; + default: + jdbcValue = jdbcMapping.getJdbcJavaType().wrap( rawJdbcValue, options ); + break; + } + } + attributeValues[attributeIndex] = jdbcMapping.convertToDomainValue( jdbcValue ); + } + return jdbcValueCount; + } + + private int wrapRawJdbcValues( + EmbeddableMappingType embeddableMappingType, + int[] orderMapping, + int[] inverseOrderMapping, + Object[] jdbcValues, + int jdbcIndex, + WrapperOptions options) throws SQLException { + final Object[] targetJdbcValues; + if ( orderMapping == null ) { + targetJdbcValues = jdbcValues; + } + else { + targetJdbcValues = jdbcValues.clone(); + } + final int numberOfAttributeMappings = embeddableMappingType.getNumberOfAttributeMappings(); + for ( int i = 0; i < numberOfAttributeMappings; i++ ) { + final AttributeMapping attributeMapping; + if ( orderMapping == null ) { + attributeMapping = embeddableMappingType.getAttributeMapping( i ); + } + else { + attributeMapping = embeddableMappingType.getAttributeMapping( orderMapping[i] ); + } + final MappingType mappedType = attributeMapping.getMappedType(); + + if ( mappedType instanceof EmbeddableMappingType ) { + final EmbeddableMappingType embeddableType = (EmbeddableMappingType) mappedType; + if ( embeddableType.getAggregateMapping() != null ) { + final AggregateJdbcType aggregateJdbcType = (AggregateJdbcType) embeddableType.getAggregateMapping() + .getJdbcMapping() + .getJdbcType(); + final Object rawJdbcValue = targetJdbcValues[jdbcIndex]; + targetJdbcValues[jdbcIndex] = aggregateJdbcType.extractJdbcValues( rawJdbcValue, options ); + jdbcIndex++; + } + else { + jdbcIndex = wrapRawJdbcValues( embeddableType, null, null, targetJdbcValues, jdbcIndex, options ); + } + } + else { + assert attributeMapping.getJdbcTypeCount() == 1; + final Object rawJdbcValue = targetJdbcValues[jdbcIndex]; + if ( rawJdbcValue != null ) { + final JdbcMapping jdbcMapping = attributeMapping.getSingleJdbcMapping(); + switch ( jdbcMapping.getJdbcType().getDefaultSqlTypeCode() ) { + case SqlTypes.TIMESTAMP_WITH_TIMEZONE: + case SqlTypes.TIMESTAMP_UTC: + // Only transform the raw jdbc value if it could be a TIMESTAMPTZ + targetJdbcValues[jdbcIndex] = jdbcMapping.getJdbcJavaType() + .wrap( transformRawJdbcValue( rawJdbcValue, options ), options ); + break; + default: + targetJdbcValues[jdbcIndex] = jdbcMapping.getJdbcJavaType().wrap( rawJdbcValue, options ); + break; + } + } + jdbcIndex++; + } + } + if ( orderMapping != null ) { + StructHelper.orderJdbcValues( embeddableMappingType, inverseOrderMapping, targetJdbcValues, jdbcValues ); + } + return jdbcIndex; + } + + protected Object transformRawJdbcValue(Object rawJdbcValue, WrapperOptions options) { + return rawJdbcValue; + } + +} diff --git a/hibernate-core/src/main/java/org/hibernate/procedure/internal/PostgreSQLCallableStatementSupport.java b/hibernate-core/src/main/java/org/hibernate/procedure/internal/PostgreSQLCallableStatementSupport.java index fe6b354e8c..b99ff0b259 100644 --- a/hibernate-core/src/main/java/org/hibernate/procedure/internal/PostgreSQLCallableStatementSupport.java +++ b/hibernate-core/src/main/java/org/hibernate/procedure/internal/PostgreSQLCallableStatementSupport.java @@ -9,7 +9,7 @@ package org.hibernate.procedure.internal; import java.util.List; import org.hibernate.HibernateException; -import org.hibernate.dialect.PostgreSQLStructJdbcType; +import org.hibernate.dialect.AbstractPostgreSQLStructJdbcType; import org.hibernate.procedure.spi.FunctionReturnImplementor; import org.hibernate.procedure.spi.ProcedureCallImplementor; import org.hibernate.procedure.spi.ProcedureParameterImplementor; @@ -156,9 +156,9 @@ public class PostgreSQLCallableStatementSupport extends AbstractStandardCallable ); final OutputableType type = registration.getParameterType(); final String castType; - if ( type != null && type.getJdbcType() instanceof PostgreSQLStructJdbcType ) { + if ( type != null && type.getJdbcType() instanceof AbstractPostgreSQLStructJdbcType ) { // We have to cast struct type parameters so that PostgreSQL understands nulls - castType = ( (PostgreSQLStructJdbcType) type.getJdbcType() ).getTypeName(); + castType = ( (AbstractPostgreSQLStructJdbcType) type.getJdbcType() ).getTypeName(); buffer.append( "cast(" ); } else { diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/ArrayJdbcType.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/ArrayJdbcType.java index 2bc67e9857..9108a18cfb 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/ArrayJdbcType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/jdbc/ArrayJdbcType.java @@ -37,19 +37,6 @@ import org.hibernate.type.spi.TypeConfiguration; public class ArrayJdbcType implements JdbcType { public static final ArrayJdbcType INSTANCE = new ArrayJdbcType( ObjectJdbcType.INSTANCE ); - private static final ClassValue NAME_BINDER = new ClassValue<>() { - @Override - protected Method computeValue(Class type) { - try { - return type.getMethod( "setArray", String.class, java.sql.Array.class ); - } - catch ( Exception ex ) { - // add logging? Did we get NoSuchMethodException or SecurityException? - // Doesn't matter which. We can't use it. - } - return null; - } - }; private final JdbcType elementJdbcType; @@ -126,25 +113,11 @@ public class ArrayJdbcType implements JdbcType { protected void doBind(CallableStatement st, X value, String name, WrapperOptions options) throws SQLException { final java.sql.Array arr = getArray( value, containerJavaType, options ); - final Method nameBinder = NAME_BINDER.get( st.getClass() ); - if ( nameBinder == null ) { - try { - st.setObject( name, arr, java.sql.Types.ARRAY ); - return; - } - catch (SQLException ex) { - throw new HibernateException( "JDBC driver does not support named parameters for setArray. Use positional.", ex ); - } - } - // Note that it's supposed to have setArray(String,Array) by standard. - // There are numerous missing methods that only have versions for positional parameter, - // but not named ones. - try { - nameBinder.invoke( st, name, arr ); + st.setObject( name, arr, java.sql.Types.ARRAY ); } - catch ( Throwable t ) { - throw new HibernateException( t ); + catch (SQLException ex) { + throw new HibernateException( "JDBC driver does not support named parameters for setArray. Use positional.", ex ); } } diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/id/usertype/inet/InetJdbcType.java b/hibernate-core/src/test/java/org/hibernate/orm/test/id/usertype/inet/InetJdbcType.java index 93d4c8fa75..8e63b99019 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/id/usertype/inet/InetJdbcType.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/id/usertype/inet/InetJdbcType.java @@ -7,6 +7,7 @@ package org.hibernate.orm.test.id.usertype.inet; import org.hibernate.dialect.PostgreSQLInetJdbcType; +import org.hibernate.service.ServiceRegistry; import org.hibernate.type.descriptor.WrapperOptions; import org.hibernate.type.descriptor.java.BasicJavaType; import org.hibernate.type.descriptor.java.JavaType; diff --git a/hibernate-core/src/test/java/org/hibernate/orm/test/id/usertype/json/JsonType.java b/hibernate-core/src/test/java/org/hibernate/orm/test/id/usertype/json/JsonType.java index b04366691d..0ec7e0a888 100644 --- a/hibernate-core/src/test/java/org/hibernate/orm/test/id/usertype/json/JsonType.java +++ b/hibernate-core/src/test/java/org/hibernate/orm/test/id/usertype/json/JsonType.java @@ -6,7 +6,7 @@ */ package org.hibernate.orm.test.id.usertype.json; -import org.hibernate.dialect.PostgreSQLJsonbJdbcType; +import org.hibernate.dialect.PostgreSQLJsonPGObjectJsonbType; import org.hibernate.type.AbstractSingleColumnStandardBasicType; public class JsonType extends AbstractSingleColumnStandardBasicType { @@ -14,7 +14,7 @@ public class JsonType extends AbstractSingleColumnStandardBasicType { public static final JsonType INSTANCE = new JsonType(); public JsonType() { - super( PostgreSQLJsonbJdbcType.INSTANCE, JsonJavaType.INSTANCE ); + super( new PostgreSQLJsonPGObjectJsonbType(), JsonJavaType.INSTANCE ); } @Override diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/contributor/ContributorImplementor.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/contributor/ContributorImplementor.java index 26bf65c13d..dcdec13cc8 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/contributor/ContributorImplementor.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/contributor/ContributorImplementor.java @@ -18,7 +18,7 @@ import org.hibernate.spatial.JTSGeometryJavaType; */ public interface ContributorImplementor { - default void contributeJavaTypes(TypeContributions typeContributions) { + default void contributeJavaTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) { typeContributions.contributeJavaType( GeolatteGeometryJavaType.GEOMETRY_INSTANCE ); typeContributions.contributeJavaType( GeolatteGeometryJavaType.POINT_INSTANCE ); typeContributions.contributeJavaType( GeolatteGeometryJavaType.LINESTRING_INSTANCE ); @@ -40,7 +40,7 @@ public interface ContributorImplementor { } - void contributeJdbcTypes(TypeContributions typeContributions); + void contributeJdbcTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry); void contributeFunctions(FunctionContributions functionContributions); diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/contributor/SpatialTypeContributor.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/contributor/SpatialTypeContributor.java index 35e6a9abb4..1d1e0b82a6 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/contributor/SpatialTypeContributor.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/contributor/SpatialTypeContributor.java @@ -18,8 +18,8 @@ public class SpatialTypeContributor implements TypeContributor { ContributorImplementor contributorImplementor = ContributorResolver.resolveSpatialtypeContributorImplementor( serviceRegistry ); if (contributorImplementor != null) { - contributorImplementor.contributeJavaTypes( typeContributions ); - contributorImplementor.contributeJdbcTypes( typeContributions ); + contributorImplementor.contributeJavaTypes( typeContributions, serviceRegistry ); + contributorImplementor.contributeJdbcTypes( typeContributions, serviceRegistry ); } } diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/cockroachdb/CockroachDbContributor.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/cockroachdb/CockroachDbContributor.java index e10fff4c57..dcca4f5125 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/cockroachdb/CockroachDbContributor.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/cockroachdb/CockroachDbContributor.java @@ -9,7 +9,7 @@ package org.hibernate.spatial.dialect.cockroachdb; import org.hibernate.boot.model.FunctionContributions; import org.hibernate.boot.model.TypeContributions; -import org.hibernate.dialect.PostgreSQLPGObjectJdbcType; +import org.hibernate.dialect.PgJdbcHelper; import org.hibernate.query.sqm.function.SqmFunctionRegistry; import org.hibernate.service.ServiceRegistry; import org.hibernate.spatial.FunctionKey; @@ -30,9 +30,9 @@ public class CockroachDbContributor implements ContributorImplementor { } @Override - public void contributeJdbcTypes(TypeContributions typeContributions) { + public void contributeJdbcTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) { HSMessageLogger.SPATIAL_MSG_LOGGER.typeContributions( this.getClass().getCanonicalName() ); - if ( PostgreSQLPGObjectJdbcType.isUsable() ) { + if ( PgJdbcHelper.isUsable( serviceRegistry ) ) { typeContributions.contributeJdbcType( PGGeometryJdbcType.INSTANCE_WKB_2 ); typeContributions.contributeJdbcType( PGGeographyJdbcType.INSTANCE_WKB_2 ); } diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/h2gis/H2GisDialectContributor.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/h2gis/H2GisDialectContributor.java index 2a242ae0d4..d99105e964 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/h2gis/H2GisDialectContributor.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/h2gis/H2GisDialectContributor.java @@ -23,7 +23,7 @@ public class H2GisDialectContributor implements ContributorImplementor { this.serviceRegistry = serviceRegistry; } - public void contributeJdbcTypes(TypeContributions typeContributions) { + public void contributeJdbcTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) { HSMessageLogger.SPATIAL_MSG_LOGGER.typeContributions( this.getClass().getCanonicalName() ); typeContributions.contributeJdbcType( H2GISGeometryType.INSTANCE ); } diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/mariadb/MariaDBDialectContributor.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/mariadb/MariaDBDialectContributor.java index 3e8f5890e8..5df0d9462c 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/mariadb/MariaDBDialectContributor.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/mariadb/MariaDBDialectContributor.java @@ -24,7 +24,7 @@ public class MariaDBDialectContributor implements ContributorImplementor { this.serviceRegistry = serviceRegistry; } - public void contributeJdbcTypes(TypeContributions typeContributions) { + public void contributeJdbcTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) { HSMessageLogger.SPATIAL_MSG_LOGGER.typeContributions( this.getClass().getCanonicalName() ); typeContributions.contributeJdbcType( MySQLGeometryJdbcType.INSTANCE ); } diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/mysql/MySQLDialectContributor.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/mysql/MySQLDialectContributor.java index 1fb8d614c4..beb0b4a14a 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/mysql/MySQLDialectContributor.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/mysql/MySQLDialectContributor.java @@ -24,7 +24,7 @@ public class MySQLDialectContributor implements ContributorImplementor { } @Override - public void contributeJdbcTypes(TypeContributions typeContributions) { + public void contributeJdbcTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) { HSMessageLogger.SPATIAL_MSG_LOGGER.typeContributions( this.getClass().getCanonicalName() ); typeContributions.contributeJdbcType( MySQLGeometryJdbcType.INSTANCE); } diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/OracleDialectContributor.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/OracleDialectContributor.java index 3fc774e3d6..0d4456b04b 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/OracleDialectContributor.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/oracle/OracleDialectContributor.java @@ -38,7 +38,7 @@ public class OracleDialectContributor implements ContributorImplementor { } @Override - public void contributeJdbcTypes(TypeContributions typeContributions) { + public void contributeJdbcTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) { HSMessageLogger.SPATIAL_MSG_LOGGER.typeContributions( this.getClass().getCanonicalName() ); final ConfigurationService cfgService = getServiceRegistry().getService( ConfigurationService.class ); final StrategySelector strategySelector = getServiceRegistry().getService( StrategySelector.class ); diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisDialectContributor.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisDialectContributor.java index 8479224ee8..8253f232b6 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisDialectContributor.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/postgis/PostgisDialectContributor.java @@ -9,7 +9,7 @@ package org.hibernate.spatial.dialect.postgis; import org.hibernate.boot.model.FunctionContributions; import org.hibernate.boot.model.TypeContributions; -import org.hibernate.dialect.PostgreSQLPGObjectJdbcType; +import org.hibernate.dialect.PgJdbcHelper; import org.hibernate.query.sqm.function.SqmFunctionRegistry; import org.hibernate.service.ServiceRegistry; import org.hibernate.spatial.HSMessageLogger; @@ -17,16 +17,16 @@ import org.hibernate.spatial.contributor.ContributorImplementor; public class PostgisDialectContributor implements ContributorImplementor { - private final ServiceRegistry serviceRegistryegistry; + private final ServiceRegistry serviceRegistry; public PostgisDialectContributor(ServiceRegistry serviceRegistry) { - this.serviceRegistryegistry = serviceRegistry; + this.serviceRegistry = serviceRegistry; } @Override - public void contributeJdbcTypes(TypeContributions typeContributions) { + public void contributeJdbcTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) { HSMessageLogger.SPATIAL_MSG_LOGGER.typeContributions( this.getClass().getCanonicalName() ); - if ( PostgreSQLPGObjectJdbcType.isUsable() ) { + if ( PgJdbcHelper.isUsable( serviceRegistry ) ) { typeContributions.contributeJdbcType( PGGeometryJdbcType.INSTANCE_WKB_2 ); typeContributions.contributeJdbcType( PGGeographyJdbcType.INSTANCE_WKB_2 ); } @@ -50,6 +50,6 @@ public class PostgisDialectContributor implements ContributorImplementor { @Override public ServiceRegistry getServiceRegistry() { - return this.serviceRegistryegistry; + return this.serviceRegistry; } } diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/SqlServerDialectContributor.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/SqlServerDialectContributor.java index 5022169d12..1169baec9e 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/SqlServerDialectContributor.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/dialect/sqlserver/SqlServerDialectContributor.java @@ -22,7 +22,7 @@ public class SqlServerDialectContributor implements ContributorImplementor { } @Override - public void contributeJdbcTypes(TypeContributions typeContributions) { + public void contributeJdbcTypes(TypeContributions typeContributions, ServiceRegistry serviceRegistry) { HSMessageLogger.SPATIAL_MSG_LOGGER.typeContributions( this.getClass().getCanonicalName() ); typeContributions.contributeJdbcType( SqlServerGeometryType.INSTANCE ); typeContributions.contributeJdbcType( SqlServerGeographyType.INSTANCE );