Skip to content

Commit 0744580

Browse files
mp911dechristophstrobl
authored andcommitted
Move EntityProjection from inner class to top-level class.
Original Pull Request: #2420
1 parent 0c80e9f commit 0744580

File tree

3 files changed

+247
-226
lines changed

3 files changed

+247
-226
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,240 @@
1+
/*
2+
* Copyright 2021 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package org.springframework.data.mapping.context;
17+
18+
import java.util.Collections;
19+
import java.util.List;
20+
import java.util.function.Consumer;
21+
22+
import org.springframework.data.mapping.PropertyPath;
23+
import org.springframework.data.util.ClassTypeInformation;
24+
import org.springframework.data.util.TypeInformation;
25+
import org.springframework.lang.Nullable;
26+
27+
/**
28+
* Descriptor for a top-level mapped type representing a view onto a domain type structure. The view may exactly match
29+
* the domain type or be a DTO/interface {@link #isProjection() projection}.
30+
*
31+
* @param <M> the mapped type acting as view onto the domain type.
32+
* @param <D> the domain type.
33+
* @since 2.7
34+
*/
35+
public class EntityProjection<M, D> {
36+
37+
private final TypeInformation<M> mappedType;
38+
private final TypeInformation<D> domainType;
39+
private final List<PropertyProjection<?, ?>> properties;
40+
private final boolean projection;
41+
private final boolean closedProjection;
42+
43+
EntityProjection(TypeInformation<M> mappedType, TypeInformation<D> domainType,
44+
List<PropertyProjection<?, ?>> properties, boolean projection, boolean closedProjection) {
45+
this.mappedType = mappedType;
46+
this.domainType = domainType;
47+
this.properties = properties;
48+
this.projection = projection;
49+
this.closedProjection = closedProjection;
50+
}
51+
52+
/**
53+
* Create a projecting variant of a mapped type.
54+
*
55+
* @param mappedType
56+
* @param domainType
57+
* @param properties
58+
* @return
59+
*/
60+
public static <M, D> EntityProjection<M, D> projecting(TypeInformation<M> mappedType, TypeInformation<D> domainType,
61+
List<PropertyProjection<?, ?>> properties, boolean closedProjection) {
62+
return new EntityProjection<>(mappedType, domainType, properties, true, closedProjection);
63+
}
64+
65+
/**
66+
* Create a non-projecting variant of a mapped type.
67+
*
68+
* @param mappedType
69+
* @param domainType
70+
* @param properties
71+
* @return
72+
*/
73+
public static <M, D> EntityProjection<M, D> nonProjecting(TypeInformation<M> mappedType,
74+
TypeInformation<D> domainType, List<PropertyProjection<?, ?>> properties) {
75+
return new EntityProjection<>(mappedType, domainType, properties, false, false);
76+
}
77+
78+
/**
79+
* Create a non-projecting variant of a {@code type}.
80+
*
81+
* @param type
82+
* @return
83+
*/
84+
public static <T> EntityProjection<T, T> nonProjecting(Class<T> type) {
85+
ClassTypeInformation<T> typeInformation = ClassTypeInformation.from(type);
86+
return new EntityProjection<>(typeInformation, typeInformation, Collections.emptyList(), false, false);
87+
}
88+
89+
/**
90+
* @return the mapped type used by this type view.
91+
*/
92+
public TypeInformation<M> getMappedType() {
93+
return mappedType;
94+
}
95+
96+
/**
97+
* @return the actual mapped type used by this type view. Should be used for collection-like and map-like properties
98+
* to determine the actual view type.
99+
*/
100+
public TypeInformation<?> getActualMappedType() {
101+
return mappedType.getRequiredActualType();
102+
}
103+
104+
/**
105+
* @return the domain type represented by this type view.
106+
*/
107+
public TypeInformation<D> getDomainType() {
108+
return domainType;
109+
}
110+
111+
/**
112+
* @return the actual domain type represented by this type view. Should be used for collection-like and map-like
113+
* properties to determine the actual domain type.
114+
*/
115+
public TypeInformation<?> getActualDomainType() {
116+
return domainType.getRequiredActualType();
117+
}
118+
119+
/**
120+
* @return {@code true} if the {@link #getMappedType()} is a projection.
121+
*/
122+
public boolean isProjection() {
123+
return projection;
124+
}
125+
126+
/**
127+
* @return {@code true} if the {@link #getMappedType()} is a closed projection.
128+
*/
129+
public boolean isClosedProjection() {
130+
return isProjection() && closedProjection;
131+
}
132+
133+
List<PropertyProjection<?, ?>> getProperties() {
134+
return properties;
135+
}
136+
137+
/**
138+
* Perform the given {@code action} for each element of the {@code ReturnedTypeDescriptor} until all elements have
139+
* been processed or the action throws an exception.
140+
*
141+
* @param action the action to be performed for each element
142+
*/
143+
public void forEach(Consumer<PropertyPath> action) {
144+
145+
for (PropertyProjection<?, ?> descriptor : properties) {
146+
147+
if (descriptor.getProperties().isEmpty()) {
148+
action.accept(descriptor.getPropertyPath());
149+
} else {
150+
descriptor.forEach(action);
151+
}
152+
}
153+
}
154+
155+
/**
156+
* Return a {@link EntityProjection} for a property identified by {@code name}.
157+
*
158+
* @param name the property name.
159+
* @return the type view, if the property is known; {@code null} otherwise.
160+
*/
161+
@Nullable
162+
public EntityProjection<?, ?> findProperty(String name) {
163+
164+
for (PropertyProjection<?, ?> descriptor : properties) {
165+
166+
if (descriptor.propertyPath.getLeafProperty().getSegment().equals(name)) {
167+
return descriptor;
168+
}
169+
}
170+
171+
return null;
172+
}
173+
174+
@Override
175+
public String toString() {
176+
177+
if (isProjection()) {
178+
return String.format("Projection(%s AS %s): %s", getActualDomainType().getType().getName(),
179+
getActualMappedType().getType().getName(), properties);
180+
}
181+
182+
return String.format("Domain(%s): %s", getActualDomainType().getType().getName(), properties);
183+
}
184+
185+
/**
186+
* Descriptor for a property-level type along its potential projection.
187+
*
188+
* @param <M> the mapped type acting as view onto the domain type.
189+
* @param <D> the domain type.
190+
*/
191+
public static class PropertyProjection<M, D> extends EntityProjection<M, D> {
192+
193+
private final PropertyPath propertyPath;
194+
195+
PropertyProjection(PropertyPath propertyPath, TypeInformation<M> mappedType, TypeInformation<D> domainType,
196+
List<PropertyProjection<?, ?>> properties, boolean projecting, boolean closedProjection) {
197+
super(mappedType, domainType, properties, projecting, closedProjection);
198+
this.propertyPath = propertyPath;
199+
}
200+
201+
/**
202+
* Create a projecting variant of a mapped type.
203+
*
204+
* @param propertyPath
205+
* @param mappedType
206+
* @param domainType
207+
* @param properties
208+
* @return
209+
*/
210+
public static <M, D> PropertyProjection<M, D> projecting(PropertyPath propertyPath, TypeInformation<M> mappedType,
211+
TypeInformation<D> domainType, List<PropertyProjection<?, ?>> properties, boolean closedProjection) {
212+
return new PropertyProjection<>(propertyPath, mappedType, domainType, properties, true, closedProjection);
213+
}
214+
215+
/**
216+
* Create a non-projecting variant of a mapped type.
217+
*
218+
* @param propertyPath
219+
* @param mappedType
220+
* @param domainType
221+
* @return
222+
*/
223+
public static <M, D> PropertyProjection<M, D> nonProjecting(PropertyPath propertyPath,
224+
TypeInformation<M> mappedType, TypeInformation<D> domainType) {
225+
return new PropertyProjection<>(propertyPath, mappedType, domainType, Collections.emptyList(), false, false);
226+
}
227+
228+
/**
229+
* @return the property path representing this property within the root domain type.
230+
*/
231+
public PropertyPath getPropertyPath() {
232+
return propertyPath;
233+
}
234+
235+
@Override
236+
public String toString() {
237+
return String.format("%s AS %s", propertyPath.toDotPath(), getActualMappedType().getType().getName());
238+
}
239+
}
240+
}

0 commit comments

Comments
 (0)