Skip to content

Commit 2b169c0

Browse files
committed
HHH-17404 add flag to disable OSON extension
1 parent c864ae0 commit 2b169c0

File tree

5 files changed

+86
-104
lines changed

5 files changed

+86
-104
lines changed

hibernate-core/src/main/java/org/hibernate/cfg/DialectSpecificSettings.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,10 @@ public interface DialectSpecificSettings {
4444
String ORACLE_APPLICATION_CONTINUITY = "hibernate.dialect.oracle.application_continuity";
4545

4646
/**
47-
* Specifies whether usage of the Oracle JSON binary format (aka OSON) should be disabled.
47+
* Specifies whether usage of the Oracle JSON binary format (also known as OSON) should be disabled.
4848
* <p>
49-
* Starting to 21c, if the ojdbc-provider-jackson-oson extension is available. JSON data in an oracle
50-
* database are stored using the OSON binary format. This setting can be used to fallback to the old implementation
49+
* Starting in 21c, if the ojdbc-provider-jackson-oson extension is available, JSON data in an oracle
50+
* database is stored using the OSON binary format. This setting can be used to fallback to the old implementation
5151
* based on String serialization.
5252
*
5353
* @settingDefault {@code false}

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

Lines changed: 42 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -70,39 +70,10 @@ public static void serializeArray(MappingType elementMappingType, Object[] value
7070
}
7171
for ( Object value : values ) {
7272
try {
73-
if (value == null) {
74-
writer.nullValue();
75-
}
76-
else if ( elementMappingType instanceof EmbeddableMappingType ) {
77-
JsonHelper.serialize( (EmbeddableMappingType) elementMappingType, value, options, writer );
78-
} else if ( elementMappingType instanceof BasicType<?> ) {
79-
//noinspection unchecked
80-
final BasicType<Object> basicType = (BasicType<Object>) elementMappingType;
81-
82-
if ( isArrayType(basicType.getJdbcType())) {
83-
final int length = Array.getLength( value );
84-
if ( length != 0 ) {
85-
//noinspection unchecked
86-
final JavaType<Object> elementJavaType = ( (BasicPluralJavaType<Object>) basicType.getJdbcJavaType() ).getElementJavaType();
87-
final JdbcType elementJdbcType = ( (ArrayJdbcType) basicType.getJdbcType() ).getElementJdbcType();
88-
final Object domainArray = basicType.convertToRelationalValue( value );
89-
for ( int j = 0; j < length; j++ ) {
90-
writer.serializeJsonValue(Array.get(domainArray,j), elementJavaType, elementJdbcType, options);
91-
}
92-
}
93-
}
94-
else {
95-
writer.serializeJsonValue(basicType.convertToRelationalValue( value),
96-
(JavaType<Object>)basicType.getJdbcJavaType(),basicType.getJdbcType(), options);
97-
}
98-
}
99-
else {
100-
throw new UnsupportedOperationException( "Support for mapping type not yet implemented: " + elementMappingType.getClass().getName() );
101-
}
73+
serialize(elementMappingType, value, options, writer);
10274
}
10375
catch (IOException e) {
104-
// TODO : do better than this
105-
throw new RuntimeException( e );
76+
throw new IllegalArgumentException( "Could not serialize JSON array value" , e );
10677
}
10778
}
10879
writer.endArray();
@@ -159,6 +130,42 @@ public static void serialize(EmbeddableMappingType embeddableMappingType,
159130
writer.endObject();
160131
}
161132

133+
private static void serialize(MappingType mappedType, Object value, WrapperOptions options, JsonDocumentWriter writer)
134+
throws IOException {
135+
if ( value == null ) {
136+
writer.nullValue();
137+
}
138+
else if ( mappedType instanceof EmbeddableMappingType ) {
139+
serialize( (EmbeddableMappingType) mappedType, value, options, writer );
140+
}
141+
else if ( mappedType instanceof BasicType<?> ) {
142+
//noinspection unchecked
143+
final BasicType<Object> basicType = (BasicType<Object>) mappedType;
144+
145+
if ( isArrayType(basicType.getJdbcType())) {
146+
final int length = Array.getLength( value );
147+
writer.startArray();
148+
if ( length != 0 ) {
149+
//noinspection unchecked
150+
final JavaType<Object> elementJavaType = ( (BasicPluralJavaType<Object>) basicType.getJdbcJavaType() ).getElementJavaType();
151+
final JdbcType elementJdbcType = ( (ArrayJdbcType) basicType.getJdbcType() ).getElementJdbcType();
152+
final Object domainArray = basicType.convertToRelationalValue( value );
153+
for ( int j = 0; j < length; j++ ) {
154+
writer.serializeJsonValue(Array.get(domainArray,j), elementJavaType, elementJdbcType, options);
155+
}
156+
}
157+
writer.endArray();
158+
}
159+
else {
160+
writer.serializeJsonValue(basicType.convertToRelationalValue( value),
161+
(JavaType<Object>)basicType.getJdbcJavaType(),basicType.getJdbcType(), options);
162+
}
163+
}
164+
else {
165+
throw new UnsupportedOperationException( "Support for mapping type not yet implemented: " + mappedType.getClass().getName() );
166+
}
167+
}
168+
162169
/**
163170
* JSON object attirbute serialization
164171
* @see #serialize(EmbeddableMappingType, Object, WrapperOptions, JsonDocumentWriter)
@@ -176,40 +183,18 @@ private static void serializeMapping(EmbeddableMappingType embeddableMappingType
176183
if ( attributeMapping instanceof SelectableMapping ) {
177184
final String name = ( (SelectableMapping) attributeMapping ).getSelectableName();
178185
writer.objectKey( name );
179-
if (values[i] == null) {
180-
writer.nullValue();
181-
}
182-
else if (attributeMapping.getMappedType() instanceof BasicType<?>) {
183-
final BasicType<Object> basicType = (BasicType<Object>) attributeMapping.getMappedType();
184-
if ( isArrayType(basicType.getJdbcType())) {
185-
final int length = Array.getLength( values[i] );
186-
writer.startArray();
187-
if ( length != 0 ) {
188-
//noinspection unchecked
189-
final JavaType<Object> elementJavaType = ( (BasicPluralJavaType<Object>) basicType.getJdbcJavaType() ).getElementJavaType();
190-
final JdbcType elementJdbcType = ( (ArrayJdbcType) basicType.getJdbcType() ).getElementJdbcType();
191-
final Object domainArray = basicType.convertToRelationalValue( values[i] );
192-
for ( int j = 0; j < length; j++ ) {
193-
writer.serializeJsonValue(Array.get(domainArray,j), elementJavaType, elementJdbcType, options);
194-
}
195-
}
196-
writer.endArray();
197-
}
198-
else {
199-
writer.serializeJsonValue(basicType.convertToRelationalValue( values[i]),
200-
(JavaType<Object>)basicType.getJdbcJavaType(),basicType.getJdbcType(), options);
201-
}
202-
}
203-
else if ( attributeMapping.getMappedType() instanceof EmbeddableMappingType ) {
186+
187+
if ( attributeMapping.getMappedType() instanceof EmbeddableMappingType ) {
204188
writer.startObject();
205189
serializeMapping( (EmbeddableMappingType)attributeMapping.getMappedType(), values[i], options,writer);
206190
writer.endObject();
191+
} else {
192+
serialize(attributeMapping.getMappedType(), values[i], options, writer);
207193
}
208194

209195
}
210196
else if ( attributeMapping instanceof EmbeddedAttributeMapping ) {
211197
if ( values[i] == null ) {
212-
//writer.nullValue();
213198
continue;
214199
}
215200
final EmbeddableMappingType mappingType = (EmbeddableMappingType) attributeMapping.getMappedType();

hibernate-core/src/main/java/org/hibernate/type/format/StringJsonDocumentReader.java

Lines changed: 18 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
*/
2626
public class StringJsonDocumentReader extends StringJsonDocument implements JsonDocumentReader {
2727

28+
private static final char ESCAPE_CHAR = '\\';
29+
2830
private final String jsonString;
2931
private final int limit;
3032
private int position;
@@ -294,30 +296,30 @@ private void moveTo(char character) throws IllegalStateException {
294296
}
295297

296298
/**
297-
* Goes through the json string to locate a character.
299+
* Goes through the JSON string to locate a character.
300+
* Escaped characters are taken into account.
301+
* ex: on 'AB\"C"' this method returns 5 (not 3)
302+
*
298303
* @param character character to be found
299-
* @param escape character to be found
300304
* @return the position of the character or -1 if not found.
301305
*/
302-
private int locateCharacter(char character, char escape) {
303-
assert character != escape;
306+
private int locateCharacter(char character) {
304307
int pointer = this.position;
305308

306-
boolean escapeIsOn = false;
307-
while ( pointer< this.limit) {
309+
while ( pointer < this.limit) {
308310
final char c = this.jsonString.charAt( pointer );
309-
if (c == escape) {
310-
escapeIsOn = true;
311+
if (c == ESCAPE_CHAR) {
312+
// We encountered an escape character.
313+
// We should just skip the next one as it is either the expected character
314+
// but as escaped one, we should ignore it, either this is something else
315+
// and we should ignore it also
316+
pointer += 2;
317+
continue;
311318
}
312319
else {
313320
if ( c == character ) {
314-
if (escapeIsOn) {
315-
escapeIsOn = false;
316-
}
317-
else {
318-
// found
319-
return pointer;
320-
}
321+
// found
322+
return pointer;
321323
}
322324
}
323325
pointer++;
@@ -365,7 +367,7 @@ private void consumeQuottedString() {
365367
this.position++;
366368

367369
//locate ending quote
368-
int endingQuote = locateCharacter( StringJsonDocumentMarker.QUOTE.getMarkerCharacter(), '\\');
370+
int endingQuote = locateCharacter( StringJsonDocumentMarker.QUOTE.getMarkerCharacter());
369371
if (endingQuote == -1) {
370372
throw new IllegalStateException("Can't find ending quote of key name");
371373
}

hibernate-core/src/main/java/org/hibernate/type/format/jackson/JacksonJsonFormatMapper.java

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,11 @@
44
*/
55
package org.hibernate.type.format.jackson;
66

7-
import org.hibernate.type.descriptor.WrapperOptions;
8-
import org.hibernate.type.descriptor.java.JavaType;
97
import org.hibernate.type.format.AbstractJsonFormatMapper;
108

119
import com.fasterxml.jackson.core.JsonProcessingException;
1210
import com.fasterxml.jackson.databind.ObjectMapper;
1311

14-
import java.io.IOException;
1512
import java.lang.reflect.Type;
1613

1714
/**
@@ -51,29 +48,4 @@ public <T> String toString(T value, Type type) {
5148
throw new IllegalArgumentException( "Could not serialize object of java type: " + type, e );
5249
}
5350
}
54-
55-
@Override
56-
public <T> void writeToTarget(T value, JavaType<T> javaType, Object target, WrapperOptions options)
57-
throws IOException {
58-
59-
try {
60-
objectMapper.writerFor(
61-
objectMapper.constructType( javaType.getJavaType() ) ).writeValueAsString( value );
62-
}
63-
catch (JsonProcessingException e) {
64-
throw new IllegalArgumentException( "Could not serialize object of java type: " + javaType.getJavaType(), e );
65-
}
66-
67-
}
68-
69-
@Override
70-
public <T> T readFromSource(JavaType<T> javaType, Object source, WrapperOptions options) throws IOException {
71-
try {
72-
return objectMapper.readValue( ((CharSequence)source).toString(), objectMapper.constructType( javaType.getJavaType() ) );
73-
}
74-
catch (JsonProcessingException e) {
75-
throw new IllegalArgumentException( "Could not deserialize string to java type: " + javaType.getJavaType(), e );
76-
}
77-
78-
}
7951
}

hibernate-core/src/test/java/org/hibernate/orm/test/dialect/resolver/DialectSpecificConfigTest.java

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import static org.hibernate.cfg.DialectSpecificSettings.MYSQL_NO_BACKSLASH_ESCAPES;
2525
import static org.hibernate.cfg.DialectSpecificSettings.ORACLE_AUTONOMOUS_DATABASE;
2626
import static org.hibernate.cfg.DialectSpecificSettings.ORACLE_EXTENDED_STRING_SIZE;
27+
import static org.hibernate.cfg.DialectSpecificSettings.ORACLE_OSON_DISABLED;
2728
import static org.hibernate.cfg.DialectSpecificSettings.SYBASE_ANSI_NULL;
2829
import static org.hibernate.dialect.DatabaseVersion.NO_VERSION;
2930

@@ -55,6 +56,28 @@ public void testOracleIsAutonomous() {
5556
assertThat( ( (OracleDialect) dialect ).isAutonomous() ).isTrue();
5657
}
5758

59+
@Test
60+
public void testOracleIsOsonEnabled() {
61+
final Dialect dialect = resolveDialect(
62+
"Oracle",
63+
values -> values.put( "emptyOne", "true" )
64+
);
65+
66+
assertThat( dialect ).isInstanceOf( OracleDialect.class );
67+
assertThat( ( (OracleDialect) dialect ).isOracleOsonDisabled() ).isFalse();
68+
}
69+
70+
@Test
71+
public void testOracleIsOsonDisabled() {
72+
final Dialect dialect = resolveDialect(
73+
"Oracle",
74+
values -> values.put( ORACLE_OSON_DISABLED, "true" )
75+
);
76+
77+
assertThat( dialect ).isInstanceOf( OracleDialect.class );
78+
assertThat( ( (OracleDialect) dialect ).isOracleOsonDisabled() ).isTrue();
79+
}
80+
5881
@Test
5982
public void testSybaseASEIsAnsiNull() {
6083
final Dialect dialect = resolveDialect(

0 commit comments

Comments
 (0)