Skip to content

Commit 63eaf9a

Browse files
committed
Added Class factory-method supports
1 parent 1d412b3 commit 63eaf9a

File tree

12 files changed

+274
-44
lines changed

12 files changed

+274
-44
lines changed

src/main/java/pro/akvel/spring/converter/generator/BeanData.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,4 +93,10 @@ public class BeanData {
9393
*/
9494
@Nullable
9595
private final Set<String> qualifierName;
96+
97+
/**
98+
* {@link AbstractBeanDefinition#getFactoryMethodName()}
99+
*/
100+
@Nullable
101+
private final String factoryMethodName;
96102
}

src/main/java/pro/akvel/spring/converter/java/JavaConfigurationGenerator.java

Lines changed: 39 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,8 @@ public void generateClass(String packageName,
156156
JBlock body = method.body();
157157

158158

159-
JInvocation aNew = JExpr._new(beanClass);
159+
final JInvocation aNew;
160+
aNew = getInvocation(it, beanClass);
160161
addParamToBeanConstructor(it, method, aNew, jc);
161162
if (constructorParamsOnly(it)) {
162163
body._return(aNew);
@@ -215,21 +216,24 @@ private void setProperties(JVar newBean, List<PropertyParam> propertyParams,
215216
invocation.arg(createValue(valueParam.getValue(), classDescription));
216217
}
217218
} else if (it instanceof PropertySubBeanParam) {
218-
PropertySubBeanParam subBeanData = (PropertySubBeanParam) it;
219+
PropertySubBeanParam subBeanDataParam = (PropertySubBeanParam) it;
220+
BeanData subBeanData = subBeanDataParam.getBeanData();
219221

220-
JClass subBeanClass = CODE_MODEL.ref(subBeanData.getBeanData().getClassName());
221-
JInvocation subBeanNew = JExpr._new(subBeanClass);
222-
if (constructorParamsOnly(subBeanData.getBeanData())) {
223-
addParamToBeanConstructor(subBeanData.getBeanData(), method, subBeanNew, classDescription);
222+
JClass subBeanClass = CODE_MODEL.ref(subBeanData.getClassName());
224223

225-
JInvocation invocation = method.body().invoke(newBean, getSetterName(subBeanData.getName(), setter));
224+
final JInvocation subBeanNew = getInvocation(subBeanData, subBeanClass);
225+
226+
if (constructorParamsOnly(subBeanData)) {
227+
addParamToBeanConstructor(subBeanData, method, subBeanNew, classDescription);
228+
229+
JInvocation invocation = method.body().invoke(newBean, getSetterName(subBeanDataParam.getName(), setter));
226230
invocation.arg(subBeanNew);
227231
} else {
228232
JVar newBeanVar = method.body().decl(subBeanClass, "bean" + fieldIndex++, subBeanNew);
229-
setProperties(newBeanVar, subBeanData.getBeanData().getPropertyParams(), method, true, classDescription);
230-
addParamToBeanConstructor(subBeanData.getBeanData(), method, subBeanNew, classDescription);
233+
setProperties(newBeanVar, subBeanData.getPropertyParams(), method, true, classDescription);
234+
addParamToBeanConstructor(subBeanData, method, subBeanNew, classDescription);
231235

232-
JInvocation invocation = method.body().invoke(newBean, getSetterName(subBeanData.getName(), setter));
236+
JInvocation invocation = method.body().invoke(newBean, getSetterName(subBeanDataParam.getName(), setter));
233237
invocation.arg(newBeanVar);
234238
}
235239
} else if (it instanceof PropertyMergeableParam) {
@@ -266,7 +270,7 @@ private static JExpression createValue(String value, JDefinedClass clazz) {
266270
//value
267271
var placeHolderValue = matcher.group(2);
268272

269-
log.trace("Found placeholder {} = {}", placeholder, placeHolderValue);
273+
log.debug("Found placeholder {} = {}", placeholder, placeHolderValue);
270274

271275
String fieldName = CaseUtils.toCamelCase(placeHolderValue, false, '.', '-');
272276
if (!clazz.fields().containsKey(fieldName)) {
@@ -284,9 +288,9 @@ private static JExpression createValue(String value, JDefinedClass clazz) {
284288
JExpression resultExpression = null;
285289
String[] split = result.split("\\$\\{\\}");
286290

287-
if (result.equals(PLACEHOLDER_VARIABLE)){
288-
if (fields.size() != 1){
289-
throw new IllegalStateException("Plaseholder filed not one value " + value);
291+
if (result.equals(PLACEHOLDER_VARIABLE)) {
292+
if (fields.size() != 1) {
293+
throw new IllegalStateException("Placeholder filed not one value " + value);
290294
}
291295

292296
return JExpr.ref(fields.get(0));
@@ -298,7 +302,7 @@ private static JExpression createValue(String value, JDefinedClass clazz) {
298302
if (!s.isEmpty()) {
299303
if (resultExpression == null) {
300304
resultExpression = JExpr.lit(s);
301-
}else {
305+
} else {
302306
resultExpression = resultExpression.plus(JExpr.lit(s));
303307
}
304308
}
@@ -308,7 +312,7 @@ private static JExpression createValue(String value, JDefinedClass clazz) {
308312
log.trace("Get {} {}", i, field);
309313
if (resultExpression != null) {
310314
resultExpression = resultExpression.plus(JExpr.ref(field));
311-
}else {
315+
} else {
312316
resultExpression = JExpr.ref(field);
313317
}
314318
}
@@ -362,17 +366,21 @@ private void processConstructor(JMethod method,
362366
}
363367

364368
if (arg instanceof ConstructorSubBeanParam) {
365-
ConstructorSubBeanParam subBeanData = (ConstructorSubBeanParam) arg;
369+
ConstructorSubBeanParam subBeanDataParam = (ConstructorSubBeanParam) arg;
370+
BeanData subBeanData = subBeanDataParam.getBeanData();
371+
372+
JClass subBeanClass = CODE_MODEL.ref(subBeanData.getClassName());
373+
374+
final JInvocation subBeanNew;
375+
subBeanNew = getInvocation(subBeanData, subBeanClass);
366376

367-
JClass subBeanClass = CODE_MODEL.ref(subBeanData.getBeanData().getClassName());
368-
JInvocation subBeanNew = JExpr._new(subBeanClass);
369-
if (constructorParamsOnly(subBeanData.getBeanData())) {
370-
addParamToBeanConstructor(subBeanData.getBeanData(), method, subBeanNew, classDescription);
377+
if (constructorParamsOnly(subBeanData)) {
378+
addParamToBeanConstructor(subBeanData, method, subBeanNew, classDescription);
371379
aNew.arg(subBeanNew);
372380
} else {
373381
JVar newBeanVar = method.body().decl(subBeanClass, "bean" + fieldIndex++, subBeanNew);
374-
setProperties(newBeanVar, subBeanData.getBeanData().getPropertyParams(), method, true, classDescription);
375-
addParamToBeanConstructor(subBeanData.getBeanData(), method, subBeanNew, classDescription);
382+
setProperties(newBeanVar, subBeanData.getPropertyParams(), method, true, classDescription);
383+
addParamToBeanConstructor(subBeanData, method, subBeanNew, classDescription);
376384
aNew.arg(newBeanVar);
377385
}
378386
}
@@ -411,6 +419,14 @@ private void processConstructor(JMethod method,
411419
}
412420
}
413421

422+
private JInvocation getInvocation(BeanData subBeanData, JClass subBeanClass) {
423+
if (subBeanData.getFactoryMethodName() != null) {
424+
return subBeanClass.staticInvoke(subBeanData.getFactoryMethodName());
425+
} else {
426+
return JExpr._new(subBeanClass);
427+
}
428+
}
429+
414430
private void addMethodParams(BeanData beanData, JMethod method, Set<String> guard) {
415431
beanData.getConstructorParams()
416432
.forEach(arg -> {

src/main/java/pro/akvel/spring/converter/xml/BeanSupportValidator.java

Lines changed: 23 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -42,15 +42,15 @@ public Optional<NotSupportBeanType> isBeanSupport(BeanDefinition beanDefinition,
4242
}
4343

4444
private Optional<NotSupportBeanType> isBeanSupport(BeanDefinition beanDefinition,
45-
String name,
46-
Set<BeanDefinition> guard,
47-
BeanDefinitionRegistry beanDefinitionRegistry, boolean subCheck) {
45+
String name,
46+
Set<BeanDefinition> guard,
47+
BeanDefinitionRegistry beanDefinitionRegistry, boolean subCheck) {
4848

4949
//pass all beans read from Java configurations
50-
if (beanDefinition instanceof AnnotatedBeanDefinition){
50+
if (beanDefinition instanceof AnnotatedBeanDefinition) {
5151
if (subCheck) {
5252
return Optional.empty();
53-
}else {
53+
} else {
5454
log.debug("Skipped annotated bean {}", name);
5555
return Optional.of(NotSupportBeanType.ANNOTATED_BEAN);
5656
}
@@ -68,27 +68,26 @@ private Optional<NotSupportBeanType> isBeanSupport(BeanDefinition beanDefinition
6868
}
6969

7070
if (beanDefinition.getParentName() != null) {
71-
log.debug("Skipped" + name + ". Beans with parent not supported");
71+
log.debug("Skipped {}. Beans with parent not supported", name);
7272
return Optional.of(NotSupportBeanType.BEAN_WITH_PARENT);
7373
}
7474

7575
if ((beanDefinition instanceof AbstractBeanDefinition)
7676
&& ((AbstractBeanDefinition) beanDefinition).getAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE) {
77-
log.debug("Skipped {}. Beans with AUTOWIRE_BY_TYPE not supported {}",
78-
name,
77+
log.debug("Skipped {}. Beans with AUTOWIRE_BY_TYPE not supported {}", name,
7978
((AbstractBeanDefinition) beanDefinition).getAutowireMode());
8079
return Optional.of(NotSupportBeanType.BEAT_WITH_NOT_SUPPORTED_AUTOWIRE_BY_TYPE);
8180
}
8281

8382
if ((beanDefinition instanceof AbstractBeanDefinition)
8483
&& ((AbstractBeanDefinition) beanDefinition).getAutowireMode() == AutowireCapableBeanFactory.AUTOWIRE_CONSTRUCTOR) {
85-
log.debug("Skipped" + name + ". Beans with AUTOWIRE_CONSTRUCTOR not supported");
84+
log.debug("Skipped {}. Beans with AUTOWIRE_CONSTRUCTOR not supported", name);
8685
return Optional.of(NotSupportBeanType.BEAT_WITH_NOT_SUPPORTED_AUTOWIRE_CONSTRUCTOR);
8786
}
8887

8988
if (!beanDefinition.getConstructorArgumentValues().getIndexedArgumentValues().isEmpty()
9089
&& !beanDefinition.getConstructorArgumentValues().getGenericArgumentValues().isEmpty()) {
91-
log.debug("Skipped" + name + ". Mixed constructor params with \"index\" attr and without not supported");
90+
log.debug("Skipped {}. Mixed constructor params with \"index\" attr and without not supported", name);
9291
return Optional.of(NotSupportBeanType.BEAT_WITH_MIXED_CONSTRUCTO_PARAM);
9392
}
9493

@@ -179,7 +178,8 @@ private Optional<NotSupportBeanType> isBeanSupport(BeanDefinition beanDefinition
179178
return isBeanSupport(it.getBeanDefinition(), it.getBeanName(), newGuard, beanDefinitionRegistry, true);
180179
})
181180
.filter(Optional::isPresent)
182-
.findAny();;
181+
.findAny();
182+
;
183183
if (checkBeanDefinition.isPresent()) {
184184
log.debug("Skipped {}. Found sub bean type that not supported - {}", name, checkBeanDefinition.get());
185185
return checkBeanDefinition.get();
@@ -200,7 +200,18 @@ private boolean isContainEL(TypedStringValue it) {
200200
}
201201

202202
private boolean isBeanHashFactory(BeanDefinition beanDefinition) {
203-
return beanDefinition.getFactoryBeanName() != null || beanDefinition.getFactoryMethodName() != null;
203+
if (beanDefinition.getFactoryBeanName() != null) {
204+
log.debug("Bean with factory bean");
205+
return true;
206+
}
207+
208+
if (beanDefinition.getFactoryMethodName() != null &&
209+
!beanDefinition.getPropertyValues().isEmpty()) {
210+
log.debug("Bean with factory method and properties not supported");
211+
return true;
212+
}
213+
214+
return false;
204215
}
205216

206217
private Optional<NotSupportBeanType> isRefBeanValid(BeanDefinition beanDefinition, Set<BeanDefinition> guard, BeanDefinitionRegistry beanDefinitionRegistry, RuntimeBeanReference it) {

src/main/java/pro/akvel/spring/converter/xml/ConfigurationDataConverter.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ public BeanData getConfigurationData(@Nonnull BeanDefinition beanDefinition,
105105
.primary(beanDefinition.isPrimary())
106106
.lazyInit(beanDefinition.isLazyInit())
107107
.qualifierName(getQualifier(beanDefinition))
108+
.factoryMethodName(beanDefinition.getFactoryMethodName())
108109
.build();
109110
}
110111

src/test/java/pro/akvel/spring/converter/xml/BeanSupportValidatorTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ public void BeanWithRefBeanWithFactoryProp() {
8585
public void BeanWithSubBeanWithFactory() {
8686
String beanName = "BeanWithSubBeanWithFactory";
8787
BeanDefinition definition = reader.getBeanFactory().get().getBeanDefinition(beanName);
88-
assertEquals(Optional.of(NotSupportBeanType.BEAT_WITH_FACTORY),
88+
assertEquals(Optional.empty(),
8989
validator.isBeanSupport(definition, "test", mockRegistry, false));
9090
}
9191

src/test/java/pro/akvel/spring/converter/xml/ConfigurationDataConverterTest.java

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -816,6 +816,102 @@ public void BeanWithSubBeanProperty() {
816816
assertGeneratedConfigClass(actualObject, bean);
817817
}
818818

819+
@Test
820+
public void BeanWithFactoryMethod() {
821+
String bean = "BeanWithFactoryMethod";
822+
BeanData actualObject = ConfigurationDataConverter.getInstance()
823+
.getConfigurationData(bean, reader.getBeanFactory().get());
824+
825+
var expectedObject = BeanData.builder()
826+
.id(bean)
827+
.className(PACKAGE + bean)
828+
.factoryMethodName("getBean")
829+
.constructorParams(List.of(
830+
ConstructorConstantParam.builder()
831+
.type("java.lang.String")
832+
.value("param")
833+
.build()
834+
))
835+
.build();
836+
837+
assertThat(actualObject).usingRecursiveComparison().isEqualTo(expectedObject);
838+
839+
assertGeneratedConfigClass(actualObject, bean);
840+
}
841+
842+
@Test
843+
public void BeanWithFactoryMethodParamRef() {
844+
String bean = "BeanWithFactoryMethodParamRef";
845+
BeanData actualObject = ConfigurationDataConverter.getInstance()
846+
.getConfigurationData(bean, reader.getBeanFactory().get());
847+
848+
var expectedObject = BeanData.builder()
849+
.id(bean)
850+
.className(PACKAGE + bean)
851+
.factoryMethodName("getBean")
852+
.constructorParams(List.of(
853+
ConstructorBeanParam.builder()
854+
.ref("bean1")
855+
.className(CLASS_BEAN_1)
856+
.build()
857+
))
858+
.build();
859+
860+
assertThat(actualObject).usingRecursiveComparison().isEqualTo(expectedObject);
861+
862+
assertGeneratedConfigClass(actualObject, bean);
863+
}
864+
865+
@Test
866+
public void BeanWithSubBeanWithFactory() {
867+
String bean = "BeanWithSubBeanWithFactory";
868+
BeanData actualObject = ConfigurationDataConverter.getInstance()
869+
.getConfigurationData(bean, reader.getBeanFactory().get());
870+
871+
var expectedObject = BeanData.builder()
872+
.id(bean)
873+
.className(PACKAGE + bean)
874+
.constructorParams(List.of(
875+
ConstructorSubBeanParam.builder()
876+
.beanData(BeanData.builder()
877+
.className("org.springframework.beans.ManagementServerNode")
878+
.factoryMethodName("getManagementServerId")
879+
.build())
880+
.build()
881+
))
882+
.build();
883+
884+
assertThat(actualObject).usingRecursiveComparison().isEqualTo(expectedObject);
885+
886+
assertGeneratedConfigClass(actualObject, bean);
887+
}
888+
889+
@Test
890+
public void BeanWithSubBeanWithFactoryProp() {
891+
String bean = "BeanWithSubBeanWithFactoryProp";
892+
BeanData actualObject = ConfigurationDataConverter.getInstance()
893+
.getConfigurationData(bean, reader.getBeanFactory().get());
894+
895+
var expectedObject = BeanData.builder()
896+
.id(bean)
897+
.className(PACKAGE + bean)
898+
.propertyParams(List.of(
899+
PropertySubBeanParam.builder()
900+
.name("param1")
901+
.beanData(BeanData.builder()
902+
.className("org.springframework.beans.ManagementServerNode")
903+
.factoryMethodName("getManagementServerId")
904+
.build())
905+
.build()
906+
))
907+
.build();
908+
909+
assertThat(actualObject).usingRecursiveComparison().isEqualTo(expectedObject);
910+
911+
assertGeneratedConfigClass(actualObject, bean);
912+
}
913+
914+
819915

820916
@Test
821917
public void BeanWithDependsOnJavaConfiguration() {

src/test/resources/pro/akvel/spring/converter/xml/configs/spring-bean-configuration-full.xml

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -401,13 +401,18 @@
401401
<bean id="BeanWithAutowire" class="org.springframework.beans.BeanWithAutowire" autowire="constructor"/>
402402

403403

404-
<!-- Not supported -->
405-
<bean id="BeanWithSubBeanWithFactory" class="org.springframework.beans.BeanWithSubBeanWithFactory" >
404+
<bean id="BeanWithSubBeanWithFactory" class="pro.akvel.spring.converter.testbean.BeanWithSubBeanWithFactory" >
406405
<constructor-arg>
407406
<bean class="org.springframework.beans.ManagementServerNode" factory-method="getManagementServerId" />
408407
</constructor-arg>
409408
</bean>
410409

410+
<bean id="BeanWithSubBeanWithFactoryProp" class="pro.akvel.spring.converter.testbean.BeanWithSubBeanWithFactoryProp" >
411+
<property name="param1">
412+
<bean class="org.springframework.beans.ManagementServerNode" factory-method="getManagementServerId" />
413+
</property>
414+
</bean>
415+
411416
<!-- Not supported -->
412417
<bean id="BeanWithRefBeanWithFactoryConst" class="org.springframework.beans.BeanWithRefBeanWithFactoryConst" >
413418
<constructor-arg ref="BeanWithFactoryBean"/>
@@ -417,4 +422,13 @@
417422
<bean id="BeanWithRefBeanWithFactoryProp" class="org.springframework.beans.BeanWithRefBeanWithFactoryProp" >
418423
<property name="test" ref="BeanWithFactoryBean"/>
419424
</bean>
425+
426+
427+
<bean id="BeanWithFactoryMethod" class="pro.akvel.spring.converter.testbean.BeanWithFactoryMethod" factory-method="getBean">
428+
<constructor-arg value="param"/>
429+
</bean>
430+
431+
<bean id="BeanWithFactoryMethodParamRef" class="pro.akvel.spring.converter.testbean.BeanWithFactoryMethodParamRef" factory-method="getBean">
432+
<constructor-arg ref="bean1"/>
433+
</bean>
420434
</beans>
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
2+
package pro.akvel.spring.converter.generator;
3+
4+
import org.springframework.context.annotation.Bean;
5+
import org.springframework.context.annotation.Configuration;
6+
7+
8+
/**
9+
* Generated Java based configuration
10+
*
11+
*/
12+
@Configuration
13+
public class BeanWithFactoryMethod {
14+
15+
16+
@Bean("BeanWithFactoryMethod")
17+
public pro.akvel.spring.converter.testbean.BeanWithFactoryMethod BeanWithFactoryMethod() {
18+
return pro.akvel.spring.converter.testbean.BeanWithFactoryMethod.getBean("param");
19+
}
20+
21+
}

0 commit comments

Comments
 (0)