Skip to content

Commit 9fc4240

Browse files
committed
Polishing.
Capture class name from within the builder callback. Simplify name handling.
1 parent e2327a6 commit 9fc4240

File tree

4 files changed

+51
-66
lines changed

4 files changed

+51
-66
lines changed

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

Lines changed: 18 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,8 @@
2929
import org.apache.commons.logging.Log;
3030
import org.apache.commons.logging.LogFactory;
3131
import org.jspecify.annotations.Nullable;
32+
3233
import org.springframework.aot.generate.Generated;
33-
import org.springframework.aot.generate.GeneratedTypeReference;
34-
import org.springframework.aot.hint.TypeReference;
3534
import org.springframework.data.projection.ProjectionFactory;
3635
import org.springframework.data.repository.aot.generate.AotRepositoryFragmentMetadata.ConstructorArgument;
3736
import org.springframework.data.repository.core.RepositoryInformation;
@@ -62,9 +61,9 @@ class AotRepositoryBuilder {
6261

6362
private @Nullable Consumer<AotRepositoryConstructorBuilder> constructorCustomizer;
6463
private @Nullable MethodContributorFactory methodContributorFactory;
64+
private @Nullable String targetClassName;
6565
private Consumer<AotRepositoryClassBuilder> classCustomizer;
66-
private @Nullable TypeReference targetClassName;
67-
private RepositoryConstructorBuilder constructorBuilder;
66+
private final RepositoryConstructorBuilder constructorBuilder;
6867

6968
private AotRepositoryBuilder(RepositoryInformation repositoryInformation, String moduleName,
7069
ProjectionFactory projectionFactory) {
@@ -128,15 +127,15 @@ public AotRepositoryBuilder withQueryMethodContributor(MethodContributorFactory
128127
return this;
129128
}
130129

131-
public AotRepositoryBuilder prepare(@Nullable ClassName targetClassName) {
132-
if (targetClassName == null) {
133-
withTargetClassName(null);
134-
} else {
135-
withTargetClassName(GeneratedTypeReference.of(targetClassName));
136-
}
137-
if (constructorCustomizer != null) {
138-
constructorCustomizer.accept(constructorBuilder);
139-
}
130+
/**
131+
* Configure the {@link Class#getSimpleName() simple class name} of the generated repository implementation.
132+
*
133+
* @param className the class name to use for the generated repository implementation. Defaults to the simple
134+
* {@link RepositoryInformation#getRepositoryInterface()} class name suffixed with {@code Impl}
135+
* @return {@code this}.
136+
*/
137+
public AotRepositoryBuilder withClassName(@Nullable String className) {
138+
this.targetClassName = className;
140139
return this;
141140
}
142141

@@ -184,30 +183,19 @@ public AotBundle build(TypeSpec.Builder builder) {
184183
}
185184

186185
public AotBundle build() {
187-
188-
ClassName className = ClassName
189-
.bestGuess((targetClassName != null ? targetClassName : intendedTargetClassName()).getCanonicalName());
190-
return build(TypeSpec.classBuilder(className).addAnnotation(Generated.class));
186+
return build(TypeSpec.classBuilder(getClassName()).addAnnotation(Generated.class));
191187
}
192188

193-
public TypeReference intendedTargetClassName() {
194-
return TypeReference.of("%s.%s".formatted(packageName(), typeName()));
189+
public ClassName getClassName() {
190+
return ClassName.get(packageName(), targetClassName != null ? targetClassName : typeName());
195191
}
196192

197-
public @Nullable TypeReference actualTargetClassName() {
193+
private MethodSpec buildConstructor() {
198194

199-
if (targetClassName == null) {
200-
return null;
195+
if (constructorCustomizer != null) {
196+
constructorCustomizer.accept(constructorBuilder);
201197
}
202-
return targetClassName;
203-
}
204198

205-
AotRepositoryBuilder withTargetClassName(@Nullable TypeReference targetClassName) {
206-
this.targetClassName = targetClassName;
207-
return this;
208-
}
209-
210-
private MethodSpec buildConstructor() {
211199
return constructorBuilder.buildConstructor();
212200
}
213201

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

Lines changed: 29 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
import org.apache.commons.logging.Log;
2121
import org.apache.commons.logging.LogFactory;
2222
import org.jspecify.annotations.Nullable;
23+
2324
import org.springframework.aot.generate.GeneratedClass;
2425
import org.springframework.aot.generate.GeneratedTypeReference;
2526
import org.springframework.aot.generate.GenerationContext;
@@ -31,7 +32,6 @@
3132
import org.springframework.data.repository.config.AotRepositoryContext;
3233
import org.springframework.data.repository.core.RepositoryInformation;
3334
import org.springframework.data.repository.query.QueryMethod;
34-
import org.springframework.javapoet.ClassName;
3535
import org.springframework.javapoet.TypeName;
3636

3737
/**
@@ -46,8 +46,7 @@ public class RepositoryContributor {
4646
private static final Log logger = LogFactory.getLog(RepositoryContributor.class);
4747
private static final String FEATURE_NAME = "AotRepository";
4848

49-
private AotRepositoryBuilder builder;
50-
private final AotRepositoryContext repositoryContext;
49+
private final AotRepositoryBuilder builder;
5150
private @Nullable TypeReference contributedTypeName;
5251

5352
/**
@@ -57,7 +56,6 @@ public class RepositoryContributor {
5756
*/
5857
public RepositoryContributor(AotRepositoryContext repositoryContext) {
5958

60-
this.repositoryContext = repositoryContext;
6159
builder = AotRepositoryBuilder.forRepository(repositoryContext.getRepositoryInformation(),
6260
repositoryContext.getModuleName(), createProjectionFactory());
6361
}
@@ -99,38 +97,38 @@ public void contribute(GenerationContext generationContext) {
9997
.withQueryMethodContributor(this::contributeQueryMethod); //
10098

10199
GeneratedClass generatedClass = generationContext.getGeneratedClasses().getOrAddForFeatureComponent(FEATURE_NAME,
102-
ClassName.bestGuess(builder.intendedTargetClassName().getCanonicalName()), targetTypeSpec -> {
100+
builder.getClassName(), targetTypeSpec -> {
101+
102+
// capture the actual type name early on so that we can use it in the constructor.
103+
builder.withClassName(targetTypeSpec.build().name());
103104

104105
AotBundle aotBundle = builder.build(targetTypeSpec);
105-
{
106-
Class<?> repositoryInterface = getRepositoryInformation().getRepositoryInterface();
107-
String repositoryJsonFileName = getRepositoryJsonFileName(repositoryInterface);
108-
String repositoryJson;
109-
try {
110-
repositoryJson = aotBundle.metadata().toJson().toString(2);
111-
} catch (JSONException e) {
112-
throw new RuntimeException(e);
113-
}
114-
115-
if (logger.isTraceEnabled()) {
116-
logger.trace("""
117-
------ AOT Repository.json: %s ------
118-
%s
119-
-------------------
120-
""".formatted(repositoryJsonFileName, repositoryJson));
121-
122-
logger.trace("""
123-
------ AOT Generated Repository: %s ------
124-
%s
125-
-------------------
126-
""".formatted(null, aotBundle.javaFile()));
127-
}
128-
129-
generationContext.getGeneratedFiles().addResourceFile(repositoryJsonFileName, repositoryJson);
106+
Class<?> repositoryInterface = getRepositoryInformation().getRepositoryInterface();
107+
String repositoryJsonFileName = getRepositoryJsonFileName(repositoryInterface);
108+
String repositoryJson;
109+
try {
110+
repositoryJson = aotBundle.metadata().toJson().toString(2);
111+
} catch (JSONException e) {
112+
throw new RuntimeException(e);
130113
}
114+
115+
if (logger.isTraceEnabled()) {
116+
logger.trace("""
117+
------ AOT Repository.json: %s ------
118+
%s
119+
-------------------
120+
""".formatted(repositoryJsonFileName, repositoryJson));
121+
122+
logger.trace("""
123+
------ AOT Generated Repository: %s ------
124+
%s
125+
-------------------
126+
""".formatted(null, aotBundle.javaFile()));
127+
}
128+
129+
generationContext.getGeneratedFiles().addResourceFile(repositoryJsonFileName, repositoryJson);
131130
});
132131

133-
builder.prepare(generatedClass.getName()); // initialize ctor argument resolution and set type name to target
134132
this.contributedTypeName = GeneratedTypeReference.of(generatedClass.getName());
135133

136134
// generate native runtime hints - needed cause we're using the repository proxy

src/main/java/org/springframework/data/repository/config/AotRepositoryBeanDefinitionPropertiesDecorator.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ public AotRepositoryBeanDefinitionPropertiesDecorator(Supplier<CodeBlock> inheri
5252
*/
5353
public CodeBlock decorate() {
5454

55-
Assert.notNull(repositoryContributor.getContributedTypeName(), "contributed type name must not be null");
55+
Assert.notNull(repositoryContributor.getContributedTypeName(), "Contributed type name must not be null");
5656

5757
CodeBlock.Builder builder = CodeBlock.builder();
5858
// bring in properties as usual

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

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,6 @@
3838
import org.springframework.data.repository.core.support.AnnotationRepositoryMetadata;
3939
import org.springframework.data.repository.core.support.RepositoryFragment;
4040
import org.springframework.data.repository.query.QueryMethod;
41-
import org.springframework.javapoet.ClassName;
4241
import org.springframework.javapoet.MethodSpec;
4342
import org.springframework.javapoet.TypeName;
4443
import org.springframework.stereotype.Repository;
@@ -82,7 +81,7 @@ void appliesCtorArguments() {
8281
ctor.addParameter("param2", String.class);
8382
ctor.addParameter("ctorScoped", TypeName.get(Object.class), false);
8483
});
85-
assertThat(repoBuilder.prepare(null).build().javaFile().toString()) //
84+
assertThat(repoBuilder.withClassName(null).build().javaFile().toString()) //
8685
.contains("private final Metric param1;") //
8786
.contains("private final String param2;") //
8887
.doesNotContain("private final Object ctorScoped;") //
@@ -102,7 +101,7 @@ void appliesCtorCodeBlock() {
102101
code.addStatement("throw new $T($S)", IllegalStateException.class, "initialization error");
103102
});
104103
});
105-
repoBuilder.prepare(null);
104+
repoBuilder.withClassName(null);
106105
assertThat(repoBuilder.build().javaFile().toString()).containsIgnoringWhitespaces(
107106
"UserRepositoryImpl() { throw new IllegalStateException(\"initialization error\"); }");
108107
}
@@ -196,7 +195,7 @@ void usesTargetTypeName() {
196195

197196
TypeReference targetType = TypeReference.of("%s__AotPostfix".formatted(UserRepository.class.getCanonicalName()));
198197

199-
assertThat(repoBuilder.prepare(ClassName.bestGuess(targetType.getCanonicalName())).build().javaFile().toString()) //
198+
assertThat(repoBuilder.withClassName(targetType.getSimpleName()).build().javaFile().toString()) //
200199
.contains("class %s".formatted(targetType.getSimpleName())) //
201200
.contains("public %s(Metric param1, String param2, Object ctorScoped)".formatted(targetType.getSimpleName()));
202201
}

0 commit comments

Comments
 (0)