1717
1818import java .util .ArrayList ;
1919import java .util .Collection ;
20+ import java .util .Collections ;
2021import java .util .List ;
2122import java .util .function .Function ;
2223import java .util .stream .Stream ;
3637import org .springframework .data .mapping .context .MappingContext ;
3738import org .springframework .data .repository .query .FluentQuery .FetchableFluentQuery ;
3839import org .springframework .data .support .PageableExecutionUtils ;
39- import org .springframework .lang .Nullable ;
4040import org .springframework .util .Assert ;
4141
4242/**
4747 * @param <R> Result type
4848 * @author Greg Turnquist
4949 * @author Mark Paluch
50+ * @author Jens Schauder
5051 * @since 2.6
5152 */
52- class FetchableFluentQueryByExample <S , R > extends FluentQuerySupport <R > implements FetchableFluentQuery <R > {
53+ class FetchableFluentQueryByExample <S , R > extends FluentQuerySupport <S , R > implements FetchableFluentQuery <R > {
5354
5455 private final Example <S > example ;
5556 private final Function <Sort , TypedQuery <S >> finder ;
5657 private final Function <Example <S >, Long > countOperation ;
5758 private final Function <Example <S >, Boolean > existsOperation ;
5859 private final EntityManager entityManager ;
5960 private final EscapeCharacter escapeCharacter ;
61+ private final Projector <TypedQuery <?>> projector ;
6062
6163 public FetchableFluentQueryByExample (Example <S > example , Function <Sort , TypedQuery <S >> finder ,
6264 Function <Example <S >, Long > countOperation , Function <Example <S >, Boolean > existsOperation ,
6365 MappingContext <? extends PersistentEntity <?, ?>, ? extends PersistentProperty <?>> context ,
6466 EntityManager entityManager , EscapeCharacter escapeCharacter ) {
65- this (example , (Class <R >) example .getProbeType (), Sort .unsorted (), null , finder , countOperation , existsOperation ,
66- context , entityManager , escapeCharacter );
67+ this (example , example .getProbeType (), (Class <R >) example .getProbeType (), Sort .unsorted (), Collections .emptySet (),
68+ finder , countOperation , existsOperation , context , entityManager , escapeCharacter ,
69+ new TypedQueryProjector (entityManager ));
6770 }
6871
69- private FetchableFluentQueryByExample (Example <S > example , Class <R > returnType , Sort sort ,
70- @ Nullable Collection <String > properties , Function <Sort , TypedQuery <S >> finder ,
71- Function <Example <S >, Long > countOperation , Function < Example < S >, Boolean > existsOperation ,
72+ private FetchableFluentQueryByExample (Example <S > example , Class <S > entityType , Class < R > returnType , Sort sort ,
73+ Collection <String > properties , Function <Sort , TypedQuery <S >> finder , Function < Example < S >, Long > countOperation ,
74+ Function <Example <S >, Boolean > existsOperation ,
7275 MappingContext <? extends PersistentEntity <?, ?>, ? extends PersistentProperty <?>> context ,
73- EntityManager entityManager , EscapeCharacter escapeCharacter ) {
76+ EntityManager entityManager , EscapeCharacter escapeCharacter , Projector < TypedQuery <?>> projector ) {
7477
75- super (returnType , sort , properties , context );
78+ super (returnType , sort , properties , context , entityType );
7679 this .example = example ;
7780 this .finder = finder ;
7881 this .countOperation = countOperation ;
7982 this .existsOperation = existsOperation ;
8083 this .entityManager = entityManager ;
8184 this .escapeCharacter = escapeCharacter ;
85+ this .projector = projector ;
8286 }
8387
8488 /*
@@ -90,8 +94,9 @@ public FetchableFluentQuery<R> sortBy(Sort sort) {
9094
9195 Assert .notNull (sort , "Sort must not be null!" );
9296
93- return new FetchableFluentQueryByExample <>(this .example , this .resultType , this .sort .and (sort ), this .properties ,
94- this .finder , this .countOperation , this .existsOperation , this .context , this .entityManager , this .escapeCharacter );
97+ return new FetchableFluentQueryByExample <>(example , entityType , resultType , sort .and (sort ), properties , finder ,
98+ countOperation , existsOperation , context , entityManager , escapeCharacter ,
99+ new TypedQueryProjector (entityManager ));
95100 }
96101
97102 /*
@@ -106,8 +111,9 @@ public <NR> FetchableFluentQuery<NR> as(Class<NR> resultType) {
106111 throw new UnsupportedOperationException ("Class-based DTOs are not yet supported." );
107112 }
108113
109- return new FetchableFluentQueryByExample <>(this .example , resultType , this .sort , this .properties , this .finder ,
110- this .countOperation , this .existsOperation , this .context , this .entityManager , this .escapeCharacter );
114+ return new FetchableFluentQueryByExample <>(example , entityType , resultType , sort , properties , finder ,
115+ countOperation , existsOperation , context , entityManager , escapeCharacter ,
116+ new TypedQueryProjector (entityManager ));
111117 }
112118
113119 /*
@@ -117,8 +123,9 @@ public <NR> FetchableFluentQuery<NR> as(Class<NR> resultType) {
117123 @ Override
118124 public FetchableFluentQuery <R > project (Collection <String > properties ) {
119125
120- return new FetchableFluentQueryByExample <>(this .example , this .resultType , this .sort , mergeProperties (properties ),
121- this .finder , this .countOperation , this .existsOperation , this .context , this .entityManager , this .escapeCharacter );
126+ return new FetchableFluentQueryByExample <>(example , entityType , resultType , sort , mergeProperties (properties ),
127+ finder , countOperation , existsOperation , context , entityManager , escapeCharacter ,
128+ new TypedQueryProjector (entityManager ));
122129 }
123130
124131 /*
@@ -128,7 +135,7 @@ public FetchableFluentQuery<R> project(Collection<String> properties) {
128135 @ Override
129136 public R oneValue () {
130137
131- TypedQuery <S > limitedQuery = this . finder . apply ( this . sort );
138+ TypedQuery <S > limitedQuery = createSortedAndProjectedQuery ( );
132139 limitedQuery .setMaxResults (2 ); // Never need more than 2 values
133140
134141 List <S > results = limitedQuery .getResultList ();
@@ -147,7 +154,7 @@ public R oneValue() {
147154 @ Override
148155 public R firstValue () {
149156
150- TypedQuery <S > limitedQuery = this . finder . apply ( this . sort );
157+ TypedQuery <S > limitedQuery = createSortedAndProjectedQuery ( );
151158 limitedQuery .setMaxResults (1 ); // Never need more than 1 value
152159
153160 List <S > results = limitedQuery .getResultList ();
@@ -162,7 +169,7 @@ public R firstValue() {
162169 @ Override
163170 public List <R > all () {
164171
165- List <S > resultList = this . finder . apply ( this . sort ).getResultList ();
172+ List <S > resultList = createSortedAndProjectedQuery ( ).getResultList ();
166173
167174 return convert (resultList );
168175 }
@@ -183,7 +190,7 @@ public Page<R> page(Pageable pageable) {
183190 @ Override
184191 public Stream <R > stream () {
185192
186- return this . finder . apply ( this . sort ) //
193+ return createSortedAndProjectedQuery ( ) //
187194 .getResultStream () //
188195 .map (getConversionFunction ());
189196 }
@@ -194,7 +201,7 @@ public Stream<R> stream() {
194201 */
195202 @ Override
196203 public long count () {
197- return this . countOperation .apply (example );
204+ return countOperation .apply (example );
198205 }
199206
200207 /*
@@ -203,12 +210,12 @@ public long count() {
203210 */
204211 @ Override
205212 public boolean exists () {
206- return this . existsOperation .apply (example );
213+ return existsOperation .apply (example );
207214 }
208215
209216 private Page <R > readPage (Pageable pageable ) {
210217
211- TypedQuery <S > pagedQuery = this . finder . apply ( this . sort );
218+ TypedQuery <S > pagedQuery = createSortedAndProjectedQuery ( );
212219
213220 if (pageable .isPaged ()) {
214221 pagedQuery .setFirstResult ((int ) pageable .getOffset ());
@@ -217,7 +224,15 @@ private Page<R> readPage(Pageable pageable) {
217224
218225 List <R > paginatedResults = convert (pagedQuery .getResultList ());
219226
220- return PageableExecutionUtils .getPage (paginatedResults , pageable , () -> this .countOperation .apply (this .example ));
227+ return PageableExecutionUtils .getPage (paginatedResults , pageable , () -> countOperation .apply (example ));
228+ }
229+
230+ private TypedQuery <S > createSortedAndProjectedQuery () {
231+
232+ TypedQuery <S > query = finder .apply (sort );
233+ projector .apply (entityType , query , properties );
234+
235+ return query ;
221236 }
222237
223238 private List <R > convert (List <S > resultList ) {
@@ -232,7 +247,7 @@ private List<R> convert(List<S> resultList) {
232247 }
233248
234249 private Function <Object , R > getConversionFunction () {
235- return getConversionFunction (this . example .getProbeType (), this . resultType );
250+ return getConversionFunction (example .getProbeType (), resultType );
236251 }
237252
238253}
0 commit comments