HHH-12410 - Cannot use AttributeConverter with spatial types

HHH-12443 - Introduce TypeConfiguration
This commit is contained in:
Steve Ebersole 2018-03-29 23:16:12 -05:00
parent 216ad13e6c
commit c14180ea5b
39 changed files with 1009 additions and 135 deletions

View File

@ -24,6 +24,8 @@ ext {
javassistVersion = '3.22.0-GA' javassistVersion = '3.22.0-GA'
byteBuddyVersion = '1.8.0' // Now with JDK10 compatibility and preliminary support for JDK11 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 // Wildfly version targeted by module ZIP; Arquillian/Shrinkwrap versions used for CDI testing and testing the module ZIP
wildflyVersion = '12.0.0.Final' wildflyVersion = '12.0.0.Final'
arquillianVersion = '1.1.11.Final' arquillianVersion = '1.1.11.Final'
@ -31,6 +33,8 @@ ext {
shrinkwrapDescriptorsVersion = '2.0.0-alpha-8' shrinkwrapDescriptorsVersion = '2.0.0-alpha-8'
wildflyArquillianContainerVersion = '2.0.0.Final' wildflyArquillianContainerVersion = '2.0.0.Final'
jodaTimeVersion = '2.3'
libraries = [ libraries = [
// Ant // Ant
ant: 'org.apache.ant:ant:1.8.2', 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: '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', 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 // Animal Sniffer Ant Task and Java 1.6 API signature file
// not using 1.9 for the time being due to MANIMALSNIFFER-34 // not using 1.9 for the time being due to MANIMALSNIFFER-34
animal_sniffer: 'org.codehaus.mojo:animal-sniffer-ant-tasks:1.13', animal_sniffer: 'org.codehaus.mojo:animal-sniffer-ant-tasks:1.13',
@ -105,6 +111,8 @@ ext {
db2: 'com.ibm.db2:db2jcc:10.5', 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 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', informix: 'com.ibm.informix:jdbc:4.10.7.20160517',
jboss_jta: "org.jboss.jbossts:jbossjta:4.16.4.Final", jboss_jta: "org.jboss.jbossts:jbossjta:4.16.4.Final",
xapool: "com.experlog:xapool:1.5.0", xapool: "com.experlog:xapool:1.5.0",

View File

@ -69,7 +69,7 @@ dependencies {
testCompile( libraries.classmate ) testCompile( libraries.classmate )
testCompile( libraries.mockito ) testCompile( libraries.mockito )
testCompile( libraries.mockito_inline ) testCompile( libraries.mockito_inline )
testCompile( 'joda-time:joda-time:2.3' ) testCompile( libraries.jodaTime )
testCompile( libraries.cdi ) { testCompile( libraries.cdi ) {
// we need to force it to make sure we influence the one coming from arquillian // we need to force it to make sure we influence the one coming from arquillian

View File

@ -7,6 +7,8 @@
package org.hibernate.boot.model; package org.hibernate.boot.model;
import org.hibernate.type.BasicType; 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.sql.SqlTypeDescriptor;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor; import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
@ -19,34 +21,56 @@ import org.hibernate.usertype.UserType;
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public interface TypeContributions { 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); void contributeType(BasicType type);
/** /**
* @deprecated (since 5.3) It will be replaced by {@link #contributeType(BasicType)} * @deprecated (since 5.3) Use {@link #contributeType(BasicType)} instead. Basic
* but do not move to it before 6.0 * 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 @Deprecated
void contributeType(BasicType type, String... keys); void contributeType(BasicType type, String... keys);
/** /**
* @deprecated (since 5.3) It will be replaced by {@link #contributeType(BasicType)} * @deprecated (since 5.3) Use {@link #contributeType(BasicType)} instead.
* but do not move to it before 6.0 * {@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); void contributeType(UserType type, String... keys);
/** /**
* @deprecated (since 5.3) It will be replaced by {@link #contributeType(BasicType)} * @deprecated (since 5.3) Use {@link #contributeType(BasicType)} instead.
* but do not move to it before 6.0 * {@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); void contributeType(CompositeUserType type, String... keys);
/*
* Add the JavaTypeDescriptor to the
* @param descriptor
*/
void contributeJavaTypeDescriptor(JavaTypeDescriptor descriptor);
void contributeSqlTypeDescriptor(SqlTypeDescriptor descriptor);
TypeConfiguration getTypeConfiguration();
} }

View File

@ -7,7 +7,7 @@
package org.hibernate.boot.model.convert.spi; package org.hibernate.boot.model.convert.spi;
import org.hibernate.resource.beans.spi.ManagedBeanRegistry; 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 * Access to information that implementors of

View File

@ -64,7 +64,7 @@ public class StandardServiceRegistryBuilder {
* @param bootstrapServiceRegistry Provided bootstrap registry to use. * @param bootstrapServiceRegistry Provided bootstrap registry to use.
*/ */
public StandardServiceRegistryBuilder(BootstrapServiceRegistry bootstrapServiceRegistry) { 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. * @param bootstrapServiceRegistry Provided bootstrap registry to use.
*/ */
public StandardServiceRegistryBuilder(BootstrapServiceRegistry bootstrapServiceRegistry, LoadedConfig loadedConfigBaseline) { public StandardServiceRegistryBuilder(
BootstrapServiceRegistry bootstrapServiceRegistry,
LoadedConfig loadedConfigBaseline) {
this.settings = Environment.getProperties(); this.settings = Environment.getProperties();
this.bootstrapServiceRegistry = bootstrapServiceRegistry; this.bootstrapServiceRegistry = bootstrapServiceRegistry;
this.configLoader = new ConfigLoader( 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. * Read settings from a {@link java.util.Properties} file by resource name.
* * <p>
* Differs from {@link #configure()} and {@link #configure(String)} in that here we expect to read a * 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. * {@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()
* @see #configure(String) * @see #configure(String)
*/ */
@SuppressWarnings( {"unchecked"}) @SuppressWarnings({"unchecked"})
public StandardServiceRegistryBuilder loadProperties(String resourceName) { public StandardServiceRegistryBuilder loadProperties(String resourceName) {
settings.putAll( configLoader.loadProperties( resourceName ) ); settings.putAll( configLoader.loadProperties( resourceName ) );
return this; return this;
@ -122,7 +124,7 @@ public class StandardServiceRegistryBuilder {
/** /**
* Read settings from a {@link java.util.Properties} file by File reference * Read settings from a {@link java.util.Properties} file by File reference
* * <p>
* Differs from {@link #configure()} and {@link #configure(String)} in that here we expect to read a * 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. * {@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()
* @see #configure(String) * @see #configure(String)
*/ */
@SuppressWarnings( {"unchecked"}) @SuppressWarnings({"unchecked"})
public StandardServiceRegistryBuilder loadProperties(File file) { public StandardServiceRegistryBuilder loadProperties(File file) {
settings.putAll( configLoader.loadProperties( file ) ); settings.putAll( configLoader.loadProperties( file ) );
return this; return this;
@ -171,7 +173,7 @@ public class StandardServiceRegistryBuilder {
return configure( configLoader.loadConfigXmlUrl( url ) ); return configure( configLoader.loadConfigXmlUrl( url ) );
} }
@SuppressWarnings( {"unchecked"}) @SuppressWarnings({"unchecked"})
public StandardServiceRegistryBuilder configure(LoadedConfig loadedConfig) { public StandardServiceRegistryBuilder configure(LoadedConfig loadedConfig) {
aggregatedCfgXml.merge( loadedConfig ); aggregatedCfgXml.merge( loadedConfig );
settings.putAll( loadedConfig.getConfigurationValues() ); settings.putAll( loadedConfig.getConfigurationValues() );
@ -187,7 +189,7 @@ public class StandardServiceRegistryBuilder {
* *
* @return this, for method chaining * @return this, for method chaining
*/ */
@SuppressWarnings( {"unchecked", "UnusedDeclaration"}) @SuppressWarnings({"unchecked", "UnusedDeclaration"})
public StandardServiceRegistryBuilder applySetting(String settingName, Object value) { public StandardServiceRegistryBuilder applySetting(String settingName, Object value) {
settings.put( settingName, value ); settings.put( settingName, value );
return this; return this;
@ -200,7 +202,7 @@ public class StandardServiceRegistryBuilder {
* *
* @return this, for method chaining * @return this, for method chaining
*/ */
@SuppressWarnings( {"unchecked", "UnusedDeclaration"}) @SuppressWarnings({"unchecked", "UnusedDeclaration"})
public StandardServiceRegistryBuilder applySettings(Map settings) { public StandardServiceRegistryBuilder applySettings(Map settings) {
this.settings.putAll( settings ); this.settings.putAll( settings );
return this; return this;
@ -213,7 +215,7 @@ public class StandardServiceRegistryBuilder {
* *
* @return this, for method chaining * @return this, for method chaining
*/ */
@SuppressWarnings( {"UnusedDeclaration"}) @SuppressWarnings({"UnusedDeclaration"})
public StandardServiceRegistryBuilder addInitiator(StandardServiceInitiator initiator) { public StandardServiceRegistryBuilder addInitiator(StandardServiceInitiator initiator) {
initiators.add( initiator ); initiators.add( initiator );
return this; return this;
@ -227,7 +229,7 @@ public class StandardServiceRegistryBuilder {
* *
* @return this, for method chaining * @return this, for method chaining
*/ */
@SuppressWarnings( {"unchecked"}) @SuppressWarnings({"unchecked"})
public StandardServiceRegistryBuilder addService(final Class serviceRole, final Service service) { public StandardServiceRegistryBuilder addService(final Class serviceRole, final Service service) {
providedServices.add( new ProvidedService( serviceRole, service ) ); providedServices.add( new ProvidedService( serviceRole, service ) );
return this; return this;
@ -289,9 +291,11 @@ public class StandardServiceRegistryBuilder {
@SuppressWarnings("deprecation") @SuppressWarnings("deprecation")
private void applyServiceContributingIntegrators() { 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 ) ) { 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(); ( (StandardServiceRegistryImpl) serviceRegistry ).destroy();
} }
} }

View File

@ -50,13 +50,13 @@ import org.hibernate.type.Type;
import org.hibernate.type.descriptor.JdbcTypeNameMapper; import org.hibernate.type.descriptor.JdbcTypeNameMapper;
import org.hibernate.type.descriptor.converter.AttributeConverterSqlTypeDescriptorAdapter; import org.hibernate.type.descriptor.converter.AttributeConverterSqlTypeDescriptorAdapter;
import org.hibernate.type.descriptor.converter.AttributeConverterTypeAdapter; 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.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.JdbcTypeJavaClassMappings;
import org.hibernate.type.descriptor.sql.LobTypeMappings; import org.hibernate.type.descriptor.sql.LobTypeMappings;
import org.hibernate.type.descriptor.sql.NationalizedTypeMappings; import org.hibernate.type.descriptor.sql.NationalizedTypeMappings;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptorRegistry;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
import org.hibernate.usertype.DynamicParameterizedType; import org.hibernate.usertype.DynamicParameterizedType;
@ -576,13 +576,13 @@ public class SimpleValue implements KeyValue {
} }
@Override @Override
public JavaTypeDescriptorRegistry getJavaTypeDescriptorRegistry() { public org.hibernate.type.descriptor.java.spi.JavaTypeDescriptorRegistry getJavaTypeDescriptorRegistry() {
return metadata.getTypeConfiguration().getJavaTypeDescriptorRegistry(); return metadata.getTypeConfiguration().getJavaTypeDescriptorRegistry();
} }
} }
); );
final JavaTypeDescriptor entityAttributeJavaTypeDescriptor = jpaAttributeConverter.getDomainJavaTypeDescriptor(); final BasicJavaDescriptor entityAttributeJavaTypeDescriptor = jpaAttributeConverter.getDomainJavaTypeDescriptor();
// build the SqlTypeDescriptor adapter ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // 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 // 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 // of ResultSets). See JdbcTypeJavaClassMappings for details. Again, given example, this should return
// VARCHAR/CHAR // 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 ( isLob() ) {
if ( LobTypeMappings.INSTANCE.hasCorrespondingLobCode( jdbcTypeCode ) ) { if ( LobTypeMappings.INSTANCE.hasCorrespondingLobCode( jdbcTypeCode ) ) {
jdbcTypeCode = LobTypeMappings.INSTANCE.getCorrespondingLobCode( jdbcTypeCode ); jdbcTypeCode = LobTypeMappings.INSTANCE.getCorrespondingLobCode( jdbcTypeCode );

View File

@ -10,6 +10,7 @@ import javax.persistence.AttributeConverter;
import org.hibernate.metamodel.model.convert.spi.JpaAttributeConverter; import org.hibernate.metamodel.model.convert.spi.JpaAttributeConverter;
import org.hibernate.resource.beans.spi.ManagedBean; import org.hibernate.resource.beans.spi.ManagedBean;
import org.hibernate.type.descriptor.java.BasicJavaDescriptor;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor; import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/** /**
@ -20,8 +21,8 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
public class JpaAttributeConverterImpl<O,R> implements JpaAttributeConverter<O,R> { public class JpaAttributeConverterImpl<O,R> implements JpaAttributeConverter<O,R> {
private final ManagedBean<AttributeConverter<O,R>> attributeConverterBean; private final ManagedBean<AttributeConverter<O,R>> attributeConverterBean;
private final JavaTypeDescriptor<AttributeConverter<O, R>> converterJavaTypeDescriptor; private final JavaTypeDescriptor<AttributeConverter<O, R>> converterJavaTypeDescriptor;
private final JavaTypeDescriptor<O> domainJavaTypeDescriptor; private final BasicJavaDescriptor<O> domainJavaTypeDescriptor;
private final JavaTypeDescriptor<R> relationalJavaTypeDescriptor; private final BasicJavaDescriptor<R> relationalJavaTypeDescriptor;
public JpaAttributeConverterImpl( public JpaAttributeConverterImpl(
ManagedBean<AttributeConverter<O, R>> attributeConverterBean, ManagedBean<AttributeConverter<O, R>> attributeConverterBean,
@ -30,8 +31,13 @@ public class JpaAttributeConverterImpl<O,R> implements JpaAttributeConverter<O,R
JavaTypeDescriptor<R> relationalJavaTypeDescriptor) { JavaTypeDescriptor<R> relationalJavaTypeDescriptor) {
this.attributeConverterBean = attributeConverterBean; this.attributeConverterBean = attributeConverterBean;
this.converterJavaTypeDescriptor = converterJavaTypeDescriptor; this.converterJavaTypeDescriptor = converterJavaTypeDescriptor;
this.domainJavaTypeDescriptor = domainJavaTypeDescriptor; this.domainJavaTypeDescriptor = (BasicJavaDescriptor<O>) domainJavaTypeDescriptor;
this.relationalJavaTypeDescriptor = relationalJavaTypeDescriptor; this.relationalJavaTypeDescriptor = (BasicJavaDescriptor<R>) relationalJavaTypeDescriptor;
}
@Override
public ManagedBean<AttributeConverter<O, R>> getConverterBean() {
return attributeConverterBean;
} }
@Override @Override
@ -50,12 +56,12 @@ public class JpaAttributeConverterImpl<O,R> implements JpaAttributeConverter<O,R
} }
@Override @Override
public JavaTypeDescriptor<O> getDomainJavaTypeDescriptor() { public BasicJavaDescriptor<O> getDomainJavaTypeDescriptor() {
return domainJavaTypeDescriptor; return domainJavaTypeDescriptor;
} }
@Override @Override
public JavaTypeDescriptor<R> getRelationalJavaTypeDescriptor() { public BasicJavaDescriptor<R> getRelationalJavaTypeDescriptor() {
return relationalJavaTypeDescriptor; return relationalJavaTypeDescriptor;
} }
} }

View File

@ -8,6 +8,8 @@ package org.hibernate.metamodel.model.convert.spi;
import javax.persistence.AttributeConverter; 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; import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
/** /**
@ -17,6 +19,9 @@ import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
*/ */
public interface JpaAttributeConverter<O,R> extends BasicValueConverter<O,R> { public interface JpaAttributeConverter<O,R> extends BasicValueConverter<O,R> {
JavaTypeDescriptor<AttributeConverter<O,R>> getConverterJavaTypeDescriptor(); JavaTypeDescriptor<AttributeConverter<O,R>> getConverterJavaTypeDescriptor();
JavaTypeDescriptor<O> getDomainJavaTypeDescriptor();
JavaTypeDescriptor<R> getRelationalJavaTypeDescriptor(); ManagedBean<AttributeConverter<O,R>> getConverterBean();
BasicJavaDescriptor<O> getDomainJavaTypeDescriptor();
BasicJavaDescriptor<R> getRelationalJavaTypeDescriptor();
} }

View File

@ -11,7 +11,7 @@ package org.hibernate.service;
* *
* @author Steve Ebersole * @author Steve Ebersole
*/ */
public interface ServiceRegistry { public interface ServiceRegistry extends AutoCloseable {
/** /**
* Retrieve this registry's parent registry. * Retrieve this registry's parent registry.
* *
@ -56,4 +56,6 @@ public interface ServiceRegistry {
return service; return service;
} }
@Override
void close();
} }

View File

@ -25,6 +25,11 @@ public interface ServiceRegistryImplementor extends ServiceRegistry {
*/ */
<R extends Service> ServiceBinding<R> locateServiceBinding(Class<R> serviceRole); <R extends Service> ServiceBinding<R> locateServiceBinding(Class<R> serviceRole);
@Override
default void close() {
destroy();
}
/** /**
* Release resources * Release resources
*/ */

View File

@ -91,7 +91,7 @@ public abstract class AbstractStandardBasicType<T>
@Override @Override
public String[] getRegistrationKeys() { public String[] getRegistrationKeys() {
return registerUnderJavaType() return registerUnderJavaType()
? new String[] { getName(), javaTypeDescriptor.getJavaTypeClass().getName() } ? new String[] { getName(), javaTypeDescriptor.getJavaType().getName() }
: new String[] { getName() }; : new String[] { getName() };
} }
@ -128,7 +128,7 @@ public abstract class AbstractStandardBasicType<T>
@Override @Override
public final Class getReturnedClass() { public final Class getReturnedClass() {
return javaTypeDescriptor.getJavaTypeClass(); return javaTypeDescriptor.getJavaType();
} }
@Override @Override

View File

@ -169,6 +169,12 @@ public class BasicTypeRegistry implements Serializable {
register( new CompositeCustomType( type, keys ) ); register( new CompositeCustomType( type, keys ) );
} }
public void unregister(String... keys) {
for ( String key : keys ) {
registry.remove( key );
}
}
public BasicType getRegisteredType(String key) { public BasicType getRegisteredType(String key) {
return registry.get( key ); return registry.get( key );
} }

View File

@ -16,11 +16,13 @@ import java.util.UUID;
import org.hibernate.type.descriptor.ValueBinder; import org.hibernate.type.descriptor.ValueBinder;
import org.hibernate.type.descriptor.ValueExtractor; import org.hibernate.type.descriptor.ValueExtractor;
import org.hibernate.type.descriptor.WrapperOptions; 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.JavaTypeDescriptor;
import org.hibernate.type.descriptor.java.UUIDTypeDescriptor; import org.hibernate.type.descriptor.java.UUIDTypeDescriptor;
import org.hibernate.type.descriptor.sql.BasicBinder; import org.hibernate.type.descriptor.sql.BasicBinder;
import org.hibernate.type.descriptor.sql.BasicExtractor; import org.hibernate.type.descriptor.sql.BasicExtractor;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor; 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 * 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<UUID
return true; return true;
} }
@Override
@SuppressWarnings("unchecked")
public BasicJavaDescriptor getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) {
return (BasicJavaDescriptor) typeConfiguration.getJavaTypeDescriptorRegistry().getDescriptor( UUID.class );
}
public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) { public <X> ValueBinder<X> getBinder(final JavaTypeDescriptor<X> javaTypeDescriptor) {
return new BasicBinder<X>( javaTypeDescriptor, this ) { return new BasicBinder<X>( javaTypeDescriptor, this ) {
@Override @Override

View File

@ -16,9 +16,14 @@ import org.hibernate.internal.util.compare.EqualsHelper;
/** /**
* Abstract adapter for Java type descriptors. * 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 * @author Steve Ebersole
*/ */
public abstract class AbstractTypeDescriptor<T> implements JavaTypeDescriptor<T>, Serializable { public abstract class AbstractTypeDescriptor<T> implements BasicJavaDescriptor<T>, Serializable {
private final Class<T> type; private final Class<T> type;
private final MutabilityPlan<T> mutabilityPlan; private final MutabilityPlan<T> mutabilityPlan;
private final Comparator<T> comparator; private final Comparator<T> comparator;

View File

@ -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<T> extends JavaTypeDescriptor<T> {
/**
* 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() )
);
}
}

View File

@ -15,7 +15,7 @@ import org.hibernate.type.descriptor.WrapperOptions;
*/ */
public class EnumJavaTypeDescriptor<T extends Enum> extends AbstractTypeDescriptor<T> { public class EnumJavaTypeDescriptor<T extends Enum> extends AbstractTypeDescriptor<T> {
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
protected EnumJavaTypeDescriptor(Class<T> type) { public EnumJavaTypeDescriptor(Class<T> type) {
super( type, ImmutableMutabilityPlan.INSTANCE ); super( type, ImmutableMutabilityPlan.INSTANCE );
//JavaTypeDescriptorRegistry.INSTANCE.addDescriptor( this ); //JavaTypeDescriptorRegistry.INSTANCE.addDescriptor( this );
} }

View File

@ -9,6 +9,8 @@ package org.hibernate.type.descriptor.java;
import java.io.Serializable; import java.io.Serializable;
import java.util.Comparator; import java.util.Comparator;
import org.hibernate.internal.util.compare.ComparableComparator;
import org.hibernate.internal.util.compare.EqualsHelper;
import org.hibernate.type.descriptor.WrapperOptions; import org.hibernate.type.descriptor.WrapperOptions;
/** /**
@ -37,17 +39,18 @@ public interface JavaTypeDescriptor<T> extends Serializable {
/** /**
* Retrieve the mutability plan for this Java type. * Retrieve the mutability plan for this Java type.
*
* @return The mutability plan
*/ */
public MutabilityPlan<T> getMutabilityPlan(); @SuppressWarnings("unchecked")
default MutabilityPlan<T> getMutabilityPlan() {
return ImmutableMutabilityPlan.INSTANCE;
}
/** /**
* Retrieve the natural comparator for this type. * Retrieve the natural comparator for this type.
*
* @return The natural comparator.
*/ */
public Comparator<T> getComparator(); default Comparator<T> getComparator() {
return Comparable.class.isAssignableFrom( Comparable.class ) ? ComparableComparator.INSTANCE : null;
}
/** /**
* Extract a proper hash code for this value. * Extract a proper hash code for this value.
@ -56,7 +59,12 @@ public interface JavaTypeDescriptor<T> extends Serializable {
* *
* @return The extracted hash code. * @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 * Determine if two instances are equal
@ -66,7 +74,9 @@ public interface JavaTypeDescriptor<T> extends Serializable {
* *
* @return True if the two are considered equal; false otherwise. * @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. * Extract a loggable representation of the value.
@ -75,11 +85,15 @@ public interface JavaTypeDescriptor<T> extends Serializable {
* *
* @return The loggable representation * @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. * Unwrap an instance of our handled Java type into the requested type.
@ -97,7 +111,7 @@ public interface JavaTypeDescriptor<T> extends Serializable {
* *
* @return The unwrapped value. * @return The unwrapped value.
*/ */
public <X> X unwrap(T value, Class<X> type, WrapperOptions options); <X> X unwrap(T value, Class<X> type, WrapperOptions options);
/** /**
* Wrap a value as our handled Java type. * Wrap a value as our handled Java type.
@ -110,5 +124,5 @@ public interface JavaTypeDescriptor<T> extends Serializable {
* *
* @return The wrapped value. * @return The wrapped value.
*/ */
public <X> T wrap(X value, WrapperOptions options); <X> T wrap(X value, WrapperOptions options);
} }

View File

@ -7,7 +7,6 @@
package org.hibernate.type.descriptor.java; package org.hibernate.type.descriptor.java;
import java.io.Serializable; import java.io.Serializable;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import org.hibernate.HibernateException; import org.hibernate.HibernateException;
@ -16,6 +15,7 @@ import org.hibernate.internal.CoreLogging;
import org.hibernate.internal.CoreMessageLogger; import org.hibernate.internal.CoreMessageLogger;
import org.hibernate.internal.util.ReflectHelper; import org.hibernate.internal.util.ReflectHelper;
import org.hibernate.type.descriptor.WrapperOptions; import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.spi.RegistryHelper;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
/** /**
@ -84,8 +84,7 @@ public class JavaTypeDescriptorRegistry implements Serializable {
} }
private JavaTypeDescriptor addDescriptorInternal(JavaTypeDescriptor descriptor) { private JavaTypeDescriptor addDescriptorInternal(JavaTypeDescriptor descriptor) {
JavaTypeDescriptor javaTypeDescriptor = descriptorsByClass.put( descriptor.getJavaType(), descriptor ); return descriptorsByClass.put( descriptor.getJavaType(), descriptor );
return javaTypeDescriptor;
} }
/** /**
@ -113,43 +112,26 @@ public class JavaTypeDescriptorRegistry implements Serializable {
*/ */
@Deprecated @Deprecated
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public <T> JavaTypeDescriptor<T> getDescriptor(Class<T> cls) { public <J> JavaTypeDescriptor<J> getDescriptor(Class<J> cls) {
if ( cls == null ) { return RegistryHelper.INSTANCE.resolveDescriptor(
throw new IllegalArgumentException( "Class passed to locate Java type descriptor cannot be null" ); descriptorsByClass,
} cls,
() -> {
if ( Serializable.class.isAssignableFrom( cls ) ) {
return new SerializableTypeDescriptor( cls );
}
JavaTypeDescriptor<T> descriptor = descriptorsByClass.get( cls ); log.debugf(
if ( descriptor != null ) { "Could not find matching JavaTypeDescriptor for requested Java class [%s]; using fallback. " +
return descriptor; "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() ) { return new FallbackJavaTypeDescriptor<>( cls );
descriptor = new EnumJavaTypeDescriptor( cls ); }
descriptorsByClass.put( cls, descriptor );
return descriptor;
}
// find the first "assignable" match
for ( Map.Entry<Class, JavaTypeDescriptor> 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()
); );
checkEqualsAndHashCode( cls );
return new FallbackJavaTypeDescriptor<>( cls );
} }
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")

View File

@ -29,11 +29,9 @@ public class SerializableTypeDescriptor<T extends Serializable> extends Abstract
// unfortunately the param types cannot be the same so use something other than 'T' here to make that obvious // unfortunately the param types cannot be the same so use something other than 'T' here to make that obvious
public static class SerializableMutabilityPlan<S extends Serializable> extends MutableMutabilityPlan<S> { public static class SerializableMutabilityPlan<S extends Serializable> extends MutableMutabilityPlan<S> {
public static final SerializableMutabilityPlan<Serializable> INSTANCE = new SerializableMutabilityPlan<>();
public static final SerializableMutabilityPlan<Serializable> INSTANCE private SerializableMutabilityPlan() {
= new SerializableMutabilityPlan<Serializable>( );
public SerializableMutabilityPlan() {
} }
@Override @Override
@ -124,7 +122,7 @@ public class SerializableTypeDescriptor<T extends Serializable> extends Abstract
throw new HibernateException( e ); throw new HibernateException( e );
} }
} }
else if ( getJavaTypeClass().isInstance( value ) ) { else if ( getJavaType().isInstance( value ) ) {
return (T) value; return (T) value;
} }
throw unknownWrap( value.getClass() ); throw unknownWrap( value.getClass() );
@ -136,6 +134,6 @@ public class SerializableTypeDescriptor<T extends Serializable> extends Abstract
@SuppressWarnings({ "unchecked" }) @SuppressWarnings({ "unchecked" })
protected T fromBytes(byte[] bytes) { protected T fromBytes(byte[] bytes) {
return (T) SerializationHelper.deserialize( bytes, getJavaTypeClass().getClassLoader() ); return (T) SerializationHelper.deserialize( bytes, getJavaType().getClassLoader() );
} }
} }

View File

@ -7,10 +7,13 @@
package org.hibernate.type.descriptor.java.spi; package org.hibernate.type.descriptor.java.spi;
import java.io.Serializable; import java.io.Serializable;
import java.util.concurrent.ConcurrentHashMap;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor; import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.spi.TypeConfiguration; import org.hibernate.type.spi.TypeConfiguration;
import org.jboss.logging.Logger;
/** /**
* Basically a map from {@link Class} -> {@link JavaTypeDescriptor} * Basically a map from {@link Class} -> {@link JavaTypeDescriptor}
* *
@ -19,25 +22,41 @@ import org.hibernate.type.spi.TypeConfiguration;
* *
* @since 5.3 * @since 5.3
*/ */
public class JavaTypeDescriptorRegistry public class JavaTypeDescriptorRegistry implements Serializable {
extends org.hibernate.type.descriptor.java.JavaTypeDescriptorRegistry private static final Logger log = Logger.getLogger( JavaTypeDescriptorRegistry.class );
implements Serializable {
private final TypeConfiguration typeConfiguration;
private final org.hibernate.type.descriptor.java.JavaTypeDescriptorRegistry javaTypeDescriptorRegistry;
private ConcurrentHashMap<Class, JavaTypeDescriptor> descriptorsByClass = new ConcurrentHashMap<>();
@SuppressWarnings("unused")
public JavaTypeDescriptorRegistry(TypeConfiguration typeConfiguration) { public JavaTypeDescriptorRegistry(TypeConfiguration typeConfiguration) {
this.typeConfiguration = typeConfiguration;
javaTypeDescriptorRegistry = org.hibernate.type.descriptor.java.JavaTypeDescriptorRegistry.INSTANCE;
} }
@Override
public <T> JavaTypeDescriptor<T> getDescriptor(Class<T> javaType) { public <T> JavaTypeDescriptor<T> getDescriptor(Class<T> 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) { 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
);
}
} }
} }

View File

@ -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 <J> JavaTypeDescriptor<J> resolveDescriptor(
Map<Class,JavaTypeDescriptor> descriptorsByClass,
Class<J> cls,
Supplier<JavaTypeDescriptor<J>> defaultValueSupplier) {
if ( cls == null ) {
throw new IllegalArgumentException( "Class passed to locate JavaTypeDescriptor cannot be null" );
}
JavaTypeDescriptor<J> 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<Class, JavaTypeDescriptor> 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();
}
}

View File

@ -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?
* <p/>
* 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();
}

View File

@ -10,7 +10,9 @@ import java.io.Serializable;
import org.hibernate.type.descriptor.ValueBinder; import org.hibernate.type.descriptor.ValueBinder;
import org.hibernate.type.descriptor.ValueExtractor; import org.hibernate.type.descriptor.ValueExtractor;
import org.hibernate.type.descriptor.java.BasicJavaDescriptor;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor; import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.spi.TypeConfiguration;
/** /**
* Descriptor for the <tt>SQL</tt>/<tt>JDBC</tt> side of a value mapping. * Descriptor for the <tt>SQL</tt>/<tt>JDBC</tt> side of a value mapping.
@ -38,6 +40,15 @@ public interface SqlTypeDescriptor extends Serializable {
*/ */
boolean canBeRemapped(); boolean canBeRemapped();
@SuppressWarnings("unchecked")
default <T> BasicJavaDescriptor<T> getJdbcRecommendedJavaTypeMapping(TypeConfiguration typeConfiguration) {
// match legacy behavior
return (BasicJavaDescriptor<T>) 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 * Get the binder (setting JDBC in-going parameter values) capable of handling values of the type described by the
* passed descriptor. * passed descriptor.

View File

@ -151,7 +151,7 @@ public class SqlTypeDescriptorRegistry implements Serializable {
@Override @Override
public <X> ValueBinder<X> getBinder(JavaTypeDescriptor<X> javaTypeDescriptor) { public <X> ValueBinder<X> getBinder(JavaTypeDescriptor<X> javaTypeDescriptor) {
if ( Serializable.class.isAssignableFrom( javaTypeDescriptor.getJavaTypeClass() ) ) { if ( Serializable.class.isAssignableFrom( javaTypeDescriptor.getJavaType() ) ) {
return VarbinaryTypeDescriptor.INSTANCE.getBinder( javaTypeDescriptor ); return VarbinaryTypeDescriptor.INSTANCE.getBinder( javaTypeDescriptor );
} }
@ -173,7 +173,7 @@ public class SqlTypeDescriptorRegistry implements Serializable {
@Override @Override
@SuppressWarnings("unchecked") @SuppressWarnings("unchecked")
public ValueExtractor getExtractor(JavaTypeDescriptor javaTypeDescriptor) { public ValueExtractor getExtractor(JavaTypeDescriptor javaTypeDescriptor) {
if ( Serializable.class.isAssignableFrom( javaTypeDescriptor.getJavaTypeClass() ) ) { if ( Serializable.class.isAssignableFrom( javaTypeDescriptor.getJavaType() ) ) {
return VarbinaryTypeDescriptor.INSTANCE.getExtractor( javaTypeDescriptor ); return VarbinaryTypeDescriptor.INSTANCE.getExtractor( javaTypeDescriptor );
} }

View File

@ -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" );
}
}
}

View File

@ -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<MyCustomJavaType, String> {
@Override
public String convertToDatabaseColumn(MyCustomJavaType attribute) {
return null;
}
@Override
public MyCustomJavaType convertToEntityAttribute(String dbData) {
return null;
}
}

View File

@ -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<MyCustomJavaType> {
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() );
}
}

View File

@ -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<MyCustomJavaType> {
/**
* Singleton access
*/
public static final MyCustomJavaTypeDescriptor INSTANCE = new MyCustomJavaTypeDescriptor();
private final MutableMutabilityPlan<MyCustomJavaType> mutabilityPlan = new MutableMutabilityPlan<MyCustomJavaType>() {
@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 );
}
}

View File

@ -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 <X> ValueBinder<X> getBinder(JavaTypeDescriptor<X> javaTypeDescriptor) {
return new BasicBinder<X>( 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 <X> ValueExtractor<X> getExtractor(JavaTypeDescriptor<X> javaTypeDescriptor) {
return VarcharTypeDescriptor.INSTANCE.getExtractor( javaTypeDescriptor );
}
}

View File

@ -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;
}
}

View File

@ -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;

View File

@ -83,7 +83,7 @@ public class Java8DateTimeTests extends BaseNonConfigCoreFunctionalTestCase {
String.format( String.format(
"%s (%s) -> %s", "%s (%s) -> %s",
propertyBinding.getName(), propertyBinding.getName(),
javaTypeDescriptor.getJavaTypeClass().getSimpleName(), javaTypeDescriptor.getJavaType().getSimpleName(),
javaTypeDescriptor.toString( propertyBinding.getGetter( TheEntity.class ).get( theEntity ) ) javaTypeDescriptor.toString( propertyBinding.getGetter( TheEntity.class ).get( theEntity ) )
) )
); );

View File

@ -1,3 +1,5 @@
import org.apache.tools.ant.filters.ReplaceTokens
/* /*
* Hibernate, Relational Persistence for Idiomatic Java * Hibernate, Relational Persistence for Idiomatic Java
* *
@ -8,13 +10,27 @@
apply from: rootProject.file( 'gradle/published-java-module.gradle' ) apply from: rootProject.file( 'gradle/published-java-module.gradle' )
apply plugin: 'hibernate-matrix-testing' 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' description = 'Integrate support for Spatial/GIS data into Hibernate O/RM'
dependencies { 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) { compile(libraries.dom4j) {
transitive = false transitive = false
} }
@ -40,3 +56,25 @@ sourceSets.test.resources {
setSrcDirs(['src/test/java', 'src/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] )
}
}
}

View File

@ -7,9 +7,12 @@
package org.hibernate.spatial; package org.hibernate.spatial;
import java.sql.Types;
import org.hibernate.type.descriptor.WrapperOptions; import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.AbstractTypeDescriptor; 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.Geometry;
import org.geolatte.geom.codec.Wkt; import org.geolatte.geom.codec.Wkt;
@ -35,6 +38,11 @@ public class GeolatteGeometryJavaTypeDescriptor extends AbstractTypeDescriptor<G
super( Geometry.class ); super( Geometry.class );
} }
@Override
public SqlTypeDescriptor getJdbcRecommendedSqlType(JdbcRecommendedSqlTypeMappingContext context) {
return context.getTypeConfiguration().getSqlTypeDescriptorRegistry().getDescriptor( Types.ARRAY );
}
@Override @Override
public String toString(Geometry value) { public String toString(Geometry value) {
return value.toString(); return value.toString();

View File

@ -27,6 +27,18 @@ import org.geolatte.geom.Polygon;
*/ */
public class GeolatteGeometryType extends AbstractSingleColumnStandardBasicType<Geometry> implements Spatial { public class GeolatteGeometryType extends AbstractSingleColumnStandardBasicType<Geometry> 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} * Constructs an instance with the specified {@code SqlTypeDescriptor}
* *
@ -38,17 +50,7 @@ public class GeolatteGeometryType extends AbstractSingleColumnStandardBasicType<
@Override @Override
public String[] getRegistrationKeys() { public String[] getRegistrationKeys() {
return new String[] { return 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"
};
} }
@Override @Override

View File

@ -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<Geometry,byte[]> {
@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 );
}
}

View File

@ -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() );
}
}
}
}

View File

@ -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;
}
}

View File

@ -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;