HHH-14905 - Verify that custom JavaType and JdbcType registration combo works

This commit is contained in:
Steve Ebersole 2021-11-03 15:13:55 -05:00
parent e28d61330e
commit 34cdd3077c
16 changed files with 775 additions and 8 deletions

View File

@ -64,6 +64,7 @@ dependencies {
testImplementation libraries.mockito_inline testImplementation libraries.mockito_inline
testImplementation libraries.jodaTime testImplementation libraries.jodaTime
testImplementation libraries.assertj testImplementation libraries.assertj
testImplementation 'org.orbisgis:h2gis:1.5.0'
testRuntimeOnly libraries.byteBuddy testRuntimeOnly libraries.byteBuddy
testRuntimeOnly libraries.jakarta_weld testRuntimeOnly libraries.jakarta_weld

View File

@ -16,6 +16,7 @@ import java.util.stream.Stream;
import java.util.stream.StreamSupport; import java.util.stream.StreamSupport;
import org.hibernate.CacheMode; import org.hibernate.CacheMode;
import org.hibernate.Internal;
import org.hibernate.LockOptions; import org.hibernate.LockOptions;
import org.hibernate.ScrollMode; import org.hibernate.ScrollMode;
import org.hibernate.cache.spi.QueryKey; import org.hibernate.cache.spi.QueryKey;
@ -89,6 +90,28 @@ public class JdbcSelectExecutorStandardImpl implements JdbcSelectExecutor {
); );
} }
@Internal
public <R> List<R> list(
JdbcSelect jdbcSelect,
JdbcParameterBindings jdbcParameterBindings,
ExecutionContext executionContext,
RowTransformer<R> rowTransformer,
ListResultsConsumer.UniqueSemantic uniqueSemantic,
Function<Function<String, PreparedStatement>, DeferredResultSetAccess> resultSetAccessCreator) {
// Only do auto flushing for top level queries
return executeQuery(
jdbcSelect,
executionContext,
rowTransformer,
(sql) -> executionContext.getSession()
.getJdbcCoordinator()
.getStatementPreparer()
.prepareStatement( sql ),
resultSetAccessCreator,
ListResultsConsumer.instance( uniqueSemantic )
);
}
@Override @Override
public <R> ScrollableResultsImplementor<R> scroll( public <R> ScrollableResultsImplementor<R> scroll(
JdbcSelect jdbcSelect, JdbcSelect jdbcSelect,
@ -112,6 +135,26 @@ public class JdbcSelectExecutorStandardImpl implements JdbcSelectExecutor {
); );
} }
@Internal
public <R> ScrollableResultsImplementor<R> scroll(
JdbcSelect jdbcSelect,
ExecutionContext executionContext,
RowTransformer<R> rowTransformer,
Function<Function<String, PreparedStatement>, DeferredResultSetAccess> resultSetAccessCreator) {
// Only do auto flushing for top level queries
return executeQuery(
jdbcSelect,
executionContext,
rowTransformer,
(sql) -> executionContext.getSession()
.getJdbcCoordinator()
.getStatementPreparer()
.prepareStatement( sql ),
resultSetAccessCreator,
ScrollableResultsConsumer.instance()
);
}
@Override @Override
public <R> Stream<R> stream( public <R> Stream<R> stream(
JdbcSelect jdbcSelect, JdbcSelect jdbcSelect,
@ -132,6 +175,25 @@ public class JdbcSelectExecutorStandardImpl implements JdbcSelectExecutor {
return stream.onClose( scrollableResults::close ); return stream.onClose( scrollableResults::close );
} }
@Internal
public <R> Stream<R> stream(
JdbcSelect jdbcSelect,
ExecutionContext executionContext,
RowTransformer<R> rowTransformer,
Function<Function<String, PreparedStatement>, DeferredResultSetAccess> resultSetAccessCreator) {
final ScrollableResultsImplementor<R> scrollableResults = scroll(
jdbcSelect,
executionContext,
rowTransformer,
resultSetAccessCreator
);
final ScrollableResultsIterator<R> iterator = new ScrollableResultsIterator<>( scrollableResults );
final Spliterator<R> spliterator = Spliterators.spliteratorUnknownSize( iterator, Spliterator.NONNULL );
final Stream<R> stream = StreamSupport.stream( spliterator, false );
return stream.onClose( scrollableResults::close );
}
private <T, R> T executeQuery( private <T, R> T executeQuery(
JdbcSelect jdbcSelect, JdbcSelect jdbcSelect,
JdbcParameterBindings jdbcParameterBindings, JdbcParameterBindings jdbcParameterBindings,
@ -163,6 +225,7 @@ public class JdbcSelectExecutorStandardImpl implements JdbcSelectExecutor {
} }
} }
} }
private <T, R> T doExecuteQuery( private <T, R> T doExecuteQuery(
JdbcSelect jdbcSelect, JdbcSelect jdbcSelect,
JdbcParameterBindings jdbcParameterBindings, JdbcParameterBindings jdbcParameterBindings,
@ -170,19 +233,38 @@ public class JdbcSelectExecutorStandardImpl implements JdbcSelectExecutor {
RowTransformer<R> rowTransformer, RowTransformer<R> rowTransformer,
Function<String, PreparedStatement> statementCreator, Function<String, PreparedStatement> statementCreator,
ResultsConsumer<T, R> resultsConsumer) { ResultsConsumer<T, R> resultsConsumer) {
return executeQuery(
final DeferredResultSetAccess deferredResultSetAccess = new DeferredResultSetAccess(
jdbcSelect, jdbcSelect,
jdbcParameterBindings,
executionContext, executionContext,
statementCreator rowTransformer,
(sql) -> executionContext.getSession()
.getJdbcCoordinator()
.getStatementPreparer()
.prepareStatement( sql ),
(stmntCreator) -> new DeferredResultSetAccess(
jdbcSelect,
jdbcParameterBindings,
executionContext,
statementCreator
),
resultsConsumer
); );
}
private <T, R> T executeQuery(
JdbcSelect jdbcSelect,
ExecutionContext executionContext,
RowTransformer<R> rowTransformer,
Function<String,PreparedStatement> statementCreator,
Function<Function<String, PreparedStatement>, DeferredResultSetAccess> resultSetAccessCreator,
ResultsConsumer<T,R> resultsConsumer) {
final DeferredResultSetAccess resultSetAccess = resultSetAccessCreator.apply( statementCreator );
final JdbcValues jdbcValues = resolveJdbcValuesSource( final JdbcValues jdbcValues = resolveJdbcValuesSource(
executionContext.getQueryIdentifier( deferredResultSetAccess.getFinalSql() ), executionContext.getQueryIdentifier( resultSetAccess.getFinalSql() ),
jdbcSelect, jdbcSelect,
resultsConsumer.canResultsBeCached(), resultsConsumer.canResultsBeCached(),
executionContext, executionContext,
deferredResultSetAccess resultSetAccess
); );
if ( rowTransformer == null ) { if ( rowTransformer == null ) {
@ -251,7 +333,7 @@ public class JdbcSelectExecutorStandardImpl implements JdbcSelectExecutor {
// because these lock options are only for Initializers. // because these lock options are only for Initializers.
// If we wouldn't omit this, the follow on lock requests would be no-ops, // If we wouldn't omit this, the follow on lock requests would be no-ops,
// because the EntityEntrys would already have the desired lock mode // because the EntityEntrys would already have the desired lock mode
deferredResultSetAccess.usesFollowOnLocking() resultSetAccess.usesFollowOnLocking()
? LockOptions.NONE ? LockOptions.NONE
: executionContext.getQueryOptions().getLockOptions(), : executionContext.getQueryOptions().getLockOptions(),
rowTransformer, rowTransformer,

View File

@ -214,7 +214,7 @@ public class DeferredResultSetAccess extends AbstractResultSetAccess {
} }
try { try {
eventListenerManager.jdbcExecuteStatementStart(); eventListenerManager.jdbcExecuteStatementStart();
resultSet = preparedStatement.executeQuery(); resultSet = wrapResultSet( preparedStatement.executeQuery() );
} }
finally { finally {
eventListenerManager.jdbcExecuteStatementEnd(); eventListenerManager.jdbcExecuteStatementEnd();
@ -260,6 +260,10 @@ public class DeferredResultSetAccess extends AbstractResultSetAccess {
} }
} }
protected ResultSet wrapResultSet(ResultSet resultSet) throws SQLException {
return resultSet;
}
protected LockMode determineFollowOnLockMode(LockOptions lockOptions) { protected LockMode determineFollowOnLockMode(LockOptions lockOptions) {
final LockMode lockModeToUse = lockOptions.findGreatestLockMode(); final LockMode lockModeToUse = lockOptions.findGreatestLockMode();

View File

@ -0,0 +1,59 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.orm.test.mapping.type.contribution.jts;
import org.hibernate.annotations.JavaType;
import jakarta.persistence.Basic;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.Table;
import org.locationtech.jts.geom.Point;
/**
* @author Steve Ebersole
*/
@Entity(name = "FirePoint")
@Table(name = "FirePoint")
public class FirePoint {
@Id
private Integer id;
@Basic
private String name;
@Basic
@JavaType( PointJavaType.class )
private Point coordinate;
private FirePoint() {
}
public FirePoint(Integer id, String name, Point coordinate) {
this.id = id;
this.name = name;
this.coordinate = coordinate;
}
public Integer getId() {
return id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Point getCoordinate() {
return coordinate;
}
public void setCoordinate(Point coordinate) {
this.coordinate = coordinate;
}
}

View File

@ -0,0 +1,56 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.orm.test.mapping.type.contribution.jts;
import org.hibernate.boot.model.TypeContributor;
import org.hibernate.orm.test.mapping.type.contribution.jts.infrastructure.CustomConnectionProviderInitiator;
import org.hibernate.orm.test.mapping.type.contribution.jts.infrastructure.CustomJdbcServicesInitiator;
import org.hibernate.testing.orm.junit.BootstrapServiceRegistry;
import org.hibernate.testing.orm.junit.BootstrapServiceRegistry.JavaService;
import org.hibernate.testing.orm.junit.DomainModel;
import org.hibernate.testing.orm.junit.ServiceRegistry;
import org.hibernate.testing.orm.junit.SessionFactory;
import org.hibernate.testing.orm.junit.SessionFactoryScope;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;
import org.locationtech.jts.geom.Coordinate;
import org.locationtech.jts.geom.GeometryFactory;
/**
* @author Steve Ebersole
*/
@BootstrapServiceRegistry(
javaServices = @JavaService( role = TypeContributor.class, impl = JtsTypeContributor.class )
)
@ServiceRegistry(
initiators = { CustomJdbcServicesInitiator.class, CustomConnectionProviderInitiator.class }
)
@DomainModel( annotatedClasses = FirePoint.class )
@SessionFactory
public class JtsContributorTests {
@Test
public void simpleTest(SessionFactoryScope scope) {
scope.inTransaction( (session) -> {
// save one with a Point
final GeometryFactory geometryFactory = new GeometryFactory();
session.save( new FirePoint( 1, "alpha", geometryFactory.createPoint( new Coordinate( 1, 2, 3 ) ) ) );
// and one without (null)
session.save( new FirePoint( 2, "bravo", null ) );
} );
scope.inTransaction( (session) -> {
session.createQuery( "select fp.coordinate from FirePoint fp" ).list();
} );
}
@AfterEach
public void dropTestData(SessionFactoryScope scope) {
scope.inTransaction( (session) -> session.createQuery( "delete FirePoint" ).executeUpdate() );
}
}

View File

@ -0,0 +1,22 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.orm.test.mapping.type.contribution.jts;
import org.hibernate.boot.model.TypeContributions;
import org.hibernate.boot.model.TypeContributor;
import org.hibernate.service.ServiceRegistry;
/**
* TypeContributor for applying the H2GIS JTS type descriptors
*/
public class JtsTypeContributor implements TypeContributor {
@Override
public void contribute(TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
typeContributions.contributeJavaTypeDescriptor( PointJavaType.INSTANCE );
typeContributions.contributeJdbcTypeDescriptor( new PointJdbcType() );
}
}

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.orm.test.mapping.type.contribution.jts;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.BasicJavaType;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.hibernate.type.descriptor.jdbc.JdbcTypeDescriptorIndicators;
import org.locationtech.jts.geom.Point;
/**
* @author Steve Ebersole
*/
public class PointJavaType implements BasicJavaType<Point> {
/**
* Singleton access
*/
public static final PointJavaType INSTANCE = new PointJavaType();
@Override
public Class<Point> getJavaTypeClass() {
return Point.class;
}
@Override
public JdbcType getRecommendedJdbcType(JdbcTypeDescriptorIndicators context) {
return context
.getTypeConfiguration()
.getJdbcTypeDescriptorRegistry()
.getDescriptor( PointJdbcType.POINT_TYPE_CODE );
}
@Override
public Point fromString(CharSequence string) {
throw unsupported( String.class );
}
private static UnsupportedOperationException unsupported(Class<?> type) {
return new UnsupportedOperationException( "At the moment, Point cannot be converted to/from other types : " + type.getName() );
}
@SuppressWarnings("unchecked")
@Override
public <X> X unwrap(Point value, Class<X> type, WrapperOptions options) {
if ( value == null || type.isInstance( value ) ) {
return (X) value;
}
throw unsupported( type );
}
@Override
public <X> Point wrap(X value, WrapperOptions options) {
if ( value == null || value instanceof Point ) {
return (Point) value;
}
throw unsupported( value.getClass() );
}
}

View File

@ -0,0 +1,94 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.orm.test.mapping.type.contribution.jts;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import org.hibernate.type.SqlTypes;
import org.hibernate.type.descriptor.ValueBinder;
import org.hibernate.type.descriptor.ValueExtractor;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.JavaType;
import org.hibernate.type.descriptor.jdbc.BasicBinder;
import org.hibernate.type.descriptor.jdbc.BasicExtractor;
import org.hibernate.type.descriptor.jdbc.JdbcType;
import org.locationtech.jts.geom.Point;
/**
* @author Steve Ebersole
*/
public class PointJdbcType implements JdbcType {
public static final int POINT_TYPE_CODE = SqlTypes.GEOMETRY;
@Override
public String getFriendlyName() {
return "POINT";
}
@Override
public int getJdbcTypeCode() {
return POINT_TYPE_CODE;
}
private final ValueBinder<Point> binder = new BasicBinder<Point>( PointJavaType.INSTANCE, this ) {
@Override
protected void doBindNull(PreparedStatement st, int index, WrapperOptions options) throws SQLException {
// according to documentation, can be treated as character data
st.setNull( index, Types.VARCHAR );
}
@Override
protected void doBind(PreparedStatement st, Point value, int index, WrapperOptions options) throws SQLException {
st.setObject( index,value );
}
@Override
protected void doBindNull(CallableStatement st, String name, WrapperOptions options) throws SQLException {
// according to documentation, can be treated as character data
st.setNull( name, Types.VARCHAR );
}
@Override
protected void doBind(CallableStatement st, Point value, String name, WrapperOptions options) throws SQLException {
st.setObject( name, value );
}
};
private final ValueExtractor<Point> extractor = new BasicExtractor<Point>( PointJavaType.INSTANCE, this ) {
@Override
protected Point doExtract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException {
return rs.getObject( paramIndex, Point.class );
}
@Override
protected Point doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
return statement.getObject( index, Point.class );
}
@Override
protected Point doExtract(CallableStatement statement, String name, WrapperOptions options) throws SQLException {
return statement.getObject( name, Point.class );
}
};
@Override
public <X> ValueBinder<X> getBinder(JavaType<X> javaTypeDescriptor) {
//noinspection unchecked
return (ValueBinder<X>) binder;
}
@Override
public <X> ValueExtractor<X> getExtractor(JavaType<X> javaTypeDescriptor) {
//noinspection unchecked
return (ValueExtractor<X>) extractor;
}
}

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.orm.test.mapping.type.contribution.jts.infrastructure;
import java.sql.Connection;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.Map;
import org.hibernate.engine.jdbc.connections.internal.ConnectionProviderInitiator;
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.exception.JDBCConnectionException;
import org.hibernate.service.spi.Configurable;
import org.hibernate.service.spi.ServiceRegistryAwareService;
import org.hibernate.service.spi.ServiceRegistryImplementor;
import org.hibernate.service.spi.Stoppable;
import org.h2gis.utilities.SFSUtilities;
/**
* @author Steve Ebersole
*/
public class CustomConnectionProvider implements ConnectionProvider, Stoppable {
private final ConnectionProvider delegate;
public CustomConnectionProvider(Map configurationValues, ServiceRegistryImplementor registry) {
delegate = ConnectionProviderInitiator.INSTANCE.initiateService( configurationValues, registry );
( (Configurable) delegate ).configure( configurationValues );
( (ServiceRegistryAwareService) delegate ).injectServices( registry );
}
@Override
public Connection getConnection() throws SQLException {
final Connection wrappedConnection = SFSUtilities.wrapConnection( delegate.getConnection() );
try {
final Statement statement = wrappedConnection.createStatement();
statement.execute( "CREATE ALIAS IF NOT EXISTS H2GIS_SPATIAL FOR \"org.h2gis.functions.factory.H2GISFunctions.load\"" );
statement.execute( "CALL H2GIS_SPATIAL()" );
return wrappedConnection;
}
catch (SQLException e) {
throw new JDBCConnectionException( "Error creating H2GIS wrapped Connection", e );
}
}
@Override
public void closeConnection(Connection conn) throws SQLException {
delegate.closeConnection( conn );
}
@Override
public boolean supportsAggressiveRelease() {
return false;
}
@Override
public boolean isUnwrappableAs(Class unwrapType) {
return false;
}
@Override
public <T> T unwrap(Class<T> unwrapType) {
return null;
}
@Override
public void stop() {
if ( delegate instanceof Stoppable ) {
( (Stoppable) delegate ).stop();
}
}
}

View File

@ -0,0 +1,28 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.orm.test.mapping.type.contribution.jts.infrastructure;
import java.util.Map;
import org.hibernate.boot.registry.StandardServiceInitiator;
import org.hibernate.engine.jdbc.connections.spi.ConnectionProvider;
import org.hibernate.service.spi.ServiceRegistryImplementor;
/**
* @author Steve Ebersole
*/
public class CustomConnectionProviderInitiator implements StandardServiceInitiator<ConnectionProvider> {
@Override
public ConnectionProvider initiateService(Map configurationValues, ServiceRegistryImplementor registry) {
return new CustomConnectionProvider( configurationValues, registry );
}
@Override
public Class<ConnectionProvider> getServiceInitiated() {
return ConnectionProvider.class;
}
}

View File

@ -0,0 +1,92 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.orm.test.mapping.type.contribution.jts.infrastructure;
import java.util.List;
import java.util.stream.Stream;
import org.hibernate.ScrollMode;
import org.hibernate.query.spi.ScrollableResultsImplementor;
import org.hibernate.sql.exec.internal.JdbcSelectExecutorStandardImpl;
import org.hibernate.sql.exec.spi.ExecutionContext;
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
import org.hibernate.sql.exec.spi.JdbcSelect;
import org.hibernate.sql.exec.spi.JdbcSelectExecutor;
import org.hibernate.sql.results.spi.ListResultsConsumer;
import org.hibernate.sql.results.spi.RowTransformer;
/**
* @author Steve Ebersole
*/
public class CustomJdbcSelectExecutor implements JdbcSelectExecutor {
private final JdbcSelectExecutorStandardImpl standardSelectExecutor;
public CustomJdbcSelectExecutor() {
this.standardSelectExecutor = JdbcSelectExecutorStandardImpl.INSTANCE;
}
@Override
public <R> List<R> list(
JdbcSelect jdbcSelect,
JdbcParameterBindings jdbcParameterBindings,
ExecutionContext executionContext,
RowTransformer<R> rowTransformer,
ListResultsConsumer.UniqueSemantic uniqueSemantic) {
return standardSelectExecutor.list(
jdbcSelect,
jdbcParameterBindings,
executionContext,
rowTransformer,
uniqueSemantic,
(preparedStatementFunction) -> new CustomResultSetAccess(
jdbcSelect,
jdbcParameterBindings,
executionContext,
preparedStatementFunction
)
);
}
@Override
public <R> ScrollableResultsImplementor<R> scroll
(JdbcSelect jdbcSelect,
ScrollMode scrollMode,
JdbcParameterBindings jdbcParameterBindings,
ExecutionContext executionContext,
RowTransformer<R> rowTransformer) {
return standardSelectExecutor.scroll(
jdbcSelect,
executionContext,
rowTransformer,
(preparedStatementFunction) -> new CustomResultSetAccess(
jdbcSelect,
jdbcParameterBindings,
executionContext,
preparedStatementFunction
)
);
}
@Override
public <R> Stream<R> stream(
JdbcSelect jdbcSelect,
JdbcParameterBindings jdbcParameterBindings,
ExecutionContext executionContext,
RowTransformer<R> rowTransformer) {
return standardSelectExecutor.stream(
jdbcSelect,
executionContext,
rowTransformer,
(preparedStatementFunction) -> new CustomResultSetAccess(
jdbcSelect,
jdbcParameterBindings,
executionContext,
preparedStatementFunction
)
);
}
}

View File

@ -0,0 +1,96 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.orm.test.mapping.type.contribution.jts.infrastructure;
import java.util.Map;
import org.hibernate.dialect.Dialect;
import org.hibernate.engine.jdbc.LobCreationContext;
import org.hibernate.engine.jdbc.LobCreator;
import org.hibernate.engine.jdbc.connections.spi.JdbcConnectionAccess;
import org.hibernate.engine.jdbc.env.spi.ExtractedDatabaseMetaData;
import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.engine.jdbc.spi.SqlExceptionHelper;
import org.hibernate.engine.jdbc.spi.SqlStatementLogger;
import org.hibernate.service.spi.Configurable;
import org.hibernate.service.spi.ServiceRegistryAwareService;
import org.hibernate.service.spi.ServiceRegistryImplementor;
import org.hibernate.sql.exec.spi.JdbcMutationExecutor;
import org.hibernate.sql.exec.spi.JdbcSelectExecutor;
/**
* @author Steve Ebersole
*/
public class CustomJdbcServices implements JdbcServices, ServiceRegistryAwareService, Configurable {
private final JdbcServices delegate;
private final CustomJdbcSelectExecutor selectExecutor;
public CustomJdbcServices(JdbcServices delegate) {
this.delegate = delegate;
selectExecutor = new CustomJdbcSelectExecutor();
}
@Override
public JdbcSelectExecutor getJdbcSelectExecutor() {
return selectExecutor;
}
@Override
public JdbcEnvironment getJdbcEnvironment() {
return delegate.getJdbcEnvironment();
}
@Override
public JdbcConnectionAccess getBootstrapJdbcConnectionAccess() {
return delegate.getBootstrapJdbcConnectionAccess();
}
@Override
public Dialect getDialect() {
return delegate.getDialect();
}
@Override
public SqlStatementLogger getSqlStatementLogger() {
return delegate.getSqlStatementLogger();
}
@Override
public SqlExceptionHelper getSqlExceptionHelper() {
return delegate.getSqlExceptionHelper();
}
@Override
public ExtractedDatabaseMetaData getExtractedMetaDataSupport() {
return delegate.getExtractedMetaDataSupport();
}
@Override
public LobCreator getLobCreator(LobCreationContext lobCreationContext) {
return delegate.getLobCreator( lobCreationContext );
}
@Override
public JdbcMutationExecutor getJdbcMutationExecutor() {
return delegate.getJdbcMutationExecutor();
}
@Override
public void configure(Map configurationValues) {
if ( delegate instanceof Configurable ) {
( (Configurable) delegate ).configure( configurationValues );
}
}
@Override
public void injectServices(ServiceRegistryImplementor serviceRegistry) {
if ( delegate instanceof ServiceRegistryAwareService ) {
( (ServiceRegistryAwareService) delegate ).injectServices( serviceRegistry );
}
}
}

View File

@ -0,0 +1,30 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.orm.test.mapping.type.contribution.jts.infrastructure;
import java.util.Map;
import org.hibernate.boot.registry.StandardServiceInitiator;
import org.hibernate.engine.jdbc.internal.JdbcServicesInitiator;
import org.hibernate.engine.jdbc.spi.JdbcServices;
import org.hibernate.service.spi.ServiceRegistryImplementor;
/**
* @author Steve Ebersole
*/
public class CustomJdbcServicesInitiator implements StandardServiceInitiator<JdbcServices> {
@Override
public JdbcServices initiateService(Map configurationValues, ServiceRegistryImplementor registry) {
final JdbcServices standard = JdbcServicesInitiator.INSTANCE.initiateService( configurationValues, registry );
return new CustomJdbcServices( standard );
}
@Override
public Class<JdbcServices> getServiceInitiated() {
return JdbcServices.class;
}
}

View File

@ -0,0 +1,37 @@
/*
* Hibernate, Relational Persistence for Idiomatic Java
*
* License: GNU Lesser General Public License (LGPL), version 2.1 or later
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html
*/
package org.hibernate.orm.test.mapping.type.contribution.jts.infrastructure;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.function.Function;
import org.hibernate.sql.exec.spi.ExecutionContext;
import org.hibernate.sql.exec.spi.JdbcParameterBindings;
import org.hibernate.sql.exec.spi.JdbcSelect;
import org.hibernate.sql.results.jdbc.internal.DeferredResultSetAccess;
import org.h2gis.utilities.SpatialResultSet;
/**
* @author Steve Ebersole
*/
public class CustomResultSetAccess extends DeferredResultSetAccess {
public CustomResultSetAccess(
JdbcSelect jdbcSelect,
JdbcParameterBindings jdbcParameterBindings,
ExecutionContext executionContext,
Function<String, PreparedStatement> statementCreator) {
super( jdbcSelect, jdbcParameterBindings, executionContext, statementCreator );
}
@Override
protected ResultSet wrapResultSet(ResultSet resultSet) throws SQLException {
return resultSet.unwrap( SpatialResultSet.class );
}
}

View File

@ -0,0 +1,14 @@
/*
* Hibernate, Relational Persistence for 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
*/
/**
* Verify support for contributing Java and JDBC type extensions using
* H2 JTS support.
*
* Smoke test for hibernate-spatial
*/
package org.hibernate.orm.test.mapping.type.contribution.jts;

View File

@ -72,14 +72,27 @@ public @interface ServiceRegistry {
Class<? extends StandardServiceInitiator>[] initiators() default {}; Class<? extends StandardServiceInitiator>[] initiators() default {};
Service[] services() default {}; Service[] services() default {};
JavaService[] javaServices() default {};
Setting[] settings() default {}; Setting[] settings() default {};
SettingProvider[] settingProviders() default {}; SettingProvider[] settingProviders() default {};
/**
* A Hibernate Service registration
*/
@interface Service { @interface Service {
Class<? extends org.hibernate.service.Service> role(); Class<? extends org.hibernate.service.Service> role();
Class<? extends org.hibernate.service.Service> impl(); Class<? extends org.hibernate.service.Service> impl();
} }
/**
* A Java service loadable via {@link java.util.ServiceLoader}
*/
@interface JavaService {
Class<?> role();
Class<?>[] impls();
}
} }