HHH-15417 Add test for issue

This commit is contained in:
Andrea Boriero 2022-07-25 16:59:42 +02:00 committed by Christian Beikov
parent 4a7c58b983
commit 4674f689aa
1 changed files with 231 additions and 0 deletions

View File

@ -0,0 +1,231 @@
/*
* 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.type;
import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
import org.hibernate.testing.TestForIssue;
import org.hibernate.testing.orm.junit.DomainModel;
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 jakarta.persistence.AttributeConverter;
import jakarta.persistence.CascadeType;
import jakarta.persistence.Column;
import jakarta.persistence.Convert;
import jakarta.persistence.Entity;
import jakarta.persistence.MappedSuperclass;
import jakarta.persistence.OneToMany;
import jakarta.persistence.Table;
@DomainModel(
annotatedClasses = {
UUIDTypeConverterTest.Image.class,
UUIDTypeConverterTest.MarbleBox.class,
UUIDTypeConverterTest.Marble.class
}
)
@SessionFactory
@TestForIssue(jiraKey = "HHH-15417")
public class UUIDTypeConverterTest {
@AfterEach
public void tearDown(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
session.createMutationQuery( "delete from Image" ).executeUpdate();
session.createMutationQuery( "delete from MarbleBox" ).executeUpdate();
session.createMutationQuery( "delete from Marble" ).executeUpdate();
}
);
}
@Test
public void testMerge(SessionFactoryScope scope) {
scope.inTransaction(
session ->
session.merge( new Image() )
);
}
@Test
public void testMergeAndFlushDetached(SessionFactoryScope scope) {
Image image = scope.fromTransaction(
session ->
session.merge( new Image() )
);
scope.inTransaction(
session -> {
image.setThumbId( UUID.randomUUID() );
session.merge( image );
session.flush();
}
);
}
@Test
public void testMergeAndFlush(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
Image image = session.merge( new Image() );
image.setThumbId( UUID.randomUUID() );
session.merge( image );
session.flush();
}
);
}
@Test
public void testMerge2(SessionFactoryScope scope) {
scope.inTransaction(
session -> {
MarbleBox marbleBox = new MarbleBox( List.of( new Marble() ) );
MarbleBox saved = session.merge( marbleBox );
saved.getMarbles().get( 0 ).setMaterialId( UUID.randomUUID() );
session.merge( saved );
}
);
}
@Test
public void testMergeDetached(SessionFactoryScope scope) {
MarbleBox marbleBox = scope.fromTransaction(
session -> {
MarbleBox saved = session.merge( new MarbleBox( List.of( new Marble() ) ) );
return saved;
}
);
scope.inTransaction(
session -> {
marbleBox.getMarbles().get( 0 ).setMaterialId( UUID.randomUUID() );
session.merge( marbleBox );
}
);
}
@MappedSuperclass
public static class Id {
@Column(unique = true, length = 16, nullable = false)
@jakarta.persistence.Id
@Convert(converter = UuidBase64TypeConverter.class)
private UUID id = UUID.randomUUID();
}
@Entity(name = "Image")
@Table(name = "TEST_IMAGE")
public static class Image extends Id {
@Column(unique = true, length = 16, nullable = false)
@Convert(converter = UuidBase64TypeConverter.class)
private UUID thumbId = UUID.randomUUID();
private int position;
public void setThumbId(UUID thumbId) {
this.thumbId = thumbId;
}
public void setPosition(int position) {
this.position = position;
}
}
@Entity(name = "MarbleBox")
public static class MarbleBox extends Id {
@OneToMany(cascade = CascadeType.ALL, orphanRemoval = true)
private List<Marble> marbles = new ArrayList<>();
private String description;
public MarbleBox() {
}
public MarbleBox(List<Marble> marbles) {
this.marbles = marbles;
}
public List<Marble> getMarbles() {
return marbles;
}
}
@Entity(name = "Marble")
public static class Marble extends Id {
@Column(length = 16)
@Convert(converter = UuidBase64TypeConverter.class)
private UUID materialId;
private String color;
public void setMaterialId(UUID materialId) {
this.materialId = materialId;
}
}
public static class UuidBase64TypeConverter implements AttributeConverter<UUID, byte[]> {
@Override
public byte[] convertToDatabaseColumn(UUID attribute) {
return toBytes( attribute );
}
@Override
public UUID convertToEntityAttribute(byte[] dbData) {
return toUuid( dbData );
}
private UUID toUuid(byte[] bytes) {
if ( bytes == null || bytes.length < 16 ) {
return null;
}
long mostSignificantBits = getMostSignificantBits( bytes );
long leastSignificantBits = getLeastSignificantBits( bytes );
return new UUID( mostSignificantBits, leastSignificantBits );
}
private long getMostSignificantBits(byte[] bytes) {
byte[] b = new byte[8];
for ( int i = 0; i < 8; i++ ) {
b[i] = bytes[i];
}
return toLong( b );
}
private long getLeastSignificantBits(byte[] bytes) {
byte[] b = new byte[8];
int j = 0;
for ( int i = 8; i < 16; i++ ) {
b[j++] = bytes[i];
}
return toLong( b );
}
private long toLong(byte[] bytes) {
return ByteBuffer.wrap( bytes ).getLong();
}
private byte[] toBytes(UUID uuid) {
if ( uuid == null ) {
return new byte[] {};
}
ByteBuffer bb = ByteBuffer.wrap( new byte[16] );
bb.putLong( uuid.getMostSignificantBits() );
bb.putLong( uuid.getLeastSignificantBits() );
return bb.array();
}
}
}