HHH-15458 Interpret String with JSON/XML type code as plain JSON/XML

This commit is contained in:
Christian Beikov 2022-08-23 17:30:41 +02:00
parent 33d2a7fc72
commit eb1f56d542
5 changed files with 46 additions and 2 deletions

View File

@ -32,6 +32,7 @@ import jakarta.persistence.Table;
import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo; import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.isOneOf;
/** /**
* @author Christian Beikov * @author Christian Beikov
@ -73,23 +74,29 @@ public abstract class JsonMappingTests {
final BasicAttributeMapping payloadAttribute = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "payload" ); final BasicAttributeMapping payloadAttribute = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "payload" );
final BasicAttributeMapping objectMapAttribute = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "objectMap" ); final BasicAttributeMapping objectMapAttribute = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "objectMap" );
final BasicAttributeMapping listAttribute = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "list" ); final BasicAttributeMapping listAttribute = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "list" );
final BasicAttributeMapping jsonAttribute = (BasicAttributeMapping) entityDescriptor.findAttributeMapping( "jsonString" );
assertThat( payloadAttribute.getJavaType().getJavaTypeClass(), equalTo( Map.class ) ); assertThat( payloadAttribute.getJavaType().getJavaTypeClass(), equalTo( Map.class ) );
assertThat( objectMapAttribute.getJavaType().getJavaTypeClass(), equalTo( Map.class ) ); assertThat( objectMapAttribute.getJavaType().getJavaTypeClass(), equalTo( Map.class ) );
assertThat( listAttribute.getJavaType().getJavaTypeClass(), equalTo( List.class ) ); assertThat( listAttribute.getJavaType().getJavaTypeClass(), equalTo( List.class ) );
assertThat( jsonAttribute.getJavaType().getJavaTypeClass(), equalTo( String.class ) );
final JdbcType jsonType = jdbcTypeRegistry.getDescriptor( SqlTypes.JSON ); final JdbcType jsonType = jdbcTypeRegistry.getDescriptor( SqlTypes.JSON );
assertThat( payloadAttribute.getJdbcMapping().getJdbcType(), is( jsonType ) ); assertThat( payloadAttribute.getJdbcMapping().getJdbcType(), is( jsonType ) );
assertThat( objectMapAttribute.getJdbcMapping().getJdbcType(), is( jsonType ) ); assertThat( objectMapAttribute.getJdbcMapping().getJdbcType(), is( jsonType ) );
assertThat( listAttribute.getJdbcMapping().getJdbcType(), is( jsonType ) ); assertThat( listAttribute.getJdbcMapping().getJdbcType(), is( jsonType ) );
assertThat( jsonAttribute.getJdbcMapping().getJdbcType(), is( jsonType ) );
Map<String, String> stringMap = Map.of( "name", "ABC" ); Map<String, String> stringMap = Map.of( "name", "ABC" );
Map<StringNode, StringNode> objectMap = supportsObjectMapKey ? Map.of( new StringNode( "name" ), new StringNode( "ABC" ) ) : null; Map<StringNode, StringNode> objectMap = supportsObjectMapKey ? Map.of( new StringNode( "name" ), new StringNode( "ABC" ) ) : null;
List<StringNode> list = List.of( new StringNode( "ABC" ) ); List<StringNode> list = List.of( new StringNode( "ABC" ) );
String json = "{\"name\":\"abc\"}";
// PostgreSQL returns the JSON slightly formatted
String alternativeJson = "{\"name\": \"abc\"}";
scope.inTransaction( scope.inTransaction(
(session) -> { (session) -> {
session.persist( new EntityWithJson( 1, stringMap, objectMap, list ) ); session.persist( new EntityWithJson( 1, stringMap, objectMap, list, json ) );
} }
); );
@ -99,6 +106,14 @@ public abstract class JsonMappingTests {
assertThat( entityWithJson.payload, is( stringMap ) ); assertThat( entityWithJson.payload, is( stringMap ) );
assertThat( entityWithJson.objectMap, is( objectMap ) ); assertThat( entityWithJson.objectMap, is( objectMap ) );
assertThat( entityWithJson.list, is( list ) ); assertThat( entityWithJson.list, is( list ) );
assertThat( entityWithJson.jsonString, isOneOf( json, alternativeJson ) );
String nativeJson = session.createNativeQuery(
"select jsonString from EntityWithJson",
String.class
)
.getResultList()
.get( 0 );
assertThat( nativeJson, isOneOf( json, alternativeJson ) );
} }
); );
} }
@ -120,6 +135,9 @@ public abstract class JsonMappingTests {
@JdbcTypeCode( SqlTypes.JSON ) @JdbcTypeCode( SqlTypes.JSON )
private List<StringNode> list; private List<StringNode> list;
@JdbcTypeCode( SqlTypes.JSON )
private String jsonString;
public EntityWithJson() { public EntityWithJson() {
} }
@ -127,11 +145,13 @@ public abstract class JsonMappingTests {
Integer id, Integer id,
Map<String, String> payload, Map<String, String> payload,
Map<StringNode, StringNode> objectMap, Map<StringNode, StringNode> objectMap,
List<StringNode> list) { List<StringNode> list,
String jsonString) {
this.id = id; this.id = id;
this.payload = payload; this.payload = payload;
this.objectMap = objectMap; this.objectMap = objectMap;
this.list = list; this.list = list;
this.jsonString = jsonString;
} }
} }

View File

@ -32,6 +32,9 @@ public final class JacksonJsonFormatMapper implements FormatMapper {
@Override @Override
public <T> T fromString(CharSequence charSequence, JavaType<T> javaType, WrapperOptions wrapperOptions) { public <T> T fromString(CharSequence charSequence, JavaType<T> javaType, WrapperOptions wrapperOptions) {
if ( javaType.getJavaType() == String.class ) {
return (T) charSequence.toString();
}
try { try {
return objectMapper.readValue( charSequence.toString(), objectMapper.constructType( javaType.getJavaType() ) ); return objectMapper.readValue( charSequence.toString(), objectMapper.constructType( javaType.getJavaType() ) );
} }
@ -42,6 +45,9 @@ public final class JacksonJsonFormatMapper implements FormatMapper {
@Override @Override
public <T> String toString(T value, JavaType<T> javaType, WrapperOptions wrapperOptions) { public <T> String toString(T value, JavaType<T> javaType, WrapperOptions wrapperOptions) {
if ( javaType.getJavaType() == String.class ) {
return (String) value;
}
try { try {
return objectMapper.writerFor( objectMapper.constructType( javaType.getJavaType() ) ) return objectMapper.writerFor( objectMapper.constructType( javaType.getJavaType() ) )
.writeValueAsString( value ); .writeValueAsString( value );

View File

@ -33,6 +33,9 @@ public final class JacksonXmlFormatMapper implements FormatMapper {
@Override @Override
public <T> T fromString(CharSequence charSequence, JavaType<T> javaType, WrapperOptions wrapperOptions) { public <T> T fromString(CharSequence charSequence, JavaType<T> javaType, WrapperOptions wrapperOptions) {
if ( javaType.getJavaType() == String.class ) {
return (T) charSequence.toString();
}
try { try {
return objectMapper.readValue( charSequence.toString(), objectMapper.constructType( javaType.getJavaType() ) ); return objectMapper.readValue( charSequence.toString(), objectMapper.constructType( javaType.getJavaType() ) );
} }
@ -43,6 +46,9 @@ public final class JacksonXmlFormatMapper implements FormatMapper {
@Override @Override
public <T> String toString(T value, JavaType<T> javaType, WrapperOptions wrapperOptions) { public <T> String toString(T value, JavaType<T> javaType, WrapperOptions wrapperOptions) {
if ( javaType.getJavaType() == String.class ) {
return (String) value;
}
try { try {
return objectMapper.writerFor( objectMapper.constructType( javaType.getJavaType() ) ) return objectMapper.writerFor( objectMapper.constructType( javaType.getJavaType() ) )
.writeValueAsString( value ); .writeValueAsString( value );

View File

@ -33,6 +33,9 @@ public final class JsonBJsonFormatMapper implements FormatMapper {
@Override @Override
public <T> T fromString(CharSequence charSequence, JavaType<T> javaType, WrapperOptions wrapperOptions) { public <T> T fromString(CharSequence charSequence, JavaType<T> javaType, WrapperOptions wrapperOptions) {
if ( javaType.getJavaType() == String.class ) {
return (T) charSequence.toString();
}
try { try {
return jsonb.fromJson( charSequence.toString(), javaType.getJavaType() ); return jsonb.fromJson( charSequence.toString(), javaType.getJavaType() );
} }
@ -43,6 +46,9 @@ public final class JsonBJsonFormatMapper implements FormatMapper {
@Override @Override
public <T> String toString(T value, JavaType<T> javaType, WrapperOptions wrapperOptions) { public <T> String toString(T value, JavaType<T> javaType, WrapperOptions wrapperOptions) {
if ( javaType.getJavaType() == String.class ) {
return (String) value;
}
try { try {
return jsonb.toJson( value, javaType.getJavaType() ); return jsonb.toJson( value, javaType.getJavaType() );
} }

View File

@ -51,6 +51,9 @@ public final class JaxbXmlFormatMapper implements FormatMapper {
@Override @Override
public <T> T fromString(CharSequence charSequence, JavaType<T> javaType, WrapperOptions wrapperOptions) { public <T> T fromString(CharSequence charSequence, JavaType<T> javaType, WrapperOptions wrapperOptions) {
if ( javaType.getJavaType() == String.class ) {
return (T) charSequence.toString();
}
try { try {
if ( Map.class.isAssignableFrom( javaType.getJavaTypeClass() ) ) { if ( Map.class.isAssignableFrom( javaType.getJavaTypeClass() ) ) {
final JAXBContext context; final JAXBContext context;
@ -191,6 +194,9 @@ public final class JaxbXmlFormatMapper implements FormatMapper {
@Override @Override
public <T> String toString(T value, JavaType<T> javaType, WrapperOptions wrapperOptions) { public <T> String toString(T value, JavaType<T> javaType, WrapperOptions wrapperOptions) {
if ( javaType.getJavaType() == String.class ) {
return (String) value;
}
try { try {
final StringWriter stringWriter = new StringWriter(); final StringWriter stringWriter = new StringWriter();
if ( Map.class.isAssignableFrom( javaType.getJavaTypeClass() ) ) { if ( Map.class.isAssignableFrom( javaType.getJavaTypeClass() ) ) {