Skip to content

Commit 35466f5

Browse files
committed
Graphpocalypse: one more refactor for extra typesafety
1 parent 3d60bfa commit 35466f5

File tree

4 files changed

+170
-52
lines changed

4 files changed

+170
-52
lines changed

hibernate-core/src/main/java/org/hibernate/graph/internal/AttributeNodeImpl.java

Lines changed: 160 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
package org.hibernate.graph.internal;
66

77
import jakarta.persistence.metamodel.Attribute;
8+
import org.hibernate.AssertionFailure;
89
import org.hibernate.graph.CannotContainSubGraphException;
910
import org.hibernate.graph.spi.AttributeNodeImplementor;
1011
import org.hibernate.graph.spi.SubGraphImplementor;
@@ -14,6 +15,7 @@
1415
import org.hibernate.metamodel.model.domain.PersistentAttribute;
1516
import org.hibernate.metamodel.model.domain.PluralPersistentAttribute;
1617
import org.hibernate.metamodel.model.domain.SimpleDomainType;
18+
import org.hibernate.metamodel.model.domain.SingularPersistentAttribute;
1719

1820
import java.util.HashMap;
1921
import java.util.Map;
@@ -32,38 +34,64 @@
3234
* @author Steve Ebersole
3335
* @author Gavin King
3436
*/
35-
public class AttributeNodeImpl<J, E, K>
37+
public abstract class AttributeNodeImpl<J, E, K>
3638
extends AbstractGraphNode<J>
3739
implements AttributeNodeImplementor<J, E, K> {
38-
private final PersistentAttribute<?, J> attribute;
39-
private final DomainType<E> valueGraphType;
40-
private final SimpleDomainType<K> keyGraphType;
4140

42-
private SubGraphImplementor<E> valueSubgraph;
43-
private SubGraphImplementor<K> keySubgraph;
41+
protected final PersistentAttribute<?, J> attribute;
42+
protected final DomainType<E> valueGraphType;
43+
protected final SimpleDomainType<K> keyGraphType;
4444

45-
static <X,J> AttributeNodeImpl<J,?,?> create(PersistentAttribute<X, J> attribute, boolean mutable) {
46-
return new AttributeNodeImpl<>( attribute, mutable, attribute.getValueGraphType(), attribute.getKeyGraphType() );
45+
protected SubGraphImplementor<E> valueSubgraph;
46+
protected SubGraphImplementor<K> keySubgraph;
47+
48+
static <J> AttributeNodeImpl<J,?,?> create(
49+
PersistentAttribute<?, J> attribute, boolean mutable) {
50+
if ( attribute instanceof PluralPersistentAttribute<?, J, ?> pluralAttribute ) {
51+
return create( pluralAttribute, mutable );
52+
}
53+
else if ( attribute instanceof SingularPersistentAttribute<?, J> singularAttribute ) {
54+
return new SingularAttributeNodeImpl<>( singularAttribute, mutable,
55+
singularAttribute.getValueGraphType() );
56+
}
57+
else {
58+
throw new AssertionFailure( "Unrecognized attribute type: " + attribute );
59+
}
60+
}
61+
62+
static <J,E> AttributeNodeImpl<J,E,?> create(
63+
PluralPersistentAttribute<?, J, E> attribute, boolean mutable) {
64+
if ( attribute instanceof MapPersistentAttribute<?, ?, ?> mapAttribute ) {
65+
return create( attribute, mapAttribute, mutable );
66+
}
67+
else {
68+
return new PluralAttributeNodeImpl<>( attribute, mutable,
69+
attribute.getValueGraphType() );
70+
}
4771
}
4872

49-
static <X,J,E> AttributeNodeImpl<J,E,?> create(PluralPersistentAttribute<X, J, E> attribute, boolean mutable) {
50-
return new AttributeNodeImpl<>( attribute, mutable, attribute.getValueGraphType(), attribute.getKeyGraphType() );
73+
static <K,V> AttributeNodeImpl<Map<K,V>,V,K> create(
74+
MapPersistentAttribute<?, K, V> attribute, boolean mutable) {
75+
return new MapAttributeNodeImpl<>( attribute, attribute, mutable,
76+
attribute.getValueGraphType(), attribute.getKeyGraphType() );
5177
}
5278

53-
static <X,K,V> AttributeNodeImpl<Map<K,V>,V,K> create(MapPersistentAttribute<X, K, V> attribute, boolean mutable) {
54-
return new AttributeNodeImpl<>( attribute, mutable, attribute.getValueGraphType(), attribute.getKeyGraphType() );
79+
private static <J,K,V> AttributeNodeImpl<J,V,K> create(
80+
PluralPersistentAttribute<?, J, V> plural, MapPersistentAttribute<?, K, ?> attribute, boolean mutable) {
81+
return new MapAttributeNodeImpl<>( plural, attribute, mutable,
82+
plural.getValueGraphType(), attribute.getKeyGraphType() );
5583
}
5684

57-
private <X> AttributeNodeImpl(
58-
PersistentAttribute<X, J> attribute, boolean mutable,
85+
AttributeNodeImpl(
86+
PersistentAttribute<?, J> attribute, boolean mutable,
5987
DomainType<E> valueGraphType, SimpleDomainType<K> keyGraphType) {
6088
super( mutable );
6189
this.attribute = attribute;
6290
this.valueGraphType = valueGraphType;
6391
this.keyGraphType = keyGraphType;
6492
}
6593

66-
private AttributeNodeImpl(AttributeNodeImpl<J, E,K> that, boolean mutable) {
94+
private AttributeNodeImpl(AttributeNodeImpl<J, E, K> that, boolean mutable) {
6795
super( mutable );
6896
attribute = that.attribute;
6997
valueGraphType = that.valueGraphType;
@@ -72,6 +100,101 @@ private AttributeNodeImpl(AttributeNodeImpl<J, E,K> that, boolean mutable) {
72100
keySubgraph = that.keySubgraph == null ? null : that.keySubgraph.makeCopy( mutable );
73101
}
74102

103+
private static class SingularAttributeNodeImpl<J> extends AttributeNodeImpl<J, J, Void> {
104+
private SingularAttributeNodeImpl(
105+
SingularPersistentAttribute<?,J> attribute,
106+
boolean mutable,
107+
DomainType<J> valueGraphType) {
108+
super( attribute, mutable, valueGraphType, null );
109+
}
110+
111+
private SingularAttributeNodeImpl(AttributeNodeImpl<J, J, Void> that, boolean mutable) {
112+
super( that, mutable );
113+
}
114+
115+
@Override
116+
public SubGraphImplementor<J> addSingularSubgraph() {
117+
checkToOne();
118+
verifyMutability();
119+
if ( valueSubgraph == null ) {
120+
valueSubgraph = new SubGraphImpl<>( asManagedType( valueGraphType ), true );
121+
}
122+
return valueSubgraph;
123+
}
124+
125+
@Override
126+
public AttributeNodeImplementor<J, J, Void> makeCopy(boolean mutable) {
127+
return !mutable && !isMutable() ? this : new SingularAttributeNodeImpl<>( this, mutable );
128+
}
129+
}
130+
131+
private static class PluralAttributeNodeImpl<J,E> extends AttributeNodeImpl<J, E, Void> {
132+
private PluralAttributeNodeImpl(
133+
PluralPersistentAttribute<?,J,E> attribute,
134+
boolean mutable,
135+
DomainType<E> valueGraphType) {
136+
super( attribute, mutable, valueGraphType, null );
137+
}
138+
139+
private PluralAttributeNodeImpl(AttributeNodeImpl<J, E, Void> that, boolean mutable) {
140+
super( that, mutable );
141+
}
142+
143+
@Override
144+
public SubGraphImplementor<E> addElementSubgraph() {
145+
checkToMany();
146+
verifyMutability();
147+
if ( valueSubgraph == null ) {
148+
valueSubgraph = new SubGraphImpl<>( asManagedType( valueGraphType ), true );
149+
}
150+
return valueSubgraph;
151+
}
152+
153+
@Override
154+
public AttributeNodeImplementor<J, E, Void> makeCopy(boolean mutable) {
155+
return !mutable && !isMutable() ? this : new PluralAttributeNodeImpl<>( this, mutable );
156+
}
157+
}
158+
159+
static class MapAttributeNodeImpl<J,K,V> extends AttributeNodeImpl<J, V, K> {
160+
private MapAttributeNodeImpl(
161+
PluralPersistentAttribute<?,J,V> pluralAttribute,
162+
@SuppressWarnings("unused") // a "witness" that this is really a Map
163+
MapPersistentAttribute<?,K,?> attribute,
164+
boolean mutable,
165+
DomainType<V> valueGraphType, SimpleDomainType<K> keyGraphType) {
166+
super( pluralAttribute, mutable, valueGraphType, keyGraphType );
167+
}
168+
169+
private MapAttributeNodeImpl(AttributeNodeImpl<J, V, K> that, boolean mutable) {
170+
super( that, mutable );
171+
}
172+
173+
@Override
174+
public SubGraphImplementor<K> addKeySubgraph() {
175+
verifyMutability();
176+
if ( keySubgraph == null ) {
177+
keySubgraph = new SubGraphImpl<>( asManagedType( keyGraphType ), true );
178+
}
179+
return keySubgraph;
180+
}
181+
182+
@Override
183+
public SubGraphImplementor<V> addElementSubgraph() {
184+
checkToMany();
185+
verifyMutability();
186+
if ( valueSubgraph == null ) {
187+
valueSubgraph = new SubGraphImpl<>( asManagedType( valueGraphType ), true );
188+
}
189+
return valueSubgraph;
190+
}
191+
192+
@Override
193+
public AttributeNodeImplementor<J, V, K> makeCopy(boolean mutable) {
194+
return !mutable && !isMutable() ? this : new MapAttributeNodeImpl<>( this, mutable );
195+
}
196+
}
197+
75198
@Override
76199
public String getAttributeName() {
77200
return getAttributeDescriptor().getName();
@@ -84,6 +207,7 @@ public PersistentAttribute<?, J> getAttributeDescriptor() {
84207

85208
@Override
86209
public SubGraphImplementor<E> addValueSubgraph() {
210+
verifyMutability();
87211
// this one is intentionally lenient and disfavored
88212
if ( valueSubgraph == null ) {
89213
valueSubgraph = new SubGraphImpl<>( asManagedType( valueGraphType ), true );
@@ -93,42 +217,27 @@ public SubGraphImplementor<E> addValueSubgraph() {
93217

94218
@Override
95219
public SubGraphImplementor<J> addSingularSubgraph() {
96-
checkToOne();
97-
if ( valueSubgraph == null ) {
98-
valueSubgraph = new SubGraphImpl<>( asManagedType( valueGraphType ), true );
99-
}
100-
// Safe cast, in this case E = J
101-
// TODO: would be more elegant to separate singularSubgraph vs elementSubgraph fields
102-
//noinspection unchecked
103-
return (SubGraphImplementor<J>) valueSubgraph;
220+
throw new UnsupportedOperationException("Not a singular attribute node");
104221
}
105222

106223
@Override
107224
public SubGraphImplementor<E> addElementSubgraph() {
108-
checkToMany();
109-
if ( valueSubgraph == null ) {
110-
valueSubgraph = new SubGraphImpl<>( asManagedType( valueGraphType ), true );
111-
}
112-
return valueSubgraph;
225+
throw new UnsupportedOperationException( "Not a collection-valued attribute node" );
113226
}
114227

115228
@Override
116229
public SubGraphImplementor<K> addKeySubgraph() {
117-
checkMap();
118-
if ( keySubgraph == null ) {
119-
keySubgraph = new SubGraphImpl<>( asManagedType( keyGraphType ), true );
120-
}
121-
return keySubgraph;
230+
throw new UnsupportedOperationException( "Not a Map-valued attribute node" );
122231
}
123232

124-
private void checkToOne() {
233+
protected void checkToOne() {
125234
final Attribute.PersistentAttributeType attributeType = attribute.getPersistentAttributeType();
126235
if ( attributeType != MANY_TO_ONE && attributeType != ONE_TO_ONE && attributeType != EMBEDDED ) {
127236
throw new CannotContainSubGraphException( "Attribute '" + attribute.getName() + "' is not a to-one association" );
128237
}
129238
}
130239

131-
private void checkToMany() {
240+
protected void checkToMany() {
132241
final Attribute.PersistentAttributeType attributeType = attribute.getPersistentAttributeType();
133242
if ( attributeType != MANY_TO_MANY && attributeType != ONE_TO_MANY ) {
134243
throw new CannotContainSubGraphException( "Attribute '" + attribute.getName() + "' is not a to-many association" );
@@ -187,7 +296,7 @@ private void checkMap() {
187296
}
188297
}
189298

190-
private <T> ManagedDomainType<T> asManagedType(DomainType<T> domainType) {
299+
protected <T> ManagedDomainType<T> asManagedType(DomainType<T> domainType) {
191300
if ( domainType instanceof ManagedDomainType<T> managedDomainType ) {
192301
return managedDomainType;
193302
}
@@ -208,16 +317,10 @@ public String toString() {
208317
}
209318

210319
@Override
211-
public AttributeNodeImplementor<J, E, K> makeCopy(boolean mutable) {
212-
return !mutable && !isMutable() ? this : new AttributeNodeImpl<>( this, mutable );
213-
}
214-
215-
@Override
216-
public void merge(AttributeNodeImplementor<J, E, K> other) {
217-
assert other.isMutable() == isMutable();
218-
assert other.getAttributeDescriptor() == attribute;
219-
final AttributeNodeImpl<J, E, K> that = (AttributeNodeImpl<J, E, K>) other;
220-
final SubGraphImplementor<E> otherValueSubgraph = that.valueSubgraph;
320+
public void merge(AttributeNodeImplementor<J, E, K> that) {
321+
assert that.isMutable() == isMutable();
322+
assert that.getAttributeDescriptor() == attribute;
323+
final SubGraphImplementor<E> otherValueSubgraph = that.getValueSubgraph();
221324
if ( otherValueSubgraph != null ) {
222325
if ( valueSubgraph == null ) {
223326
valueSubgraph = otherValueSubgraph.makeCopy( isMutable() );
@@ -227,7 +330,7 @@ public void merge(AttributeNodeImplementor<J, E, K> other) {
227330
valueSubgraph.mergeInternal( otherValueSubgraph );
228331
}
229332
}
230-
final SubGraphImplementor<K> otherKeySubgraph = that.keySubgraph;
333+
final SubGraphImplementor<K> otherKeySubgraph = that.getKeySubgraph();
231334
if ( otherKeySubgraph != null ) {
232335
if ( keySubgraph == null ) {
233336
keySubgraph = otherKeySubgraph.makeCopy( isMutable() );
@@ -262,4 +365,14 @@ public Map<Class<?>, SubGraphImplementor<?>> getKeySubGraphs() {
262365
return map;
263366
}
264367
}
368+
369+
@Override
370+
public SubGraphImplementor<E> getValueSubgraph() {
371+
return valueSubgraph;
372+
}
373+
374+
@Override
375+
public SubGraphImplementor<K> getKeySubgraph() {
376+
return keySubgraph;
377+
}
265378
}

hibernate-core/src/main/java/org/hibernate/graph/spi/AttributeNodeImplementor.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@
1414
*
1515
* @param <J> The type of the attribute
1616
* @param <E> The element type, if this node represents a
17-
* {@linkplain jakarta.persistence.metamodel.PluralAttribute plural attribute}
17+
* {@linkplain jakarta.persistence.metamodel.PluralAttribute plural attribute},
18+
* or the type of the singular attribute, if it doesn't
1819
* @param <K> The map key type, if this node represents a
1920
* {@linkplain jakarta.persistence.metamodel.MapAttribute map attribute}
2021
*
@@ -25,7 +26,7 @@
2526
public interface AttributeNodeImplementor<J, E, K> extends AttributeNode<J>, GraphNodeImplementor<J> {
2627

2728
@Override
28-
AttributeNodeImplementor<J, E,K> makeCopy(boolean mutable);
29+
AttributeNodeImplementor<J, E, K> makeCopy(boolean mutable);
2930

3031
/**
3132
* Create a value subgraph, without knowing whether it represents a singular value or
@@ -70,4 +71,8 @@ public interface AttributeNodeImplementor<J, E, K> extends AttributeNode<J>, Gra
7071

7172
@Override
7273
Map<Class<?>, SubGraphImplementor<?>> getKeySubGraphs();
74+
75+
SubGraphImplementor<E> getValueSubgraph();
76+
77+
SubGraphImplementor<K> getKeySubgraph();
7378
}

hibernate-core/src/main/java/org/hibernate/metamodel/model/domain/SingularPersistentAttribute.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ public interface SingularPersistentAttribute<D,J>
3232
* attribute type
3333
*/
3434
@Override
35-
default DomainType<?> getValueGraphType() {
35+
default DomainType<J> getValueGraphType() {
3636
return getType();
3737
}
3838

hibernate-core/src/test/java/org/hibernate/orm/test/fetching/GraphParsingTest.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -99,7 +99,7 @@ public void testEntityKeyParsing() {
9999
//tag::fetching-strategies-dynamic-fetching-entity-graph-parsing-key-example-2[]
100100
final EntityGraph<Ticket> graph = GraphParser.parse(
101101
Ticket.class,
102-
"showing.key(movie(cast))",
102+
"showing(id(movie(cast)))",
103103
entityManager
104104
);
105105
//end::fetching-strategies-dynamic-fetching-entity-graph-parsing-key-example-2[]
@@ -199,7 +199,7 @@ public static class Movie {
199199

200200
@ElementCollection
201201
// @OneToMany
202-
Map<Person,String> cast;
202+
Map<Person,String> cast;
203203
}
204204

205205
@Entity(name = "Theater")

0 commit comments

Comments
 (0)