Skip to content

Commit c8c0f85

Browse files
committed
Generate @bean method bodies
1 parent 3a6e7fa commit c8c0f85

File tree

6 files changed

+218
-20
lines changed

6 files changed

+218
-20
lines changed

src/main/java/org/openrewrite/spring/xml/AddConfigurationClass.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ public boolean isIdempotent() {
4747
@Override
4848
public J visitCompilationUnit(J.CompilationUnit cu) {
4949
if (cu.getMetadata()
50-
.getOrDefault("spring.beans.fileType", "unknown")
50+
.getOrDefault(SpringMetadata.FILE_TYPE, "unknown")
5151
.equals("ConfigurationClass")) {
5252
return super.visitCompilationUnit(cu);
5353
}

src/main/java/org/openrewrite/spring/xml/SpringMetadata.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,18 @@
1+
/*
2+
* Copyright 2020 the original author or authors.
3+
* <p>
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
* <p>
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
* <p>
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
116
package org.openrewrite.spring.xml;
217

318
import org.openrewrite.Metadata;

src/main/java/org/openrewrite/spring/xml/bean/AddBeanForClassNotInSourceSet.java

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,13 +15,12 @@
1515
*/
1616
package org.openrewrite.spring.xml.bean;
1717

18-
import org.openrewrite.spring.xml.parse.RewriteBeanDefinitionRegistry;
1918
import org.openrewrite.java.tree.J;
20-
import org.openrewrite.java.tree.JavaType;
19+
import org.openrewrite.spring.xml.parse.RewriteBeanDefinition;
20+
import org.openrewrite.spring.xml.parse.RewriteBeanDefinitionRegistry;
2121

2222
import java.nio.file.Path;
23-
24-
import static java.util.Collections.emptyList;
23+
import java.util.Map;
2524

2625
public class AddBeanForClassNotInSourceSet extends BeanDefinitionVisitor {
2726
private final Path mainSourceSet;
@@ -34,13 +33,16 @@ public AddBeanForClassNotInSourceSet(J.ClassDecl profileConfigurationClass, Rewr
3433
@Override
3534
public J visitClassDecl(J.ClassDecl classDecl) {
3635
if (isScope()) {
37-
registry.getBeanDefinitions(null).entrySet().stream()
38-
.filter(bdByName -> !mainSourceSet.resolve(bdByName.getValue().getBeanClassName().replace(".", "/"))
39-
.toFile().exists())
40-
.forEach(bean -> {
41-
JavaType.Class beanType = JavaType.Class.build(bean.getValue().getBeanClassName());
42-
andThen(new AddBeanMethod(classDecl, bean.getKey(), beanType, false, emptyList()));
43-
});
36+
for (Map.Entry<String, RewriteBeanDefinition> beanDefinitionByName : registry.getBeanDefinitions(null).entrySet()) {
37+
RewriteBeanDefinition bean = beanDefinitionByName.getValue();
38+
if (!mainSourceSet.resolve(bean.getBeanClassName().replace(".", "/"))
39+
.toFile().exists()) {
40+
AddBeanMethod beanMethod = new AddBeanMethod(classDecl, beanDefinitionByName.getKey(), bean, registry);
41+
andThen(beanMethod);
42+
43+
andThen(new AddBeanMethodBody(beanMethod.getMethodId(), bean.getBeanDefinitionBody()));
44+
}
45+
}
4446
}
4547

4648
return super.visitClassDecl(classDecl);

src/main/java/org/openrewrite/spring/xml/bean/AddBeanMethod.java

Lines changed: 108 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,17 @@
1616
package org.openrewrite.spring.xml.bean;
1717

1818
import org.openrewrite.Formatting;
19+
import org.openrewrite.java.refactor.AddAnnotation;
1920
import org.openrewrite.java.refactor.ScopedJavaRefactorVisitor;
2021
import org.openrewrite.java.tree.*;
22+
import org.openrewrite.spring.xml.parse.RewriteBeanDefinition;
23+
import org.openrewrite.spring.xml.parse.RewriteBeanDefinitionRegistry;
2124

25+
import javax.annotation.Nullable;
2226
import java.util.ArrayList;
2327
import java.util.List;
2428
import java.util.UUID;
29+
import java.util.stream.Collectors;
2530

2631
import static java.util.Collections.emptyList;
2732
import static java.util.Collections.singletonList;
@@ -36,14 +41,92 @@ class AddBeanMethod extends ScopedJavaRefactorVisitor {
3641
private final boolean statik;
3742
private final List<Statement> arguments;
3843

44+
@Nullable
45+
private final String initMethod;
46+
47+
@Nullable
48+
private final String destroyMethod;
49+
3950
private final UUID methodId = randomId();
4051

41-
public AddBeanMethod(J.ClassDecl scope, String name, JavaType.Class returnType, boolean statik, List<Statement> arguments) {
52+
public AddBeanMethod(J.ClassDecl scope,
53+
String beanName,
54+
RewriteBeanDefinition bean,
55+
RewriteBeanDefinitionRegistry registry) {
56+
this(scope, beanName, bean.getType(), false,
57+
Formatting.formatFirstPrefix(bean.getPropertyValues().stream()
58+
.map(pv -> {
59+
RewriteBeanDefinition propertyBean = registry.getBeanDefinition(pv.getName());
60+
JavaType.Class propertyBeanType = JavaType.Class.build(propertyBean.getBeanClassName());
61+
62+
return new J.VariableDecls(
63+
randomId(),
64+
emptyList(),
65+
emptyList(),
66+
J.Ident.build(
67+
randomId(),
68+
propertyBeanType.getClassName(),
69+
propertyBeanType,
70+
Formatting.EMPTY
71+
),
72+
null,
73+
emptyList(),
74+
singletonList(new J.VariableDecls.NamedVar(
75+
randomId(),
76+
J.Ident.build(
77+
randomId(),
78+
pv.getName(),
79+
propertyBeanType,
80+
format(" ")),
81+
emptyList(),
82+
null,
83+
propertyBeanType,
84+
EMPTY)
85+
),
86+
format(" "));
87+
})
88+
.collect(Collectors.toList()), ""),
89+
bean.isLazyInit(),
90+
bean.isPrototype(),
91+
bean.getInitMethodName(),
92+
bean.getDestroyMethodName());
93+
}
94+
95+
public AddBeanMethod(J.ClassDecl scope,
96+
String name,
97+
JavaType.Class returnType,
98+
boolean statik,
99+
List<Statement> arguments) {
100+
this(scope, name, returnType, statik, arguments, false, false, null, null);
101+
}
102+
103+
public AddBeanMethod(J.ClassDecl scope,
104+
String name,
105+
JavaType.Class returnType,
106+
boolean statik,
107+
List<Statement> arguments,
108+
boolean lazy,
109+
boolean prototype,
110+
@Nullable String initMethod,
111+
@Nullable String destroyMethod) {
42112
super(scope.getId());
43113
this.name = name;
44114
this.returnType = returnType;
45115
this.statik = statik;
46116
this.arguments = arguments;
117+
this.initMethod = initMethod;
118+
this.destroyMethod = destroyMethod;
119+
120+
if (lazy) {
121+
andThen(new AddAnnotation(methodId, "org.springframework.context.annotation.Lazy"));
122+
}
123+
124+
if (prototype) {
125+
JavaType.Class cbf = JavaType.Class.build("org.springframework.beans.factory.config.ConfigurableBeanFactory");
126+
maybeAddImport(cbf.getFullyQualifiedName());
127+
andThen(new AddAnnotation(methodId, "org.springframework.context.annotation.Scope",
128+
TreeBuilder.buildName("ConfigurableBeanFactory.SCOPE_PROTOTYPE").withType(cbf)));
129+
}
47130
}
48131

49132
public UUID getMethodId() {
@@ -75,7 +158,7 @@ public J visitClassDecl(J.ClassDecl classDecl) {
75158
Formatting format = formatter.format(classDecl.getBody());
76159

77160
J.MethodDecl beanMethod = new J.MethodDecl(methodId,
78-
singletonList(buildBeanAnnotation(emptyList())),
161+
singletonList(buildBeanAnnotation()),
79162
emptyList(),
80163
null,
81164
TreeBuilder.buildName(returnType.getClassName(), EMPTY).withType(returnType),
@@ -102,7 +185,29 @@ public J visitClassDecl(J.ClassDecl classDecl) {
102185
return c;
103186
}
104187

105-
private static J.Annotation buildBeanAnnotation(List<Expression> arguments) {
188+
private J.Annotation buildBeanAnnotation() {
189+
List<Expression> arguments = new ArrayList<>();
190+
191+
if(initMethod != null) {
192+
arguments.add(new J.Assign(
193+
randomId(),
194+
J.Ident.build(randomId(), "initMethod", JavaType.Primitive.String, EMPTY),
195+
new J.Literal(randomId(), initMethod, "\"" + initMethod + "\"", JavaType.Primitive.String, EMPTY),
196+
JavaType.Primitive.String,
197+
EMPTY
198+
));
199+
}
200+
201+
if(destroyMethod != null) {
202+
arguments.add(new J.Assign(
203+
randomId(),
204+
J.Ident.build(randomId(), "destroyMethod", JavaType.Primitive.String, EMPTY),
205+
new J.Literal(randomId(), destroyMethod, "\"" + destroyMethod + "\"", JavaType.Primitive.String, EMPTY),
206+
JavaType.Primitive.String,
207+
initMethod != null ? format(" ") : EMPTY
208+
));
209+
}
210+
106211
return new J.Annotation(randomId(),
107212
J.Ident.build(randomId(), BEAN_TYPE.getClassName(), BEAN_TYPE, EMPTY),
108213
arguments.isEmpty() ? null : new J.Annotation.Arguments(randomId(), arguments, EMPTY),

src/main/java/org/openrewrite/spring/xml/parse/RewriteBeanDefinition.java

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,19 @@
1616
package org.openrewrite.spring.xml.parse;
1717

1818
import org.openrewrite.internal.lang.NonNull;
19+
import org.openrewrite.java.tree.JavaType;
1920
import org.springframework.beans.MutablePropertyValues;
2021
import org.springframework.beans.PropertyValue;
2122
import org.springframework.beans.factory.config.BeanDefinition;
2223
import org.springframework.beans.factory.config.ConstructorArgumentValues;
2324
import org.springframework.core.ResolvableType;
2425
import org.springframework.lang.Nullable;
2526

27+
import java.util.ArrayList;
28+
import java.util.List;
29+
import java.util.Objects;
2630
import java.util.Optional;
31+
import java.util.stream.Collectors;
2732

2833
public class RewriteBeanDefinition implements BeanDefinition {
2934
public static final String TYPE_PROPERTY_KEY = "__rewrite_type";
@@ -34,6 +39,74 @@ public RewriteBeanDefinition(BeanDefinition delegate) {
3439
this.delegate = delegate;
3540
}
3641

42+
public JavaType.Class getType() {
43+
return JavaType.Class.build(getBeanClassName());
44+
}
45+
46+
public String getBeanDefinitionBody() {
47+
JavaType.Class beanType = getType();
48+
String newClass = "new " + beanType.getClassName() + "(";
49+
50+
ConstructorArgumentValues cav = getConstructorArgumentValues();
51+
if(!cav.isEmpty()) {
52+
if(!cav.getIndexedArgumentValues().isEmpty()) {
53+
newClass = cav.getIndexedArgumentValues().values().stream()
54+
.map(ConstructorArgumentValues.ValueHolder::getName)
55+
.collect(Collectors.joining(","));
56+
}
57+
else {
58+
List<ConstructorArgumentValues.ValueHolder> args = cav.getGenericArgumentValues();
59+
Optional<List<ConstructorArgumentValues.ValueHolder>> argsInOrder = beanType.getConstructors().stream()
60+
.filter(c -> c.getParamNames().size() == args.size())
61+
.map(c -> {
62+
List<ConstructorArgumentValues.ValueHolder> outOfOrder = new ArrayList<>(args);
63+
List<ConstructorArgumentValues.ValueHolder> inOrder = new ArrayList<>();
64+
65+
for(JavaType paramType : c.getGenericSignature().getParamTypes()) {
66+
if (!(paramType instanceof JavaType.FullyQualified)) {
67+
return null;
68+
}
69+
70+
String paramTypeName = ((JavaType.FullyQualified) paramType).getFullyQualifiedName();
71+
for(int i = 0; i < outOfOrder.size(); i++) {
72+
if(paramTypeName.equals(outOfOrder.get(i).getType())) {
73+
inOrder.add(outOfOrder.get(i));
74+
outOfOrder.remove(i);
75+
break;
76+
}
77+
}
78+
}
79+
80+
return outOfOrder.isEmpty() ? inOrder : null;
81+
})
82+
.filter(Objects::nonNull)
83+
.findAny();
84+
}
85+
}
86+
87+
newClass += ")";
88+
89+
if(getPropertyValues().isEmpty()) {
90+
return "return " + newClass;
91+
}
92+
93+
else {
94+
final String variableName = beanType.getClassName().substring(0, 1).toLowerCase() +
95+
beanType.getClassName().substring(1);
96+
97+
return beanType.getClassName() + " " + variableName + " = " + newClass + ";" +
98+
getPropertyValues().getPropertyValueList().stream()
99+
.map(pv -> variableName + ".set" +
100+
pv.getName().substring(0, 1).toUpperCase() +
101+
pv.getName().substring(1) +
102+
"(" +
103+
pv.getName() +
104+
");")
105+
.collect(Collectors.joining("\n", "\n", "\n")) +
106+
"return " + variableName + ";\n";
107+
}
108+
}
109+
37110
@SuppressWarnings("unchecked")
38111
public final <T> Optional<T> getProperty(String property) {
39112
PropertyValue propertyValue = getPropertyValues().getPropertyValue(property);

src/test/kotlin/org/openrewrite/spring/xml/AddConfigurationClassTest.kt

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ class AddConfigurationClassTest {
2525

2626
private val config = J.CompilationUnit
2727
.buildEmptyClass(mainSourceSet, "my.org", "MyConfiguration")
28-
.withMetadata(listOf("spring.beans.fileType" to "ConfigurationClass").toMap())
28+
.withMetadata(listOf(SpringMetadata.FILE_TYPE to "ConfigurationClass").toMap())
2929

3030
@Test
3131
fun propertyPlaceholder() {
@@ -122,20 +122,23 @@ class AddConfigurationClassTest {
122122
package my.org;
123123
124124
import org.apache.tomcat.jdbc.pool.DataSource;
125+
import org.springframework.context.annotation.Bean;
126+
import org.springframework.context.annotation.Configuration;
125127
import org.springframework.jdbc.datasource.DataSourceTransactionManager;
126128
127129
@Configuration
128130
public class MyConfiguration {
131+
129132
@Bean(destroyMethod="close")
130133
public DataSource dataSource() {
131134
return new DataSource();
132135
}
133-
136+
134137
@Bean
135138
public DataSourceTransactionManager transactionManager(DataSource dataSource) {
136-
DataSourceTransactionManager dstm = new DataSourceTransactionManager();
137-
dstm.setDataSource(dataSource);
138-
return dstm;
139+
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
140+
dataSourceTransactionManager.setDataSource(dataSource);
141+
return dataSourceTransactionManager;
139142
}
140143
}
141144
""")

0 commit comments

Comments
 (0)