Skip to content

Commit 06f16f9

Browse files
committed
HHH-4396 - Ability to patternize embedded column names
1 parent e0e9c90 commit 06f16f9

File tree

2 files changed

+207
-0
lines changed

2 files changed

+207
-0
lines changed
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
5+
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
6+
*/
7+
package org.hibernate.annotations;
8+
9+
import java.lang.annotation.Retention;
10+
import java.lang.annotation.Target;
11+
12+
import static java.lang.annotation.ElementType.FIELD;
13+
import static java.lang.annotation.ElementType.METHOD;
14+
import static java.lang.annotation.RetentionPolicy.RUNTIME;
15+
16+
/**
17+
* Allows specifying a pattern to be applied to the naming of columns for
18+
* a particular {@linkplain jakarta.persistence.Embedded embedded mapping}.
19+
*
20+
* @author Steve Ebersole
21+
*/
22+
@Target({METHOD, FIELD})
23+
@Retention(RUNTIME)
24+
public @interface EmbeddedColumnNaming {
25+
/**
26+
* The naming pattern. It is expected to contain a single pattern marker ({@code %})
27+
* into which the "raw" column name will be injected. E.g., given a typical {@code Address}
28+
* embeddable and {@code @Embedded @EmbeddedColumnNaming("home_%s)}, we will get columns named
29+
* {@code home_street}, {@code home_city}, etc.
30+
*/
31+
String value();
32+
}
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* License: GNU Lesser General Public License (LGPL), version 2.1 or later.
5+
* See the lgpl.txt file in the root directory or http://www.gnu.org/licenses/lgpl-2.1.html.
6+
*/
7+
package org.hibernate.orm.test.naming;
8+
9+
import org.hibernate.MappingException;
10+
import org.hibernate.SessionFactory;
11+
import org.hibernate.annotations.EmbeddedColumnNaming;
12+
import org.hibernate.boot.Metadata;
13+
import org.hibernate.boot.MetadataSources;
14+
import org.hibernate.engine.spi.SessionFactoryImplementor;
15+
import org.hibernate.mapping.Component;
16+
import org.hibernate.mapping.PersistentClass;
17+
import org.hibernate.mapping.Property;
18+
import org.hibernate.mapping.Value;
19+
import org.hibernate.persister.entity.EntityPersister;
20+
21+
import org.hibernate.testing.orm.junit.DomainModel;
22+
import org.hibernate.testing.orm.junit.DomainModelScope;
23+
import org.hibernate.testing.orm.junit.FailureExpected;
24+
import org.hibernate.testing.orm.junit.Jira;
25+
import org.hibernate.testing.orm.junit.ServiceRegistry;
26+
import org.hibernate.testing.orm.junit.ServiceRegistryScope;
27+
import org.junit.jupiter.api.Test;
28+
29+
import jakarta.persistence.Embeddable;
30+
import jakarta.persistence.Embedded;
31+
import jakarta.persistence.Entity;
32+
import jakarta.persistence.Id;
33+
import jakarta.persistence.Table;
34+
35+
import static org.assertj.core.api.Assertions.assertThat;
36+
import static org.assertj.core.api.Assertions.fail;
37+
38+
/**
39+
* @author Steve Ebersole
40+
*/
41+
@SuppressWarnings("JUnitMalformedDeclaration")
42+
@Jira( "https://hibernate.atlassian.net/browse/HHH-4396" )
43+
public class EmbeddedColumnNamingTests {
44+
@Test
45+
@ServiceRegistry
46+
@DomainModel(annotatedClasses = {Address.class,BadPerson.class})
47+
void testNoNamingPattern(DomainModelScope domainModelScope) {
48+
final PersistentClass entityBinding = domainModelScope.getEntityBinding( BadPerson.class );
49+
try {
50+
entityBinding.validate( domainModelScope.getDomainModel() );
51+
fail( "Expecting an exception" );
52+
}
53+
catch (MappingException expected) {
54+
// expected outcome
55+
assertThat( expected.getMessage() ).contains( "when mapping multiple properties to the same column" );
56+
}
57+
}
58+
59+
@Test
60+
@ServiceRegistry
61+
@DomainModel(annotatedClasses = {Address.class,GoodPerson.class})
62+
@FailureExpected( jiraKey = "HHH-4396", reason = "@EmbeddedColumnNaming support is not implemented yet" )
63+
void testGoodNamingPattern(DomainModelScope domainModelScope) {
64+
final PersistentClass entityBinding = domainModelScope.getEntityBinding( GoodPerson.class );
65+
entityBinding.validate( domainModelScope.getDomainModel() );
66+
67+
final Property homeAddress = entityBinding.getProperty( "homeAddress" );
68+
final Component homeAddressValue = (Component) homeAddress.getValue();
69+
70+
final Property workAddress = entityBinding.getProperty( "workAddress" );
71+
final Component workAddressValue = (Component) workAddress.getValue();
72+
}
73+
74+
@Test
75+
@ServiceRegistry
76+
@DomainModel(annotatedClasses = {Address.class,BadPatternPerson1.class})
77+
@FailureExpected( jiraKey = "HHH-4396", reason = "@EmbeddedColumnNaming support is not implemented yet" )
78+
void testBadNamingPattern1(DomainModelScope domainModelScope) {
79+
final PersistentClass entityBinding = domainModelScope.getEntityBinding( BadPatternPerson1.class );
80+
try {
81+
entityBinding.validate( domainModelScope.getDomainModel() );
82+
fail( "Expecting an exception" );
83+
}
84+
catch (MappingException expected) {
85+
// expected outcome
86+
assertThat( expected.getMessage() ).contains( "bad embedded naming pattern" );
87+
}
88+
}
89+
90+
@Test
91+
@ServiceRegistry
92+
@DomainModel(annotatedClasses = {Address.class,BadPatternPerson2.class})
93+
@FailureExpected( jiraKey = "HHH-4396", reason = "@EmbeddedColumnNaming support is not implemented yet" )
94+
void testBadNamingPattern2(DomainModelScope domainModelScope) {
95+
final PersistentClass entityBinding = domainModelScope.getEntityBinding( BadPatternPerson2.class );
96+
try {
97+
entityBinding.validate( domainModelScope.getDomainModel() );
98+
fail( "Expecting an exception" );
99+
}
100+
catch (MappingException expected) {
101+
// expected outcome
102+
assertThat( expected.getMessage() ).contains( "bad embedded naming pattern" );
103+
}
104+
}
105+
106+
@Embeddable
107+
public static class Address {
108+
private String street;
109+
private String city;
110+
private String state;
111+
private String zip;
112+
}
113+
114+
@Entity(name="BadPerson")
115+
@Table(name="bad_person")
116+
public static class BadPerson {
117+
@Id
118+
private Integer id;
119+
private String name;
120+
121+
@Embedded
122+
private Address homeAddress;
123+
124+
@Embedded
125+
private Address workAddress;
126+
}
127+
128+
@Entity(name="GoodPerson")
129+
@Table(name="good_person")
130+
public static class GoodPerson {
131+
@Id
132+
private Integer id;
133+
private String name;
134+
135+
@Embedded
136+
@EmbeddedColumnNaming("home_%s")
137+
private Address homeAddress;
138+
139+
@Embedded
140+
@EmbeddedColumnNaming("work_%s")
141+
private Address workAddress;
142+
}
143+
144+
@Entity(name="BadPatternPerson1")
145+
@Table(name="bad_pattern_person_1")
146+
public static class BadPatternPerson1 {
147+
@Id
148+
private Integer id;
149+
private String name;
150+
151+
@Embedded
152+
@EmbeddedColumnNaming("%s_home_%s")
153+
private Address homeAddress;
154+
155+
@Embedded
156+
@EmbeddedColumnNaming("work_%s")
157+
private Address workAddress;
158+
}
159+
160+
@Entity(name="BadPatternPerson2")
161+
@Table(name="bad_pattern_person_2")
162+
public static class BadPatternPerson2 {
163+
@Id
164+
private Integer id;
165+
private String name;
166+
167+
@Embedded
168+
@EmbeddedColumnNaming("home")
169+
private Address homeAddress;
170+
171+
@Embedded
172+
@EmbeddedColumnNaming("work_%s")
173+
private Address workAddress;
174+
}
175+
}

0 commit comments

Comments
 (0)