Skip to content

Commit 93d4dbd

Browse files
committed
Avoid harcoding the names of tables and repositories
1 parent 5a8e1ee commit 93d4dbd

6 files changed

Lines changed: 95 additions & 27 deletions

File tree

utbot-framework/src/main/kotlin/org/utbot/framework/codegen/domain/builtin/SpringBuiltins.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,4 +5,4 @@ import org.utbot.framework.plugin.api.BuiltinClassId
55
internal val autowiredClassId = BuiltinClassId(
66
canonicalName = "org.springframework.beans.factory.annotation.Autowired",
77
simpleName = "Autowired",
8-
)
8+
)

utbot-instrumentation/src/main/kotlin/org/utbot/instrumentation/instrumentation/execution/SpringUtExecutionInstrumentation.kt

Lines changed: 27 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -14,10 +14,12 @@ import org.utbot.instrumentation.instrumentation.Instrumentation
1414
import org.utbot.instrumentation.instrumentation.execution.mock.SpringInstrumentationContext
1515
import org.utbot.instrumentation.instrumentation.execution.phases.ModelConstructionPhase
1616
import org.utbot.instrumentation.process.HandlerClassesLoader
17+
import org.utbot.instrumentation.util.ReflectionUtils
1718
import org.utbot.spring.api.context.ContextWrapper
1819
import org.utbot.spring.api.instantiator.InstantiationSettings
1920
import org.utbot.spring.api.instantiator.ApplicationInstantiatorFacade
2021
import org.utbot.spring.api.repositoryWrapper.RepositoryInteraction
22+
import java.lang.reflect.ParameterizedType
2123
import java.security.ProtectionDomain
2224

2325
/**
@@ -79,22 +81,37 @@ class SpringUtExecutionInstrumentation(
7981
parameters: Any?
8082
): UtConcreteExecutionResult {
8183
RepositoryInteraction.recordedInteractions.clear()
82-
// TODO properly detect which beans need to be reset, right now "orderRepository" and "orderService" are hardcoded
83-
val beanNamesToReset = listOf("orderRepository", "orderService")
8484

85-
beanNamesToReset.forEach { beanNameToReset ->
86-
val beanDefToReset = springContext.getBeanDefinition(beanNameToReset)
87-
springContext.removeBeanDefinition(beanNameToReset)
88-
springContext.registerBeanDefinition(beanNameToReset, beanDefToReset)
89-
}
85+
val relatedBeanDefinitions = springContext.getRelatedBeanTypes(clazz)
86+
val typesFromClass = ReflectionUtils().collectAccessibleTypes(clazz)
87+
88+
//val beanNamesToReset = listOf("orderRepository", "orderService")
89+
val beanNamesToReset = relatedBeanDefinitions
90+
.filter { typesFromClass.any { typeFromClass -> it.beanType.isAssignableFrom(typeFromClass) } }
91+
.map { it.beanName }
92+
93+
beanNamesToReset.forEach { beanNameToReset -> springContext.resetBean(beanNameToReset) }
9094

9195
val jdbcTemplate = getBean("jdbcTemplate")
92-
// TODO properly detect which repositories need to be cleared, right now "orders" is hardcoded
93-
val sql = "TRUNCATE TABLE orders"
96+
97+
//val tableNames = "orders"
98+
val entityNames = relatedBeanDefinitions
99+
.filter {
100+
val implementedInterfaces = it.beanType.genericInterfaces.map { i -> i.javaClass.canonicalName }
101+
"org.springframework.data.repository.Repository" in implementedInterfaces
102+
}
103+
.map { (it.beanType.genericInterfaces[0] as ParameterizedType).actualTypeArguments[0] }
104+
.map { it.typeName }
105+
106+
//TODO: table name may be different from entity name (set with annotation on entity)
107+
//TODO: plural form is not always obtained with "+s", it can be even Person->People
108+
val tableNames = entityNames.map { it + "s" }
109+
110+
val sql = "TRUNCATE TABLE $entityNames"
94111
jdbcTemplate::class.java
95112
.getMethod("execute", sql::class.java)
96113
.invoke(jdbcTemplate, sql)
97-
val sql2 = "ALTER TABLE orders ALTER COLUMN id RESTART WITH 1"
114+
val sql2 = "ALTER TABLE $entityNames ALTER COLUMN id RESTART WITH 1"
98115
jdbcTemplate::class.java
99116
.getMethod("execute", sql::class.java)
100117
.invoke(jdbcTemplate, sql2)
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package org.utbot.instrumentation.util
2+
3+
class ReflectionUtils {
4+
5+
private val collectedFieldTypes = mutableSetOf<Class<*>>()
6+
private val alreadyAnalyzedTypes = mutableSetOf<Class<*>>()
7+
8+
fun collectAccessibleTypes(clazz: Class<*>): Set<Class<*>> {
9+
collectedFieldTypes.clear()
10+
alreadyAnalyzedTypes.clear()
11+
12+
return collectAccessibleFieldTypes(clazz)
13+
}
14+
15+
private fun collectAccessibleFieldTypes(clazz: Class<*>, isTopLevel: Boolean = true): Set<Class<*>> {
16+
if (alreadyAnalyzedTypes.contains(clazz)) {
17+
return emptySet()
18+
}
19+
20+
collectedFieldTypes += collectFieldTypes(clazz)
21+
22+
val fieldTypes = clazz.fields.map { it.type }
23+
for (fieldType in fieldTypes) {
24+
collectedFieldTypes += collectAccessibleFieldTypes(fieldType)
25+
}
26+
27+
return collectedFieldTypes
28+
}
29+
30+
private fun collectFieldTypes(clazz: Class<*>): Set<Class<*>> {
31+
val types = mutableSetOf<Class<*>>()
32+
33+
var current: Class<*> = clazz
34+
while (current.superclass != null) {
35+
types += current.fields.map { it.type }
36+
current = current.superclass
37+
}
38+
39+
return types
40+
}
41+
}

utbot-spring-commons-api/src/main/kotlin/org/utbot/spring/api/context/ContextWrapper.kt

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,14 @@ package org.utbot.spring.api.context
33
interface ContextWrapper {
44
val context: Any?
55

6-
fun getBeanDefinition(beanName: String): Any
6+
fun getBean(beanName: String): Any
77

8-
fun removeBeanDefinition(beanName: String)
8+
fun getRelatedBeanTypes(clazz: Class<*>): Set<SimpleBeanDefinition>
99

10-
fun registerBeanDefinition(beanName: String, beanDefinition: Any)
10+
fun resetBean(beanName: String): Any
11+
}
1112

12-
fun getBean(beanName: String): Any
13-
}
13+
data class SimpleBeanDefinition(
14+
val beanName: String,
15+
val beanType: Class<*>,
16+
)

utbot-spring-commons-api/src/main/kotlin/org/utbot/spring/api/repositoryWrapper/RepositoryInteraction.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,4 @@ data class RepositoryInteraction(
1111
companion object {
1212
val recordedInteractions = mutableListOf<RepositoryInteraction>()
1313
}
14-
}
14+
}
Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,30 @@
11
package org.utbot.spring.context
22

3-
import org.springframework.beans.factory.config.BeanDefinition
43
import org.springframework.beans.factory.support.BeanDefinitionRegistry
54
import org.springframework.context.ConfigurableApplicationContext
65
import org.utbot.spring.api.context.ContextWrapper
6+
import org.utbot.spring.api.context.SimpleBeanDefinition
77

88
class SpringContextWrapper(override val context: ConfigurableApplicationContext) : ContextWrapper {
9-
override fun getBeanDefinition(beanName: String): BeanDefinition = context.beanFactory.getBeanDefinition(beanName)
10-
11-
override fun removeBeanDefinition(beanName: String) {
12-
val beanDefinitionRegistry = context.beanFactory as BeanDefinitionRegistry
13-
beanDefinitionRegistry.removeBeanDefinition(beanName)
9+
override fun getBean(beanName: String): Any = context.getBean(beanName)
10+
override fun getRelatedBeanTypes(clazz: Class<*>): Set<SimpleBeanDefinition> {
11+
val cutName = clazz.canonicalName
12+
return context.beanDefinitionNames
13+
.map { name -> name to context.getBean(name) }
14+
.filter {
15+
val bean = it.second
16+
val typeName = bean.javaClass.canonicalName
17+
typeName != null && cutName.commonPrefixWith(typeName).isNotEmpty()
18+
}
19+
.map { nameToBean -> SimpleBeanDefinition(nameToBean.first, nameToBean.second.javaClass) }
20+
.toSet()
1421
}
1522

16-
override fun registerBeanDefinition(beanName: String, beanDefinition: Any) {
23+
override fun resetBean(beanName: String) {
1724
val beanDefinitionRegistry = context.beanFactory as BeanDefinitionRegistry
18-
beanDefinition as BeanDefinition
25+
26+
val beanDefinition = context.beanFactory.getBeanDefinition(beanName)
27+
beanDefinitionRegistry.removeBeanDefinition(beanName)
1928
beanDefinitionRegistry.registerBeanDefinition(beanName, beanDefinition)
2029
}
21-
22-
override fun getBean(beanName: String): Any = context.getBean(beanName)
2330
}

0 commit comments

Comments
 (0)