Skip to content

Commit 15d4db3

Browse files
committed
HHH-17017 Add test for issue
1 parent 65d4613 commit 15d4db3

File tree

1 file changed

+160
-0
lines changed

1 file changed

+160
-0
lines changed
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
package org.hibernate.orm.test.mapping.enumeratedvalue;
2+
3+
import org.hibernate.annotations.JdbcTypeCode;
4+
import org.hibernate.dialect.H2Dialect;
5+
import org.hibernate.dialect.MariaDBDialect;
6+
import org.hibernate.dialect.MySQLDialect;
7+
import org.hibernate.dialect.OracleDialect;
8+
import org.hibernate.dialect.PostgreSQLDialect;
9+
import org.hibernate.type.SqlTypes;
10+
11+
import org.hibernate.testing.orm.junit.DomainModel;
12+
import org.hibernate.testing.orm.junit.JiraKey;
13+
import org.hibernate.testing.orm.junit.RequiresDialect;
14+
import org.hibernate.testing.orm.junit.SessionFactory;
15+
import org.hibernate.testing.orm.junit.SessionFactoryScope;
16+
import org.junit.jupiter.api.Test;
17+
18+
import jakarta.persistence.Column;
19+
import jakarta.persistence.Entity;
20+
import jakarta.persistence.EntityManagerFactory;
21+
import jakarta.persistence.EnumType;
22+
import jakarta.persistence.Enumerated;
23+
import jakarta.persistence.EnumeratedValue;
24+
import jakarta.persistence.Id;
25+
import jakarta.persistence.Table;
26+
27+
import static org.assertj.core.api.AssertionsForInterfaceTypes.assertThat;
28+
29+
@DomainModel(
30+
annotatedClasses = {
31+
EnumAndColumnDefinitionTest.TestEntity.class
32+
}
33+
)
34+
@SessionFactory
35+
@JiraKey("HHH-17017")
36+
@RequiresDialect( MySQLDialect.class)
37+
@RequiresDialect( MariaDBDialect.class)
38+
@RequiresDialect( H2Dialect.class)
39+
public class EnumAndColumnDefinitionTest {
40+
41+
private EntityManagerFactory entityManagerFactory;
42+
43+
@Test
44+
public void testFind(SessionFactoryScope scope) {
45+
var id = 1L;
46+
var enumValue = MyEnum.A;
47+
var anotherEnumValue = AnotherMyEnum.B;
48+
var anotherEnumValue2 = AnotherMyEnum.A;
49+
scope.inTransaction(
50+
session ->
51+
session.persist( new TestEntity( id, enumValue, anotherEnumValue, anotherEnumValue2 ) )
52+
);
53+
54+
scope.inSession(
55+
session -> {
56+
var selectMyEnum = session.createNativeQuery(
57+
"select my_enum from test_entity",
58+
String.class
59+
)
60+
.getSingleResult();
61+
assertThat( selectMyEnum ).isEqualTo( "0" );
62+
63+
var selectAnotherMyEnum = session.createNativeQuery(
64+
"select another_my_enum from test_entity",
65+
String.class
66+
)
67+
.getSingleResult();
68+
assertThat( selectAnotherMyEnum ).isEqualTo( "1" );
69+
70+
var selectAnotherMyEnum2 = session.createNativeQuery(
71+
"select another_my_enum_2 from test_entity",
72+
String.class
73+
)
74+
.getSingleResult();
75+
// because the attribute is annotated with @JdbcTypeCode(SqlTypes.VARCHAR)
76+
// the enum string value has been saved
77+
assertThat( selectAnotherMyEnum2 ).isEqualTo( "A" );
78+
}
79+
);
80+
81+
scope.inSession(
82+
session -> {
83+
var testEntity = session.find( TestEntity.class, id );
84+
assertThat( testEntity.myEnum ).isEqualTo( enumValue );
85+
assertThat( testEntity.anotherMyEnum ).isEqualTo( anotherEnumValue );
86+
assertThat( testEntity.anotherMyEnum2 ).isEqualTo( anotherEnumValue2 );
87+
}
88+
);
89+
}
90+
91+
public enum MyEnum {
92+
A( 0 ),
93+
B( 1 );
94+
95+
@EnumeratedValue
96+
final int intValue;
97+
98+
MyEnum(int intValue) {
99+
this.intValue = intValue;
100+
}
101+
}
102+
103+
public enum AnotherMyEnum {
104+
A,
105+
B;
106+
}
107+
108+
@Entity(name = "TestEntity")
109+
@Table(name = "test_entity")
110+
public static class TestEntity {
111+
@Id
112+
Long id;
113+
114+
@Enumerated(value = EnumType.ORDINAL)
115+
@Column(name = "my_enum", columnDefinition = "VARCHAR(255) NOT NULL")
116+
/*
117+
annotating the enum with @EnumeratedValue permits to store the ordinal value
118+
and retrieve the correct enum value even when the colum is VARCHAR
119+
*/
120+
MyEnum myEnum;
121+
122+
@Enumerated(value = EnumType.ORDINAL)
123+
@Column(name = "another_my_enum", columnDefinition = "VARCHAR(255) NOT NULL")
124+
/*
125+
Without specifying the JdbcTypeCode Hibernate has no clue
126+
of the column being a VARCHAR and being the enum type an
127+
ordinal, a TinyIntJdbcType is used.
128+
To insert the enum value PreparedStatement#setByte() is used passing value 0
129+
while to retrieve the value PreparedStatement#getByte() is used
130+
and MySQL returns 48 causing the ArrayIndexOutOfBoundsException when trying
131+
to wrap the corresponding enum value.
132+
In previous version it worked probably because instead of TinyIntJdbcType an IntegerJdbcType
133+
has been used.
134+
135+
Using @JdbcTypeCode(SqlTypes.VARCHAR) the enum string value is save
136+
while using @JdbcTypeCode(SqlTypes.INTEGER) the ordinal values is saved
137+
138+
*/
139+
@JdbcTypeCode(SqlTypes.INTEGER)
140+
AnotherMyEnum anotherMyEnum;
141+
142+
@Enumerated(value = EnumType.ORDINAL)
143+
@Column(name = "another_my_enum_2", columnDefinition = "VARCHAR(255) NOT NULL")
144+
@JdbcTypeCode(SqlTypes.VARCHAR)
145+
AnotherMyEnum anotherMyEnum2;
146+
147+
String name;
148+
149+
public TestEntity() {
150+
151+
}
152+
153+
public TestEntity(Long id, MyEnum myEnum, AnotherMyEnum anotherMyEnum, AnotherMyEnum anotherMyEnum2) {
154+
this.id = id;
155+
this.myEnum = myEnum;
156+
this.anotherMyEnum = anotherMyEnum;
157+
this.anotherMyEnum2 = anotherMyEnum2;
158+
}
159+
}
160+
}

0 commit comments

Comments
 (0)