Skip to content

Commit ecfed98

Browse files
committed
HHH-17404 Cleanup JdbcTypes and Jackson/OSON availability detection
1 parent c8a3cd6 commit ecfed98

File tree

15 files changed

+331
-134
lines changed

15 files changed

+331
-134
lines changed

hibernate-core/src/main/java/org/hibernate/boot/internal/SessionFactoryOptionsBuilder.java

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -793,13 +793,10 @@ private static FormatMapper determineJsonFormatMapper(Object setting, StrategySe
793793
FormatMapper.class,
794794
setting,
795795
(Callable<FormatMapper>) () -> {
796-
FormatMapper jsonJacksonFormatMapper = null;
797-
if (JacksonIntegration.isOracleOsonExtensionAvailable()) {
798-
jsonJacksonFormatMapper = getOsonJacksonFormatMapperOrNull();
799-
}
800-
else {
801-
jsonJacksonFormatMapper = getJsonJacksonFormatMapperOrNull();
802-
}
796+
// Prefer the OSON Jackson FormatMapper by default if available
797+
final FormatMapper jsonJacksonFormatMapper = JacksonIntegration.isJacksonOsonExtensionAvailable()
798+
? getOsonJacksonFormatMapperOrNull()
799+
: getJsonJacksonFormatMapperOrNull();
803800
return jsonJacksonFormatMapper != null ? jsonJacksonFormatMapper : getJakartaJsonBFormatMapperOrNull();
804801
}
805802
);

hibernate-core/src/main/java/org/hibernate/boot/registry/selector/internal/StrategySelectorBuilder.java

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -308,20 +308,18 @@ private static void addJsonFormatMappers(StrategySelectorImpl strategySelector)
308308
JsonBJsonFormatMapper.SHORT_NAME,
309309
JsonBJsonFormatMapper.class
310310
);
311-
if ( JacksonIntegration.isOracleOsonExtensionAvailable() ) {
311+
strategySelector.registerStrategyImplementor(
312+
FormatMapper.class,
313+
JacksonJsonFormatMapper.SHORT_NAME,
314+
JacksonJsonFormatMapper.class
315+
);
316+
if ( JacksonIntegration.isJacksonOsonExtensionAvailable() ) {
312317
strategySelector.registerStrategyImplementor(
313318
FormatMapper.class,
314319
JacksonOsonFormatMapper.SHORT_NAME,
315320
JacksonOsonFormatMapper.class
316321
);
317322
}
318-
else {
319-
strategySelector.registerStrategyImplementor(
320-
FormatMapper.class,
321-
JacksonJsonFormatMapper.SHORT_NAME,
322-
JacksonJsonFormatMapper.class
323-
);
324-
}
325323
}
326324

327325
private static void addXmlFormatMappers(StrategySelectorImpl strategySelector) {

hibernate-core/src/main/java/org/hibernate/dialect/OracleDialect.java

Lines changed: 9 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@
1010
import org.hibernate.QueryTimeoutException;
1111
import org.hibernate.boot.model.FunctionContributions;
1212
import org.hibernate.boot.model.TypeContributions;
13-
import org.hibernate.cfg.MappingSettings;
1413
import org.hibernate.dialect.aggregate.AggregateSupport;
1514
import org.hibernate.dialect.aggregate.OracleAggregateSupport;
1615
import org.hibernate.dialect.function.CommonFunctionFactory;
@@ -91,8 +90,6 @@
9190
import org.hibernate.type.descriptor.sql.internal.NamedNativeEnumDdlTypeImpl;
9291
import org.hibernate.type.descriptor.sql.internal.NamedNativeOrdinalEnumDdlTypeImpl;
9392
import org.hibernate.type.descriptor.sql.spi.DdlTypeRegistry;
94-
import org.hibernate.type.format.jackson.JacksonIntegration;
95-
import org.hibernate.type.format.jackson.JacksonJsonFormatMapper;
9693
import org.hibernate.type.spi.TypeConfiguration;
9794

9895
import java.sql.CallableStatement;
@@ -253,14 +250,6 @@ public boolean isApplicationContinuity() {
253250
return applicationContinuity;
254251
}
255252

256-
private static boolean isJacksonJsonFormatMapper(ConfigurationService configService) {
257-
// Mirror the behavior of SessionFactoryOptionsBuilder#determineJsonFormatMapper
258-
final String mapperName = configService.getSetting( MappingSettings.JSON_FORMAT_MAPPER,
259-
StandardConverters.STRING,JacksonJsonFormatMapper.SHORT_NAME);
260-
return JacksonJsonFormatMapper.SHORT_NAME.equalsIgnoreCase( mapperName )
261-
|| mapperName == null && JacksonIntegration.getJsonJacksonFormatMapperOrNull() != null;
262-
}
263-
264253
@Override
265254
protected DatabaseVersion getMinimumSupportedVersion() {
266255
return MINIMUM_VERSION;
@@ -1002,22 +991,21 @@ public void contributeTypes(TypeContributions typeContributions, ServiceRegistry
1002991
);
1003992
}
1004993

1005-
1006994
if ( getVersion().isSameOrAfter( 21 ) ) {
1007-
final boolean osonDisabled = getBoolean( ORACLE_OSON_DISABLED , configurationService.getSettings() );
1008-
if ( !osonDisabled && JacksonIntegration.isOracleOsonExtensionAvailable() && isJacksonJsonFormatMapper( configurationService )) {
995+
final boolean osonDisabled = getBoolean( ORACLE_OSON_DISABLED, configurationService.getSettings() );
996+
if ( !osonDisabled && OracleJdbcHelper.isOsonAvailable( serviceRegistry ) ) {
1009997
// We must check that that extension is available and actually used.
1010-
typeContributions.contributeJdbcType( OracleOsonJacksonJdbcType.INSTANCE );
998+
typeContributions.contributeJdbcType( OracleOsonJdbcType.INSTANCE );
1011999
typeContributions.contributeJdbcTypeConstructor( OracleOsonArrayJdbcTypeConstructor.INSTANCE );
10121000

1013-
DIALECT_LOGGER.log( Logger.Level.DEBUG, "Oracle OSON Jackson extension used" );
1001+
DIALECT_LOGGER.log( Logger.Level.DEBUG, "Oracle OSON extension enabled" );
10141002
}
10151003
else {
1016-
if (DIALECT_LOGGER.isDebugEnabled()) {
1017-
DIALECT_LOGGER.log( Logger.Level.DEBUG, "Oracle OSON Jackson extension not used" );
1018-
DIALECT_LOGGER.log( Logger.Level.DEBUG,
1019-
"JacksonIntegration.isOracleOsonExtensionAvailable(): " +
1020-
JacksonIntegration.isOracleOsonExtensionAvailable());
1004+
if ( osonDisabled ) {
1005+
DIALECT_LOGGER.log( Logger.Level.DEBUG, "Oracle OSON extension disabled" );
1006+
}
1007+
else {
1008+
DIALECT_LOGGER.log( Logger.Level.DEBUG, "Oracle OSON extension not available" );
10211009
}
10221010
typeContributions.contributeJdbcType( OracleJsonJdbcType.INSTANCE );
10231011
typeContributions.contributeJdbcTypeConstructor( OracleJsonArrayJdbcTypeConstructor.NATIVE_INSTANCE );

hibernate-core/src/main/java/org/hibernate/dialect/OracleJdbcHelper.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,16 @@ public static boolean isUsable(ServiceRegistry serviceRegistry) {
3131
return false;
3232
}
3333
}
34+
public static boolean isOsonAvailable(ServiceRegistry serviceRegistry) {
35+
final ClassLoaderService classLoaderService = serviceRegistry.requireService( ClassLoaderService.class );
36+
try {
37+
classLoaderService.classForName( "oracle.sql.json.OracleJsonFactory" );
38+
return true;
39+
}
40+
catch (ClassLoadingException ex) {
41+
return false;
42+
}
43+
}
3444

3545
public static JdbcTypeConstructor getArrayJdbcTypeConstructor(ServiceRegistry serviceRegistry) {
3646
return create( serviceRegistry, "org.hibernate.dialect.OracleArrayJdbcTypeConstructor" );

hibernate-core/src/main/java/org/hibernate/dialect/OracleOsonJacksonArrayJdbcType.java renamed to hibernate-core/src/main/java/org/hibernate/dialect/OracleOsonArrayJdbcType.java

Lines changed: 80 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@
44
*/
55
package org.hibernate.dialect;
66

7-
import com.fasterxml.jackson.core.JsonParser;
87
import oracle.jdbc.OracleType;
98
import oracle.jdbc.driver.DatabaseError;
109
import oracle.sql.json.OracleJsonDatum;
@@ -28,15 +27,15 @@
2827
import org.hibernate.type.format.OsonDocumentWriter;
2928

3029
import java.io.ByteArrayOutputStream;
30+
import java.io.Closeable;
3131
import java.io.InputStream;
3232
import java.nio.charset.StandardCharsets;
3333
import java.sql.CallableStatement;
3434
import java.sql.PreparedStatement;
3535
import java.sql.ResultSet;
3636
import java.sql.SQLException;
3737

38-
import static org.hibernate.dialect.OracleOsonJacksonJdbcType.OSON_JACKSON_FACTORY;
39-
import static org.hibernate.dialect.OracleOsonJacksonJdbcType.OSON_JSON_FACTORY;
38+
import static org.hibernate.dialect.OracleOsonJdbcType.OSON_JSON_FACTORY;
4039

4140
/**
4241
*
@@ -47,21 +46,19 @@
4746
* @author Emmanuel Jannetti
4847
* @author Bidyadhar Mohanty
4948
*/
50-
public class OracleOsonJacksonArrayJdbcType extends OracleJsonArrayJdbcType {
49+
public class OracleOsonArrayJdbcType extends OracleJsonArrayJdbcType {
5150

52-
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( OracleOsonJacksonArrayJdbcType.class );
51+
private static final CoreMessageLogger LOG = CoreLogging.messageLogger( OracleOsonArrayJdbcType.class );
5352

54-
public OracleOsonJacksonArrayJdbcType(JdbcType elementJdbcType) {
53+
public OracleOsonArrayJdbcType(JdbcType elementJdbcType) {
5554
super(elementJdbcType);
5655
}
5756

58-
5957
@Override
6058
public String toString() {
61-
return "OracleOsonJacksonArrayJdbcType";
59+
return "OracleOsonArrayJdbcType";
6260
}
6361

64-
6562
@Override
6663
public <X> ValueBinder<X> getBinder(JavaType<X> javaType) {
6764

@@ -73,7 +70,9 @@ private <T> byte[] toOsonStream(T value, JavaType<T> javaType, WrapperOptions op
7370
try (OracleJsonGenerator generator = OSON_JSON_FACTORY.createJsonBinaryGenerator( out )) {
7471
final JavaType<?> elementJavaType = ((BasicPluralJavaType<?>) javaType).getElementJavaType();
7572
if ( elementJavaType instanceof UnknownBasicJavaType<?> ) {
76-
options.getJsonFormatMapper().writeToTarget( value, javaType, generator, options);
73+
try (Closeable osonGen = OracleOsonJacksonHelper.createWriteTarget( out )) {
74+
options.getJsonFormatMapper().writeToTarget( value, javaType, osonGen, options );
75+
}
7776
}
7877
else {
7978
final OsonDocumentWriter writer = new OsonDocumentWriter( generator );
@@ -92,15 +91,31 @@ private <T> byte[] toOsonStream(T value, JavaType<T> javaType, WrapperOptions op
9291
);
9392
}
9493
}
95-
return out.toByteArray();
9694
}
95+
return out.toByteArray();
96+
}
9797

98+
private boolean useUtf8(WrapperOptions options) {
99+
final JavaType<?> elementJavaType = ((BasicPluralJavaType<?>) getJavaType()).getElementJavaType();
100+
return elementJavaType instanceof UnknownBasicJavaType<?>
101+
&& !options.getJsonFormatMapper().supportsTargetType( OracleOsonJacksonHelper.WRITER_CLASS );
98102
}
103+
99104
@Override
100105
protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options)
101106
throws SQLException {
102107
try {
103-
st.setObject( index, toOsonStream( value, getJavaType(), options ), OracleType.JSON );
108+
if ( useUtf8( options ) ) {
109+
final String json = OracleOsonArrayJdbcType.this.toString(
110+
value,
111+
getJavaType(),
112+
options
113+
);
114+
st.setBytes( index, json.getBytes( StandardCharsets.UTF_8 ) );
115+
}
116+
else {
117+
st.setObject( index, toOsonStream( value, getJavaType(), options ), OracleType.JSON );
118+
}
104119
}
105120
catch (Exception e) {
106121
throw new SQLException( e );
@@ -111,7 +126,17 @@ protected void doBind(PreparedStatement st, X value, int index, WrapperOptions o
111126
protected void doBind(CallableStatement st, X value, String name, WrapperOptions options)
112127
throws SQLException {
113128
try {
114-
st.setObject( name, toOsonStream( value, getJavaType(), options ) , OracleType.JSON);
129+
if ( useUtf8( options ) ) {
130+
final String json = OracleOsonArrayJdbcType.this.toString(
131+
value,
132+
getJavaType(),
133+
options
134+
);
135+
st.setBytes( name, json.getBytes( StandardCharsets.UTF_8 ) );
136+
}
137+
else {
138+
st.setObject( name, toOsonStream( value, getJavaType(), options ), OracleType.JSON );
139+
}
115140
}
116141
catch (Exception e) {
117142
throw new SQLException( e );
@@ -127,7 +152,7 @@ public <X> ValueExtractor<X> getExtractor(JavaType<X> javaType) {
127152

128153
private X fromOson(InputStream osonBytes, WrapperOptions options) throws Exception {
129154
if ( ((BasicPluralJavaType<?>) getJavaType()).getElementJavaType() instanceof UnknownBasicJavaType<?> ) {
130-
try (JsonParser oParser = OSON_JACKSON_FACTORY.createParser( osonBytes )) {
155+
try (Closeable oParser = OracleOsonJacksonHelper.createReadSource( osonBytes )) {
131156
return options.getJsonFormatMapper().readFromSource( getJavaType(), oParser, options );
132157
}
133158
}
@@ -155,21 +180,40 @@ private X doExtraction(OracleJsonDatum datum, WrapperOptions options) throws SQ
155180
}
156181
}
157182

183+
private boolean useUtf8(WrapperOptions options) {
184+
final JavaType<?> elementJavaType = ((BasicPluralJavaType<?>) getJavaType()).getElementJavaType();
185+
return elementJavaType instanceof UnknownBasicJavaType<?>
186+
&& !options.getJsonFormatMapper().supportsTargetType( OracleOsonJacksonHelper.READER_CLASS );
187+
}
188+
189+
private X fromString(byte[] json, WrapperOptions options) throws SQLException {
190+
if ( json == null ) {
191+
return null;
192+
}
193+
return OracleOsonArrayJdbcType.this.fromString(
194+
new String( json, StandardCharsets.UTF_8 ),
195+
getJavaType(),
196+
options
197+
);
198+
}
199+
158200
@Override
159201
protected X doExtract(ResultSet rs, int paramIndex, WrapperOptions options) throws SQLException {
160202
try {
161-
OracleJsonDatum ojd = rs.getObject( paramIndex, OracleJsonDatum.class );
162-
return doExtraction( ojd, options);
203+
if ( useUtf8( options ) ) {
204+
return fromString( rs.getBytes( paramIndex ), options );
205+
}
206+
else {
207+
OracleJsonDatum ojd = rs.getObject( paramIndex, OracleJsonDatum.class );
208+
return doExtraction( ojd, options );
209+
}
163210
} catch (SQLException exc) {
164211
if ( exc.getErrorCode() == DatabaseError.JDBC_ERROR_BASE + DatabaseError.EOJ_INVALID_COLUMN_TYPE) {
165212
// This may happen if we are fetching data from an existing schema
166213
// that uses BLOB for JSON column In that case we assume bytes are
167214
// UTF-8 bytes (i.e not OSON) and we fall back to previous String-based implementation
168215
LOG.invalidJSONColumnType( OracleType.CLOB.getName(), OracleType.JSON.getName() );
169-
return OracleOsonJacksonArrayJdbcType.this.fromString(
170-
new String( rs.getBytes( paramIndex ), StandardCharsets.UTF_8 ),
171-
getJavaType(),
172-
options);
216+
return fromString( rs.getBytes( paramIndex ), options );
173217
} else {
174218
throw exc;
175219
}
@@ -179,18 +223,20 @@ protected X doExtract(ResultSet rs, int paramIndex, WrapperOptions options) thro
179223
@Override
180224
protected X doExtract(CallableStatement statement, int index, WrapperOptions options) throws SQLException {
181225
try {
182-
OracleJsonDatum ojd = statement.getObject( index, OracleJsonDatum.class );
183-
return doExtraction( ojd, options);
226+
if ( useUtf8( options ) ) {
227+
return fromString( statement.getBytes( index ), options );
228+
}
229+
else {
230+
OracleJsonDatum ojd = statement.getObject( index, OracleJsonDatum.class );
231+
return doExtraction( ojd, options );
232+
}
184233
} catch (SQLException exc) {
185234
if ( exc.getErrorCode() == DatabaseError.JDBC_ERROR_BASE + DatabaseError.EOJ_INVALID_COLUMN_TYPE) {
186235
// This may happen if we are fetching data from an existing schema
187236
// that uses BLOB for JSON column In that case we assume bytes are
188237
// UTF-8 bytes (i.e not OSON) and we fall back to previous String-based implementation
189238
LOG.invalidJSONColumnType( OracleType.CLOB.getName(), OracleType.JSON.getName() );
190-
return OracleOsonJacksonArrayJdbcType.this.fromString(
191-
new String( statement.getBytes( index ), StandardCharsets.UTF_8 ),
192-
getJavaType(),
193-
options);
239+
return fromString( statement.getBytes( index ), options );
194240
} else {
195241
throw exc;
196242
}
@@ -201,18 +247,20 @@ protected X doExtract(CallableStatement statement, int index, WrapperOptions opt
201247
protected X doExtract(CallableStatement statement, String name, WrapperOptions options)
202248
throws SQLException {
203249
try {
204-
OracleJsonDatum ojd = statement.getObject( name, OracleJsonDatum.class );
205-
return doExtraction( ojd, options);
250+
if ( useUtf8( options ) ) {
251+
return fromString( statement.getBytes( name ), options );
252+
}
253+
else {
254+
OracleJsonDatum ojd = statement.getObject( name, OracleJsonDatum.class );
255+
return doExtraction( ojd, options );
256+
}
206257
} catch (SQLException exc) {
207258
if ( exc.getErrorCode() == DatabaseError.JDBC_ERROR_BASE + DatabaseError.EOJ_INVALID_COLUMN_TYPE) {
208259
// This may happen if we are fetching data from an existing schema
209260
// that uses BLOB for JSON column In that case we assume bytes are
210261
// UTF-8 bytes (i.e not OSON) and we fall back to previous String-based implementation
211262
LOG.invalidJSONColumnType( OracleType.CLOB.getName(), OracleType.JSON.getName() );
212-
return OracleOsonJacksonArrayJdbcType.this.fromString(
213-
new String( statement.getBytes( name ), StandardCharsets.UTF_8 ),
214-
getJavaType(),
215-
options);
263+
return fromString( statement.getBytes( name ), options );
216264
} else {
217265
throw exc;
218266
}

hibernate-core/src/main/java/org/hibernate/dialect/OracleOsonArrayJdbcTypeConstructor.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import org.hibernate.type.spi.TypeConfiguration;
1313

1414
/**
15-
* Factory for {@link OracleOsonJacksonArrayJdbcType}.
15+
* Factory for {@link OracleOsonArrayJdbcType}.
1616
* @author Emmanuel Jannetti
1717
*/
1818
public class OracleOsonArrayJdbcTypeConstructor implements JdbcTypeConstructor {
@@ -33,7 +33,7 @@ public JdbcType resolveType(
3333
Dialect dialect,
3434
JdbcType elementType,
3535
ColumnTypeInformation columnTypeInformation) {
36-
return new OracleOsonJacksonArrayJdbcType( elementType );
36+
return new OracleOsonArrayJdbcType( elementType );
3737
}
3838

3939
@Override

0 commit comments

Comments
 (0)