@@ -6,6 +6,7 @@ import org.utbot.framework.plugin.api.*
6
6
import org.utbot.framework.plugin.api.util.*
7
7
import org.utbot.framework.plugin.api.visible.UtStreamConsumingException
8
8
import java.lang.reflect.Modifier
9
+ import java.lang.reflect.Proxy
9
10
import java.util.*
10
11
import java.util.stream.BaseStream
11
12
@@ -85,6 +86,52 @@ class UtModelConstructor(
85
86
return UtLambdaModel .createFake(handleId(value), classId, baseClass)
86
87
}
87
88
89
+ private fun isProxy (value : Any? ): Boolean =
90
+ value != null && Proxy .isProxyClass(value::class .java)
91
+
92
+ /* *
93
+ * Using `UtAssembleModel` for dynamic proxies helps to avoid exceptions like
94
+ * `java.lang.ClassNotFoundException: jdk.proxy3.$Proxy184` during code generation.
95
+ */
96
+ private fun constructProxy (value : Any , classId : ClassId ): UtAssembleModel {
97
+ val newProxyInstanceExecutableId = java.lang.reflect.Proxy ::newProxyInstance.executableId
98
+
99
+ // we don't want to construct deep models for invocationHandlers, since they can be quite large
100
+ val argsRemainingDepth = 0L
101
+
102
+ val classLoader = UtAssembleModel (
103
+ id = computeUnusedIdAndUpdate(),
104
+ classId = newProxyInstanceExecutableId.parameters[0 ],
105
+ modelName = " systemClassLoader" ,
106
+ instantiationCall = UtExecutableCallModel (
107
+ instance = null ,
108
+ executable = ClassLoader ::getSystemClassLoader.executableId,
109
+ params = emptyList()
110
+ )
111
+ )
112
+ val interfaces = construct(
113
+ value::class .java.interfaces,
114
+ newProxyInstanceExecutableId.parameters[1 ],
115
+ remainingDepth = argsRemainingDepth
116
+ )
117
+ val invocationHandler = construct(
118
+ Proxy .getInvocationHandler(value),
119
+ newProxyInstanceExecutableId.parameters[2 ],
120
+ remainingDepth = argsRemainingDepth
121
+ )
122
+
123
+ return UtAssembleModel (
124
+ id = handleId(value),
125
+ classId = classId,
126
+ modelName = " dynamicProxy" ,
127
+ instantiationCall = UtExecutableCallModel (
128
+ instance = null ,
129
+ executable = newProxyInstanceExecutableId,
130
+ params = listOf (classLoader, interfaces, invocationHandler)
131
+ )
132
+ )
133
+ }
134
+
88
135
/* *
89
136
* Constructs a UtModel from a concrete [value] with a specific [classId]. The result can be a [UtAssembleModel]
90
137
* as well.
@@ -103,6 +150,9 @@ class UtModelConstructor(
103
150
if (isProxyLambda(value)) {
104
151
return constructFakeLambda(value!! , classId)
105
152
}
153
+ if (isProxy(value)) {
154
+ return constructProxy(value!! , classId)
155
+ }
106
156
return when (value) {
107
157
null -> UtNullModel (classId)
108
158
is Unit -> UtVoidModel
@@ -294,15 +344,19 @@ class UtModelConstructor(
294
344
constructedObjects.getOrElse(value) {
295
345
tryConstructCustomModel(value, remainingDepth)
296
346
? : findEqualValueOfWellKnownType(value)
297
- ?.takeIf { classId.jClass.isInstance(it) }
298
- ?.let { tryConstructCustomModel(it, remainingDepth) }
347
+ ?.takeIf { (_, replacementClassId) -> replacementClassId isSubtypeOf classId }
348
+ ?.let { (replacement, replacementClassId) ->
349
+ // right now replacements only work with `UtAssembleModel`
350
+ (tryConstructCustomModel(replacement, remainingDepth) as ? UtAssembleModel )
351
+ ?.copy(classId = replacementClassId)
352
+ }
299
353
? : constructCompositeModel(value, remainingDepth)
300
354
}
301
355
302
- private fun findEqualValueOfWellKnownType (value : Any ): Any? = when (value) {
303
- is List <* > -> ArrayList (value)
304
- is Set <* > -> LinkedHashSet (value)
305
- is Map <* , * > -> LinkedHashMap (value)
356
+ private fun findEqualValueOfWellKnownType (value : Any ): Pair < Any , ClassId > ? = when (value) {
357
+ is List <* > -> ArrayList (value) to listClassId
358
+ is Set <* > -> LinkedHashSet (value) to setClassId
359
+ is Map <* , * > -> LinkedHashMap (value) to mapClassId
306
360
else -> null
307
361
}
308
362
0 commit comments