diff --git a/gradle/libraries.gradle b/gradle/libraries.gradle index 4b8548d8b3..8aa97bd43b 100644 --- a/gradle/libraries.gradle +++ b/gradle/libraries.gradle @@ -24,6 +24,8 @@ ext { javassistVersion = '3.22.0-GA' byteBuddyVersion = '1.8.0' // Now with JDK10 compatibility and preliminary support for JDK11 + geolatteVersion = '1.3.0' + // Wildfly version targeted by module ZIP; Arquillian/Shrinkwrap versions used for CDI testing and testing the module ZIP wildflyVersion = '12.0.0.Final' arquillianVersion = '1.1.11.Final' @@ -31,6 +33,8 @@ ext { shrinkwrapDescriptorsVersion = '2.0.0-alpha-8' wildflyArquillianContainerVersion = '2.0.0.Final' + jodaTimeVersion = '2.3' + libraries = [ // Ant ant: 'org.apache.ant:ant:1.8.2', @@ -74,6 +78,8 @@ ext { jaxb2_jaxb: 'org.jvnet.jaxb2_commons:jaxb2-basics-jaxb:2.2.4-1', jaxb2_jaxb_xjc: 'org.jvnet.jaxb2_commons:jaxb2-basics-jaxb-xjc:2.2.4-1', + geolatte: "org.geolatte:geolatte-geom:${geolatteVersion}", + // Animal Sniffer Ant Task and Java 1.6 API signature file // not using 1.9 for the time being due to MANIMALSNIFFER-34 animal_sniffer: 'org.codehaus.mojo:animal-sniffer-ant-tasks:1.13', @@ -105,6 +111,8 @@ ext { db2: 'com.ibm.db2:db2jcc:10.5', hana: 'com.sap.db.jdbc:ngdbc:2.2.1', // for HANA 1 the minimum required client version is 1.120.20 + jodaTime: "joda-time:joda-time:${jodaTimeVersion}", + informix: 'com.ibm.informix:jdbc:4.10.7.20160517', jboss_jta: "org.jboss.jbossts:jbossjta:4.16.4.Final", xapool: "com.experlog:xapool:1.5.0", diff --git a/hibernate-core/hibernate-core.gradle b/hibernate-core/hibernate-core.gradle index b2a9c3ee82..50263efd75 100644 --- a/hibernate-core/hibernate-core.gradle +++ b/hibernate-core/hibernate-core.gradle @@ -69,7 +69,7 @@ dependencies { testCompile( libraries.classmate ) testCompile( libraries.mockito ) testCompile( libraries.mockito_inline ) - testCompile( 'joda-time:joda-time:2.3' ) + testCompile( libraries.jodaTime ) testCompile( libraries.cdi ) { // we need to force it to make sure we influence the one coming from arquillian diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/TypeContributions.java b/hibernate-core/src/main/java/org/hibernate/boot/model/TypeContributions.java index d85c8912e5..8f2dcbfa94 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/TypeContributions.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/TypeContributions.java @@ -7,6 +7,8 @@ package org.hibernate.boot.model; import org.hibernate.type.BasicType; +import org.hibernate.type.StandardBasicTypeTemplate; +import org.hibernate.type.descriptor.java.spi.JavaTypeDescriptorRegistry; import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; import org.hibernate.type.descriptor.java.JavaTypeDescriptor; import org.hibernate.type.spi.TypeConfiguration; @@ -19,34 +21,56 @@ import org.hibernate.usertype.UserType; * @author Steve Ebersole */ public interface TypeContributions { + TypeConfiguration getTypeConfiguration(); + + /** + * Add the JavaTypeDescriptor to the {@link TypeConfiguration}'s + * {@link JavaTypeDescriptorRegistry} + */ + void contributeJavaTypeDescriptor(JavaTypeDescriptor descriptor); + + /** + * Add the JavaTypeDescriptor to the {@link TypeConfiguration}'s + * {@link JavaTypeDescriptorRegistry} + */ + void contributeSqlTypeDescriptor(SqlTypeDescriptor descriptor); + void contributeType(BasicType type); /** - * @deprecated (since 5.3) It will be replaced by {@link #contributeType(BasicType)} - * but do not move to it before 6.0 + * @deprecated (since 5.3) Use {@link #contributeType(BasicType)} instead. Basic + * types will be defined and handled much differently in 6.0 based on a combination + * of {@link JavaTypeDescriptor}, {@link SqlTypeDescriptor} and a concept of a "value + * converter" (a JPA AttributeConverter, an enum value resolver, etc). To get as + * close as possible in 5.3 use existing {@link JavaTypeDescriptor} and + * {@link SqlTypeDescriptor} implementations (or write your own for custom types) + * and use {@link StandardBasicTypeTemplate} to combine those with + * registration keys and call {@link #contributeType(BasicType)} instead */ @Deprecated void contributeType(BasicType type, String... keys); /** - * @deprecated (since 5.3) It will be replaced by {@link #contributeType(BasicType)} - * but do not move to it before 6.0 + * @deprecated (since 5.3) Use {@link #contributeType(BasicType)} instead. + * {@link UserType}, as currently defined, will be done very differently in 6.0. + * In most cases a {@link UserType} can be simply replaced with proper + * {@link JavaTypeDescriptor}. To get as close as possible to 6.0 in 5.3 use + * existing {@link JavaTypeDescriptor} and {@link SqlTypeDescriptor} + * implementations (or write your own for custom impls) and use + * {@link StandardBasicTypeTemplate} to combine those with registration keys + * and call {@link #contributeType(BasicType)} instead */ + @Deprecated void contributeType(UserType type, String... keys); /** - * @deprecated (since 5.3) It will be replaced by {@link #contributeType(BasicType)} - * but do not move to it before 6.0 + * @deprecated (since 5.3) Use {@link #contributeType(BasicType)} instead. + * {@link CompositeUserType}, as currently defined, will be done very differently + * in 6.0. {@link CompositeUserType} should be replaced with a normal Hibernate + * component or JPA embeddable (different names, same thing. This embeddable + * may contain, in turn, custom types that should be handled as described on these + * methods */ + @Deprecated void contributeType(CompositeUserType type, String... keys); - - /* - * Add the JavaTypeDescriptor to the - * @param descriptor - */ - void contributeJavaTypeDescriptor(JavaTypeDescriptor descriptor); - - void contributeSqlTypeDescriptor(SqlTypeDescriptor descriptor); - - TypeConfiguration getTypeConfiguration(); } diff --git a/hibernate-core/src/main/java/org/hibernate/boot/model/convert/spi/JpaAttributeConverterCreationContext.java b/hibernate-core/src/main/java/org/hibernate/boot/model/convert/spi/JpaAttributeConverterCreationContext.java index bb9c19af9f..03a9bd34ef 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/model/convert/spi/JpaAttributeConverterCreationContext.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/model/convert/spi/JpaAttributeConverterCreationContext.java @@ -7,7 +7,7 @@ package org.hibernate.boot.model.convert.spi; import org.hibernate.resource.beans.spi.ManagedBeanRegistry; -import org.hibernate.type.descriptor.java.JavaTypeDescriptorRegistry; +import org.hibernate.type.descriptor.java.spi.JavaTypeDescriptorRegistry; /** * Access to information that implementors of diff --git a/hibernate-core/src/main/java/org/hibernate/boot/registry/StandardServiceRegistryBuilder.java b/hibernate-core/src/main/java/org/hibernate/boot/registry/StandardServiceRegistryBuilder.java index 302b9f4763..4dff977e74 100644 --- a/hibernate-core/src/main/java/org/hibernate/boot/registry/StandardServiceRegistryBuilder.java +++ b/hibernate-core/src/main/java/org/hibernate/boot/registry/StandardServiceRegistryBuilder.java @@ -64,7 +64,7 @@ public class StandardServiceRegistryBuilder { * @param bootstrapServiceRegistry Provided bootstrap registry to use. */ public StandardServiceRegistryBuilder(BootstrapServiceRegistry bootstrapServiceRegistry) { - this( bootstrapServiceRegistry, LoadedConfig.baseline() ); + this( bootstrapServiceRegistry, LoadedConfig.baseline() ); } /** @@ -72,7 +72,9 @@ public class StandardServiceRegistryBuilder { * * @param bootstrapServiceRegistry Provided bootstrap registry to use. */ - public StandardServiceRegistryBuilder(BootstrapServiceRegistry bootstrapServiceRegistry, LoadedConfig loadedConfigBaseline) { + public StandardServiceRegistryBuilder( + BootstrapServiceRegistry bootstrapServiceRegistry, + LoadedConfig loadedConfigBaseline) { this.settings = Environment.getProperties(); this.bootstrapServiceRegistry = bootstrapServiceRegistry; this.configLoader = new ConfigLoader( bootstrapServiceRegistry ); @@ -103,7 +105,7 @@ public class StandardServiceRegistryBuilder { /** * Read settings from a {@link java.util.Properties} file by resource name. - * + *

* Differs from {@link #configure()} and {@link #configure(String)} in that here we expect to read a * {@link java.util.Properties} file while for {@link #configure} we read the XML variant. * @@ -114,7 +116,7 @@ public class StandardServiceRegistryBuilder { * @see #configure() * @see #configure(String) */ - @SuppressWarnings( {"unchecked"}) + @SuppressWarnings({"unchecked"}) public StandardServiceRegistryBuilder loadProperties(String resourceName) { settings.putAll( configLoader.loadProperties( resourceName ) ); return this; @@ -122,7 +124,7 @@ public class StandardServiceRegistryBuilder { /** * Read settings from a {@link java.util.Properties} file by File reference - * + *

* Differs from {@link #configure()} and {@link #configure(String)} in that here we expect to read a * {@link java.util.Properties} file while for {@link #configure} we read the XML variant. * @@ -133,7 +135,7 @@ public class StandardServiceRegistryBuilder { * @see #configure() * @see #configure(String) */ - @SuppressWarnings( {"unchecked"}) + @SuppressWarnings({"unchecked"}) public StandardServiceRegistryBuilder loadProperties(File file) { settings.putAll( configLoader.loadProperties( file ) ); return this; @@ -171,7 +173,7 @@ public class StandardServiceRegistryBuilder { return configure( configLoader.loadConfigXmlUrl( url ) ); } - @SuppressWarnings( {"unchecked"}) + @SuppressWarnings({"unchecked"}) public StandardServiceRegistryBuilder configure(LoadedConfig loadedConfig) { aggregatedCfgXml.merge( loadedConfig ); settings.putAll( loadedConfig.getConfigurationValues() ); @@ -187,7 +189,7 @@ public class StandardServiceRegistryBuilder { * * @return this, for method chaining */ - @SuppressWarnings( {"unchecked", "UnusedDeclaration"}) + @SuppressWarnings({"unchecked", "UnusedDeclaration"}) public StandardServiceRegistryBuilder applySetting(String settingName, Object value) { settings.put( settingName, value ); return this; @@ -200,7 +202,7 @@ public class StandardServiceRegistryBuilder { * * @return this, for method chaining */ - @SuppressWarnings( {"unchecked", "UnusedDeclaration"}) + @SuppressWarnings({"unchecked", "UnusedDeclaration"}) public StandardServiceRegistryBuilder applySettings(Map settings) { this.settings.putAll( settings ); return this; @@ -213,7 +215,7 @@ public class StandardServiceRegistryBuilder { * * @return this, for method chaining */ - @SuppressWarnings( {"UnusedDeclaration"}) + @SuppressWarnings({"UnusedDeclaration"}) public StandardServiceRegistryBuilder addInitiator(StandardServiceInitiator initiator) { initiators.add( initiator ); return this; @@ -227,7 +229,7 @@ public class StandardServiceRegistryBuilder { * * @return this, for method chaining */ - @SuppressWarnings( {"unchecked"}) + @SuppressWarnings({"unchecked"}) public StandardServiceRegistryBuilder addService(final Class serviceRole, final Service service) { providedServices.add( new ProvidedService( serviceRole, service ) ); return this; @@ -289,9 +291,11 @@ public class StandardServiceRegistryBuilder { @SuppressWarnings("deprecation") private void applyServiceContributingIntegrators() { - for ( Integrator integrator : bootstrapServiceRegistry.getService( IntegratorService.class ).getIntegrators() ) { + for ( Integrator integrator : bootstrapServiceRegistry.getService( IntegratorService.class ) + .getIntegrators() ) { if ( org.hibernate.integrator.spi.ServiceContributingIntegrator.class.isInstance( integrator ) ) { - org.hibernate.integrator.spi.ServiceContributingIntegrator.class.cast( integrator ).prepareServices( this ); + org.hibernate.integrator.spi.ServiceContributingIntegrator.class.cast( integrator ).prepareServices( + this ); } } } @@ -332,4 +336,4 @@ public class StandardServiceRegistryBuilder { ( (StandardServiceRegistryImpl) serviceRegistry ).destroy(); } -} +} \ No newline at end of file diff --git a/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java b/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java index b6e59d6a4a..a563522f18 100644 --- a/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java +++ b/hibernate-core/src/main/java/org/hibernate/mapping/SimpleValue.java @@ -50,13 +50,13 @@ import org.hibernate.type.Type; import org.hibernate.type.descriptor.JdbcTypeNameMapper; import org.hibernate.type.descriptor.converter.AttributeConverterSqlTypeDescriptorAdapter; import org.hibernate.type.descriptor.converter.AttributeConverterTypeAdapter; +import org.hibernate.type.descriptor.java.BasicJavaDescriptor; import org.hibernate.type.descriptor.java.JavaTypeDescriptor; -import org.hibernate.type.descriptor.java.JavaTypeDescriptorRegistry; +import org.hibernate.type.descriptor.spi.JdbcRecommendedSqlTypeMappingContext; import org.hibernate.type.descriptor.sql.JdbcTypeJavaClassMappings; import org.hibernate.type.descriptor.sql.LobTypeMappings; import org.hibernate.type.descriptor.sql.NationalizedTypeMappings; import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; -import org.hibernate.type.descriptor.sql.SqlTypeDescriptorRegistry; import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.usertype.DynamicParameterizedType; @@ -576,13 +576,13 @@ public class SimpleValue implements KeyValue { } @Override - public JavaTypeDescriptorRegistry getJavaTypeDescriptorRegistry() { + public org.hibernate.type.descriptor.java.spi.JavaTypeDescriptorRegistry getJavaTypeDescriptorRegistry() { return metadata.getTypeConfiguration().getJavaTypeDescriptorRegistry(); } } ); - final JavaTypeDescriptor entityAttributeJavaTypeDescriptor = jpaAttributeConverter.getDomainJavaTypeDescriptor(); + final BasicJavaDescriptor entityAttributeJavaTypeDescriptor = jpaAttributeConverter.getDomainJavaTypeDescriptor(); // build the SqlTypeDescriptor adapter ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ @@ -591,7 +591,11 @@ public class SimpleValue implements KeyValue { // corresponding to the AttributeConverter's declared "databaseColumnJavaType" (how we read that value out // of ResultSets). See JdbcTypeJavaClassMappings for details. Again, given example, this should return // VARCHAR/CHAR - int jdbcTypeCode = JdbcTypeJavaClassMappings.INSTANCE.determineJdbcTypeCodeForJavaClass( jpaAttributeConverter.getRelationalJavaTypeDescriptor().getJavaType() ); + final SqlTypeDescriptor recommendedSqlType = jpaAttributeConverter.getRelationalJavaTypeDescriptor().getJdbcRecommendedSqlType( + // todo (6.0) : handle the other JdbcRecommendedSqlTypeMappingContext methods + metadata::getTypeConfiguration + ); + int jdbcTypeCode = recommendedSqlType.getSqlType(); if ( isLob() ) { if ( LobTypeMappings.INSTANCE.hasCorrespondingLobCode( jdbcTypeCode ) ) { jdbcTypeCode = LobTypeMappings.INSTANCE.getCorrespondingLobCode( jdbcTypeCode ); diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/convert/internal/JpaAttributeConverterImpl.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/convert/internal/JpaAttributeConverterImpl.java index 941a37ecca..6be89acaf1 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/convert/internal/JpaAttributeConverterImpl.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/convert/internal/JpaAttributeConverterImpl.java @@ -10,6 +10,7 @@ import javax.persistence.AttributeConverter; import org.hibernate.metamodel.model.convert.spi.JpaAttributeConverter; import org.hibernate.resource.beans.spi.ManagedBean; +import org.hibernate.type.descriptor.java.BasicJavaDescriptor; import org.hibernate.type.descriptor.java.JavaTypeDescriptor; /** @@ -20,8 +21,8 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor; public class JpaAttributeConverterImpl implements JpaAttributeConverter { private final ManagedBean> attributeConverterBean; private final JavaTypeDescriptor> converterJavaTypeDescriptor; - private final JavaTypeDescriptor domainJavaTypeDescriptor; - private final JavaTypeDescriptor relationalJavaTypeDescriptor; + private final BasicJavaDescriptor domainJavaTypeDescriptor; + private final BasicJavaDescriptor relationalJavaTypeDescriptor; public JpaAttributeConverterImpl( ManagedBean> attributeConverterBean, @@ -30,8 +31,13 @@ public class JpaAttributeConverterImpl implements JpaAttributeConverter relationalJavaTypeDescriptor) { this.attributeConverterBean = attributeConverterBean; this.converterJavaTypeDescriptor = converterJavaTypeDescriptor; - this.domainJavaTypeDescriptor = domainJavaTypeDescriptor; - this.relationalJavaTypeDescriptor = relationalJavaTypeDescriptor; + this.domainJavaTypeDescriptor = (BasicJavaDescriptor) domainJavaTypeDescriptor; + this.relationalJavaTypeDescriptor = (BasicJavaDescriptor) relationalJavaTypeDescriptor; + } + + @Override + public ManagedBean> getConverterBean() { + return attributeConverterBean; } @Override @@ -50,12 +56,12 @@ public class JpaAttributeConverterImpl implements JpaAttributeConverter getDomainJavaTypeDescriptor() { + public BasicJavaDescriptor getDomainJavaTypeDescriptor() { return domainJavaTypeDescriptor; } @Override - public JavaTypeDescriptor getRelationalJavaTypeDescriptor() { + public BasicJavaDescriptor getRelationalJavaTypeDescriptor() { return relationalJavaTypeDescriptor; } } diff --git a/hibernate-core/src/main/java/org/hibernate/metamodel/model/convert/spi/JpaAttributeConverter.java b/hibernate-core/src/main/java/org/hibernate/metamodel/model/convert/spi/JpaAttributeConverter.java index 2dad1c1b0d..a5f5d4f4b7 100644 --- a/hibernate-core/src/main/java/org/hibernate/metamodel/model/convert/spi/JpaAttributeConverter.java +++ b/hibernate-core/src/main/java/org/hibernate/metamodel/model/convert/spi/JpaAttributeConverter.java @@ -8,6 +8,8 @@ package org.hibernate.metamodel.model.convert.spi; import javax.persistence.AttributeConverter; +import org.hibernate.resource.beans.spi.ManagedBean; +import org.hibernate.type.descriptor.java.BasicJavaDescriptor; import org.hibernate.type.descriptor.java.JavaTypeDescriptor; /** @@ -17,6 +19,9 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor; */ public interface JpaAttributeConverter extends BasicValueConverter { JavaTypeDescriptor> getConverterJavaTypeDescriptor(); - JavaTypeDescriptor getDomainJavaTypeDescriptor(); - JavaTypeDescriptor getRelationalJavaTypeDescriptor(); + + ManagedBean> getConverterBean(); + + BasicJavaDescriptor getDomainJavaTypeDescriptor(); + BasicJavaDescriptor getRelationalJavaTypeDescriptor(); } diff --git a/hibernate-core/src/main/java/org/hibernate/service/ServiceRegistry.java b/hibernate-core/src/main/java/org/hibernate/service/ServiceRegistry.java index fb77f52810..da5e34d782 100644 --- a/hibernate-core/src/main/java/org/hibernate/service/ServiceRegistry.java +++ b/hibernate-core/src/main/java/org/hibernate/service/ServiceRegistry.java @@ -11,7 +11,7 @@ package org.hibernate.service; * * @author Steve Ebersole */ -public interface ServiceRegistry { +public interface ServiceRegistry extends AutoCloseable { /** * Retrieve this registry's parent registry. * @@ -56,4 +56,6 @@ public interface ServiceRegistry { return service; } + @Override + void close(); } diff --git a/hibernate-core/src/main/java/org/hibernate/service/spi/ServiceRegistryImplementor.java b/hibernate-core/src/main/java/org/hibernate/service/spi/ServiceRegistryImplementor.java index fc9b545a20..5122727498 100644 --- a/hibernate-core/src/main/java/org/hibernate/service/spi/ServiceRegistryImplementor.java +++ b/hibernate-core/src/main/java/org/hibernate/service/spi/ServiceRegistryImplementor.java @@ -25,6 +25,11 @@ public interface ServiceRegistryImplementor extends ServiceRegistry { */ ServiceBinding locateServiceBinding(Class serviceRole); + @Override + default void close() { + destroy(); + } + /** * Release resources */ diff --git a/hibernate-core/src/main/java/org/hibernate/type/AbstractStandardBasicType.java b/hibernate-core/src/main/java/org/hibernate/type/AbstractStandardBasicType.java index c7b330ccb3..eb91251e35 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/AbstractStandardBasicType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/AbstractStandardBasicType.java @@ -91,7 +91,7 @@ public abstract class AbstractStandardBasicType @Override public String[] getRegistrationKeys() { return registerUnderJavaType() - ? new String[] { getName(), javaTypeDescriptor.getJavaTypeClass().getName() } + ? new String[] { getName(), javaTypeDescriptor.getJavaType().getName() } : new String[] { getName() }; } @@ -128,7 +128,7 @@ public abstract class AbstractStandardBasicType @Override public final Class getReturnedClass() { - return javaTypeDescriptor.getJavaTypeClass(); + return javaTypeDescriptor.getJavaType(); } @Override diff --git a/hibernate-core/src/main/java/org/hibernate/type/BasicTypeRegistry.java b/hibernate-core/src/main/java/org/hibernate/type/BasicTypeRegistry.java index 3b4b996dbd..cead4fd315 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/BasicTypeRegistry.java +++ b/hibernate-core/src/main/java/org/hibernate/type/BasicTypeRegistry.java @@ -169,6 +169,12 @@ public class BasicTypeRegistry implements Serializable { register( new CompositeCustomType( type, keys ) ); } + public void unregister(String... keys) { + for ( String key : keys ) { + registry.remove( key ); + } + } + public BasicType getRegisteredType(String key) { return registry.get( key ); } diff --git a/hibernate-core/src/main/java/org/hibernate/type/PostgresUUIDType.java b/hibernate-core/src/main/java/org/hibernate/type/PostgresUUIDType.java index d04bf5e26c..3b7ee81fa4 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/PostgresUUIDType.java +++ b/hibernate-core/src/main/java/org/hibernate/type/PostgresUUIDType.java @@ -16,11 +16,13 @@ import java.util.UUID; import org.hibernate.type.descriptor.ValueBinder; import org.hibernate.type.descriptor.ValueExtractor; import org.hibernate.type.descriptor.WrapperOptions; +import org.hibernate.type.descriptor.java.BasicJavaDescriptor; import org.hibernate.type.descriptor.java.JavaTypeDescriptor; import org.hibernate.type.descriptor.java.UUIDTypeDescriptor; import org.hibernate.type.descriptor.sql.BasicBinder; import org.hibernate.type.descriptor.sql.BasicExtractor; import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; +import org.hibernate.type.spi.TypeConfiguration; /** * Specialized type mapping for {@link UUID} and the Postgres UUID data type (which is mapped as OTHER in its @@ -59,6 +61,12 @@ public class PostgresUUIDType extends AbstractSingleColumnStandardBasicType ValueBinder getBinder(final JavaTypeDescriptor javaTypeDescriptor) { return new BasicBinder( javaTypeDescriptor, this ) { @Override diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/AbstractTypeDescriptor.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/AbstractTypeDescriptor.java index 2ea2036701..0266f6f423 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/AbstractTypeDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/AbstractTypeDescriptor.java @@ -16,9 +16,14 @@ import org.hibernate.internal.util.compare.EqualsHelper; /** * Abstract adapter for Java type descriptors. * + * @apiNote This abstract descriptor implements BasicJavaDescriptor + * because we currently only categorize "basic" JavaTypeDescriptors, + * as in the {@link javax.persistence.metamodel.Type.PersistenceType#BASIC} + * sense + * * @author Steve Ebersole */ -public abstract class AbstractTypeDescriptor implements JavaTypeDescriptor, Serializable { +public abstract class AbstractTypeDescriptor implements BasicJavaDescriptor, Serializable { private final Class type; private final MutabilityPlan mutabilityPlan; private final Comparator comparator; diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/BasicJavaDescriptor.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/BasicJavaDescriptor.java new file mode 100644 index 0000000000..7bca9ce773 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/BasicJavaDescriptor.java @@ -0,0 +1,36 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.type.descriptor.java; + +import org.hibernate.type.descriptor.spi.JdbcRecommendedSqlTypeMappingContext; +import org.hibernate.type.descriptor.sql.JdbcTypeJavaClassMappings; +import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; + +/** + * @apiNote Currently this is the only high-level categorization of + * JavaTypeDescriptor, but 6.0 will have specific JavaTypeDescriptor + * categorizations for managed-type, mapped-superclass, identifiable-type, entity, embeddable, + * collections. + * + * @author Steve Ebersole + */ +public interface BasicJavaDescriptor extends JavaTypeDescriptor { + /** + * Obtain the "recommended" SQL type descriptor for this Java type. The recommended + * aspect comes from the JDBC spec (mostly). + * + * @param context Contextual information + * + * @return The recommended SQL type descriptor + */ + default SqlTypeDescriptor getJdbcRecommendedSqlType(JdbcRecommendedSqlTypeMappingContext context) { + // match legacy behavior + return context.getTypeConfiguration().getSqlTypeDescriptorRegistry().getDescriptor( + JdbcTypeJavaClassMappings.INSTANCE.determineJdbcTypeCodeForJavaClass( getJavaType() ) + ); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/EnumJavaTypeDescriptor.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/EnumJavaTypeDescriptor.java index a3fa10babd..1b1039968f 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/EnumJavaTypeDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/EnumJavaTypeDescriptor.java @@ -15,7 +15,7 @@ import org.hibernate.type.descriptor.WrapperOptions; */ public class EnumJavaTypeDescriptor extends AbstractTypeDescriptor { @SuppressWarnings("unchecked") - protected EnumJavaTypeDescriptor(Class type) { + public EnumJavaTypeDescriptor(Class type) { super( type, ImmutableMutabilityPlan.INSTANCE ); //JavaTypeDescriptorRegistry.INSTANCE.addDescriptor( this ); } diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/JavaTypeDescriptor.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/JavaTypeDescriptor.java index 18489391bb..bf8c81e456 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/JavaTypeDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/JavaTypeDescriptor.java @@ -9,6 +9,8 @@ package org.hibernate.type.descriptor.java; import java.io.Serializable; import java.util.Comparator; +import org.hibernate.internal.util.compare.ComparableComparator; +import org.hibernate.internal.util.compare.EqualsHelper; import org.hibernate.type.descriptor.WrapperOptions; /** @@ -37,17 +39,18 @@ public interface JavaTypeDescriptor extends Serializable { /** * Retrieve the mutability plan for this Java type. - * - * @return The mutability plan */ - public MutabilityPlan getMutabilityPlan(); + @SuppressWarnings("unchecked") + default MutabilityPlan getMutabilityPlan() { + return ImmutableMutabilityPlan.INSTANCE; + } /** * Retrieve the natural comparator for this type. - * - * @return The natural comparator. */ - public Comparator getComparator(); + default Comparator getComparator() { + return Comparable.class.isAssignableFrom( Comparable.class ) ? ComparableComparator.INSTANCE : null; + } /** * Extract a proper hash code for this value. @@ -56,7 +59,12 @@ public interface JavaTypeDescriptor extends Serializable { * * @return The extracted hash code. */ - public int extractHashCode(T value); + default int extractHashCode(T value) { + if ( value == null ) { + throw new IllegalArgumentException( "Value to extract hashCode from cannot be null" ); + } + return value.hashCode(); + } /** * Determine if two instances are equal @@ -66,7 +74,9 @@ public interface JavaTypeDescriptor extends Serializable { * * @return True if the two are considered equal; false otherwise. */ - public boolean areEqual(T one, T another); + default boolean areEqual(T one, T another) { + return EqualsHelper.areEqual( one, another ); + } /** * Extract a loggable representation of the value. @@ -75,11 +85,15 @@ public interface JavaTypeDescriptor extends Serializable { * * @return The loggable representation */ - public String extractLoggableRepresentation(T value); + default String extractLoggableRepresentation(T value) { + return toString( value ); + } - public String toString(T value); + default String toString(T value) { + return value == null ? "null" : value.toString(); + } - public T fromString(String string); + T fromString(String string); /** * Unwrap an instance of our handled Java type into the requested type. @@ -97,7 +111,7 @@ public interface JavaTypeDescriptor extends Serializable { * * @return The unwrapped value. */ - public X unwrap(T value, Class type, WrapperOptions options); + X unwrap(T value, Class type, WrapperOptions options); /** * Wrap a value as our handled Java type. @@ -110,5 +124,5 @@ public interface JavaTypeDescriptor extends Serializable { * * @return The wrapped value. */ - public T wrap(X value, WrapperOptions options); + T wrap(X value, WrapperOptions options); } diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/JavaTypeDescriptorRegistry.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/JavaTypeDescriptorRegistry.java index e1d85ace0e..981dcee298 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/JavaTypeDescriptorRegistry.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/JavaTypeDescriptorRegistry.java @@ -7,7 +7,6 @@ package org.hibernate.type.descriptor.java; import java.io.Serializable; -import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import org.hibernate.HibernateException; @@ -16,6 +15,7 @@ import org.hibernate.internal.CoreLogging; import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.util.ReflectHelper; import org.hibernate.type.descriptor.WrapperOptions; +import org.hibernate.type.descriptor.java.spi.RegistryHelper; import org.hibernate.type.spi.TypeConfiguration; /** @@ -84,8 +84,7 @@ public class JavaTypeDescriptorRegistry implements Serializable { } private JavaTypeDescriptor addDescriptorInternal(JavaTypeDescriptor descriptor) { - JavaTypeDescriptor javaTypeDescriptor = descriptorsByClass.put( descriptor.getJavaType(), descriptor ); - return javaTypeDescriptor; + return descriptorsByClass.put( descriptor.getJavaType(), descriptor ); } /** @@ -113,43 +112,26 @@ public class JavaTypeDescriptorRegistry implements Serializable { */ @Deprecated @SuppressWarnings("unchecked") - public JavaTypeDescriptor getDescriptor(Class cls) { - if ( cls == null ) { - throw new IllegalArgumentException( "Class passed to locate Java type descriptor cannot be null" ); - } + public JavaTypeDescriptor getDescriptor(Class cls) { + return RegistryHelper.INSTANCE.resolveDescriptor( + descriptorsByClass, + cls, + () -> { + if ( Serializable.class.isAssignableFrom( cls ) ) { + return new SerializableTypeDescriptor( cls ); + } - JavaTypeDescriptor descriptor = descriptorsByClass.get( cls ); - if ( descriptor != null ) { - return descriptor; - } + log.debugf( + "Could not find matching JavaTypeDescriptor for requested Java class [%s]; using fallback. " + + "This means Hibernate does not know how to perform certain basic operations in relation to this Java type." + + "", + cls.getName() + ); + checkEqualsAndHashCode( cls ); - if ( cls.isEnum() ) { - descriptor = new EnumJavaTypeDescriptor( cls ); - descriptorsByClass.put( cls, descriptor ); - return descriptor; - } - - // find the first "assignable" match - for ( Map.Entry entry : descriptorsByClass.entrySet() ) { - if ( entry.getKey().isAssignableFrom( cls ) ) { - log.debugf( "Using cached JavaTypeDescriptor instance for Java class [%s]", cls.getName() ); - return entry.getValue(); - } - } - - if ( Serializable.class.isAssignableFrom( cls ) ) { - return new SerializableTypeDescriptor( cls ); - } - - log.debugf( - "Could not find matching JavaTypeDescriptor for requested Java class [%s]; using fallback. " + - "This means Hibernate does not know how to perform certain basic operations in relation to this Java type." + - "", - cls.getName() + return new FallbackJavaTypeDescriptor<>( cls ); + } ); - checkEqualsAndHashCode( cls ); - - return new FallbackJavaTypeDescriptor<>( cls ); } @SuppressWarnings("unchecked") diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/SerializableTypeDescriptor.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/SerializableTypeDescriptor.java index 08a914703e..90fdafaf2b 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/SerializableTypeDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/SerializableTypeDescriptor.java @@ -29,11 +29,9 @@ public class SerializableTypeDescriptor extends Abstract // unfortunately the param types cannot be the same so use something other than 'T' here to make that obvious public static class SerializableMutabilityPlan extends MutableMutabilityPlan { + public static final SerializableMutabilityPlan INSTANCE = new SerializableMutabilityPlan<>(); - public static final SerializableMutabilityPlan INSTANCE - = new SerializableMutabilityPlan( ); - - public SerializableMutabilityPlan() { + private SerializableMutabilityPlan() { } @Override @@ -124,7 +122,7 @@ public class SerializableTypeDescriptor extends Abstract throw new HibernateException( e ); } } - else if ( getJavaTypeClass().isInstance( value ) ) { + else if ( getJavaType().isInstance( value ) ) { return (T) value; } throw unknownWrap( value.getClass() ); @@ -136,6 +134,6 @@ public class SerializableTypeDescriptor extends Abstract @SuppressWarnings({ "unchecked" }) protected T fromBytes(byte[] bytes) { - return (T) SerializationHelper.deserialize( bytes, getJavaTypeClass().getClassLoader() ); + return (T) SerializationHelper.deserialize( bytes, getJavaType().getClassLoader() ); } } diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/spi/JavaTypeDescriptorRegistry.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/spi/JavaTypeDescriptorRegistry.java index 11b96bb444..a71b4529a1 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/spi/JavaTypeDescriptorRegistry.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/spi/JavaTypeDescriptorRegistry.java @@ -7,10 +7,13 @@ package org.hibernate.type.descriptor.java.spi; import java.io.Serializable; +import java.util.concurrent.ConcurrentHashMap; import org.hibernate.type.descriptor.java.JavaTypeDescriptor; import org.hibernate.type.spi.TypeConfiguration; +import org.jboss.logging.Logger; + /** * Basically a map from {@link Class} -> {@link JavaTypeDescriptor} * @@ -19,25 +22,41 @@ import org.hibernate.type.spi.TypeConfiguration; * * @since 5.3 */ -public class JavaTypeDescriptorRegistry - extends org.hibernate.type.descriptor.java.JavaTypeDescriptorRegistry - implements Serializable { +public class JavaTypeDescriptorRegistry implements Serializable { + private static final Logger log = Logger.getLogger( JavaTypeDescriptorRegistry.class ); - private final TypeConfiguration typeConfiguration; - private final org.hibernate.type.descriptor.java.JavaTypeDescriptorRegistry javaTypeDescriptorRegistry; + private ConcurrentHashMap descriptorsByClass = new ConcurrentHashMap<>(); + + @SuppressWarnings("unused") public JavaTypeDescriptorRegistry(TypeConfiguration typeConfiguration) { - this.typeConfiguration = typeConfiguration; - javaTypeDescriptorRegistry = org.hibernate.type.descriptor.java.JavaTypeDescriptorRegistry.INSTANCE; } - @Override public JavaTypeDescriptor getDescriptor(Class javaType) { - return javaTypeDescriptorRegistry.getDescriptor( javaType ); + return RegistryHelper.INSTANCE.resolveDescriptor( + descriptorsByClass, + javaType, + () -> { + log.debugf( + "Could not find matching scoped JavaTypeDescriptor for requested Java class [%s]; " + + "falling back to static registry", + javaType.getName() + ); + + return org.hibernate.type.descriptor.java.JavaTypeDescriptorRegistry.INSTANCE.getDescriptor( javaType ); + } + ); } - @Override public void addDescriptor(JavaTypeDescriptor descriptor) { - javaTypeDescriptorRegistry.addDescriptor( descriptor ); + JavaTypeDescriptor old = descriptorsByClass.put( descriptor.getJavaType(), descriptor ); + if ( old != null ) { + log.debugf( + "JavaTypeDescriptorRegistry entry replaced : %s -> %s (was %s)", + descriptor.getJavaType(), + descriptor, + old + ); + } } } diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/spi/RegistryHelper.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/spi/RegistryHelper.java new file mode 100644 index 0000000000..da449213eb --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/java/spi/RegistryHelper.java @@ -0,0 +1,63 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.type.descriptor.java.spi; + +import java.io.Serializable; +import java.util.Map; +import java.util.function.Supplier; + +import org.hibernate.type.descriptor.java.EnumJavaTypeDescriptor; +import org.hibernate.type.descriptor.java.JavaTypeDescriptor; +import org.hibernate.type.descriptor.java.SerializableTypeDescriptor; + +import org.jboss.logging.Logger; + +/** + * @author Steve Ebersole + */ +public class RegistryHelper { + private static final Logger log = Logger.getLogger( RegistryHelper.class ); + + /** + * Singleton access + */ + public static final RegistryHelper INSTANCE = new RegistryHelper(); + + private RegistryHelper() { + } + + @SuppressWarnings("unchecked") + public JavaTypeDescriptor resolveDescriptor( + Map descriptorsByClass, + Class cls, + Supplier> defaultValueSupplier) { + if ( cls == null ) { + throw new IllegalArgumentException( "Class passed to locate JavaTypeDescriptor cannot be null" ); + } + + JavaTypeDescriptor descriptor = descriptorsByClass.get( cls ); + if ( descriptor != null ) { + return descriptor; + } + + if ( cls.isEnum() ) { + descriptor = new EnumJavaTypeDescriptor( cls ); + descriptorsByClass.put( cls, descriptor ); + return descriptor; + } + + // find the first "assignable" match + for ( Map.Entry entry : descriptorsByClass.entrySet() ) { + if ( entry.getKey().isAssignableFrom( cls ) ) { + log.debugf( "Using cached JavaTypeDescriptor instance for Java class [%s]", cls.getName() ); + return entry.getValue(); + } + } + + return defaultValueSupplier.get(); + } +} diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/spi/JdbcRecommendedSqlTypeMappingContext.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/spi/JdbcRecommendedSqlTypeMappingContext.java new file mode 100644 index 0000000000..79803b64f6 --- /dev/null +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/spi/JdbcRecommendedSqlTypeMappingContext.java @@ -0,0 +1,64 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.type.descriptor.spi; + +import java.sql.Types; +import javax.persistence.EnumType; + +import org.hibernate.type.spi.TypeConfiguration; + +/** + * More-or-less a parameter-object intended for use in determining the SQL/JDBC type recommended + * by the JDBC spec (explicitly or implicitly) for a given Java type. + * + * @see org.hibernate.type.descriptor.java.BasicJavaDescriptor#getJdbcRecommendedSqlType + * + * @author Steve Ebersole + */ +public interface JdbcRecommendedSqlTypeMappingContext { + /** + * Was nationalized character datatype requested for the given Java type? + * + * @return {@code true} if nationalized character datatype should be used; {@code false} otherwise. + */ + default boolean isNationalized() { + return false; + } + + /** + * Was LOB datatype requested for the given Java type? + * + * @return {@code true} if LOB datatype should be used; {@code false} otherwise. + */ + default boolean isLob() { + return false; + } + + /** + * For enum mappings, what style of storage was requested (name vs. ordinal)? + * + * @return The enum type. + */ + default EnumType getEnumeratedType() { + return EnumType.ORDINAL; + } + + /** + * When mapping a boolean type to the database what is the preferred SQL type code to use? + *

+ * Specifically names the key into the + * {@link org.hibernate.type.descriptor.sql.spi.SqlTypeDescriptorRegistry}. + */ + default int getPreferredSqlTypeCodeForBoolean() { + return Types.BOOLEAN; + } + + /** + * Provides access to the TypeConfiguration for access to various type-system registries. + */ + TypeConfiguration getTypeConfiguration(); +} diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/SqlTypeDescriptor.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/SqlTypeDescriptor.java index a580346ad3..3b5431f84c 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/SqlTypeDescriptor.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/SqlTypeDescriptor.java @@ -10,7 +10,9 @@ import java.io.Serializable; import org.hibernate.type.descriptor.ValueBinder; import org.hibernate.type.descriptor.ValueExtractor; +import org.hibernate.type.descriptor.java.BasicJavaDescriptor; import org.hibernate.type.descriptor.java.JavaTypeDescriptor; +import org.hibernate.type.spi.TypeConfiguration; /** * Descriptor for the SQL/JDBC side of a value mapping. @@ -38,6 +40,15 @@ public interface SqlTypeDescriptor extends Serializable { */ boolean canBeRemapped(); + @SuppressWarnings("unchecked") + default BasicJavaDescriptor getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) { + // match legacy behavior + return (BasicJavaDescriptor) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( + JdbcTypeJavaClassMappings.INSTANCE.determineJavaClassForJdbcTypeCode( getSqlType() ) + ); + + } + /** * Get the binder (setting JDBC in-going parameter values) capable of handling values of the type described by the * passed descriptor. diff --git a/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/SqlTypeDescriptorRegistry.java b/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/SqlTypeDescriptorRegistry.java index ac333aabbc..71ad7f6450 100644 --- a/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/SqlTypeDescriptorRegistry.java +++ b/hibernate-core/src/main/java/org/hibernate/type/descriptor/sql/SqlTypeDescriptorRegistry.java @@ -151,7 +151,7 @@ public class SqlTypeDescriptorRegistry implements Serializable { @Override public ValueBinder getBinder(JavaTypeDescriptor javaTypeDescriptor) { - if ( Serializable.class.isAssignableFrom( javaTypeDescriptor.getJavaTypeClass() ) ) { + if ( Serializable.class.isAssignableFrom( javaTypeDescriptor.getJavaType() ) ) { return VarbinaryTypeDescriptor.INSTANCE.getBinder( javaTypeDescriptor ); } @@ -173,7 +173,7 @@ public class SqlTypeDescriptorRegistry implements Serializable { @Override @SuppressWarnings("unchecked") public ValueExtractor getExtractor(JavaTypeDescriptor javaTypeDescriptor) { - if ( Serializable.class.isAssignableFrom( javaTypeDescriptor.getJavaTypeClass() ) ) { + if ( Serializable.class.isAssignableFrom( javaTypeDescriptor.getJavaType() ) ) { return VarbinaryTypeDescriptor.INSTANCE.getExtractor( javaTypeDescriptor ); } diff --git a/hibernate-core/src/test/java/org/hibernate/test/converter/custom/CustomTypeConverterTest.java b/hibernate-core/src/test/java/org/hibernate/test/converter/custom/CustomTypeConverterTest.java new file mode 100644 index 0000000000..5182e1ab9c --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/converter/custom/CustomTypeConverterTest.java @@ -0,0 +1,95 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.test.converter.custom; + +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistry; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.boot.spi.MetadataBuilderImplementor; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.tool.schema.Action; +import org.hibernate.type.spi.TypeConfiguration; + +import org.hibernate.testing.junit4.BaseUnitTestCase; +import org.junit.Test; + +import static org.hamcrest.CoreMatchers.sameInstance; +import static org.hamcrest.MatcherAssert.assertThat; + +/** + * @author Steve Ebersole + */ +public class CustomTypeConverterTest extends BaseUnitTestCase { + @Test + public void testConverterAppliedStaticRegistration() { + // this is how we told users to do it previously using the static reference - + // make sure it still works for now + org.hibernate.type.descriptor.java.JavaTypeDescriptorRegistry.INSTANCE.addDescriptor( MyCustomJavaTypeDescriptor.INSTANCE ); + org.hibernate.type.descriptor.sql.SqlTypeDescriptorRegistry.INSTANCE.addDescriptor( MyCustomSqlTypeDescriptor.INSTANCE ); + + try ( final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder() + .applySetting( AvailableSettings.HBM2DDL_AUTO, Action.CREATE_DROP ) + .build() ) { + final MetadataSources metadataSources = new MetadataSources( ssr ) + .addAnnotatedClass( MyCustomConverter.class ) + .addAnnotatedClass( MyEntity.class ); + final MetadataBuilderImplementor metadataBuilder = (MetadataBuilderImplementor) metadataSources.getMetadataBuilder(); + + final TypeConfiguration bootTypeConfiguration = metadataBuilder.getBootstrapContext().getTypeConfiguration(); + performAssertions( metadataBuilder, bootTypeConfiguration ); + + } + } + + @Test + public void testConverterAppliedScopedRegistration() { + + try ( final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder() + .applySetting( AvailableSettings.HBM2DDL_AUTO, Action.CREATE_DROP ) + .build() ) { + final MetadataSources metadataSources = new MetadataSources( ssr ) + .addAnnotatedClass( MyCustomConverter.class ) + .addAnnotatedClass( MyEntity.class ); + final MetadataBuilderImplementor metadataBuilder = (MetadataBuilderImplementor) metadataSources.getMetadataBuilder(); + + // now the new scoped way + final TypeConfiguration bootTypeConfiguration = metadataBuilder.getBootstrapContext().getTypeConfiguration(); + bootTypeConfiguration.getJavaTypeDescriptorRegistry() + .addDescriptor( MyCustomJavaTypeDescriptor.INSTANCE ); + bootTypeConfiguration.getSqlTypeDescriptorRegistry() + .addDescriptor( MyCustomSqlTypeDescriptor.INSTANCE ); + + performAssertions( metadataBuilder, bootTypeConfiguration ); + } + } + + protected void performAssertions( + MetadataBuilderImplementor metadataBuilder, + TypeConfiguration bootTypeConfiguration) { + try ( final SessionFactoryImplementor sessionFactory = (SessionFactoryImplementor) metadataBuilder.build().buildSessionFactory()) { + assertThat( + sessionFactory.getMetamodel().getTypeConfiguration(), + sameInstance( bootTypeConfiguration ) + ); + + assertThat( + bootTypeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( MyCustomJavaType.class ), + sameInstance( MyCustomJavaTypeDescriptor.INSTANCE ) + ); + + assertThat( + bootTypeConfiguration.getSqlTypeDescriptorRegistry().getDescriptor( MyCustomSqlTypeDescriptor.INSTANCE.getSqlType() ), + sameInstance( MyCustomSqlTypeDescriptor.INSTANCE ) + ); + + final EntityPersister entityPersister = sessionFactory.getMetamodel().entityPersister( MyEntity.class ); + entityPersister.getPropertyType( "customType" ); + } + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/converter/custom/MyCustomConverter.java b/hibernate-core/src/test/java/org/hibernate/test/converter/custom/MyCustomConverter.java new file mode 100644 index 0000000000..4d3024ccd0 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/converter/custom/MyCustomConverter.java @@ -0,0 +1,26 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.test.converter.custom; + +import javax.persistence.AttributeConverter; +import javax.persistence.Converter; + +/** + * @author Steve Ebersole + */ +@Converter( autoApply = true ) +public class MyCustomConverter implements AttributeConverter { + @Override + public String convertToDatabaseColumn(MyCustomJavaType attribute) { + return null; + } + + @Override + public MyCustomJavaType convertToEntityAttribute(String dbData) { + return null; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/converter/custom/MyCustomJavaType.java b/hibernate-core/src/test/java/org/hibernate/test/converter/custom/MyCustomJavaType.java new file mode 100644 index 0000000000..928a37fad9 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/converter/custom/MyCustomJavaType.java @@ -0,0 +1,43 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.test.converter.custom; + +/** + * @author Steve Ebersole + */ +public class MyCustomJavaType implements Comparable { + private String payload; + + public MyCustomJavaType() { + this( null ); + } + + public MyCustomJavaType(String payload) { + this.payload = payload; + } + + public String getPayload() { + return payload; + } + + public void setPayload(String payload) { + this.payload = payload; + } + + @Override + public int compareTo(MyCustomJavaType other) { + if ( getPayload() == null ) { + return -1; + } + + if ( other == null || other.getPayload() == null ) { + return 1; + } + + return getPayload().compareTo( other.getPayload() ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/converter/custom/MyCustomJavaTypeDescriptor.java b/hibernate-core/src/test/java/org/hibernate/test/converter/custom/MyCustomJavaTypeDescriptor.java new file mode 100644 index 0000000000..228f702828 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/converter/custom/MyCustomJavaTypeDescriptor.java @@ -0,0 +1,77 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.test.converter.custom; + +import org.hibernate.internal.util.StringHelper; +import org.hibernate.type.descriptor.WrapperOptions; +import org.hibernate.type.descriptor.java.BasicJavaDescriptor; +import org.hibernate.type.descriptor.java.JavaTypeDescriptor; +import org.hibernate.type.descriptor.java.MutabilityPlan; +import org.hibernate.type.descriptor.java.MutableMutabilityPlan; +import org.hibernate.type.descriptor.spi.JdbcRecommendedSqlTypeMappingContext; +import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; + +/** + * @author Steve Ebersole + */ +public class MyCustomJavaTypeDescriptor implements BasicJavaDescriptor { + /** + * Singleton access + */ + public static final MyCustomJavaTypeDescriptor INSTANCE = new MyCustomJavaTypeDescriptor(); + + private final MutableMutabilityPlan mutabilityPlan = new MutableMutabilityPlan() { + @Override + protected MyCustomJavaType deepCopyNotNull(MyCustomJavaType value) { + return value == null ? null : new MyCustomJavaType( value.getPayload() ); + } + }; + + private MyCustomJavaTypeDescriptor() { + } + + @Override + public Class getJavaTypeClass() { + return MyCustomJavaType.class; + } + + @Override + public SqlTypeDescriptor getJdbcRecommendedSqlType(JdbcRecommendedSqlTypeMappingContext context) { + return MyCustomSqlTypeDescriptor.INSTANCE; + } + + @Override + public MutabilityPlan getMutabilityPlan() { + return mutabilityPlan; + } + + @Override + public MyCustomJavaType fromString(String string) { + return StringHelper.isEmpty( string ) ? null : new MyCustomJavaType( string ); + } + + @Override + public MyCustomJavaType wrap(Object value, WrapperOptions options) { + if ( value == null ) { + return null; + } + else if ( String.class.isInstance( value ) ) { + return new MyCustomJavaType( (String) value ); + } + + throw new UnsupportedOperationException( "Wrapping value as MyCustomJavaType only supported for String or MyCustomJdbcType : " + value ); + } + + @Override + public Object unwrap(MyCustomJavaType value, Class type, WrapperOptions options) { + if ( String.class.isAssignableFrom( type ) ) { + return value.getPayload(); + } + + throw new UnsupportedOperationException( "Unwrapping MyCustomJavaType value only supported for String or MyCustomJdbcType : " + value ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/converter/custom/MyCustomSqlTypeDescriptor.java b/hibernate-core/src/test/java/org/hibernate/test/converter/custom/MyCustomSqlTypeDescriptor.java new file mode 100644 index 0000000000..a9f336232d --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/converter/custom/MyCustomSqlTypeDescriptor.java @@ -0,0 +1,83 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.test.converter.custom; + +import java.sql.CallableStatement; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Types; + +import org.hibernate.type.descriptor.ValueBinder; +import org.hibernate.type.descriptor.ValueExtractor; +import org.hibernate.type.descriptor.WrapperOptions; +import org.hibernate.type.descriptor.java.JavaTypeDescriptor; +import org.hibernate.type.descriptor.sql.BasicBinder; +import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; +import org.hibernate.type.descriptor.sql.VarcharTypeDescriptor; + +/** + * A custom SqlTypeDescriptor. For example, this might be used to provide support + * for a "non-standard" SQL type or to provide some special handling of values (e.g. + * Oracle's dodgy handling of `""` as `null` but only in certain uses). + * + * This descriptor shows an example of replacing how VARCHAR values are handled. + * + * @author Steve Ebersole + */ +public class MyCustomSqlTypeDescriptor implements SqlTypeDescriptor { + /** + * Singleton access + */ + public static final MyCustomSqlTypeDescriptor INSTANCE = new MyCustomSqlTypeDescriptor(); + + private MyCustomSqlTypeDescriptor() { + } + + @Override + public int getSqlType() { + // given the Oracle example above we might want to replace the + // handling of VARCHAR + return Types.VARCHAR; + } + + @Override + public boolean canBeRemapped() { + return false; + } + + @Override + public ValueBinder getBinder(JavaTypeDescriptor javaTypeDescriptor) { + return new BasicBinder( javaTypeDescriptor, this ) { + @Override + protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options) throws SQLException { + final String valueStr = javaTypeDescriptor.unwrap( value, String.class, options ); + if ( valueStr == null || valueStr.trim().isEmpty() ) { + st.setNull( index, getSqlType() ); + } + else { + st.setString( index, valueStr ); + } + } + + @Override + protected void doBind(CallableStatement st, X value, String name, WrapperOptions options) throws SQLException { + final String valueStr = javaTypeDescriptor.unwrap( value, String.class, options ); + if ( valueStr == null || valueStr.trim().isEmpty() ) { + st.setNull( name, getSqlType() ); + } + else { + st.setString( name, valueStr ); + } + } + }; + } + + @Override + public ValueExtractor getExtractor(JavaTypeDescriptor javaTypeDescriptor) { + return VarcharTypeDescriptor.INSTANCE.getExtractor( javaTypeDescriptor ); + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/converter/custom/MyEntity.java b/hibernate-core/src/test/java/org/hibernate/test/converter/custom/MyEntity.java new file mode 100644 index 0000000000..0fbea16fd1 --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/converter/custom/MyEntity.java @@ -0,0 +1,50 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.test.converter.custom; + +import javax.persistence.Basic; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; + +/** + * @author Steve Ebersole + */ +@Entity +@Table( name = "CUST_TYPE_CONV_ENTITY") +public class MyEntity { + private Integer id; + private MyCustomJavaType customType; + + public MyEntity() { + } + + public MyEntity(Integer id, MyCustomJavaType customType) { + this.id = id; + this.customType = customType; + } + + @Id + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + // NOTE : this AttributeConverter should be auto-applied here + + @Basic + public MyCustomJavaType getCustomType() { + return customType; + } + + public void setCustomType(MyCustomJavaType customType) { + this.customType = customType; + } +} diff --git a/hibernate-core/src/test/java/org/hibernate/test/converter/custom/package-info.java b/hibernate-core/src/test/java/org/hibernate/test/converter/custom/package-info.java new file mode 100644 index 0000000000..d444591b3c --- /dev/null +++ b/hibernate-core/src/test/java/org/hibernate/test/converter/custom/package-info.java @@ -0,0 +1,12 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ + +/** + * Test illustrating use of an AttributeConverter over custom + * java / sql type descriptors + */ +package org.hibernate.test.converter.custom; diff --git a/hibernate-core/src/test/java/org/hibernate/test/type/Java8DateTimeTests.java b/hibernate-core/src/test/java/org/hibernate/test/type/Java8DateTimeTests.java index d1a5428872..22391fce9c 100644 --- a/hibernate-core/src/test/java/org/hibernate/test/type/Java8DateTimeTests.java +++ b/hibernate-core/src/test/java/org/hibernate/test/type/Java8DateTimeTests.java @@ -83,7 +83,7 @@ public class Java8DateTimeTests extends BaseNonConfigCoreFunctionalTestCase { String.format( "%s (%s) -> %s", propertyBinding.getName(), - javaTypeDescriptor.getJavaTypeClass().getSimpleName(), + javaTypeDescriptor.getJavaType().getSimpleName(), javaTypeDescriptor.toString( propertyBinding.getGetter( TheEntity.class ).get( theEntity ) ) ) ); diff --git a/hibernate-spatial/hibernate-spatial.gradle b/hibernate-spatial/hibernate-spatial.gradle index 26aac5469c..78f7b0d3dd 100644 --- a/hibernate-spatial/hibernate-spatial.gradle +++ b/hibernate-spatial/hibernate-spatial.gradle @@ -1,3 +1,5 @@ +import org.apache.tools.ant.filters.ReplaceTokens + /* * Hibernate, Relational Persistence for Idiomatic Java * @@ -8,13 +10,27 @@ apply from: rootProject.file( 'gradle/published-java-module.gradle' ) apply plugin: 'hibernate-matrix-testing' +ext { + db = project.hasProperty('db') ? project.getProperty('db') : 'h2' + dbBundle = [ + h2 : [ + 'db.dialect' : 'org.hibernate.spatial.dialect.h2geodb.GeoDBDialect', + 'jdbc.driver': 'org.h2.Driver', + 'jdbc.user' : 'sa', + 'jdbc.pass' : '', + 'jdbc.url' : 'jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1;LOCK_TIMEOUT=10000', + ] + ] +} + description = 'Integrate support for Spatial/GIS data into Hibernate O/RM' dependencies { - compile(project(':hibernate-core')) + compile( project(':hibernate-core') ) + compile( libraries.geolatte ) + + compile( 'org.postgresql:postgresql:42.1.4' ) - compile('org.postgresql:postgresql:42.1.4') - compile([group: 'org.geolatte', name: 'geolatte-geom', version: '1.3.0']) compile(libraries.dom4j) { transitive = false } @@ -40,3 +56,25 @@ sourceSets.test.resources { setSrcDirs(['src/test/java', 'src/test/resources']) } +processTestResources { + doLast { + copy { + from( sourceSets.test.java.srcDirs ) { + include '**/*.properties' + include '**/*.xml' + } + into sourceSets.test.java.outputDir + } + copy { + from file( 'src/test/resources' ) + into file( "${buildDir}/resources/test" ) + exclude 'src/test/resources/arquillian.xml' + exclude 'src/test/resources/hibernate.properties' + } + copy { + from file( 'src/test/resources/hibernate.properties' ) + into file( "${buildDir}/resources/test" ) + filter( ReplaceTokens, tokens: dbBundle[db] ) + } + } +} diff --git a/hibernate-spatial/src/main/java/org/hibernate/spatial/GeolatteGeometryJavaTypeDescriptor.java b/hibernate-spatial/src/main/java/org/hibernate/spatial/GeolatteGeometryJavaTypeDescriptor.java index a45531db2c..4c817ef1b6 100644 --- a/hibernate-spatial/src/main/java/org/hibernate/spatial/GeolatteGeometryJavaTypeDescriptor.java +++ b/hibernate-spatial/src/main/java/org/hibernate/spatial/GeolatteGeometryJavaTypeDescriptor.java @@ -7,9 +7,12 @@ package org.hibernate.spatial; +import java.sql.Types; + import org.hibernate.type.descriptor.WrapperOptions; import org.hibernate.type.descriptor.java.AbstractTypeDescriptor; -import org.hibernate.type.descriptor.java.JavaTypeDescriptorRegistry; +import org.hibernate.type.descriptor.spi.JdbcRecommendedSqlTypeMappingContext; +import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; import org.geolatte.geom.Geometry; import org.geolatte.geom.codec.Wkt; @@ -35,6 +38,11 @@ public class GeolatteGeometryJavaTypeDescriptor extends AbstractTypeDescriptor implements Spatial { + public static final String[] REG_KEYS = { + Geometry.class.getCanonicalName(), + Point.class.getCanonicalName(), + Polygon.class.getCanonicalName(), + MultiPolygon.class.getCanonicalName(), + LineString.class.getCanonicalName(), + MultiLineString.class.getCanonicalName(), + MultiPoint.class.getCanonicalName(), + GeometryCollection.class.getCanonicalName(), + "geolatte_geometry" + }; + /** * Constructs an instance with the specified {@code SqlTypeDescriptor} * @@ -38,17 +50,7 @@ public class GeolatteGeometryType extends AbstractSingleColumnStandardBasicType< @Override public String[] getRegistrationKeys() { - return new String[] { - Geometry.class.getCanonicalName(), - Point.class.getCanonicalName(), - Polygon.class.getCanonicalName(), - MultiPolygon.class.getCanonicalName(), - LineString.class.getCanonicalName(), - MultiLineString.class.getCanonicalName(), - MultiPoint.class.getCanonicalName(), - GeometryCollection.class.getCanonicalName(), - "geolatte_geometry" - }; + return REG_KEYS; } @Override diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/converter/GeometryConverter.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/converter/GeometryConverter.java new file mode 100644 index 0000000000..b1f566b6ed --- /dev/null +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/converter/GeometryConverter.java @@ -0,0 +1,36 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.spatial.testing.converter; + +import javax.persistence.AttributeConverter; +import javax.persistence.Converter; + +import org.hibernate.spatial.dialect.h2geodb.GeoDbWkb; + +import org.geolatte.geom.Geometry; + +/** + * @author Steve Ebersole + */ +@Converter( autoApply = true ) +public class GeometryConverter implements AttributeConverter { + @Override + public byte[] convertToDatabaseColumn(Geometry attribute) { + if ( attribute == null ) { + return null; + } + return GeoDbWkb.to( attribute ); + } + + @Override + public Geometry convertToEntityAttribute(byte[] dbData) { + if ( dbData == null ) { + return null; + } + return GeoDbWkb.from( dbData ); + } +} diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/converter/GeometryConverterTest.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/converter/GeometryConverterTest.java new file mode 100644 index 0000000000..8751711269 --- /dev/null +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/converter/GeometryConverterTest.java @@ -0,0 +1,76 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.spatial.testing.converter; + +import org.hibernate.boot.MetadataSources; +import org.hibernate.boot.registry.StandardServiceRegistry; +import org.hibernate.boot.registry.StandardServiceRegistryBuilder; +import org.hibernate.boot.spi.MetadataBuilderImplementor; +import org.hibernate.cfg.AvailableSettings; +import org.hibernate.engine.spi.SessionFactoryImplementor; +import org.hibernate.metamodel.model.convert.spi.JpaAttributeConverter; +import org.hibernate.persister.entity.EntityPersister; +import org.hibernate.spatial.GeolatteGeometryJavaTypeDescriptor; +import org.hibernate.spatial.dialect.h2geodb.GeoDBDialect; +import org.hibernate.tool.schema.Action; +import org.hibernate.type.descriptor.converter.AttributeConverterTypeAdapter; +import org.hibernate.type.spi.TypeConfiguration; + +import org.hibernate.testing.junit4.BaseUnitTestCase; +import org.junit.Test; + +import org.geolatte.geom.Geometry; + +import static org.hamcrest.CoreMatchers.sameInstance; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hibernate.testing.junit4.ExtraAssertions.assertTyping; + +/** + * @author Steve Ebersole + */ +public class GeometryConverterTest extends BaseUnitTestCase { + + @Test + public void testConverterUsage() { + try ( final StandardServiceRegistry ssr = new StandardServiceRegistryBuilder() + .applySetting( AvailableSettings.DIALECT, GeoDBDialect.class ) + .applySetting( AvailableSettings.HBM2DDL_AUTO, Action.CREATE_DROP ) + .build() ) { + final MetadataSources metadataSources = new MetadataSources( ssr ) + .addAnnotatedClass( GeometryConverter.class ) + .addAnnotatedClass( MyEntity.class ); + final MetadataBuilderImplementor metadataBuilder = (MetadataBuilderImplementor) metadataSources.getMetadataBuilder(); + + try ( final SessionFactoryImplementor sessionFactory = + (SessionFactoryImplementor) metadataBuilder.build().buildSessionFactory() ) { + + final TypeConfiguration typeConfiguration = sessionFactory.getMetamodel().getTypeConfiguration(); + + assertThat( + typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( Geometry.class ), + sameInstance( GeolatteGeometryJavaTypeDescriptor.INSTANCE ) + ); + + // todo (5.3) : what to assert wrt to SqlTypeDescriptor? Anything? + + final EntityPersister entityPersister = sessionFactory.getMetamodel().entityPersister( MyEntity.class ); + final AttributeConverterTypeAdapter geometryAttributeType = assertTyping( + AttributeConverterTypeAdapter.class, + entityPersister.getPropertyType( "geometry" ) + ); + + final JpaAttributeConverter converter = assertTyping( + JpaAttributeConverter.class, + geometryAttributeType.getAttributeConverter() + ); + + assert GeometryConverter.class.equals( converter.getConverterBean().getBeanClass() ); + } + } + } + +} diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/converter/MyEntity.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/converter/MyEntity.java new file mode 100644 index 0000000000..2fbb213890 --- /dev/null +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/converter/MyEntity.java @@ -0,0 +1,52 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ +package org.hibernate.spatial.testing.converter; + +import javax.persistence.Basic; +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.Table; + +import org.geolatte.geom.Geometry; + +/** + * @author Steve Ebersole + */ +@Entity +@Table( name = "SP_CUST_TYPE_CONV_ENTITY") +public class MyEntity { + private Integer id; + private Geometry geometry; + + public MyEntity() { + } + + public MyEntity(Integer id, Geometry geometry) { + this.id = id; + this.geometry = geometry; + } + + @Id + public Integer getId() { + return id; + } + + public void setId(Integer id) { + this.id = id; + } + + // NOTE : the AttributeConverter should be auto-applied here + + @Basic + public Geometry getGeometry() { + return geometry; + } + + public void setGeometry(Geometry geometry) { + this.geometry = geometry; + } +} diff --git a/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/converter/package-info.java b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/converter/package-info.java new file mode 100644 index 0000000000..9f03a58fe0 --- /dev/null +++ b/hibernate-spatial/src/test/java/org/hibernate/spatial/testing/converter/package-info.java @@ -0,0 +1,12 @@ +/* + * Hibernate, Relational Persistence for Idiomatic Java + * + * License: GNU Lesser General Public License (LGPL), version 2.1 or later + * See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html + */ + +/** + * Make sure that JPA {@link javax.persistence.AttributeConverter} + * implementations using Geolatte types work with hibernate-spatial + */ +package org.hibernate.spatial.testing.converter;