Skip to content

Commit 50a4444

Browse files
jrenaatsebersole
authored andcommitted
HHH-18198 -
Removed org.hibernate.annotations.Target Created new org.hibernate.annotations.TargetEmbeddable Signed-off-by: Jan Schatteman <[email protected]>
1 parent 6edd3f1 commit 50a4444

File tree

17 files changed

+241
-102
lines changed

17 files changed

+241
-102
lines changed

documentation/src/main/asciidoc/userguide/chapters/domain/embeddables.adoc

+24-19
Original file line numberDiff line numberDiff line change
@@ -300,52 +300,49 @@ Embeddable types that are used as collection entries, map keys or entity type id
300300
====
301301

302302
[[embeddable-Target]]
303-
==== `@Target` mapping
303+
==== `@TargetEmbeddable` mapping
304304

305-
The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/Target.html[`@Target`] annotation is used to specify the implementation class of a given association that is mapped via an interface.
306-
The
307-
{jpaJavadocUrlPrefix}ManyToOne.html[`@ManyToOne`],
308-
{jpaJavadocUrlPrefix}OneToOne.html[`@OneToOne`],
309-
{jpaJavadocUrlPrefix}OneToMany.html[`@OneToMany`], and
310-
{jpaJavadocUrlPrefix}ManyToMany.html[`@ManyToMany`]
311-
feature a {jpaJavadocUrlPrefix}ManyToOne.html#targetEntity--[`targetEntity`] attribute to specify the actual class of the entity association when an interface is used for the mapping.
305+
The https://docs.jboss.org/hibernate/orm/{majorMinorVersion}/javadocs/org/hibernate/annotations/TargetEmbeddable.html[`@TargetEmbeddable`] annotation is used to specify the implementation class of an embeddable-valued mapping when the declared type is a non-concrete type (interface, etc.).
312306

313-
The {jpaJavadocUrlPrefix}ElementCollection.html[`@ElementCollection`] association has a {jpaJavadocUrlPrefix}ElementCollection.html#targetClass--[`targetClass`] attribute for the same purpose.
307+
[NOTE]
308+
====
309+
An "embeddable-valued mapping" may be an `@EmbeddedId`, `@Embedded` or `@ElementCollection`.
310+
====
314311

315-
However, for simple embeddable types, there is no such construct and so you need to use the Hibernate-specific `@Target` annotation instead.
312+
`@TargetEmbeddable` may be specified on the embeddable-valued mapping, as shown in <<embeddable-Target-example>>, or it may be defined on the interface/class used as the declared type, illustrated in <<embeddable-Target-example2>>.
316313

317314
[[embeddable-Target-example]]
318-
.`@Target` mapping usage
315+
.Embeddable-valued mapping usage
319316
====
320317
[source, java, indent=0]
321318
----
322-
include::{example-dir-emeddable}/TargetTest.java[tags=embeddable-Target-example]
319+
include::{example-dir-emeddable}/TargetEmbeddableOnEmbeddedTest.java[tags=embeddable-Target-example]
323320
----
324321
====
325322

326323
The `coordinates` embeddable type is mapped as the `Coordinates` interface.
327324
However, Hibernate needs to know the actual implementation type, which is `GPS` in this case,
328-
hence the `@Target` annotation is used to provide this information.
325+
hence the `@TargetEmbeddable` annotation is used to provide this information.
329326

330327
Assuming we have persisted the following `City` entity:
331328

332329
[[embeddable-Target-persist-example]]
333-
.`@Target` persist example
330+
.`@TargetEmbeddable` persist example
334331
====
335332
[source, java, indent=0]
336333
----
337-
include::{example-dir-emeddable}/TargetTest.java[tags=embeddable-Target-persist-example]
334+
include::{example-dir-emeddable}/TargetEmbeddableOnEmbeddedTest.java[tags=embeddable-Target-persist-example]
338335
----
339336
====
340337

341-
When fetching the `City` entity, the `coordinates` property is mapped by the `@Target` expression:
338+
When fetching the `City` entity, the `coordinates` property is mapped by the `@TargetEmbeddable` expression:
342339

343340
[[embeddable-Target-fetching-example]]
344-
.`@Target` fetching example
341+
.`@TargetEmbeddable` fetching example
345342
====
346343
[source, java, indent=0]
347344
----
348-
include::{example-dir-emeddable}/TargetTest.java[tags=embeddable-Target-fetching-example]
345+
include::{example-dir-emeddable}/TargetEmbeddableOnEmbeddedTest.java[tags=embeddable-Target-fetching-example]
349346
----
350347
351348
[source, SQL, indent=0]
@@ -354,7 +351,15 @@ include::{extrasdir}/embeddable/embeddable-Target-fetching-example.sql[]
354351
----
355352
====
356353

357-
Therefore, the `@Target` annotation is used to define a custom join association between the parent-child association.
354+
[[embeddable-Target-example2]]
355+
.Interface mapping usage
356+
====
357+
[source, java, indent=0]
358+
----
359+
include::{example-dir-emeddable}/TargetEmbeddableOnInterfaceTest.java[tags=embeddable-Target-example2]
360+
----
361+
====
362+
358363

359364
[[embeddable-Parent]]
360365
==== `@Parent` mapping

hibernate-core/src/main/java/org/hibernate/annotations/Target.java

-32
This file was deleted.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* SPDX-License-Identifier: Apache-2.0
3+
* Copyright Red Hat Inc. and Hibernate Authors
4+
*/
5+
package org.hibernate.annotations;
6+
7+
import java.lang.annotation.Retention;
8+
9+
import static java.lang.annotation.ElementType.FIELD;
10+
import static java.lang.annotation.ElementType.METHOD;
11+
import static java.lang.annotation.ElementType.TYPE;
12+
import static java.lang.annotation.RetentionPolicy.RUNTIME;
13+
14+
/**
15+
* Specifies the target type for a {@link jakarta.persistence.Embedded} entity property.
16+
* <p>
17+
* It's intended to be used exclusively in conjunction with @Embedded.
18+
*/
19+
@java.lang.annotation.Target({FIELD, METHOD, TYPE})
20+
@Retention(RUNTIME)
21+
public @interface TargetEmbeddable {
22+
/**
23+
* The target type for a {@link jakarta.persistence.Embedded} entity property
24+
*/
25+
Class<?> value();
26+
}

hibernate-core/src/main/java/org/hibernate/boot/model/internal/BasicValueBinder.java

-8
Original file line numberDiff line numberDiff line change
@@ -1101,14 +1101,6 @@ private void normalSupplementalDetails(MemberDetails attribute) {
11011101
}
11021102
}
11031103

1104-
final var targetAnn = attribute.locateAnnotationUsage( Target.class, getSourceModelContext() );
1105-
if ( targetAnn != null ) {
1106-
DEPRECATION_LOGGER.deprecatedAnnotation( Target.class, attribute.getName() );
1107-
return (BasicJavaType<?>)
1108-
typeConfiguration.getJavaTypeRegistry()
1109-
.getDescriptor( targetAnn.value() );
1110-
}
1111-
11121104
return null;
11131105
};
11141106

hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyContainer.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
import org.hibernate.annotations.JavaType;
1717
import org.hibernate.annotations.JdbcTypeCode;
1818
import org.hibernate.annotations.ManyToAny;
19-
import org.hibernate.annotations.Target;
19+
import org.hibernate.annotations.TargetEmbeddable;
2020
import org.hibernate.annotations.Type;
2121
import org.hibernate.boot.MappingException;
2222
import org.hibernate.boot.jaxb.Origin;
@@ -326,7 +326,7 @@ private AccessType determineLocalClassDefinedAccessStrategy() {
326326
}
327327

328328
private static boolean discoverTypeWithoutReflection(ClassDetails classDetails, MemberDetails memberDetails) {
329-
if ( memberDetails.hasDirectAnnotationUsage( Target.class ) ) {
329+
if ( memberDetails.hasDirectAnnotationUsage( TargetEmbeddable.class ) ) {
330330
return true;
331331
}
332332

hibernate-core/src/main/java/org/hibernate/boot/model/internal/PropertyInferredData.java

+33-16
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@
55
package org.hibernate.boot.model.internal;
66

77
import jakarta.persistence.Access;
8+
import jakarta.persistence.Embedded;
89
import org.hibernate.MappingException;
9-
import org.hibernate.annotations.Target;
10+
import org.hibernate.annotations.TargetEmbeddable;
1011
import org.hibernate.boot.models.internal.ModelsHelper;
1112
import org.hibernate.boot.spi.AccessType;
1213
import org.hibernate.boot.spi.MetadataBuildingContext;
@@ -18,6 +19,7 @@
1819
import org.hibernate.models.spi.MemberDetails;
1920
import org.hibernate.models.spi.ModelsContext;
2021
import org.hibernate.models.spi.TypeDetails;
22+
import org.hibernate.models.spi.TypeDetails.Kind;
2123
import org.hibernate.models.spi.TypeVariableScope;
2224

2325
/**
@@ -88,23 +90,38 @@ public TypeDetails getPropertyType() throws MappingException {
8890
sourceModelContext.getClassDetailsRegistry(),
8991
() -> new DynamicClassDetails( targetName, sourceModelContext )
9092
);
91-
return new ClassTypeDetailsImpl( classDetails, TypeDetails.Kind.CLASS );
93+
return new ClassTypeDetailsImpl( classDetails, Kind.CLASS );
9294
}
9395

94-
final Target legacyTargetAnnotation = propertyMember.getDirectAnnotationUsage( Target.class );
95-
if ( legacyTargetAnnotation != null ) {
96-
return resolveLegacyTargetAnnotation( legacyTargetAnnotation, sourceModelContext );
96+
final TargetEmbeddable targetEmbeddable = getTargetEmbeddableAnnotation(propertyMember);
97+
if ( targetEmbeddable != null ) {
98+
return resolveTargetEmbeddableAnnotation( targetEmbeddable, sourceModelContext );
9799
}
98100

99101
return propertyMember.resolveRelativeType( ownerType );
100102
}
101103

102-
private static ClassTypeDetailsImpl resolveLegacyTargetAnnotation(
103-
Target legacyTargetAnnotation,
104+
private TargetEmbeddable getTargetEmbeddableAnnotation(MemberDetails memberDetails) {
105+
TargetEmbeddable targetEmbeddable = memberDetails.getDirectAnnotationUsage( TargetEmbeddable.class );
106+
if ( targetEmbeddable != null ) {
107+
if (!memberDetails.hasDirectAnnotationUsage(Embedded.class) ) {
108+
// If set on an attribute, it should be an @Embedded
109+
throw new MappingException( "The @TargetEmbeddable annotation can only be set on an element marked with @Embedded" );
110+
}
111+
}
112+
else {
113+
// Set on an interface
114+
targetEmbeddable = memberDetails.getAssociatedType().determineRawClass().getDirectAnnotationUsage( TargetEmbeddable.class );
115+
}
116+
return targetEmbeddable;
117+
}
118+
119+
private static ClassTypeDetailsImpl resolveTargetEmbeddableAnnotation(
120+
TargetEmbeddable targetEmbeddable,
104121
ModelsContext sourceModelContext) {
105122
final ClassDetailsRegistry classDetailsRegistry = sourceModelContext.getClassDetailsRegistry();
106-
final ClassDetails targetClassDetails = classDetailsRegistry.resolveClassDetails( legacyTargetAnnotation.value().getName() );
107-
return new ClassTypeDetailsImpl( targetClassDetails, TypeDetails.Kind.CLASS );
123+
final ClassDetails targetClassDetails = classDetailsRegistry.resolveClassDetails( targetEmbeddable.value().getName() );
124+
return new ClassTypeDetailsImpl( targetClassDetails, Kind.CLASS );
108125
}
109126

110127
@Override
@@ -118,12 +135,12 @@ public TypeDetails getClassOrElementType() throws MappingException {
118135
modelsContext.getClassDetailsRegistry(),
119136
() -> new DynamicClassDetails( targetName, modelsContext )
120137
);
121-
return new ClassTypeDetailsImpl( classDetails, TypeDetails.Kind.CLASS );
138+
return new ClassTypeDetailsImpl( classDetails, Kind.CLASS );
122139
}
123140

124-
final Target legacyTargetAnnotation = propertyMember.getDirectAnnotationUsage( Target.class );
125-
if ( legacyTargetAnnotation != null ) {
126-
return resolveLegacyTargetAnnotation( legacyTargetAnnotation, modelsContext );
141+
final TargetEmbeddable targetEmbeddable = getTargetEmbeddableAnnotation(propertyMember);
142+
if ( targetEmbeddable != null ) {
143+
return resolveTargetEmbeddableAnnotation( targetEmbeddable, modelsContext );
127144
}
128145

129146
return propertyMember.resolveRelativeAssociatedType( ownerType );
@@ -136,9 +153,9 @@ public ClassDetails getClassOrPluralElement() throws MappingException {
136153
return buildingContext.getMetadataCollector().getClassDetailsRegistry().getClassDetails( xmlTarget.value() );
137154
}
138155

139-
final Target legacyTarget = propertyMember.getDirectAnnotationUsage( Target.class );
140-
if ( legacyTarget != null ) {
141-
final String targetName = legacyTarget.value().getName();
156+
final TargetEmbeddable targetEmbeddable = getTargetEmbeddableAnnotation(propertyMember);
157+
if ( targetEmbeddable != null ) {
158+
final String targetName = targetEmbeddable.value().getName();
142159
return buildingContext.getMetadataCollector().getClassDetailsRegistry().getClassDetails( targetName );
143160
}
144161

hibernate-core/src/main/java/org/hibernate/boot/models/HibernateAnnotations.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -599,9 +599,9 @@ public interface HibernateAnnotations {
599599
Synchronize.class,
600600
SynchronizeAnnotation.class
601601
);
602-
OrmAnnotationDescriptor<Target,TargetLegacyAnnotation> TARGET_LEGACY = new OrmAnnotationDescriptor<>(
603-
Target.class,
604-
TargetLegacyAnnotation.class
602+
OrmAnnotationDescriptor<TargetEmbeddable,TargetEmbeddableAnnotation> TARGET_EMBEDDABLE = new OrmAnnotationDescriptor<>(
603+
TargetEmbeddable.class,
604+
TargetEmbeddableAnnotation.class
605605
);
606606
SpecializedAnnotationDescriptor<TenantId,TenantIdAnnotation> TENANT_ID = new SpecializedAnnotationDescriptor<>(
607607
TenantId.class,

hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/TargetLegacyAnnotation.java renamed to hibernate-core/src/main/java/org/hibernate/boot/models/annotations/internal/TargetEmbeddableAnnotation.java

+8-8
Original file line numberDiff line numberDiff line change
@@ -4,40 +4,40 @@
44
*/
55
package org.hibernate.boot.models.annotations.internal;
66

7+
import org.hibernate.annotations.TargetEmbeddable;
8+
import org.hibernate.models.spi.ModelsContext;
9+
710
import java.lang.annotation.Annotation;
811
import java.util.Map;
912

10-
import org.hibernate.annotations.Target;
11-
import org.hibernate.models.spi.ModelsContext;
12-
1313
@SuppressWarnings({ "ClassExplicitlyAnnotation", "unused" })
1414
@jakarta.annotation.Generated("org.hibernate.orm.build.annotations.ClassGeneratorProcessor")
15-
public class TargetLegacyAnnotation implements Target {
15+
public class TargetEmbeddableAnnotation implements TargetEmbeddable {
1616
private Class<?> value;
1717

1818
/**
1919
* Used in creating dynamic annotation instances (e.g. from XML)
2020
*/
21-
public TargetLegacyAnnotation(ModelsContext modelContext) {
21+
public TargetEmbeddableAnnotation(ModelsContext modelContext) {
2222
}
2323

2424
/**
2525
* Used in creating annotation instances from JDK variant
2626
*/
27-
public TargetLegacyAnnotation(Target annotation, ModelsContext modelContext) {
27+
public TargetEmbeddableAnnotation(TargetEmbeddable annotation, ModelsContext modelContext) {
2828
this.value = annotation.value();
2929
}
3030

3131
/**
3232
* Used in creating annotation instances from Jandex variant
3333
*/
34-
public TargetLegacyAnnotation(Map<String, Object> attributeValues, ModelsContext modelContext) {
34+
public TargetEmbeddableAnnotation(Map<String, Object> attributeValues, ModelsContext modelContext) {
3535
this.value = (Class<?>) attributeValues.get( "value" );
3636
}
3737

3838
@Override
3939
public Class<? extends Annotation> annotationType() {
40-
return Target.class;
40+
return TargetEmbeddable.class;
4141
}
4242

4343
@Override

hibernate-core/src/test/java/org/hibernate/orm/test/annotations/target/LuggageImpl.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
import jakarta.persistence.GeneratedValue;
99
import jakarta.persistence.Id;
1010

11-
import org.hibernate.annotations.Target;
11+
import org.hibernate.annotations.TargetEmbeddable;
1212

1313
/**
1414
* @author Emmanuel Bernard
@@ -21,7 +21,7 @@ public class LuggageImpl implements Luggage {
2121
private Owner owner;
2222

2323
@Embedded
24-
@Target(OwnerImpl.class)
24+
@TargetEmbeddable(OwnerImpl.class)
2525
public Owner getOwner() {
2626
return owner;
2727
}

hibernate-core/src/test/java/org/hibernate/orm/test/mapping/basic/ParentTest.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
import jakarta.persistence.Id;
1212

1313
import org.hibernate.annotations.Parent;
14-
import org.hibernate.annotations.Target;
14+
import org.hibernate.annotations.TargetEmbeddable;
1515
import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase;
1616

1717
import org.junit.Test;
@@ -110,7 +110,7 @@ public static class City {
110110
private String name;
111111

112112
@Embedded
113-
@Target(GPS.class)
113+
@TargetEmbeddable(GPS.class)
114114
private GPS coordinates;
115115

116116
//Getters and setters omitted for brevity

hibernate-core/src/test/java/org/hibernate/orm/test/mapping/embeddable/ParentTest.java

+2-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@
1111
import jakarta.persistence.Id;
1212

1313
import org.hibernate.annotations.Parent;
14-
import org.hibernate.annotations.Target;
14+
import org.hibernate.annotations.TargetEmbeddable;
1515
import org.hibernate.orm.test.jpa.BaseEntityManagerFunctionalTestCase;
1616

1717
import org.junit.Test;
@@ -110,7 +110,7 @@ public static class City {
110110
private String name;
111111

112112
@Embedded
113-
@Target(GPS.class)
113+
@TargetEmbeddable(GPS.class)
114114
private GPS coordinates;
115115

116116
//Getters and setters omitted for brevity

0 commit comments

Comments
 (0)