Skip to content

Commit a072f62

Browse files
authored
Make spring-analyzer bean post processor distinguish 3 kinds of beans: @Component-like beans, @Bean-like beans, and XML-like beans (#2178)
1 parent 2c59289 commit a072f62

File tree

1 file changed

+29
-7
lines changed

1 file changed

+29
-7
lines changed

utbot-spring-analyzer/src/main/kotlin/org/utbot/spring/postProcessors/UtBotBeanFactoryPostProcessor.kt

Lines changed: 29 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import com.jetbrains.rd.util.getLogger
44
import com.jetbrains.rd.util.info
55
import com.jetbrains.rd.util.warn
66
import org.springframework.beans.factory.BeanCreationException
7+
import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition
78
import org.springframework.beans.factory.config.BeanFactoryPostProcessor
89
import org.springframework.beans.factory.config.ConfigurableListableBeanFactory
910
import org.springframework.beans.factory.support.BeanDefinitionRegistry
@@ -30,16 +31,37 @@ object UtBotBeanFactoryPostProcessor : BeanFactoryPostProcessor, PriorityOrdered
3031
throw UtBotSpringShutdownException("Finished post-processing bean factory in UtBot", beanQualifiedNames)
3132
}
3233

33-
private fun findBeanClassNames(beanFactory: ConfigurableListableBeanFactory): List<String> {
34-
return beanFactory.beanDefinitionNames.mapNotNull {
35-
try {
36-
beanFactory.getBeanDefinition(it).beanClassName ?: beanFactory.getBean(it).javaClass.name
34+
private fun findBeanClassNames(beanFactory: ConfigurableListableBeanFactory): List<String> =
35+
beanFactory.beanDefinitionNames
36+
.mapNotNull { getBeanFqn(beanFactory, it) }
37+
.filterNot { it.startsWith("org.utbot.spring") }
38+
.distinct()
39+
40+
private fun getBeanFqn(beanFactory: ConfigurableListableBeanFactory, beanName: String): String? {
41+
val beanDefinition = beanFactory.getBeanDefinition(beanName)
42+
return if (beanDefinition is AnnotatedBeanDefinition) {
43+
if (beanDefinition.factoryMethodMetadata == null) {
44+
// there's no factoryMethod so bean is defined with @Component-like annotation rather than @Bean annotation
45+
// same approach isn't applicable for @Bean beans, because for them, it returns name of @Configuration class
46+
beanDefinition.metadata.className.also { fqn ->
47+
logger.info { "Got $fqn as metadata.className for @Component-like bean: $beanName" }
48+
}
49+
} else try {
50+
// TODO to avoid side effects, determine beanClassName without getting bean by analyzing method
51+
// defining bean, for example, by finding all its return statements and determining their common type
52+
// NOTE: do not simply use return type from method signature because it may be an interface type
53+
beanFactory.getBean(beanName)::class.java.name.also { fqn ->
54+
logger.info { "Got $fqn as runtime type for @Bean-like bean: $beanName" }
55+
}
3756
} catch (e: BeanCreationException) {
38-
logger.warn { "Failed to get bean: $it" }
57+
logger.warn { "Failed to get bean: $beanName" }
3958
null
4059
}
41-
}.filterNot { it.startsWith("org.utbot.spring") }
42-
.distinct()
60+
} else {
61+
beanDefinition.beanClassName.also { fqn ->
62+
logger.info { "Got $fqn as beanClassName for XML-like bean: $beanName" }
63+
}
64+
}
4365
}
4466

4567
private fun destroyBeanDefinitions(beanFactory: ConfigurableListableBeanFactory) {

0 commit comments

Comments
 (0)