1
1
/*
2
- * Copyright 2024- 2025 the original author or authors.
2
+ * Copyright 2025 the original author or authors.
3
3
*
4
4
* Licensed under the Apache License, Version 2.0 (the "License");
5
5
* you may not use this file except in compliance with the License.
13
13
* See the License for the specific language governing permissions and
14
14
* limitations under the License.
15
15
*/
16
- package org .springframework .data .jpa .repository .aot . generated ;
16
+ package org .springframework .data .jpa .repository .aot ;
17
17
18
18
import jakarta .persistence .EntityManager ;
19
19
import jakarta .persistence .EntityManagerFactory ;
20
20
import jakarta .persistence .Tuple ;
21
21
import jakarta .persistence .TypedQueryReference ;
22
+ import jakarta .persistence .metamodel .Metamodel ;
22
23
23
24
import java .lang .reflect .Method ;
24
25
import java .util .Arrays ;
57
58
import org .springframework .data .repository .query .QueryMethod ;
58
59
import org .springframework .data .repository .query .ReturnedType ;
59
60
import org .springframework .data .repository .query .parser .PartTree ;
61
+ import org .springframework .data .util .TypeInformation ;
60
62
import org .springframework .javapoet .CodeBlock ;
61
63
import org .springframework .javapoet .TypeName ;
62
64
import org .springframework .javapoet .TypeSpec ;
76
78
*/
77
79
public class JpaRepositoryContributor extends RepositoryContributor {
78
80
79
- private final AotMetamodel metaModel ;
81
+ private final EntityManagerFactory emf ;
82
+ private final Metamodel metaModel ;
80
83
private final PersistenceProvider persistenceProvider ;
81
84
82
85
public JpaRepositoryContributor (AotRepositoryContext repositoryContext ) {
83
86
super (repositoryContext );
84
- this .metaModel = new AotMetamodel (repositoryContext .getResolvedTypes ());
85
- this .persistenceProvider = PersistenceProvider .fromEntityManagerFactory (metaModel .getEntityManagerFactory ());
87
+ AotMetamodel amm = new AotMetamodel (repositoryContext .getResolvedTypes ());
88
+ this .metaModel = amm ;
89
+ this .emf = amm .getEntityManagerFactory ();
90
+ this .persistenceProvider = PersistenceProvider .fromEntityManagerFactory (amm .getEntityManagerFactory ());
91
+ }
92
+
93
+ public JpaRepositoryContributor (AotRepositoryContext repositoryContext , EntityManagerFactory entityManagerFactory ) {
94
+ super (repositoryContext );
95
+ this .emf = entityManagerFactory ;
96
+ this .metaModel = entityManagerFactory .getMetamodel ();
97
+ this .persistenceProvider = PersistenceProvider .fromEntityManagerFactory (entityManagerFactory );
86
98
}
87
99
88
100
@ Override
@@ -118,16 +130,31 @@ protected void customizeConstructor(AotRepositoryConstructorBuilder constructorB
118
130
return null ;
119
131
}
120
132
133
+ ReturnedType returnedType = queryMethod .getResultProcessor ().getReturnedType ();
134
+
135
+ // no interface/dynamic projections for now.
136
+ if (returnedType .isProjecting () && returnedType .getReturnedType ().isInterface ()) {
137
+ return null ;
138
+ }
139
+
140
+ if (queryMethod .getParameters ().hasDynamicProjection ()) {
141
+ return null ;
142
+ }
143
+
121
144
// no KeysetScrolling for now.
122
145
if (queryMethod .getParameters ().hasScrollPositionParameter ()) {
123
146
return null ;
124
147
}
125
148
126
149
if (queryMethod .isModifyingQuery ()) {
127
150
128
- Class <?> returnType = repositoryInformation .getReturnType (method ).getType ();
129
- if (!ClassUtils .isVoidType (returnType )
130
- && !JpaCodeBlocks .QueryExecutionBlockBuilder .returnsModifying (returnType )) {
151
+ TypeInformation <?> returnType = repositoryInformation .getReturnType (method );
152
+
153
+ boolean returnsCount = JpaCodeBlocks .QueryExecutionBlockBuilder .returnsModifying (returnType .getType ());
154
+
155
+ boolean isVoid = ClassUtils .isVoidType (returnType .getType ());
156
+
157
+ if (!returnsCount && !isVoid ) {
131
158
return null ;
132
159
}
133
160
}
@@ -140,15 +167,14 @@ protected void customizeConstructor(AotRepositoryConstructorBuilder constructorB
140
167
MergedAnnotation <NativeQuery > nativeQuery = context .getAnnotation (NativeQuery .class );
141
168
MergedAnnotation <QueryHints > queryHints = context .getAnnotation (QueryHints .class );
142
169
MergedAnnotation <Modifying > modifying = context .getAnnotation (Modifying .class );
143
- ReturnedType returnedType = context .getReturnedType ();
144
170
145
171
body .add (context .codeBlocks ().logDebug ("invoking [%s]" .formatted (context .getMethod ().getName ())));
146
172
147
173
AotQueries aotQueries = getQueries (context , query , selector , queryMethod , returnedType );
148
174
149
175
body .add (JpaCodeBlocks .queryBuilder (context , queryMethod ).filter (aotQueries )
150
- .queryReturnType (getQueryReturnType (aotQueries .result (), returnedType , context )).query ( query )
151
- .nativeQuery ( nativeQuery ). queryHints (queryHints ).build ());
176
+ .queryReturnType (getQueryReturnType (aotQueries .result (), returnedType , context )).nativeQuery ( nativeQuery )
177
+ .queryHints (queryHints ).build ());
152
178
153
179
body .add (
154
180
JpaCodeBlocks .executionBuilder (context , queryMethod ).modifying (modifying ).query (aotQueries .result ()).build ());
@@ -178,8 +204,7 @@ private AotQueries buildStringQuery(Class<?> domainType, ReturnedType returnedTy
178
204
179
205
UnaryOperator <String > operator = s -> s .replaceAll ("#\\ {#entityName}" , domainType .getName ());
180
206
boolean isNative = query .getBoolean ("nativeQuery" );
181
- Function <String , StringAotQuery > queryFunction = isNative ? StringAotQuery ::nativeQuery
182
- : StringAotQuery ::jpqlQuery ;
207
+ Function <String , StringAotQuery > queryFunction = isNative ? StringAotQuery ::nativeQuery : StringAotQuery ::jpqlQuery ;
183
208
queryFunction = operator .andThen (queryFunction );
184
209
185
210
String queryString = query .getString ("value" );
@@ -252,8 +277,6 @@ private NamedAotQuery buildNamedAotQuery(TypedQueryReference<?> namedQuery, JpaQ
252
277
returnedType .getReturnedType (), returnedType .getTypeToRead (), void .class , null , Long .class , Integer .class ,
253
278
Long .TYPE , Integer .TYPE , Number .class );
254
279
255
- EntityManagerFactory emf = metaModel .getEntityManagerFactory ();
256
-
257
280
for (Class <?> candidate : candidates ) {
258
281
259
282
Map <String , ? extends TypedQueryReference <?>> namedQueries = emf .getNamedQueries (candidate );
0 commit comments