@@ -6,6 +6,7 @@ import org.utbot.framework.plugin.api.*
66import org.utbot.framework.plugin.api.util.*
77import org.utbot.framework.plugin.api.visible.UtStreamConsumingException
88import java.lang.reflect.Modifier
9+ import java.lang.reflect.Proxy
910import java.util.*
1011import java.util.stream.BaseStream
1112
@@ -85,6 +86,52 @@ class UtModelConstructor(
8586 return UtLambdaModel .createFake(handleId(value), classId, baseClass)
8687 }
8788
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+
88135 /* *
89136 * Constructs a UtModel from a concrete [value] with a specific [classId]. The result can be a [UtAssembleModel]
90137 * as well.
@@ -103,6 +150,9 @@ class UtModelConstructor(
103150 if (isProxyLambda(value)) {
104151 return constructFakeLambda(value!! , classId)
105152 }
153+ if (isProxy(value)) {
154+ return constructProxy(value!! , classId)
155+ }
106156 return when (value) {
107157 null -> UtNullModel (classId)
108158 is Unit -> UtVoidModel
@@ -294,15 +344,19 @@ class UtModelConstructor(
294344 constructedObjects.getOrElse(value) {
295345 tryConstructCustomModel(value, remainingDepth)
296346 ? : 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+ }
299353 ? : constructCompositeModel(value, remainingDepth)
300354 }
301355
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
306360 else -> null
307361 }
308362
0 commit comments