[HHH-17294] DeepCopy non-Embedded JSON or XML JdbcTypCode attribute using FormatMapper
This commit is contained in:
parent
36c73ab342
commit
b67a0bad32
|
@ -72,6 +72,8 @@ import org.hibernate.type.descriptor.java.Immutability;
|
|||
import org.hibernate.type.descriptor.java.ImmutableMutabilityPlan;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
import org.hibernate.type.descriptor.java.MutabilityPlan;
|
||||
import org.hibernate.type.descriptor.java.spi.JsonJavaType;
|
||||
import org.hibernate.type.descriptor.java.spi.XmlJavaType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
|
||||
import org.hibernate.type.descriptor.jdbc.spi.JdbcTypeRegistry;
|
||||
|
|
|
@ -53,6 +53,7 @@ import org.hibernate.tool.schema.extract.spi.ColumnTypeInformation;
|
|||
import org.hibernate.type.BasicType;
|
||||
import org.hibernate.type.CustomType;
|
||||
import org.hibernate.type.NumericBooleanConverter;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
import org.hibernate.type.TrueFalseConverter;
|
||||
import org.hibernate.type.Type;
|
||||
import org.hibernate.type.WrapperArrayHandling;
|
||||
|
@ -62,6 +63,11 @@ import org.hibernate.type.descriptor.java.BasicJavaType;
|
|||
import org.hibernate.type.descriptor.java.BasicPluralJavaType;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
import org.hibernate.type.descriptor.java.MutabilityPlan;
|
||||
import org.hibernate.type.descriptor.java.spi.FormatMapperBasedJavaType;
|
||||
import org.hibernate.type.descriptor.java.spi.JavaTypeRegistry;
|
||||
import org.hibernate.type.descriptor.java.spi.JsonJavaType;
|
||||
import org.hibernate.type.descriptor.java.spi.RegistryHelper;
|
||||
import org.hibernate.type.descriptor.java.spi.XmlJavaType;
|
||||
import org.hibernate.type.descriptor.jdbc.BooleanJdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
|
||||
|
@ -697,15 +703,15 @@ public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resol
|
|||
|
||||
private JavaType<?> determineJavaType(JavaType<?> explicitJavaType) {
|
||||
JavaType<?> javaType = explicitJavaType;
|
||||
|
||||
if ( javaType == null ) {
|
||||
if ( implicitJavaTypeAccess != null ) {
|
||||
final java.lang.reflect.Type implicitJtd = implicitJavaTypeAccess.apply( getTypeConfiguration() );
|
||||
if ( implicitJtd != null ) {
|
||||
javaType = getTypeConfiguration().getJavaTypeRegistry().getDescriptor( implicitJtd );
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
// if ( javaType == null ) {
|
||||
// if ( implicitJavaTypeAccess != null ) {
|
||||
// final java.lang.reflect.Type implicitJtd = implicitJavaTypeAccess.apply( getTypeConfiguration() );
|
||||
// if ( implicitJtd != null ) {
|
||||
// javaType = getTypeConfiguration().getJavaTypeRegistry().getDescriptor( implicitJtd );
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
if ( javaType == null ) {
|
||||
final JavaType<?> reflectedJtd = determineReflectedJavaType();
|
||||
|
@ -720,11 +726,12 @@ public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resol
|
|||
private JavaType<?> determineReflectedJavaType() {
|
||||
final java.lang.reflect.Type impliedJavaType;
|
||||
|
||||
final TypeConfiguration typeConfiguration = getTypeConfiguration();
|
||||
if ( resolvedJavaType != null ) {
|
||||
impliedJavaType = resolvedJavaType;
|
||||
}
|
||||
else if ( implicitJavaTypeAccess != null ) {
|
||||
impliedJavaType = implicitJavaTypeAccess.apply( getTypeConfiguration() );
|
||||
impliedJavaType = implicitJavaTypeAccess.apply( typeConfiguration );
|
||||
}
|
||||
else if ( ownerName != null && propertyName != null ) {
|
||||
impliedJavaType = ReflectHelper.reflectedPropertyType(
|
||||
|
@ -743,7 +750,40 @@ public class BasicValue extends SimpleValue implements JdbcTypeIndicators, Resol
|
|||
return null;
|
||||
}
|
||||
|
||||
return getTypeConfiguration().getJavaTypeRegistry().resolveDescriptor( impliedJavaType );
|
||||
final JavaTypeRegistry javaTypeRegistry = typeConfiguration.getJavaTypeRegistry();
|
||||
final JavaType<Object> javaType = javaTypeRegistry.findDescriptor( impliedJavaType );
|
||||
final MutabilityPlan<Object> explicitMutabilityPlan = explicitMutabilityPlanAccess != null
|
||||
? explicitMutabilityPlanAccess.apply( typeConfiguration )
|
||||
: null;
|
||||
final MutabilityPlan<Object> determinedMutabilityPlan = explicitMutabilityPlan != null
|
||||
? explicitMutabilityPlan
|
||||
: RegistryHelper.INSTANCE.determineMutabilityPlan( impliedJavaType, typeConfiguration );
|
||||
if ( javaType == null ) {
|
||||
if ( jdbcTypeCode != null ) {
|
||||
// Construct special JavaType instances for JSON/XML types which can report recommended JDBC types
|
||||
// and implement toString/fromString as well as copying based on FormatMapper operations
|
||||
switch ( jdbcTypeCode ) {
|
||||
case SqlTypes.JSON:
|
||||
final JavaType<Object> jsonJavaType = new JsonJavaType<>(
|
||||
impliedJavaType,
|
||||
determinedMutabilityPlan,
|
||||
typeConfiguration
|
||||
);
|
||||
javaTypeRegistry.addDescriptor( jsonJavaType );
|
||||
return jsonJavaType;
|
||||
case SqlTypes.SQLXML:
|
||||
final JavaType<Object> xmlJavaType = new XmlJavaType<>(
|
||||
impliedJavaType,
|
||||
determinedMutabilityPlan,
|
||||
typeConfiguration
|
||||
);
|
||||
javaTypeRegistry.addDescriptor( xmlJavaType );
|
||||
return xmlJavaType;
|
||||
}
|
||||
}
|
||||
return javaTypeRegistry.resolveDescriptor( impliedJavaType );
|
||||
}
|
||||
return javaType;
|
||||
}
|
||||
|
||||
private static Resolution<?> interpretExplicitlyNamedType(
|
||||
|
|
|
@ -30,6 +30,7 @@ import org.hibernate.type.descriptor.WrapperOptions;
|
|||
import org.hibernate.type.descriptor.java.AbstractClassJavaType;
|
||||
import org.hibernate.type.descriptor.java.JavaType;
|
||||
import org.hibernate.type.descriptor.java.MutabilityPlan;
|
||||
import org.hibernate.type.descriptor.java.MutableMutabilityPlan;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcLiteralFormatter;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
|
||||
|
@ -242,7 +243,9 @@ public abstract class AbstractStandardBasicType<T>
|
|||
}
|
||||
|
||||
protected final boolean isDirty(Object old, Object current) {
|
||||
return !isSame( old, current );
|
||||
// MutableMutabilityPlan.INSTANCE is a special plan for which we always have to assume the value is dirty,
|
||||
// because we can't actually copy a value, but have no knowledge about the mutability of the java type
|
||||
return getMutabilityPlan() == MutableMutabilityPlan.INSTANCE || !isSame( old, current );
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
/*
|
||||
* 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.lang.reflect.Type;
|
||||
|
||||
import org.hibernate.Incubating;
|
||||
import org.hibernate.SharedSessionContract;
|
||||
import org.hibernate.type.descriptor.WrapperOptions;
|
||||
import org.hibernate.type.descriptor.java.AbstractJavaType;
|
||||
import org.hibernate.type.descriptor.java.MutabilityPlan;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
|
||||
import org.hibernate.type.format.FormatMapper;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
/**
|
||||
* Java type for {@link FormatMapper} based types i.e. {@link org.hibernate.type.SqlTypes#JSON}
|
||||
* or {@link org.hibernate.type.SqlTypes#SQLXML} mapped types.
|
||||
*
|
||||
* @author Christian Beikov
|
||||
*/
|
||||
@Incubating
|
||||
public abstract class FormatMapperBasedJavaType<T> extends AbstractJavaType<T> implements MutabilityPlan<T> {
|
||||
|
||||
private final TypeConfiguration typeConfiguration;
|
||||
|
||||
public FormatMapperBasedJavaType(
|
||||
Type type,
|
||||
MutabilityPlan<T> mutabilityPlan,
|
||||
TypeConfiguration typeConfiguration) {
|
||||
super( type, mutabilityPlan );
|
||||
this.typeConfiguration = typeConfiguration;
|
||||
}
|
||||
|
||||
protected abstract FormatMapper getFormatMapper(TypeConfiguration typeConfiguration);
|
||||
|
||||
@Override
|
||||
public JdbcType getRecommendedJdbcType(JdbcTypeIndicators context) {
|
||||
throw new JdbcTypeRecommendationException(
|
||||
"Could not determine recommended JdbcType for Java type '" + getJavaType().getTypeName() + "'"
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString(T value) {
|
||||
return getFormatMapper( typeConfiguration ).toString(
|
||||
value,
|
||||
this,
|
||||
typeConfiguration.getSessionFactory().getWrapperOptions()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T fromString(CharSequence string) {
|
||||
return getFormatMapper( typeConfiguration ).fromString(
|
||||
string,
|
||||
this,
|
||||
typeConfiguration.getSessionFactory().getWrapperOptions()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> X unwrap(T value, Class<X> type, WrapperOptions options) {
|
||||
if ( type.isAssignableFrom( getJavaTypeClass() ) ) {
|
||||
//noinspection unchecked
|
||||
return (X) value;
|
||||
}
|
||||
else if ( type == String.class ) {
|
||||
//noinspection unchecked
|
||||
return (X) getFormatMapper( typeConfiguration ).toString( value, this, options );
|
||||
}
|
||||
throw new UnsupportedOperationException(
|
||||
"Unwrap strategy not known for this Java type : " + getJavaType().getTypeName()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <X> T wrap(X value, WrapperOptions options) {
|
||||
if ( getJavaTypeClass().isInstance( value ) ) {
|
||||
//noinspection unchecked
|
||||
return (T) value;
|
||||
}
|
||||
else if ( value instanceof String ) {
|
||||
return getFormatMapper( typeConfiguration ).fromString( (String) value, this, options );
|
||||
}
|
||||
throw new UnsupportedOperationException(
|
||||
"Wrap strategy not known for this Java type : " + getJavaType().getTypeName()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MutabilityPlan<T> getMutabilityPlan() {
|
||||
final MutabilityPlan<T> mutabilityPlan = super.getMutabilityPlan();
|
||||
return mutabilityPlan == null ? this : mutabilityPlan;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isMutable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public T deepCopy(T value) {
|
||||
return fromString( toString( value ) );
|
||||
}
|
||||
|
||||
@Override
|
||||
public Serializable disassemble(T value, SharedSessionContract session) {
|
||||
return toString( value );
|
||||
}
|
||||
|
||||
@Override
|
||||
public T assemble(Serializable cached, SharedSessionContract session) {
|
||||
return fromString( (CharSequence) cached );
|
||||
}
|
||||
}
|
|
@ -10,6 +10,7 @@ import java.io.Serializable;
|
|||
import java.lang.reflect.ParameterizedType;
|
||||
import java.lang.reflect.Type;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
|
@ -110,6 +111,22 @@ public class JavaTypeRegistry implements JavaTypeBaseline.BaselineTarget, Serial
|
|||
}
|
||||
|
||||
public <J> JavaType<J> resolveDescriptor(Type javaType) {
|
||||
return resolveDescriptor( javaType, (elementJavaType, typeConfiguration) -> {
|
||||
final MutabilityPlan<J> determinedPlan = RegistryHelper.INSTANCE.determineMutabilityPlan(
|
||||
elementJavaType,
|
||||
typeConfiguration
|
||||
);
|
||||
if ( determinedPlan != null ) {
|
||||
return determinedPlan;
|
||||
}
|
||||
|
||||
return MutableMutabilityPlan.INSTANCE;
|
||||
} );
|
||||
}
|
||||
|
||||
public <J> JavaType<J> resolveDescriptor(
|
||||
Type javaType,
|
||||
BiFunction<Type, TypeConfiguration, MutabilityPlan<?>> mutabilityPlanCreator) {
|
||||
return resolveDescriptor(
|
||||
javaType,
|
||||
() -> {
|
||||
|
@ -131,21 +148,10 @@ public class JavaTypeRegistry implements JavaTypeBaseline.BaselineTarget, Serial
|
|||
elementTypeDescriptor = null;
|
||||
}
|
||||
if ( elementTypeDescriptor == null ) {
|
||||
//noinspection unchecked
|
||||
elementTypeDescriptor = RegistryHelper.INSTANCE.createTypeDescriptor(
|
||||
elementJavaType,
|
||||
() -> {
|
||||
final MutabilityPlan<J> determinedPlan = RegistryHelper.INSTANCE.determineMutabilityPlan(
|
||||
elementJavaType,
|
||||
typeConfiguration
|
||||
);
|
||||
if ( determinedPlan != null ) {
|
||||
return determinedPlan;
|
||||
}
|
||||
|
||||
//noinspection unchecked
|
||||
return (MutabilityPlan<J>) MutableMutabilityPlan.INSTANCE;
|
||||
|
||||
},
|
||||
() -> (MutabilityPlan<J>) mutabilityPlanCreator.apply( elementJavaType, typeConfiguration ),
|
||||
typeConfiguration
|
||||
);
|
||||
}
|
||||
|
|
|
@ -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.type.descriptor.java.spi;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import org.hibernate.Incubating;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
import org.hibernate.type.descriptor.java.MutabilityPlan;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
|
||||
import org.hibernate.type.format.FormatMapper;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
@Incubating
|
||||
public class JsonJavaType<T> extends FormatMapperBasedJavaType<T> {
|
||||
|
||||
public JsonJavaType(
|
||||
Type type,
|
||||
MutabilityPlan<T> mutabilityPlan,
|
||||
TypeConfiguration typeConfiguration) {
|
||||
super( type, mutabilityPlan, typeConfiguration );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FormatMapper getFormatMapper(TypeConfiguration typeConfiguration) {
|
||||
return typeConfiguration.getSessionFactory().getFastSessionServices().getJsonFormatMapper();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcType getRecommendedJdbcType(JdbcTypeIndicators context) {
|
||||
return context.getJdbcType( SqlTypes.JSON );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "JsonJavaType(" + getJavaType().getTypeName() + ")";
|
||||
}
|
||||
}
|
|
@ -62,11 +62,7 @@ public class RegistryHelper {
|
|||
return typeConfiguration.createMutabilityPlan( annotation.value() );
|
||||
}
|
||||
|
||||
if ( javaTypeClass.isEnum() ) {
|
||||
return ImmutableMutabilityPlan.instance();
|
||||
}
|
||||
|
||||
if ( javaTypeClass.isPrimitive() ) {
|
||||
if ( javaTypeClass.isEnum() || javaTypeClass.isPrimitive() || ReflectHelper.isRecord( javaTypeClass ) ) {
|
||||
return ImmutableMutabilityPlan.instance();
|
||||
}
|
||||
|
||||
|
|
|
@ -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.type.descriptor.java.spi;
|
||||
|
||||
import java.lang.reflect.Type;
|
||||
|
||||
import org.hibernate.Incubating;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
import org.hibernate.type.descriptor.java.MutabilityPlan;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcType;
|
||||
import org.hibernate.type.descriptor.jdbc.JdbcTypeIndicators;
|
||||
import org.hibernate.type.format.FormatMapper;
|
||||
import org.hibernate.type.spi.TypeConfiguration;
|
||||
|
||||
@Incubating
|
||||
public class XmlJavaType<T> extends FormatMapperBasedJavaType<T> {
|
||||
|
||||
public XmlJavaType(
|
||||
Type type,
|
||||
MutabilityPlan<T> mutabilityPlan,
|
||||
TypeConfiguration typeConfiguration) {
|
||||
super( type, mutabilityPlan, typeConfiguration );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected FormatMapper getFormatMapper(TypeConfiguration typeConfiguration) {
|
||||
return typeConfiguration.getSessionFactory().getFastSessionServices().getXmlFormatMapper();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JdbcType getRecommendedJdbcType(JdbcTypeIndicators context) {
|
||||
return context.getJdbcType( SqlTypes.SQLXML );
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "XmlJavaType(" + getJavaType().getTypeName() + ")";
|
||||
}
|
||||
}
|
|
@ -466,4 +466,11 @@ public class Aggregate {
|
|||
}
|
||||
return Objects.equals( mutableValue, that.mutableValue );
|
||||
}
|
||||
|
||||
@Override
|
||||
public int hashCode() {
|
||||
int result = Objects.hash(theBoolean, theNumericBoolean, theStringBoolean, theString, theInteger, theInt, theDouble, theUrl, theClob, theDate, theTime, theTimestamp, theInstant, theUuid, gender, convertedGender, ordinalGender, theDuration, theLocalDateTime, theLocalDate, theLocalTime, theZonedDateTime, theOffsetDateTime, mutableValue);
|
||||
result = 31 * result + Arrays.hashCode(theBinary);
|
||||
return result;
|
||||
}
|
||||
}
|
|
@ -12,23 +12,24 @@ import org.hibernate.annotations.JdbcTypeCode;
|
|||
import org.hibernate.testing.orm.junit.BaseSessionFactoryFunctionalTest;
|
||||
import org.hibernate.testing.orm.junit.DialectFeatureChecks;
|
||||
import org.hibernate.testing.orm.junit.JiraKey;
|
||||
import org.hibernate.testing.orm.junit.RequiresDialectFeature;
|
||||
|
||||
import org.hibernate.testing.orm.junit.RequiresDialectFeature;
|
||||
import org.hibernate.type.SqlTypes;
|
||||
import org.junit.jupiter.api.AfterEach;
|
||||
import org.junit.jupiter.api.Assertions;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
//@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsJsonAggregate.class)
|
||||
public class JsonAggregateTest extends BaseSessionFactoryFunctionalTest {
|
||||
@RequiresDialectFeature(feature = DialectFeatureChecks.SupportsJsonAggregate.class)
|
||||
public class AggregateTest extends BaseSessionFactoryFunctionalTest {
|
||||
|
||||
@Override
|
||||
protected Class<?>[] getAnnotatedClasses() {
|
||||
return new Class<?>[] {
|
||||
JsonHolder.class
|
||||
JsonHolder.class, XmlHolder.class
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -37,6 +38,7 @@ public class JsonAggregateTest extends BaseSessionFactoryFunctionalTest {
|
|||
inTransaction(
|
||||
session -> {
|
||||
session.persist( new JsonHolder( 1L, Aggregate.createAggregate2() ) );
|
||||
session.persist( new XmlHolder( 1L, Aggregate.createAggregate2() ) );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
@ -46,27 +48,41 @@ public class JsonAggregateTest extends BaseSessionFactoryFunctionalTest {
|
|||
inTransaction(
|
||||
session -> {
|
||||
session.createMutationQuery( "delete from JsonHolder h" ).executeUpdate();
|
||||
session.createMutationQuery( "delete from XmlHolder h" ).executeUpdate();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@JiraKey("HHH-17294")
|
||||
public void testDirtyChecking() {
|
||||
public void testDirtyCheckingJsonAggregate() {
|
||||
sessionFactoryScope().inTransaction(
|
||||
entityManager -> {
|
||||
JsonHolder jsonHolder = entityManager.find( JsonHolder.class, 1L );
|
||||
assertEquals("String 'abc'", jsonHolder.getAggregate().getTheString());
|
||||
jsonHolder.getAggregate().setTheString( "MyString" );
|
||||
JsonHolder aggregateHolder = entityManager.find( JsonHolder.class, 1L );
|
||||
Assertions.assertEquals("String 'abc'", aggregateHolder.getAggregate().getTheString());
|
||||
aggregateHolder.getAggregate().setTheString( "MyString" );
|
||||
entityManager.flush();
|
||||
entityManager.clear();
|
||||
// Fails, when it should pass
|
||||
assertEquals( "String 'MyString'", entityManager.find( JsonHolder.class, 1L ).getAggregate().getTheString() );
|
||||
Assertions.assertEquals( "MyString", entityManager.find( JsonHolder.class, 1L ).getAggregate().getTheString() );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
@Test
|
||||
@JiraKey("HHH-17294")
|
||||
public void testDirtyCheckingXmlAggregate() {
|
||||
sessionFactoryScope().inTransaction(
|
||||
entityManager -> {
|
||||
XmlHolder aggregateHolder = entityManager.find( XmlHolder.class, 1L );
|
||||
Assertions.assertEquals("String 'abc'", aggregateHolder.getAggregate().getTheString());
|
||||
aggregateHolder.getAggregate().setTheString( "MyString" );
|
||||
entityManager.flush();
|
||||
entityManager.clear();
|
||||
Assertions.assertEquals( "MyString", entityManager.find( XmlHolder.class, 1L ).getAggregate().getTheString() );
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
//tag::json-type-mapping-example[]
|
||||
@Entity(name = "JsonHolder")
|
||||
public static class JsonHolder {
|
||||
|
||||
|
@ -75,9 +91,6 @@ public class JsonAggregateTest extends BaseSessionFactoryFunctionalTest {
|
|||
@JdbcTypeCode(SqlTypes.JSON)
|
||||
private Aggregate aggregate;
|
||||
|
||||
//end::json-type-mapping-example[]
|
||||
//Getters and setters are omitted for brevity
|
||||
|
||||
public JsonHolder() {
|
||||
}
|
||||
|
||||
|
@ -101,10 +114,39 @@ public class JsonAggregateTest extends BaseSessionFactoryFunctionalTest {
|
|||
public void setAggregate(Aggregate aggregate) {
|
||||
this.aggregate = aggregate;
|
||||
}
|
||||
|
||||
//tag::json-type-mapping-example[]
|
||||
}
|
||||
|
||||
//end::json-type-mapping-example[]
|
||||
@Entity(name = "XmlHolder")
|
||||
public static class XmlHolder {
|
||||
|
||||
@Id
|
||||
private Long id;
|
||||
@JdbcTypeCode(SqlTypes.SQLXML)
|
||||
private Aggregate aggregate;
|
||||
|
||||
public XmlHolder() {
|
||||
}
|
||||
|
||||
public XmlHolder(Long id, Aggregate aggregate) {
|
||||
this.id = id;
|
||||
this.aggregate = aggregate;
|
||||
}
|
||||
|
||||
public Long getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Long id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public Aggregate getAggregate() {
|
||||
return aggregate;
|
||||
}
|
||||
|
||||
public void setAggregate(Aggregate aggregate) {
|
||||
this.aggregate = aggregate;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue