|
20 | 20 | import org.hibernate.graph.spi.AttributeNodeImplementor; |
21 | 21 | import org.hibernate.graph.spi.GraphImplementor; |
22 | 22 | import org.hibernate.graph.spi.RootGraphImplementor; |
| 23 | +import org.hibernate.graph.spi.SubGraphImplementor; |
23 | 24 | import org.hibernate.metamodel.model.domain.EntityDomainType; |
24 | 25 | import org.hibernate.metamodel.model.domain.ManagedDomainType; |
25 | 26 | import org.hibernate.metamodel.model.domain.PersistentAttribute; |
| 27 | +import org.hibernate.metamodel.model.domain.internal.DomainModelHelper; |
26 | 28 | import org.hibernate.query.sqm.SqmPathSource; |
27 | 29 |
|
28 | 30 | import static java.util.Collections.emptyList; |
| 31 | +import static java.util.Collections.emptyMap; |
| 32 | +import static org.hibernate.query.sqm.tree.SqmNode.log; |
29 | 33 |
|
30 | 34 | /** |
31 | | - * Base class for {@link RootGraph} and {@link SubGraph} implementations. |
| 35 | + * Base class for {@link RootGraph} and {@link SubGraph} implementations. |
32 | 36 | * |
33 | 37 | * @author Steve Ebersole |
34 | 38 | */ |
35 | 39 | public abstract class AbstractGraph<J> extends AbstractGraphNode<J> implements GraphImplementor<J> { |
36 | | - private final ManagedDomainType<J> managedType; |
37 | | - private Map<PersistentAttribute<?,?>, AttributeNodeImplementor<?>> attrNodeMap; |
38 | | - |
39 | | - public AbstractGraph(ManagedDomainType<J> managedType, boolean mutable) { |
40 | | - super( mutable ); |
41 | | - this.managedType = managedType; |
42 | | - } |
43 | | - |
44 | | - protected AbstractGraph(GraphImplementor<J> original, boolean mutable) { |
45 | | - this( original.getGraphedType(), mutable ); |
46 | | - this.attrNodeMap = new ConcurrentHashMap<>( original.getAttributeNodeList().size() ); |
47 | | - original.visitAttributeNodes( |
48 | | - node -> attrNodeMap.put( |
49 | | - node.getAttributeDescriptor(), |
50 | | - node.makeCopy( mutable ) |
51 | | - ) |
52 | | - ); |
53 | | - } |
54 | | - |
55 | | - @Override |
56 | | - public ManagedDomainType<J> getGraphedType() { |
57 | | - return managedType; |
58 | | - } |
59 | | - |
60 | | - @Override |
61 | | - public RootGraphImplementor<J> makeRootGraph(String name, boolean mutable) { |
62 | | - if ( getGraphedType() instanceof EntityDomainType ) { |
63 | | - return new RootGraphImpl<>( name, this, mutable); |
64 | | - } |
65 | | - |
66 | | - throw new CannotBecomeEntityGraphException( |
67 | | - "Cannot transform Graph to RootGraph - " + getGraphedType() + " is not an EntityType" |
68 | | - ); |
69 | | - } |
70 | | - |
71 | | - @Override |
72 | | - @SuppressWarnings("unchecked") |
73 | | - public void merge(GraphImplementor<? extends J> other) { |
74 | | - if ( other == null ) { |
75 | | - return; |
76 | | - } |
77 | | - |
78 | | - for ( AttributeNodeImplementor<?> attributeNode : other.getAttributeNodeImplementors() ) { |
79 | | - final AttributeNodeImplementor<?> localAttributeNode = findAttributeNode( |
80 | | - (PersistentAttribute<? extends J,?>) attributeNode.getAttributeDescriptor() |
81 | | - ); |
82 | | - if ( localAttributeNode != null ) { |
83 | | - // keep the local one, but merge in the incoming one |
84 | | - localAttributeNode.merge( attributeNode ); |
85 | | - } |
86 | | - else { |
87 | | - addAttributeNode( attributeNode.makeCopy( true ) ); |
88 | | - } |
89 | | - } |
90 | | - |
91 | | - } |
92 | | - |
93 | | - // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
94 | | - // AttributeNode handling |
95 | | - |
96 | | - @Override |
97 | | - public AttributeNodeImplementor<?> addAttributeNode(AttributeNodeImplementor<?> incomingAttributeNode) { |
98 | | - verifyMutability(); |
99 | | - |
100 | | - AttributeNodeImplementor<?> attributeNode = null; |
101 | | - if ( attrNodeMap == null ) { |
102 | | - attrNodeMap = new HashMap<>(); |
103 | | - } |
104 | | - else { |
105 | | - attributeNode = attrNodeMap.get( incomingAttributeNode.getAttributeDescriptor() ); |
106 | | - } |
107 | | - |
108 | | - if ( attributeNode == null ) { |
109 | | - attributeNode = incomingAttributeNode; |
110 | | - attrNodeMap.put( incomingAttributeNode.getAttributeDescriptor(), attributeNode ); |
111 | | - } |
112 | | - else { |
113 | | - @SuppressWarnings("rawtypes") |
114 | | - final AttributeNodeImplementor attributeNodeFinal = attributeNode; |
115 | | - incomingAttributeNode.visitSubGraphs( |
116 | | - // we assume the subGraph has been properly copied if needed |
117 | | - (subType, subGraph) -> attributeNodeFinal.addSubGraph( subGraph ) |
118 | | - ); |
119 | | - } |
120 | | - |
121 | | - return attributeNode; |
122 | | - } |
123 | | - |
124 | | - @Override |
125 | | - @SuppressWarnings("unchecked") |
126 | | - public <AJ> AttributeNodeImplementor<AJ> findAttributeNode(String attributeName) { |
127 | | - PersistentAttribute<? super J, ?> attribute = managedType.findAttributeInSuperTypes( attributeName ); |
128 | | - if ( attribute instanceof SqmPathSource && ( (SqmPathSource<?>) attribute ).isGeneric() ) { |
129 | | - attribute = managedType.findConcreteGenericAttribute( attributeName ); |
130 | | - } |
131 | | - return attribute == null ? null : findAttributeNode( (PersistentAttribute<? extends J, AJ>) attribute ); |
132 | | - } |
133 | | - |
134 | | - @Override |
135 | | - @SuppressWarnings("unchecked") |
136 | | - public <AJ> AttributeNodeImplementor<AJ> findAttributeNode(PersistentAttribute<? extends J, AJ> attribute) { |
137 | | - return attrNodeMap == null ? null : (AttributeNodeImplementor<AJ>) attrNodeMap.get( attribute ); |
138 | | - } |
139 | | - |
140 | | - @Override |
141 | | - @SuppressWarnings({"unchecked", "rawtypes"}) |
142 | | - public List<AttributeNode<?>> getGraphAttributeNodes() { |
143 | | - return (List) getAttributeNodeImplementors(); |
144 | | - } |
145 | | - |
146 | | - @Override |
147 | | - public List<AttributeNodeImplementor<?>> getAttributeNodeImplementors() { |
148 | | - return attrNodeMap == null ? emptyList() : new ArrayList<>( attrNodeMap.values() ); |
149 | | - } |
150 | | - |
151 | | - @Override |
152 | | - public <AJ> AttributeNodeImplementor<AJ> addAttributeNode(String attributeName) |
153 | | - throws CannotContainSubGraphException { |
154 | | - return findOrCreateAttributeNode( attributeName ); |
155 | | - } |
156 | | - |
157 | | - @Override |
158 | | - public <AJ> AttributeNodeImplementor<AJ> addAttributeNode(PersistentAttribute<? extends J, AJ> attribute) |
159 | | - throws CannotContainSubGraphException { |
160 | | - return findOrCreateAttributeNode( attribute ); |
161 | | - } |
162 | | - |
163 | | - @Override |
164 | | - @SuppressWarnings("unchecked") |
165 | | - public <AJ> AttributeNodeImplementor<AJ> findOrCreateAttributeNode(PersistentAttribute<? extends J, AJ> attribute) { |
166 | | - verifyMutability(); |
167 | | - |
168 | | - AttributeNodeImplementor<AJ> attrNode = null; |
169 | | - if ( attrNodeMap == null ) { |
170 | | - attrNodeMap = new HashMap<>(); |
171 | | - } |
172 | | - else { |
173 | | - attrNode = (AttributeNodeImplementor<AJ>) attrNodeMap.get( attribute ); |
174 | | - } |
175 | | - |
176 | | - if ( attrNode == null ) { |
177 | | - attrNode = new AttributeNodeImpl<>(attribute, isMutable()); |
178 | | - attrNodeMap.put( attribute, attrNode ); |
179 | | - } |
180 | | - |
181 | | - return attrNode; |
182 | | - } |
| 40 | + private final ManagedDomainType<J> managedType; |
| 41 | + private Map<PersistentAttribute<?, ?>, AttributeNodeImplementor<?>> attrNodeMap; |
| 42 | + private Map<Class<? extends J>, SubGraphImplementor<? extends J>> subclassSubgraphs; |
| 43 | + |
| 44 | + |
| 45 | + public AbstractGraph(ManagedDomainType<J> managedType, boolean mutable) { |
| 46 | + super(mutable); |
| 47 | + this.managedType = managedType; |
| 48 | + } |
| 49 | + |
| 50 | + protected AbstractGraph(GraphImplementor<J> original, boolean mutable) { |
| 51 | + this(original.getGraphedType(), mutable); |
| 52 | + this.attrNodeMap = new ConcurrentHashMap<>(original.getAttributeNodeList().size()); |
| 53 | + this.subclassSubgraphs = Map.copyOf(original.getSubclassSubgraphs()); |
| 54 | + original.visitAttributeNodes( |
| 55 | + node -> attrNodeMap.put( |
| 56 | + node.getAttributeDescriptor(), |
| 57 | + node.makeCopy(mutable) |
| 58 | + ) |
| 59 | + ); |
| 60 | + } |
| 61 | + |
| 62 | + @Override |
| 63 | + public Map<Class<? extends J>, SubGraphImplementor<? extends J>> getSubclassSubgraphs() { |
| 64 | + return subclassSubgraphs == null ? emptyMap() : subclassSubgraphs; |
| 65 | + } |
| 66 | + |
| 67 | + @Override |
| 68 | + public <S extends J> SubGraphImplementor<S> getSubclassSubgraph(Class<S> subtype) { |
| 69 | + return subclassSubgraphs == null ? null : (SubGraphImplementor) subclassSubgraphs.get(subtype); |
| 70 | + } |
| 71 | + |
| 72 | + @Override |
| 73 | + public <S extends J> SubGraphImplementor<S> addTreatedSubgraph(Class<S> subType) { |
| 74 | + if (subclassSubgraphs == null) { |
| 75 | + this.subclassSubgraphs = new HashMap<>(); |
| 76 | + } |
| 77 | + |
| 78 | + final SubGraphImplementor<S> existingSubgraph = (SubGraphImplementor<S>) subclassSubgraphs.get(subType); |
| 79 | + |
| 80 | + if (existingSubgraph != null) { |
| 81 | + return existingSubgraph; |
| 82 | + } |
| 83 | + |
| 84 | + ManagedDomainType<S> subTypeEntityDomainType = DomainModelHelper.findSubType(this.managedType, subType); |
| 85 | + |
| 86 | + SubGraphImplementor<S> subgraph = new SubGraphImpl<S>(subTypeEntityDomainType, (GraphImplementor) this, true); |
| 87 | + |
| 88 | + subclassSubgraphs.put(subType, subgraph); |
| 89 | + |
| 90 | + return subgraph; |
| 91 | + } |
| 92 | + |
| 93 | + @Override |
| 94 | + public <S extends J> SubGraphImplementor<S> addSubclassSubgraph(SubGraphImplementor<S> subgraph) { |
| 95 | + if (subclassSubgraphs == null) { |
| 96 | + this.subclassSubgraphs = new HashMap<>(); |
| 97 | + } |
| 98 | + |
| 99 | + SubGraphImplementor<? extends J> previous = subclassSubgraphs.put(subgraph.getClassType(), subgraph); |
| 100 | + |
| 101 | + if (previous != null) { |
| 102 | + log.debugf("Adding sub-graph [%s] over-wrote existing [%s]", subgraph, previous); |
| 103 | + } |
| 104 | + |
| 105 | + return subgraph; |
| 106 | + } |
| 107 | + |
| 108 | + |
| 109 | + @Override |
| 110 | + public ManagedDomainType<J> getGraphedType() { |
| 111 | + return managedType; |
| 112 | + } |
| 113 | + |
| 114 | + @Override |
| 115 | + public RootGraphImplementor<J> makeRootGraph(String name, boolean mutable) { |
| 116 | + if (getGraphedType() instanceof EntityDomainType) { |
| 117 | + return new RootGraphImpl<>(name, this, mutable); |
| 118 | + } |
| 119 | + |
| 120 | + throw new CannotBecomeEntityGraphException( |
| 121 | + "Cannot transform Graph to RootGraph - " + getGraphedType() + " is not an EntityType" |
| 122 | + ); |
| 123 | + } |
| 124 | + |
| 125 | + @Override |
| 126 | + @SuppressWarnings("unchecked") |
| 127 | + public void merge(GraphImplementor<? extends J> other) { |
| 128 | + if (other == null) { |
| 129 | + return; |
| 130 | + } |
| 131 | + |
| 132 | + other |
| 133 | + .getSubclassSubgraphs() |
| 134 | + .forEach((otherSubType, otherSubTypeSubgraph) -> { |
| 135 | + |
| 136 | + var alreadyExistingSubtypeSubgraph = subclassSubgraphs.get(otherSubType); |
| 137 | + if (alreadyExistingSubtypeSubgraph == null) { |
| 138 | + subclassSubgraphs.put(otherSubType, otherSubTypeSubgraph); |
| 139 | + } else { |
| 140 | + alreadyExistingSubtypeSubgraph.merge((GraphImplementor) otherSubTypeSubgraph); |
| 141 | + } |
| 142 | + |
| 143 | + }); |
| 144 | + |
| 145 | + for (AttributeNodeImplementor<?> attributeNode : other.getAttributeNodeImplementors()) { |
| 146 | + final AttributeNodeImplementor<?> localAttributeNode = findAttributeNode( |
| 147 | + (PersistentAttribute<? extends J, ?>) attributeNode.getAttributeDescriptor() |
| 148 | + ); |
| 149 | + if (localAttributeNode != null) { |
| 150 | + // keep the local one, but merge in the incoming one |
| 151 | + localAttributeNode.merge(attributeNode); |
| 152 | + } else { |
| 153 | + addAttributeNode(attributeNode.makeCopy(true)); |
| 154 | + } |
| 155 | + } |
| 156 | + |
| 157 | + } |
| 158 | + |
| 159 | + // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ |
| 160 | + // AttributeNode handling |
| 161 | + |
| 162 | + @Override |
| 163 | + public AttributeNodeImplementor<?> addAttributeNode(AttributeNodeImplementor<?> incomingAttributeNode) { |
| 164 | + verifyMutability(); |
| 165 | + |
| 166 | + AttributeNodeImplementor<?> attributeNode = null; |
| 167 | + if (attrNodeMap == null) { |
| 168 | + attrNodeMap = new HashMap<>(); |
| 169 | + } else { |
| 170 | + attributeNode = attrNodeMap.get(incomingAttributeNode.getAttributeDescriptor()); |
| 171 | + } |
| 172 | + |
| 173 | + if (attributeNode == null) { |
| 174 | + attributeNode = incomingAttributeNode; |
| 175 | + attrNodeMap.put(incomingAttributeNode.getAttributeDescriptor(), attributeNode); |
| 176 | + } else { |
| 177 | + @SuppressWarnings("rawtypes") final AttributeNodeImplementor attributeNodeFinal = attributeNode; |
| 178 | + attributeNodeFinal.getSubgraph().merge(this); |
| 179 | + incomingAttributeNode.visitSubGraphs( |
| 180 | + // we assume the subGraph has been properly copied if needed |
| 181 | + (subType, subGraph) -> attributeNodeFinal.addSubGraph(subGraph) |
| 182 | + ); |
| 183 | + } |
| 184 | + |
| 185 | + return attributeNode; |
| 186 | + } |
| 187 | + |
| 188 | + @Override |
| 189 | + @SuppressWarnings("unchecked") |
| 190 | + public <AJ> AttributeNodeImplementor<AJ> findAttributeNode(String attributeName) { |
| 191 | + PersistentAttribute<? super J, ?> attribute = managedType.findAttributeInSuperTypes(attributeName); |
| 192 | + if (attribute instanceof SqmPathSource && ((SqmPathSource<?>) attribute).isGeneric()) { |
| 193 | + attribute = managedType.findConcreteGenericAttribute(attributeName); |
| 194 | + } |
| 195 | + |
| 196 | + return attribute == null ? null : findAttributeNode((PersistentAttribute<? extends J, AJ>) attribute); |
| 197 | + } |
| 198 | + |
| 199 | + @Override |
| 200 | + @SuppressWarnings("unchecked") |
| 201 | + public <AJ> AttributeNodeImplementor<AJ> findAttributeNode(PersistentAttribute<? extends J, AJ> attribute) { |
| 202 | + return attrNodeMap == null ? null : (AttributeNodeImplementor<AJ>) attrNodeMap.get(attribute); |
| 203 | + } |
| 204 | + |
| 205 | + @Override |
| 206 | + @SuppressWarnings({"unchecked", "rawtypes"}) |
| 207 | + public List<AttributeNode<?>> getGraphAttributeNodes() { |
| 208 | + return (List) getAttributeNodeImplementors(); |
| 209 | + } |
| 210 | + |
| 211 | + @Override |
| 212 | + public List<AttributeNodeImplementor<?>> getAttributeNodeImplementors() { |
| 213 | + return attrNodeMap == null ? emptyList() : new ArrayList<>(attrNodeMap.values()); |
| 214 | + } |
| 215 | + |
| 216 | + @Override |
| 217 | + public <AJ> AttributeNodeImplementor<AJ> addAttributeNode(String attributeName) |
| 218 | + throws CannotContainSubGraphException { |
| 219 | + return findOrCreateAttributeNode(attributeName); |
| 220 | + } |
| 221 | + |
| 222 | + @Override |
| 223 | + public <AJ> AttributeNodeImplementor<AJ> addAttributeNode(PersistentAttribute<? extends J, AJ> attribute) |
| 224 | + throws CannotContainSubGraphException { |
| 225 | + return findOrCreateAttributeNode(attribute); |
| 226 | + } |
| 227 | + |
| 228 | + @Override |
| 229 | + @SuppressWarnings("unchecked") |
| 230 | + public <AJ> AttributeNodeImplementor<AJ> findOrCreateAttributeNode(PersistentAttribute<? extends J, AJ> attribute) { |
| 231 | + verifyMutability(); |
| 232 | + |
| 233 | + AttributeNodeImplementor<AJ> attrNode = null; |
| 234 | + if (attrNodeMap == null) { |
| 235 | + attrNodeMap = new HashMap<>(); |
| 236 | + } else { |
| 237 | + attrNode = (AttributeNodeImplementor<AJ>) attrNodeMap.get(attribute); |
| 238 | + } |
| 239 | + |
| 240 | + if (attrNode == null) { |
| 241 | + attrNode = new AttributeNodeImpl<>(attribute, isMutable()); |
| 242 | + attrNodeMap.put(attribute, attrNode); |
| 243 | + } |
| 244 | + |
| 245 | + return attrNode; |
| 246 | + } |
183 | 247 | } |
0 commit comments