Skip to content

Commit dcb98dd

Browse files
committed
Polishing.
Improve encapsulation. See #3338
1 parent 5bc8d22 commit dcb98dd

File tree

4 files changed

+60
-38
lines changed

4 files changed

+60
-38
lines changed

src/main/java/org/springframework/data/repository/aot/generate/AotQueryMethodGenerationContext.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ public List<String> getAllParameterNames() {
265265
* @return the variable name used in the generated code.
266266
*/
267267
public String localVariable(String variableName) {
268-
return targetMethodMetadata.getLocalVariables().computeIfAbsent(variableName, variableNameFactory::generateName);
268+
return targetMethodMetadata.getOrCreateLocalVariable(variableName, variableNameFactory::generateName);
269269
}
270270

271271
/**
@@ -346,7 +346,7 @@ public String localVariable(String variableName) {
346346
/**
347347
* Obtain the {@link ExpressionMarker} for the current method. Will add a local class within the method that can be
348348
* referenced via {@link ExpressionMarker#enclosingMethod()}.
349-
*
349+
*
350350
* @return the {@link ExpressionMarker} for this particular method.
351351
*/
352352
public ExpressionMarker getExpressionMarker() {

src/main/java/org/springframework/data/repository/aot/generate/AotRepositoryMethodBuilder.java

Lines changed: 23 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717

1818
import java.lang.reflect.Method;
1919
import java.lang.reflect.TypeVariable;
20+
import java.util.Map;
2021
import java.util.function.BiConsumer;
2122
import java.util.function.Function;
2223
import java.util.stream.Collectors;
@@ -25,9 +26,9 @@
2526

2627
import org.springframework.javapoet.CodeBlock;
2728
import org.springframework.javapoet.MethodSpec;
29+
import org.springframework.javapoet.ParameterSpec;
2830
import org.springframework.javapoet.TypeName;
2931
import org.springframework.javapoet.TypeVariableName;
30-
import org.springframework.util.StringUtils;
3132

3233
/**
3334
* Builder for AOT repository query methods.
@@ -82,27 +83,38 @@ public AotRepositoryMethodBuilder customize(
8283
public MethodSpec buildMethod() {
8384

8485
CodeBlock methodBody = contribution.apply(context);
86+
MethodSpec.Builder builder = initializeMethodBuilder();
87+
88+
if (context.getExpressionMarker().isInUse()) {
89+
builder.addCode(context.getExpressionMarker().declaration());
90+
}
91+
92+
builder.addCode(methodBody);
93+
94+
customizer.accept(context, builder);
95+
96+
return builder.build();
97+
}
98+
99+
private MethodSpec.Builder initializeMethodBuilder() {
85100

86101
MethodSpec.Builder builder = MethodSpec.methodBuilder(context.getMethod().getName()).addModifiers(Modifier.PUBLIC);
87102
builder.returns(TypeName.get(context.getReturnType().getType()));
88103

89104
TypeVariable<Method>[] tvs = context.getMethod().getTypeParameters();
90-
91105
for (TypeVariable<Method> tv : tvs) {
92106
builder.addTypeVariable(TypeVariableName.get(tv));
93107
}
94108

109+
MethodMetadata methodMetadata = context.getTargetMethodMetadata();
110+
Map<String, ParameterSpec> methodArguments = methodMetadata.getMethodArguments();
95111
builder.addJavadoc("AOT generated implementation of {@link $T#$L($L)}.", context.getMethod().getDeclaringClass(),
96-
context.getMethod().getName(), StringUtils.collectionToCommaDelimitedString(context.getTargetMethodMetadata()
97-
.getMethodArguments().values().stream().map(it -> it.type().toString()).collect(Collectors.toList())));
98-
context.getTargetMethodMetadata().getMethodArguments().forEach((name, spec) -> builder.addParameter(spec));
99-
if(context.getExpressionMarker().isInUse()) {
100-
builder.addCode(context.getExpressionMarker().declaration());
101-
}
102-
builder.addCode(methodBody);
103-
customizer.accept(context, builder);
112+
context.getMethod().getName(),
113+
methodArguments.values().stream().map(it -> it.type().toString()).collect(Collectors.joining(", ")));
104114

105-
return builder.build();
115+
methodArguments.forEach((name, spec) -> builder.addParameter(spec));
116+
117+
return builder;
106118
}
107119

108120
}

src/main/java/org/springframework/data/repository/aot/generate/MethodMetadata.java

Lines changed: 31 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -16,13 +16,17 @@
1616
package org.springframework.data.repository.aot.generate;
1717

1818
import java.lang.reflect.Method;
19+
import java.lang.reflect.Parameter;
1920
import java.util.ArrayList;
21+
import java.util.Collections;
2022
import java.util.LinkedHashMap;
2123
import java.util.List;
2224
import java.util.Map;
2325
import java.util.Map.Entry;
26+
import java.util.function.Function;
2427

2528
import org.jspecify.annotations.Nullable;
29+
2630
import org.springframework.core.DefaultParameterNameDiscoverer;
2731
import org.springframework.core.MethodParameter;
2832
import org.springframework.core.ParameterNameDiscoverer;
@@ -40,8 +44,8 @@
4044
*/
4145
class MethodMetadata {
4246

43-
private final Map<String, ParameterSpec> methodArguments = new LinkedHashMap<>();
44-
private final Map<String, MethodParameter> methodParameters = new LinkedHashMap<>();
47+
private final Map<String, ParameterSpec> methodArguments;
48+
private final Map<String, MethodParameter> methodParameters;
4549
private final Map<String, String> localVariables = new LinkedHashMap<>();
4650
private final ResolvableType actualReturnType;
4751
private final ResolvableType returnType;
@@ -50,24 +54,39 @@ class MethodMetadata {
5054

5155
this.returnType = repositoryInformation.getReturnType(method).toResolvableType();
5256
this.actualReturnType = repositoryInformation.getReturnedDomainTypeInformation(method).toResolvableType();
53-
this.initParameters(repositoryInformation, method, new DefaultParameterNameDiscoverer());
54-
}
5557

56-
private void initParameters(RepositoryInformation repositoryInformation, Method method,
57-
ParameterNameDiscoverer nameDiscoverer) {
58+
Map<String, ParameterSpec> methodArguments = new LinkedHashMap<>();
59+
Map<String, MethodParameter> methodParameters = new LinkedHashMap<>();
5860

5961
ResolvableType repositoryInterface = ResolvableType.forClass(repositoryInformation.getRepositoryInterface());
62+
ParameterNameDiscoverer nameDiscoverer = new DefaultParameterNameDiscoverer();
63+
64+
initializeMethodArguments(method, nameDiscoverer, repositoryInterface, methodArguments, methodParameters);
65+
66+
this.methodArguments = Collections.unmodifiableMap(methodArguments);
67+
this.methodParameters = Collections.unmodifiableMap(methodParameters);
68+
}
6069

61-
for (java.lang.reflect.Parameter parameter : method.getParameters()) {
70+
private static void initializeMethodArguments(Method method, ParameterNameDiscoverer nameDiscoverer,
71+
ResolvableType repositoryInterface, Map<String, ParameterSpec> methodArguments,
72+
Map<String, MethodParameter> methodParameters) {
73+
74+
for (Parameter parameter : method.getParameters()) {
6275

6376
MethodParameter methodParameter = MethodParameter.forParameter(parameter);
6477
methodParameter.initParameterNameDiscovery(nameDiscoverer);
6578
ResolvableType resolvableParameterType = ResolvableType.forMethodParameter(methodParameter, repositoryInterface);
6679

6780
TypeName parameterType = TypeName.get(resolvableParameterType.getType());
6881

69-
addParameter(ParameterSpec.builder(parameterType, methodParameter.getParameterName()).build());
70-
methodParameters.put(methodParameter.getParameterName(), methodParameter);
82+
ParameterSpec parameterSpec = ParameterSpec.builder(parameterType, methodParameter.getParameterName()).build();
83+
84+
if (methodArguments.containsKey(parameterSpec.name())) {
85+
throw new IllegalStateException("Parameter with name '" + parameterSpec.name() + "' already exists.");
86+
}
87+
88+
methodArguments.put(parameterSpec.name(), parameterSpec);
89+
methodParameters.put(parameterSpec.name(), methodParameter);
7190
}
7291
}
7392

@@ -79,10 +98,6 @@ ResolvableType getActualReturnType() {
7998
return actualReturnType;
8099
}
81100

82-
void addParameter(ParameterSpec parameterSpec) {
83-
this.methodArguments.put(parameterSpec.name(), parameterSpec);
84-
}
85-
86101
Map<String, ParameterSpec> getMethodArguments() {
87102
return methodArguments;
88103
}
@@ -105,8 +120,9 @@ String getParameterName(int position) {
105120
return null;
106121
}
107122

108-
Map<String, String> getLocalVariables() {
109-
return localVariables;
123+
public String getOrCreateLocalVariable(String variableName,
124+
Function<? super String, ? extends String> mappingFunction) {
125+
return localVariables.computeIfAbsent(variableName, mappingFunction);
110126
}
111127

112128
}

src/test/java/org/springframework/data/repository/aot/generate/AotRepositoryMethodBuilderUnitTests.java

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

18-
import static org.assertj.core.api.Assertions.assertThat;
19-
import static org.mockito.ArgumentMatchers.any;
20-
import static org.mockito.Mockito.doReturn;
21-
import static org.mockito.Mockito.when;
18+
import static org.assertj.core.api.Assertions.*;
19+
import static org.mockito.ArgumentMatchers.*;
20+
import static org.mockito.Mockito.*;
2221

2322
import example.UserRepository;
2423
import example.UserRepository.User;
@@ -33,11 +32,10 @@
3332
import org.junit.jupiter.params.provider.Arguments;
3433
import org.junit.jupiter.params.provider.MethodSource;
3534
import org.mockito.Mockito;
35+
3636
import org.springframework.core.ResolvableType;
3737
import org.springframework.data.repository.core.RepositoryInformation;
3838
import org.springframework.data.util.TypeInformation;
39-
import org.springframework.javapoet.ParameterSpec;
40-
import org.springframework.javapoet.ParameterizedTypeName;
4139

4240
/**
4341
* @author Christoph Strobl
@@ -66,7 +64,6 @@ void generatesMethodSkeletonBasedOnGenerationMetadata() throws NoSuchMethodExcep
6664
doReturn(TypeInformation.of(User.class)).when(repositoryInformation).getReturnType(any());
6765
doReturn(TypeInformation.of(User.class)).when(repositoryInformation).getReturnedDomainTypeInformation(any());
6866
MethodMetadata methodMetadata = new MethodMetadata(repositoryInformation, method);
69-
methodMetadata.addParameter(ParameterSpec.builder(String.class, "firstname").build());
7067
when(methodGenerationContext.getTargetMethodMetadata()).thenReturn(methodMetadata);
7168

7269
AotRepositoryMethodBuilder builder = new AotRepositoryMethodBuilder(methodGenerationContext);
@@ -84,8 +81,6 @@ void generatesMethodWithGenerics() throws NoSuchMethodException {
8481
doReturn(TypeInformation.of(User.class)).when(repositoryInformation).getReturnType(any());
8582
doReturn(TypeInformation.of(User.class)).when(repositoryInformation).getReturnedDomainTypeInformation(any());
8683
MethodMetadata methodMetadata = new MethodMetadata(repositoryInformation, method);
87-
methodMetadata
88-
.addParameter(ParameterSpec.builder(ParameterizedTypeName.get(List.class, String.class), "firstnames").build());
8984
when(methodGenerationContext.getTargetMethodMetadata()).thenReturn(methodMetadata);
9085

9186
AotRepositoryMethodBuilder builder = new AotRepositoryMethodBuilder(methodGenerationContext);
@@ -104,7 +99,6 @@ void generatesExpressionMarkerIfInUse(ExpressionMarker expressionMarker) throws
10499
doReturn(TypeInformation.of(User.class)).when(repositoryInformation).getReturnType(any());
105100
doReturn(TypeInformation.of(User.class)).when(repositoryInformation).getReturnedDomainTypeInformation(any());
106101
MethodMetadata methodMetadata = new MethodMetadata(repositoryInformation, method);
107-
methodMetadata.addParameter(ParameterSpec.builder(String.class, "firstname").build());
108102
when(methodGenerationContext.getTargetMethodMetadata()).thenReturn(methodMetadata);
109103
when(methodGenerationContext.getExpressionMarker()).thenReturn(expressionMarker);
110104

0 commit comments

Comments
 (0)