Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 2aeaa70

Browse files
committed
Polishing.
Add configuration for constructor origin. See #3344 Original pull request: #3351
1 parent 09a8d9d commit 2aeaa70

File tree

9 files changed

+483
-84
lines changed

9 files changed

+483
-84
lines changed

‎src/main/java/org/springframework/data/repository/aot/generate/AotRepositoryBeanDefinitionPropertiesDecorator.java

Lines changed: 41 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,28 @@
1515
*/
1616
package org.springframework.data.repository.aot.generate;
1717

18+
import java.util.ArrayList;
1819
import java.util.LinkedHashMap;
20+
import java.util.List;
1921
import java.util.Map;
2022
import java.util.Map.Entry;
2123
import java.util.function.Supplier;
2224

2325
import javax.lang.model.element.Modifier;
2426

2527
import org.springframework.beans.factory.BeanFactory;
28+
import org.springframework.beans.factory.config.BeanDefinition;
29+
import org.springframework.core.DefaultParameterNameDiscoverer;
30+
import org.springframework.core.MethodParameter;
2631
import org.springframework.core.ResolvableType;
32+
import org.springframework.data.repository.aot.generate.AotRepositoryFragmentMetadata.ConstructorArgument;
2733
import org.springframework.data.repository.core.support.RepositoryComposition;
2834
import org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport;
2935
import org.springframework.javapoet.CodeBlock;
3036
import org.springframework.javapoet.MethodSpec;
31-
import org.springframework.javapoet.TypeName;
3237
import org.springframework.javapoet.TypeSpec;
3338
import org.springframework.util.Assert;
39+
import org.springframework.util.ReflectionUtils;
3440
import org.springframework.util.StringUtils;
3541

3642
/**
@@ -44,14 +50,15 @@
4450
*/
4551
public class AotRepositoryBeanDefinitionPropertiesDecorator {
4652

47-
privatestatic final Map<ResolvableType, String> RESERVED_TYPES;
53+
static final Map<ResolvableType, String> RESERVED_TYPES;
4854

4955
private final Supplier<CodeBlock> inheritedProperties;
5056
private final RepositoryContributor repositoryContributor;
5157

5258
static {
5359

54-
RESERVED_TYPES = new LinkedHashMap<>(2);
60+
RESERVED_TYPES = new LinkedHashMap<>(3);
61+
RESERVED_TYPES.put(ResolvableType.forClass(BeanDefinition.class), "beanDefinition");
5562
RESERVED_TYPES.put(ResolvableType.forClass(BeanFactory.class), "beanFactory");
5663
RESERVED_TYPES.put(ResolvableType.forClass(RepositoryFactoryBeanSupport.FragmentCreationContext.class), "context");
5764
}
@@ -90,9 +97,17 @@ public CodeBlock decorate() {
9097
MethodSpec.Builder callbackMethod = MethodSpec.methodBuilder("getRepositoryFragments").addModifiers(Modifier.PUBLIC)
9198
.returns(RepositoryComposition.RepositoryFragments.class);
9299

93-
for (Entry<ResolvableType, String> entry : RESERVED_TYPES.entrySet()) {
94-
callbackMethod.addParameter(entry.getKey().toClass(), entry.getValue());
95-
}
100+
ReflectionUtils.doWithMethods(RepositoryFactoryBeanSupport.RepositoryFragmentsFunction.class, it -> {
101+
102+
for (int i = 0; i < it.getParameterCount(); i++) {
103+
104+
MethodParameter parameter = new MethodParameter(it, i);
105+
parameter.initParameterNameDiscovery(new DefaultParameterNameDiscoverer());
106+
107+
callbackMethod.addParameter(parameter.getParameterType(), parameter.getParameterName());
108+
}
109+
110+
}, method -> method.getName().equals("getRepositoryFragments"));
96111

97112
callbackMethod.addCode(buildCallbackBody());
98113

@@ -109,26 +124,33 @@ public CodeBlock decorate() {
109124
private CodeBlock buildCallbackBody() {
110125

111126
CodeBlock.Builder callback = CodeBlock.builder();
127+
List<Object> arguments = new ArrayList<>();
112128

113-
for (Entry<String, ResolvableType> entry : repositoryContributor.requiredArgs().entrySet()) {
129+
for (Entry<String, ConstructorArgument> entry : repositoryContributor.getConstructorArguments().entrySet()) {
114130

115-
TypeName argumentType = TypeName.get(entry.getValue().getType());
116-
String reservedArgumentName = RESERVED_TYPES.get(entry.getValue());
117-
if (reservedArgumentName == null) {
118-
callback.addStatement("1ドルT 2ドルL = beanFactory.getBean(1ドルT.class)", argumentType, entry.getKey());
119-
} else {
131+
ConstructorArgument argument = entry.getValue();
132+
AotRepositoryConstructorBuilder.ParameterOrigin parameterOrigin = argument.parameterOrigin();
120133

121-
if (reservedArgumentName.equals(entry.getKey())) {
122-
continue;
123-
}
134+
String ref = parameterOrigin.getReference();
135+
CodeBlock codeBlock = parameterOrigin.getCodeBlock();
124136

125-
callback.addStatement("$T $L = $L", argumentType, entry.getKey(), reservedArgumentName);
137+
if (StringUtils.hasText(ref)) {
138+
arguments.add(ref);
139+
if (!codeBlock.isEmpty()) {
140+
callback.add(codeBlock);
141+
}
142+
} else {
143+
arguments.add(codeBlock);
126144
}
127145
}
128146

129-
callback.addStatement("return $T.just(new $L($L))", RepositoryComposition.RepositoryFragments.class,
130-
repositoryContributor.getContributedTypeName().getCanonicalName(),
131-
StringUtils.collectionToDelimitedString(repositoryContributor.requiredArgs().keySet(), ", "));
147+
List<Object> args = new ArrayList<>();
148+
args.add(RepositoryComposition.RepositoryFragments.class);
149+
args.add(repositoryContributor.getContributedTypeName().getCanonicalName());
150+
args.addAll(arguments);
151+
152+
callback.addStatement("return $T.just(new $L(%s%s))".formatted("$L".repeat(arguments.isEmpty() ? 0 : 1),
153+
", $L".repeat(Math.max(0, arguments.size() - 1))), args.toArray());
132154

133155
return callback.build();
134156
}

‎src/main/java/org/springframework/data/repository/aot/generate/AotRepositoryConstructorBuilder.java

Lines changed: 175 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,15 @@
1515
*/
1616
package org.springframework.data.repository.aot.generate;
1717

18+
import java.util.function.Consumer;
19+
import java.util.function.Function;
20+
21+
import org.jspecify.annotations.Nullable;
22+
23+
import org.springframework.beans.factory.config.BeanReference;
1824
import org.springframework.core.ResolvableType;
1925
import org.springframework.javapoet.CodeBlock;
26+
import org.springframework.util.Assert;
2027

2128
/**
2229
* Builder for AOT Repository Constructors.
@@ -65,7 +72,31 @@ default void addParameter(String parameterName, Class<?> type, boolean bindToFie
6572
* @param type parameter type.
6673
* @param bindToField whether to create a field for the parameter and assign its value to the field.
6774
*/
68-
void addParameter(String parameterName, ResolvableType type, boolean bindToField);
75+
default void addParameter(String parameterName, ResolvableType type, boolean bindToField) {
76+
addParameter(parameterName, type, c -> c.bindToField(bindToField));
77+
}
78+
79+
/**
80+
* Add constructor parameter.
81+
*
82+
* @param parameterName name of the parameter.
83+
* @param type parameter type.
84+
* @param parameterCustomizer customizer for the parameter.
85+
*/
86+
default void addParameter(String parameterName, Class<?> type,
87+
Consumer<ConstructorParameterCustomizer> parameterCustomizer) {
88+
addParameter(parameterName, ResolvableType.forClass(type), parameterCustomizer);
89+
}
90+
91+
/**
92+
* Add constructor parameter.
93+
*
94+
* @param parameterName name of the parameter.
95+
* @param type parameter type.
96+
* @param parameterCustomizer customizer for the parameter.
97+
*/
98+
void addParameter(String parameterName, ResolvableType type,
99+
Consumer<ConstructorParameterCustomizer> parameterCustomizer);
69100

70101
/**
71102
* Add constructor body customizer. The customizer is invoked after adding constructor arguments and before assigning
@@ -89,4 +120,147 @@ interface ConstructorCustomizer {
89120

90121
}
91122

123+
/**
124+
* Customizer for a AOT repository constructor parameter.
125+
*/
126+
interface ConstructorParameterCustomizer {
127+
128+
/**
129+
* Bind the constructor parameter to a field of the same type using the original parameter name.
130+
*
131+
* @return {@code this} for method chaining.
132+
*/
133+
default ConstructorParameterCustomizer bindToField() {
134+
return bindToField(true);
135+
}
136+
137+
/**
138+
* Bind the constructor parameter to a field of the same type using the original parameter name.
139+
*
140+
* @return {@code this} for method chaining.
141+
*/
142+
ConstructorParameterCustomizer bindToField(boolean bindToField);
143+
144+
/**
145+
* Use the given {@link BeanReference} to define the constructor parameter origin. Bean references can be by name,
146+
* by type or by type and name. Using a bean reference renders a lookup to a local variable using the parameter name
147+
* as guidance for the local variable name
148+
*
149+
* @see FragmentParameterContext#localVariable(String)
150+
*/
151+
void origin(BeanReference reference);
152+
153+
/**
154+
* Use the given {@link BeanReference} to define the constructor parameter origin. Bean references can be by name,
155+
* by type or by type and name.
156+
*/
157+
void origin(Function<FragmentParameterContext, ParameterOrigin> originFunction);
158+
159+
}
160+
161+
/**
162+
* Context to obtain a constructor parameter value when declaring the constructor parameter origin.
163+
*/
164+
interface FragmentParameterContext {
165+
166+
/**
167+
* @return variable name of the {@link org.springframework.beans.factory.BeanFactory}.
168+
*/
169+
String beanFactory();
170+
171+
/**
172+
* @return parameter origin to obtain the {@link org.springframework.beans.factory.BeanFactory}.
173+
*/
174+
default ParameterOrigin getBeanFactory() {
175+
return ParameterOrigin.ofReference(beanFactory());
176+
}
177+
178+
/**
179+
* @return variable name of the
180+
* {@link org.springframework.data.repository.core.support.RepositoryFactoryBeanSupport.FragmentCreationContext}.
181+
*/
182+
String fragmentCreationContext();
183+
184+
/**
185+
* @return parameter origin to obtain the fragment creation context.
186+
*/
187+
default ParameterOrigin getFragmentCreationContext() {
188+
return ParameterOrigin.ofReference(fragmentCreationContext());
189+
}
190+
191+
/**
192+
* Obtain a naming-clash free variant for the given logical variable name within the local method context. Returns
193+
* the target variable name when called multiple times with the same {@code variableName}.
194+
*
195+
* @param variableName the logical variable name.
196+
* @return the variable name used in the generated code.
197+
*/
198+
String localVariable(String variableName);
199+
200+
}
201+
202+
/**
203+
* Interface describing the origin of a constructor parameter. The parameter value can be obtained either from a
204+
* {@link #getReference() reference} variable, a {@link #getCodeBlock() code block} or a combination of both.
205+
*
206+
* @author Mark Paluch
207+
* @since 4.0
208+
*/
209+
interface ParameterOrigin {
210+
211+
/**
212+
* Construct a {@link ParameterOrigin} from the given {@link CodeBlock} and reference name.
213+
*
214+
* @param reference the reference name to obtain the parameter value from.
215+
* @param codeBlock the code block that is required to set up the parameter value.
216+
* @return a {@link ParameterOrigin} from the given {@link CodeBlock} and reference name.
217+
*/
218+
static ParameterOrigin of(String reference, CodeBlock codeBlock) {
219+
220+
Assert.hasText(reference, "Parameter reference must not be empty");
221+
222+
return new DefaultParameterOrigin(reference, codeBlock);
223+
}
224+
225+
/**
226+
* Construct a {@link ParameterOrigin} from the given {@link CodeBlock}.
227+
*
228+
* @param codeBlock the code block that produces the parameter value.
229+
* @return a {@link ParameterOrigin} from the given {@link CodeBlock}.
230+
*/
231+
static ParameterOrigin of(CodeBlock codeBlock) {
232+
233+
Assert.notNull(codeBlock, "CodeBlock reference must not be empty");
234+
235+
return new DefaultParameterOrigin(null, codeBlock);
236+
}
237+
238+
/**
239+
* Construct a {@link ParameterOrigin} from the given reference name.
240+
*
241+
* @param reference the reference name of the variable to obtain the parameter value from.
242+
* @return a {@link ParameterOrigin} from the given reference name.
243+
*/
244+
static ParameterOrigin ofReference(String reference) {
245+
246+
Assert.hasText(reference, "Parameter reference must not be empty");
247+
248+
return of(reference, CodeBlock.builder().build());
249+
}
250+
251+
/**
252+
* Obtain the reference name to obtain the parameter value from. Can be {@code null} if the parameter value is
253+
* solely obtained from the {@link #getCodeBlock() code block}.
254+
*
255+
* @return name of the reference or {@literal null} if absent.
256+
*/
257+
@Nullable
258+
String getReference();
259+
260+
/**
261+
* Obtain the code block to obtain the parameter value from. Never {@literal null}, can be empty.
262+
*/
263+
CodeBlock getCodeBlock();
264+
265+
}
92266
}

‎src/main/java/org/springframework/data/repository/aot/generate/AotRepositoryCreator.java

Lines changed: 6 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,10 @@ Map<String, ResolvableType> getAutowireFields() {
110110
return autowireFields;
111111
}
112112

113+
Map<String, ConstructorArgument> getConstructorArguments() {
114+
return generationMetadata.getConstructorArguments();
115+
}
116+
113117
RepositoryInformation getRepositoryInformation() {
114118
return repositoryInformation;
115119
}
@@ -304,6 +308,8 @@ private void contributeMethod(Method method, @Nullable MethodContributorFactory
304308
logger.trace("Skipping method [%s.%s] contribution, no MethodContributor available"
305309
.formatted(repositoryInformation.getRepositoryInterface().getName(), method.getName()));
306310
}
311+
312+
return;
307313
}
308314

309315
if (contributor.contributesMethodSpec() && !repositoryInformation.isReactiveRepository()) {
@@ -313,21 +319,6 @@ private void contributeMethod(Method method, @Nullable MethodContributorFactory
313319
}
314320
}
315321

316-
/**
317-
* Customizer interface to customize the AOT repository fragment constructor through
318-
* {@link AotRepositoryConstructorBuilder}.
319-
*/
320-
public interface ConstructorCustomizer {
321-
322-
/**
323-
* Apply customization ot the AOT repository fragment constructor.
324-
*
325-
* @param constructorBuilder the builder to be customized.
326-
*/
327-
void customize(AotRepositoryConstructorBuilder constructorBuilder);
328-
329-
}
330-
331322
/**
332323
* Factory interface to conditionally create {@link MethodContributor} instances. An implementation may decide whether
333324
* to return a {@link MethodContributor} or {@literal null}, if no method (code or metadata) should be contributed.

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /