Skip to content

Commit 9a088f8

Browse files
committed
#73 - Add MutableAnnotationTarget#replace
1 parent b69d810 commit 9a088f8

File tree

3 files changed

+133
-0
lines changed

3 files changed

+133
-0
lines changed

src/main/java/org/hibernate/models/internal/AnnotationTargetSupport.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
import org.hibernate.models.spi.AnnotationDescriptorRegistry;
1818
import org.hibernate.models.spi.AnnotationUsage;
1919
import org.hibernate.models.spi.MutableAnnotationTarget;
20+
import org.hibernate.models.spi.MutableAnnotationUsage;
2021
import org.hibernate.models.spi.SourceModelBuildingContext;
2122

2223
/**
@@ -150,4 +151,20 @@ default <X extends Annotation> AnnotationUsage<X> getNamedAnnotationUsage(
150151
attributeToMatch
151152
);
152153
}
154+
155+
@Override
156+
default <S extends Annotation, P extends Annotation> MutableAnnotationUsage<P> replaceAnnotationUsage(
157+
AnnotationDescriptor<S> repeatableType,
158+
AnnotationDescriptor<P> containerType,
159+
SourceModelBuildingContext buildingContext) {
160+
assert repeatableType.isRepeatable();
161+
assert repeatableType.getRepeatableContainer() == containerType;
162+
163+
final MutableAnnotationUsage<P> containerTypeUsage = containerType.createUsage( buildingContext );
164+
// effectively overwrites any previous registrations
165+
getUsageMap().put( containerType.getAnnotationType(), containerTypeUsage );
166+
getUsageMap().put( repeatableType.getAnnotationType(), null );
167+
168+
return containerTypeUsage;
169+
}
153170
}

src/main/java/org/hibernate/models/spi/MutableAnnotationTarget.java

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,42 @@ default <A extends Annotation> MutableAnnotationUsage<A> applyAnnotationUsage(
4242
return usage;
4343
}
4444

45+
/**
46+
* Creates and replaces (if any) an existing usage of the given annotation.
47+
* <p/>
48+
* For repeatable annotations, use
49+
* Applies a usage of the given {@code annotationType} to this target. Will return
50+
* an existing usage, if one, or create a new usage.
51+
*
52+
* @apiNote Generally replacement is used with XML processing and, again generally,
53+
* only for repeatable annotations using
54+
* {@linkplain #replaceAnnotationUsage(AnnotationDescriptor, AnnotationDescriptor, SourceModelBuildingContext)}
55+
*
56+
* @see #replaceAnnotationUsage(AnnotationDescriptor, AnnotationDescriptor, SourceModelBuildingContext)
57+
*/
58+
default <A extends Annotation> MutableAnnotationUsage<A> replaceAnnotationUsage(
59+
AnnotationDescriptor<A> annotationType,
60+
SourceModelBuildingContext buildingContext) {
61+
final MutableAnnotationUsage<A> usage = annotationType.createUsage( buildingContext );
62+
// effectively overwrites any previous registration
63+
addAnnotationUsage( usage );
64+
return usage;
65+
}
66+
67+
/**
68+
* Creates and replaces (if any) an existing usage of the given annotation.
69+
* <p/>
70+
* For repeatable annotations, use
71+
* Applies a usage of the given {@code annotationType} to this target. Will return
72+
* an existing usage, if one, or create a new usage.
73+
*
74+
* @see #replaceAnnotationUsage(AnnotationDescriptor, SourceModelBuildingContext)
75+
*/
76+
<S extends Annotation, P extends Annotation> MutableAnnotationUsage<P> replaceAnnotationUsage(
77+
AnnotationDescriptor<S> repeatableType,
78+
AnnotationDescriptor<P> containerType,
79+
SourceModelBuildingContext buildingContext);
80+
4581
@Override
4682
MutableClassDetails asClassDetails();
4783

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
/*
2+
* Hibernate, Relational Persistence for Idiomatic Java
3+
*
4+
* SPDX-License-Identifier: Apache-2.0
5+
* Copyright: Red Hat Inc. and Hibernate Authors
6+
*/
7+
8+
package org.hibernate.models.annotations;
9+
10+
import java.util.ArrayList;
11+
import java.util.List;
12+
13+
import org.hibernate.models.internal.SourceModelBuildingContextImpl;
14+
import org.hibernate.models.orm.JpaAnnotations;
15+
import org.hibernate.models.spi.AnnotationDescriptor;
16+
import org.hibernate.models.spi.AnnotationDescriptorRegistry;
17+
import org.hibernate.models.spi.AnnotationUsage;
18+
import org.hibernate.models.spi.ClassDetails;
19+
import org.hibernate.models.spi.MutableAnnotationUsage;
20+
import org.hibernate.models.spi.MutableClassDetails;
21+
22+
import org.junit.jupiter.api.Test;
23+
24+
import org.jboss.jandex.Index;
25+
26+
import jakarta.persistence.SecondaryTable;
27+
import jakarta.persistence.SecondaryTables;
28+
29+
import static org.assertj.core.api.Assertions.assertThat;
30+
import static org.hibernate.models.SourceModelTestHelper.buildJandexIndex;
31+
import static org.hibernate.models.SourceModelTestHelper.createBuildingContext;
32+
33+
/**
34+
* @author Steve Ebersole
35+
*/
36+
public class AnnotationReplacementTests {
37+
@Test
38+
void testBasicReplacementWithJandex() {
39+
basicReplacementChecks( buildJandexIndex( SimpleEntity.class ) );
40+
}
41+
42+
@Test
43+
void testBasicReplacementWithoutJandex() {
44+
basicReplacementChecks( null );
45+
}
46+
47+
void basicReplacementChecks(Index index) {
48+
final SourceModelBuildingContextImpl buildingContext = createBuildingContext( index, SimpleEntity.class );
49+
50+
final MutableClassDetails classDetails = (MutableClassDetails) buildingContext.getClassDetailsRegistry().getClassDetails( SimpleEntity.class.getName() );
51+
assertThat( classDetails.hasAnnotationUsage( SecondaryTable.class ) ).isTrue();
52+
assertThat( classDetails.hasAnnotationUsage( SecondaryTables.class ) ).isFalse();
53+
54+
final MutableAnnotationUsage<SecondaryTables> replacement = classDetails.replaceAnnotationUsage(
55+
JpaAnnotations.SECONDARY_TABLE,
56+
JpaAnnotations.SECONDARY_TABLES,
57+
buildingContext
58+
);
59+
60+
assertThat( classDetails.hasAnnotationUsage( SecondaryTable.class ) ).isTrue();
61+
assertThat( classDetails.hasAnnotationUsage( SecondaryTables.class ) ).isTrue();
62+
63+
List<MutableAnnotationUsage<SecondaryTable>> valueList = replacement.getList( "value" );
64+
// because it is required
65+
assertThat( valueList ).isNull();
66+
valueList = new ArrayList<>();
67+
replacement.setAttributeValue( "value", valueList );
68+
69+
final MutableAnnotationUsage<SecondaryTable> fromXml = JpaAnnotations.SECONDARY_TABLE.createUsage( buildingContext );
70+
valueList.add( fromXml );
71+
fromXml.setAttributeValue( "name", "from_xml" );
72+
73+
final AnnotationUsage<SecondaryTable> annotationUsage = classDetails.getAnnotationUsage( SecondaryTable.class );
74+
assertThat( annotationUsage.getString( "name" ) ).isEqualTo( "from_xml" );
75+
76+
final AnnotationUsage<SecondaryTables> annotationUsage1 = classDetails.getAnnotationUsage( SecondaryTables.class );
77+
assertThat( annotationUsage1.getList( "value" ) ).isSameAs( valueList );
78+
}
79+
80+
}

0 commit comments

Comments
 (0)